You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1867 lines
48 KiB
1867 lines
48 KiB
// File: ichnldat.cpp
|
|
//
|
|
// INmChannelData
|
|
//
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <wbguid.h>
|
|
#include <confguid.h>
|
|
#include "pfnt120.h"
|
|
#include "ichnldat.h"
|
|
|
|
static const IID * g_apiidCP[] =
|
|
{
|
|
{&IID_INmChannelDataNotify2},
|
|
{&IID_INmChannelDataNotify},
|
|
{&IID_INmChannelNotify}
|
|
};
|
|
|
|
#define CopyStruct(pDest, pSrc) CopyMemory(pDest, pSrc, sizeof(*(pDest)))
|
|
#define MAX_NM_PEER 256 // Maximum number of NetMeeting Peer applications/users
|
|
|
|
|
|
#ifdef DEBUG /* T.120 Debug utilities */
|
|
LPCTSTR GetGccErrorString(GCCError uErr);
|
|
LPCTSTR GetMcsErrorString(MCSError uErr);
|
|
LPCTSTR GetGccResultString(UINT uErr);
|
|
LPCTSTR GetMcsResultString(UINT uErr);
|
|
#else
|
|
#define GetGccErrorString(uErr) ""
|
|
#define GetMcsErrorString(uErr) ""
|
|
#define GetGccResultString(uErr) ""
|
|
#define GetMcsResultString(uErr) ""
|
|
#endif /* DEBUG */
|
|
|
|
|
|
|
|
// code from nm\ui\conf\cuserdta.cpp:
|
|
static unsigned char H221IDGUID[5] = {H221GUIDKEY0,
|
|
H221GUIDKEY1,
|
|
H221GUIDKEY2,
|
|
H221GUIDKEY3,
|
|
H221GUIDKEY4};
|
|
// Create an H.221 application key with a guid
|
|
VOID NMINTERNAL CreateH221AppKeyFromGuid(LPBYTE lpb, GUID * pguid)
|
|
{
|
|
CopyMemory(lpb, H221IDGUID, sizeof(H221IDGUID));
|
|
CopyMemory(lpb + sizeof(H221IDGUID), pguid, sizeof(GUID));
|
|
}
|
|
|
|
|
|
/* S E T A P P K E Y */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: SetAppKey
|
|
|
|
Set the two pieces of an OctetString (the length and the data.)
|
|
Note that the length always includes the terminating null character.
|
|
----------------------------------------------------------------------------*/
|
|
VOID SetAppKey(LPOSTR pOct, LPBYTE lpb)
|
|
{
|
|
pOct->length = cbKeyApp;
|
|
pOct->value = lpb;
|
|
}
|
|
|
|
/* C R E A T E A P P K E Y */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: CreateAppKey
|
|
|
|
Given a guid and a userid, create the appropriate application key.
|
|
|
|
The key is formated as:
|
|
0xB5 0x00 0x53 0x4C - Microsoft Object Identifier
|
|
0x01 - guid identifier
|
|
<binary guid> - guid data
|
|
<dword node id> - user node id
|
|
----------------------------------------------------------------------------*/
|
|
VOID CreateAppKey(LPBYTE lpb, GUID * pguid, DWORD dwUserId)
|
|
{
|
|
CreateH221AppKeyFromGuid(lpb, pguid);
|
|
CopyMemory(lpb + cbKeyApp - sizeof(DWORD), &dwUserId, sizeof(DWORD));
|
|
|
|
#ifdef DEBUG
|
|
TCHAR szGuid[LENGTH_SZGUID_FORMATTED];
|
|
GuidToSz(pguid, szGuid);
|
|
DbgMsgDc("CreateAppKey: %s %08X", szGuid, dwUserId);
|
|
#endif
|
|
}
|
|
|
|
|
|
/* P M E M B E R F R O M D W U S E R I D */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: PMemberFromDwUserId
|
|
|
|
-------------------------------------------------------------------------*/
|
|
CNmMember * PMemberFromDwUserId(DWORD dwUserId, COBLIST *pList)
|
|
{
|
|
if (NULL != pList)
|
|
{
|
|
POSITION posCurr;
|
|
POSITION pos = pList->GetHeadPosition();
|
|
while (NULL != pos)
|
|
{
|
|
posCurr = pos;
|
|
CNmMember * pMember = (CNmMember *) pList->GetNext(pos);
|
|
if (dwUserId == pMember->GetGCCID())
|
|
{
|
|
pMember->AddRef();
|
|
return pMember;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* A D D N O D E */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: AddNode
|
|
|
|
Add a node to a list.
|
|
Initializes the ObList, if necessary.
|
|
Returns the position in the list or NULL if there was a problem.
|
|
-------------------------------------------------------------------------*/
|
|
POSITION AddNode(PVOID pv, COBLIST ** ppList)
|
|
{
|
|
ASSERT(NULL != ppList);
|
|
if (NULL == *ppList)
|
|
{
|
|
*ppList = new COBLIST();
|
|
if (NULL == *ppList)
|
|
return NULL;
|
|
}
|
|
|
|
return (*ppList)->AddTail(pv);
|
|
}
|
|
|
|
/* R E M O V E N O D E */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: RemoveNode
|
|
|
|
Remove a node from a list.
|
|
Sets pPos to NULL
|
|
-------------------------------------------------------------------------*/
|
|
PVOID RemoveNodePos(POSITION * pPos, COBLIST *pList)
|
|
{
|
|
if ((NULL == pList) || (NULL == pPos))
|
|
return NULL;
|
|
|
|
PVOID pv = pList->RemoveAt(*pPos);
|
|
*pPos = NULL;
|
|
return pv;
|
|
}
|
|
|
|
|
|
/* R E M O V E N O D E */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: RemoveNode
|
|
|
|
-------------------------------------------------------------------------*/
|
|
VOID RemoveNode(PVOID pv, COBLIST * pList)
|
|
{
|
|
ASSERT(NULL != pv);
|
|
|
|
if (NULL != pList)
|
|
{
|
|
POSITION pos = pList->GetPosition(pv);
|
|
RemoveNodePos(&pos, pList);
|
|
}
|
|
}
|
|
|
|
VOID CNmChannelData::InitCT120Channel(DWORD dwUserId)
|
|
{
|
|
m_dwUserId = dwUserId;
|
|
m_gcc_conference_id = 0;
|
|
m_gcc_pIAppSap = NULL;
|
|
m_mcs_channel_id = 0;
|
|
m_pmcs_sap = NULL;
|
|
m_gcc_node_id = 0;
|
|
m_scs = SCS_UNINITIALIZED;
|
|
|
|
m_pGuid = PGuid();
|
|
ASSERT((NULL != m_pGuid) && (GUID_NULL != *m_pGuid));
|
|
|
|
CreateAppKey(m_keyApp, m_pGuid, 0);
|
|
CreateAppKey(m_keyChannel, m_pGuid, dwUserId);
|
|
|
|
// initialize other gcc & mcs stuff
|
|
GCCObjectKey FAR * pObjKey;
|
|
ClearStruct(&m_gcc_session_key);
|
|
pObjKey = &(m_gcc_session_key.application_protocol_key);
|
|
pObjKey->key_type = GCC_H221_NONSTANDARD_KEY;
|
|
SetAppKey(&(pObjKey->h221_non_standard_id), m_keyApp);
|
|
ASSERT(0 == m_gcc_session_key.session_id);
|
|
|
|
ClearStruct(&m_gcc_registry_item);
|
|
ClearStruct(&m_gcc_registry_key);
|
|
CopyStruct(&m_gcc_registry_key.session_key, &m_gcc_session_key);
|
|
SetAppKey(&m_gcc_registry_key.resource_id, m_keyApp);
|
|
|
|
ClearStruct(&m_registry_item_Private);
|
|
ClearStruct(&m_registry_key_Private);
|
|
CopyStruct(&m_registry_key_Private.session_key, &m_gcc_session_key);
|
|
SetAppKey(&m_registry_key_Private.resource_id, m_keyChannel);
|
|
|
|
UpdateScState(SCS_UNINITIALIZED, 0);
|
|
}
|
|
|
|
|
|
/* C L O S E C H A N N E L */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: CloseChannel
|
|
|
|
Close the channel.
|
|
|
|
Note there are no confirm messages expected for any of the GCC/MCS calls.
|
|
----------------------------------------------------------------------------*/
|
|
VOID CNmChannelData::CloseChannel(void)
|
|
{
|
|
GCCError gccError = GCC_NO_ERROR;
|
|
MCSError mcsError = MCS_NO_ERROR;
|
|
|
|
if (SCS_UNINITIALIZED == m_scs)
|
|
{
|
|
WARNING_OUT(("in CT120Channel::CloseChannel, m_scs is SCS_UNINITIALIZED, is this OK?"));
|
|
return;
|
|
}
|
|
|
|
DbgMsgDc("CT120Channel::CloseChannel %08X (userHandle=%p)", m_mcs_channel_id, m_pmcs_sap);
|
|
|
|
m_scs = SCS_TERMINATING;
|
|
|
|
if (0 != m_mcs_channel_id)
|
|
{
|
|
ASSERT (m_pmcs_sap);
|
|
mcsError = m_pmcs_sap->ChannelLeave(m_mcs_channel_id);
|
|
DbgMsgDc("CT120Channel::CloseChannel: ChannelLeave %s", GetMcsErrorString(mcsError));
|
|
m_mcs_channel_id = 0;
|
|
}
|
|
|
|
if (NULL != m_pmcs_sap)
|
|
{
|
|
mcsError = m_pmcs_sap->ReleaseInterface();
|
|
DbgMsgDc("CT120Channel::CloseChannel: MCS ReleaseInterface %s", GetMcsErrorString(mcsError));
|
|
m_pmcs_sap = NULL;
|
|
}
|
|
|
|
if (NULL != m_gcc_pIAppSap)
|
|
{
|
|
m_gcc_pIAppSap->RegistryDeleteEntry(m_gcc_conference_id, &m_registry_key_Private);
|
|
// ignore the above result
|
|
|
|
m_gcc_pIAppSap->ReleaseInterface();
|
|
DbgMsgDc("CT120Channel::CloseChannel: GCCDeleteSap %s", GetGccErrorString(gccError));
|
|
m_gcc_pIAppSap = NULL;
|
|
}
|
|
|
|
m_scs = SCS_UNINITIALIZED;
|
|
m_gcc_conference_id = 0;
|
|
|
|
// make sure no one is around
|
|
UpdateRoster(NULL, 0, FALSE, TRUE /* fRemove */);;
|
|
}
|
|
|
|
|
|
/* U P D A T E S C S T A T E */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: UpdateScState
|
|
|
|
The system progresses from one state to another
|
|
by making an GCC (or MCS) call that is guarenteed to
|
|
produce a notification that calls this function.
|
|
The calling process is released by UnBlockThread.
|
|
----------------------------------------------------------------------------*/
|
|
VOID CNmChannelData::UpdateScState(SCSTATE scs, DWORD dwErr)
|
|
{
|
|
DBGENTRY(CNmChannelData::UpdateScState)
|
|
if (m_scs != scs)
|
|
{
|
|
WARNING_OUT(("UpdateScState - invalid state transition (%d - %d)", m_scs, scs));
|
|
dwErr = INVALID_T120_ERROR; // We should never get here
|
|
}
|
|
|
|
if (0 == dwErr)
|
|
{
|
|
switch (m_scs)
|
|
{
|
|
case SCS_UNINITIALIZED:
|
|
dwErr = DoCreateSap();
|
|
break;
|
|
case SCS_CREATESAP:
|
|
dwErr = DoAttach();
|
|
break;
|
|
case SCS_ATTACH:
|
|
dwErr = DoEnroll();
|
|
break;
|
|
case SCS_ENROLL:
|
|
dwErr = DoJoinPrivate();
|
|
break;
|
|
case SCS_JOIN_PRIVATE:
|
|
dwErr = DoRegRetrieve();
|
|
break;
|
|
case SCS_REGRETRIEVE_NEW:
|
|
dwErr = DoJoinNew();
|
|
break;
|
|
case SCS_REGRETRIEVE_EXISTS:
|
|
dwErr = DoJoinOld();
|
|
break;
|
|
case SCS_JOIN_NEW:
|
|
dwErr = DoRegChannel();
|
|
break;
|
|
case SCS_REGCHANNEL:
|
|
case SCS_JOIN_OLD:
|
|
dwErr = DoRegPrivate();
|
|
break;
|
|
case SCS_REGPRIVATE:
|
|
DbgMsgDc(">>>>>>>>>>>UpdateScState: Complete");
|
|
m_scs = SCS_CONNECTED;
|
|
NotifyChannelConnected();
|
|
break;
|
|
case SCS_CONNECTED:
|
|
case SCS_REGRETRIEVE:
|
|
// we should never be called when we're in these states
|
|
// so, treat it as an error and fall thru to the default case
|
|
default:
|
|
dwErr = INVALID_T120_ERROR; // We should never get here
|
|
break;
|
|
}
|
|
}
|
|
|
|
DbgMsgDc("UpdateScState: New state (%d) channelId=%04X", m_scs, GetMcsChannelId());
|
|
|
|
if (0 != dwErr)
|
|
{
|
|
WARNING_OUT(("UpdateScState: Err=%d", dwErr));
|
|
CloseConnection();
|
|
}
|
|
|
|
DBGEXIT(CNmChannelData::UpdateScState)
|
|
}
|
|
|
|
DWORD CNmChannelData::DoCreateSap(void)
|
|
{
|
|
ASSERT(SCS_UNINITIALIZED == m_scs);
|
|
m_scs = SCS_CREATESAP;
|
|
|
|
GCCError gccError = PFNT120::CreateAppSap(&m_gcc_pIAppSap, this, NmGccMsgHandler);
|
|
DbgMsgDc("GCCCreateSap err=%s", GetGccErrorString(gccError));
|
|
return (DWORD) gccError;
|
|
}
|
|
|
|
DWORD CNmChannelData::DoAttach(void)
|
|
{
|
|
ASSERT(SCS_CREATESAP == m_scs);
|
|
m_scs = SCS_ATTACH;
|
|
|
|
MCSError mcsError = PFNT120::AttachRequest(&m_pmcs_sap,
|
|
(DomainSelector) &m_gcc_conference_id,
|
|
sizeof(m_gcc_conference_id),
|
|
NmMcsMsgHandler,
|
|
this,
|
|
ATTACHMENT_DISCONNECT_IN_DATA_LOSS | ATTACHMENT_MCS_FREES_DATA_IND_BUFFER);
|
|
// This generates an async MCS_ATTACH_USER_CONFIRM
|
|
|
|
DbgMsgDc("MCS_AttachRequest err=%s", GetMcsErrorString(mcsError));
|
|
return (DWORD) mcsError;
|
|
}
|
|
|
|
DWORD CNmChannelData::DoEnroll(void)
|
|
{
|
|
ASSERT(SCS_ATTACH == m_scs || SCS_JOIN_STATIC_CHANNEL);
|
|
m_scs = SCS_ENROLL;
|
|
|
|
GCCEnrollRequest er;
|
|
GCCRequestTag nReqTag;
|
|
|
|
if(m_pGCCER)
|
|
{
|
|
m_pGCCER->pSessionKey = &m_gcc_session_key;
|
|
m_pGCCER->nUserID = m_mcs_sender_id;
|
|
|
|
}
|
|
else
|
|
{
|
|
// fill in enroll request structure
|
|
::ZeroMemory(&er, sizeof(er));
|
|
er.pSessionKey = &m_gcc_session_key;
|
|
er.fEnrollActively = TRUE;
|
|
er.nUserID = m_mcs_sender_id;
|
|
// er.fConductingCapabable = FALSE;
|
|
er.nStartupChannelType = MCS_DYNAMIC_MULTICAST_CHANNEL;
|
|
// er.cNonCollapsedCaps = 0;
|
|
// er.apNonCollapsedCaps = NULL;
|
|
// er.cCollapsedCaps = 0;
|
|
// er.apCollapsedCaps = NULL;
|
|
er.fEnroll = TRUE;
|
|
}
|
|
|
|
GCCError gccError = m_gcc_pIAppSap->AppEnroll(m_gcc_conference_id, m_pGCCER != NULL ? m_pGCCER : &er, &nReqTag);
|
|
|
|
DbgMsgDc("GCCApplicationEnrollRequest err=%s", GetGccErrorString(gccError));
|
|
|
|
if (GCC_NO_ERROR != gccError)
|
|
{
|
|
ERROR_OUT(("DoEnroll failed - WHY?"));
|
|
}
|
|
|
|
return (DWORD) gccError;
|
|
}
|
|
|
|
// Join the PRIVATE data channel (m_mcs_sender_id)
|
|
DWORD CNmChannelData::DoJoinPrivate(void)
|
|
{
|
|
ASSERT(SCS_ENROLL == m_scs || SCS_ATTACH == m_scs);
|
|
m_scs = SCS_JOIN_PRIVATE;
|
|
|
|
MCSError mcsError = m_pmcs_sap->ChannelJoin(m_mcs_sender_id);
|
|
// This generates an async MCS_CHANNEL_JOIN_CONFIRM
|
|
|
|
DbgMsgDc("MCSChannelJoinRequest (private) %04X, err=%s",
|
|
m_mcs_sender_id, GetMcsErrorString(mcsError));
|
|
return (DWORD) mcsError;
|
|
}
|
|
|
|
|
|
DWORD CNmChannelData::DoRegRetrieve(void)
|
|
{
|
|
ASSERT(SCS_JOIN_PRIVATE == m_scs);
|
|
m_scs = SCS_REGRETRIEVE;
|
|
|
|
GCCError gccError = m_gcc_pIAppSap->RegistryRetrieveEntry(
|
|
m_gcc_conference_id, &m_gcc_registry_key);
|
|
// This generates an async GCC_RETRIEVE_ENTRY_CONFIRM
|
|
|
|
DbgMsgDc("GCCRegistryRetrieveEntryRequest err=%s", GetGccErrorString(gccError));
|
|
return (DWORD) gccError;
|
|
}
|
|
|
|
// Register the PUBLIC channel
|
|
DWORD CNmChannelData::DoRegChannel(void)
|
|
{
|
|
ASSERT(SCS_JOIN_NEW == m_scs);
|
|
m_scs = SCS_REGCHANNEL;
|
|
|
|
GCCError gccError = m_gcc_pIAppSap->RegisterChannel(
|
|
m_gcc_conference_id, &m_gcc_registry_key, m_mcs_channel_id);
|
|
// This generates an async GCC_REGISTER_CHANNEL_CONFIRM
|
|
|
|
DbgMsgDc("GCCRegisterChannelRequest err=%s", GetGccErrorString(gccError));
|
|
return (DWORD) gccError;
|
|
}
|
|
|
|
DWORD CNmChannelData::DoJoinStatic(ChannelID staticChannel)
|
|
{
|
|
m_scs = SCS_JOIN_STATIC_CHANNEL;
|
|
MCSError mcsError = m_pmcs_sap->ChannelJoin(staticChannel);
|
|
// This generates an async MCS_CHANNEL_JOIN_CONFIRM
|
|
|
|
DbgMsgDc("MCSChannelJoinRequest %04X, err=%s",
|
|
staticChannel, GetMcsErrorString(mcsError));
|
|
return (DWORD) mcsError;
|
|
}
|
|
|
|
DWORD CNmChannelData::DoJoin(SCSTATE scs)
|
|
{
|
|
m_scs = scs;
|
|
|
|
MCSError mcsError = m_pmcs_sap->ChannelJoin(m_mcs_channel_id);
|
|
// This generates an async MCS_CHANNEL_JOIN_CONFIRM
|
|
|
|
DbgMsgDc("MCSChannelJoinRequest %04X, err=%s",
|
|
m_mcs_channel_id, GetMcsErrorString(mcsError));
|
|
return (DWORD) mcsError;
|
|
}
|
|
|
|
DWORD CNmChannelData::DoJoinNew(void)
|
|
{
|
|
ASSERT(0 == m_mcs_channel_id);
|
|
ASSERT(SCS_REGRETRIEVE_NEW == m_scs);
|
|
return DoJoin(SCS_JOIN_NEW);
|
|
}
|
|
|
|
DWORD CNmChannelData::DoJoinOld(void)
|
|
{
|
|
ASSERT(0 != m_mcs_channel_id);
|
|
ASSERT(SCS_REGRETRIEVE_EXISTS == m_scs);
|
|
return DoJoin(SCS_JOIN_OLD);
|
|
}
|
|
|
|
|
|
// Register the PRIVATE data channel. (m_mcs_sender_id)
|
|
DWORD CNmChannelData::DoRegPrivate(void)
|
|
{
|
|
ASSERT(0 != m_mcs_sender_id);
|
|
ASSERT((SCS_REGCHANNEL == m_scs) || (SCS_JOIN_OLD == m_scs));
|
|
m_scs = SCS_REGPRIVATE;
|
|
|
|
DbgMsgDc("DoRegPrivate: channelId %04X as private for %08X", m_mcs_sender_id, m_dwUserId);
|
|
|
|
GCCError gccError = m_gcc_pIAppSap->RegisterChannel(
|
|
m_gcc_conference_id, &m_registry_key_Private, m_mcs_sender_id);
|
|
// This generates an async GCC_REGISTER_CHANNEL_CONFIRM
|
|
|
|
DbgMsgDc("GCCRegisterChannelRequest err=%s", GetGccErrorString(gccError));
|
|
return (DWORD) gccError;
|
|
}
|
|
|
|
|
|
// deal with a GCC_RETRIEVE_ENTRY_CONFIRM notification
|
|
VOID CNmChannelData::ProcessEntryConfirm(GCCAppSapMsg * pMsg)
|
|
{
|
|
if (pMsg->RegistryConfirm.pRegKey->resource_id.length >=
|
|
m_gcc_registry_key.resource_id.length
|
|
&&
|
|
0 != memcmp(m_gcc_registry_key.resource_id.value,
|
|
pMsg->RegistryConfirm.pRegKey->resource_id.value,
|
|
m_gcc_registry_key.resource_id.length))
|
|
{
|
|
OnEntryConfirmRemote(pMsg);
|
|
}
|
|
else
|
|
{
|
|
OnEntryConfirmLocal(pMsg);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// deal with a GCC_REGISTRY_HANDLE_CONFIRM notification
|
|
VOID CNmChannelData::ProcessHandleConfirm(GCCAppSapMsg * pMsg)
|
|
{
|
|
ASSERT(NULL != pMsg);
|
|
NotifySink(&pMsg->RegAllocHandleConfirm, OnAllocateHandleConfirm);
|
|
}
|
|
|
|
|
|
VOID CNmChannelData::OnEntryConfirmRemote(GCCAppSapMsg * pMsg)
|
|
{
|
|
DWORD dwUserId;
|
|
ASSERT(cbKeyApp ==
|
|
pMsg->RegistryConfirm.pRegKey->resource_id.length);
|
|
CopyMemory(&dwUserId,
|
|
pMsg->RegistryConfirm.pRegKey->resource_id.value +
|
|
cbKeyApp - sizeof(DWORD), sizeof(DWORD));
|
|
|
|
DbgMsgDc("GCC_RETRIEVE_ENTRY_CONFIRM: user private channelId = %04X for userId=%04X result=%s",
|
|
pMsg->RegistryConfirm.pRegItem->channel_id, dwUserId,
|
|
GetGccResultString(pMsg->RegistryConfirm.nResult));
|
|
|
|
if (GCC_RESULT_SUCCESSFUL == pMsg->RegistryConfirm.nResult)
|
|
{
|
|
UpdateMemberChannelId(dwUserId,
|
|
pMsg->RegistryConfirm.pRegItem->channel_id);
|
|
}
|
|
else
|
|
{
|
|
CNmMemberId * pMemberId = GetMemberId(dwUserId);
|
|
if (NULL != pMemberId)
|
|
{
|
|
UINT cCount = pMemberId->GetCheckIdCount();
|
|
if (0 == cCount)
|
|
{
|
|
DbgMsgDc("CT120Channel: No more ChannelId requests %08X", dwUserId);
|
|
}
|
|
else
|
|
{
|
|
cCount--;
|
|
DbgMsgDc("CT120Channel: Request Count for %08X = %0d", dwUserId, cCount);
|
|
pMemberId->SetCheckIdCount(cCount);
|
|
|
|
// BUGBUG: T.120 should notify us when this information is available
|
|
RequestChannelId(dwUserId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID CNmChannelData::OnEntryConfirmLocal(GCCAppSapMsg * pMsg)
|
|
{
|
|
DbgMsgDc("GCC_RETRIEVE_ENTRY_CONFIRM: public channelId = %04X result=%s",
|
|
pMsg->RegistryConfirm.pRegItem->channel_id,
|
|
GetGccResultString(pMsg->RegistryConfirm.nResult));
|
|
|
|
// Processing initial request for guid channel information
|
|
ASSERT(sizeof(m_gcc_registry_item) == sizeof(*(pMsg->RegistryConfirm.pRegItem)));
|
|
CopyMemory(&m_gcc_registry_item, pMsg->RegistryConfirm.pRegItem,
|
|
sizeof(m_gcc_registry_item));
|
|
if (GCC_RESULT_SUCCESSFUL == pMsg->RegistryConfirm.nResult)
|
|
{
|
|
|
|
m_mcs_channel_id = m_gcc_registry_item.channel_id;
|
|
ASSERT(SCS_REGRETRIEVE == m_scs);
|
|
m_scs = SCS_REGRETRIEVE_EXISTS;
|
|
UpdateScState(SCS_REGRETRIEVE_EXISTS, 0);
|
|
}
|
|
else if (GCC_RESULT_ENTRY_DOES_NOT_EXIST == pMsg->RegistryConfirm.nResult)
|
|
{
|
|
DbgMsgDc(" channel does not exist - proceeding to new state");
|
|
ASSERT(0 == m_mcs_channel_id);
|
|
ASSERT(SCS_REGRETRIEVE == m_scs);
|
|
m_scs = SCS_REGRETRIEVE_NEW;
|
|
UpdateScState(SCS_REGRETRIEVE_NEW, 0);
|
|
}
|
|
}
|
|
|
|
|
|
// deal with a GCC_APP_ROSTER_REPORT_INDICATION
|
|
BOOL CNmChannelData::UpdateRoster(GCCAppSapMsg * pMsg)
|
|
{
|
|
UINT iRoster;
|
|
GCCApplicationRoster * lpAppRoster;
|
|
int iRecord;
|
|
GCCApplicationRecord * lpAppRecord;
|
|
DWORD dwUserId;
|
|
UCID rgPeerTemp[MAX_NM_PEER];
|
|
int cPeer;
|
|
int i;
|
|
BOOL fAdd = FALSE;
|
|
BOOL fRemove = FALSE;
|
|
BOOL fLocal = FALSE;
|
|
|
|
DbgMsgDc("CT120Channel::UpdateRoster: conf=%d, roster count=%d",
|
|
pMsg->AppRosterReportInd.nConfID,
|
|
pMsg->AppRosterReportInd.cRosters);
|
|
|
|
ZeroMemory(rgPeerTemp, sizeof(rgPeerTemp));
|
|
|
|
/* Create rgPeerTemp[], cPeer */
|
|
cPeer = 0;
|
|
for (iRoster = 0;
|
|
iRoster < pMsg->AppRosterReportInd.cRosters;
|
|
iRoster++)
|
|
{
|
|
lpAppRoster = pMsg->AppRosterReportInd.apAppRosters[iRoster];
|
|
if (lpAppRoster->session_key.session_id != m_gcc_session_key.session_id)
|
|
continue;
|
|
|
|
// Must pay attention to these flags to avoid GCC weirdness
|
|
if (lpAppRoster->nodes_were_added)
|
|
fAdd = TRUE;
|
|
if (lpAppRoster->nodes_were_removed)
|
|
fRemove = TRUE;
|
|
|
|
for (iRecord = 0;
|
|
iRecord < lpAppRoster->number_of_records;
|
|
iRecord++)
|
|
{
|
|
lpAppRecord = lpAppRoster->application_record_list[iRecord];
|
|
TRACE_OUT(("Node=%X, Entity=%X, AppId=%X", lpAppRecord->node_id,
|
|
lpAppRecord->entity_id, lpAppRecord->application_user_id));
|
|
|
|
// Search for the node in the list
|
|
dwUserId = lpAppRecord->node_id;
|
|
|
|
//
|
|
// Check for local node
|
|
//
|
|
fLocal |= (dwUserId == m_dwUserIdLocal);
|
|
|
|
for (i = 0; i < cPeer; i++)
|
|
{
|
|
if (dwUserId == rgPeerTemp[i].dwUserId)
|
|
break;
|
|
}
|
|
if (i >= cPeer)
|
|
{
|
|
if (cPeer >= MAX_NM_PEER)
|
|
continue; // over our limit!
|
|
|
|
// Add the node to our new list
|
|
rgPeerTemp[cPeer++].dwUserId = dwUserId;
|
|
}
|
|
|
|
|
|
// Make sure we know the sender_id's
|
|
if (MCS_DYNAMIC_PRIVATE_CHANNEL == lpAppRecord->startup_channel_type)
|
|
{
|
|
rgPeerTemp[i].sender_id_private = lpAppRecord->application_user_id;
|
|
}
|
|
else
|
|
{
|
|
rgPeerTemp[i].sender_id_public = lpAppRecord->application_user_id;
|
|
}
|
|
}
|
|
|
|
break; // out of for (iRoster) loop
|
|
}
|
|
|
|
UpdateRoster(rgPeerTemp, cPeer, fAdd, fRemove);
|
|
|
|
return (fAdd && fLocal);
|
|
}
|
|
|
|
|
|
/* H R S E N D D A T A */
|
|
/*----------------------------------------------------------------------------
|
|
%%Function: HrSendData
|
|
|
|
Send data on a specific channel
|
|
----------------------------------------------------------------------------*/
|
|
HRESULT CNmChannelData::HrSendData(ChannelID channel_id, DWORD dwUserId, LPVOID lpv, DWORD cb, DWORD dwFlags)
|
|
{
|
|
DbgMsgDc("CT120Channel::HrSendData: %d bytes", cb);
|
|
|
|
|
|
|
|
PDUPriority priority = MEDIUM_PRIORITY;
|
|
SendDataFlags allocation = APP_ALLOCATION;
|
|
DataRequestType requestType = NORMAL_SEND_DATA;
|
|
|
|
if(dwFlags)
|
|
{
|
|
if(dwFlags & TOP_PRIORITY_MASK)
|
|
{
|
|
priority = TOP_PRIORITY;
|
|
}
|
|
else if (dwFlags & HIGH_PRIORITY_MASK)
|
|
{
|
|
priority = HIGH_PRIORITY;
|
|
}
|
|
else if (dwFlags & LOW_PRIORITY_MASK)
|
|
{
|
|
priority = LOW_PRIORITY;
|
|
}
|
|
|
|
if (dwFlags & UNIFORM_SEND_DATA_MASK)
|
|
{
|
|
requestType = UNIFORM_SEND_DATA;
|
|
}
|
|
|
|
if (dwFlags & MCS_ALLOCATION_MASK)
|
|
{
|
|
allocation = MCS_ALLOCATION;
|
|
}
|
|
}
|
|
|
|
if ((0 == m_mcs_channel_id) || (NULL == m_pmcs_sap) || (0 == channel_id))
|
|
{
|
|
WARNING_OUT(("*** Attempted to send data on invalid channel"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
MCSError mcsError = m_pmcs_sap->SendData(requestType, channel_id, priority,
|
|
(unsigned char *)lpv, cb, allocation);
|
|
|
|
if (0 != mcsError)
|
|
{
|
|
TRACE_OUT(("SendData err=%s", GetMcsErrorString(mcsError)));
|
|
// Usually MCS_TRANSMIT_BUFFER_FULL
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
{ // Inform the app the data has been sent
|
|
NMN_DATA_XFER nmnData;
|
|
nmnData.pMember = NULL;
|
|
nmnData.pb = (LPBYTE) lpv;
|
|
nmnData.cb = cb;
|
|
nmnData.dwFlags = 0;
|
|
|
|
if (0 == dwUserId)
|
|
{
|
|
// send out notification with NULL member (BROADCAST)
|
|
NotifySink(&nmnData, OnNmDataSent);
|
|
}
|
|
else
|
|
{
|
|
nmnData.pMember = (INmMember *) PMemberFromDwUserId(dwUserId, GetMemberList());
|
|
if (nmnData.pMember)
|
|
{
|
|
NotifySink(&nmnData, OnNmDataSent);
|
|
nmnData.pMember->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE_OUT(("SendData completed successfully"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// Ask GCC for the private channel id.
|
|
VOID CNmChannelData::RequestChannelId(DWORD dwUserId)
|
|
{
|
|
BYTE keyChannel[cbKeyApp];
|
|
GCCRegistryKey registry_key;
|
|
|
|
DbgMsgDc("Requesting channel id for %08X", dwUserId);
|
|
|
|
CopyStruct(®istry_key.session_key, &m_gcc_session_key);
|
|
CreateAppKey(keyChannel, m_pGuid, dwUserId);
|
|
SetAppKey(®istry_key.resource_id, keyChannel);
|
|
|
|
GCCError gccError = m_gcc_pIAppSap->RegistryRetrieveEntry(
|
|
m_gcc_conference_id, ®istry_key);
|
|
// This generates an async GCC_RETRIEVE_ENTRY_CONFIRM
|
|
|
|
if (0 != gccError)
|
|
{
|
|
WARNING_OUT(("RequestChannelId - problem with GCCRegistryRectreiveEntryRequest"));
|
|
}
|
|
}
|
|
|
|
|
|
VOID CNmChannelData::NotifyChannelConnected(void)
|
|
{
|
|
DBGENTRY(CNmChannelData::NotifyChannelConnected);
|
|
if (S_OK != IsActive())
|
|
{
|
|
CConfObject * pConference = PConference();
|
|
if (NULL != pConference)
|
|
{
|
|
m_fActive = TRUE;
|
|
|
|
TRACE_OUT(("The channel is now officially active"));
|
|
// The channel is now officially active
|
|
pConference->OnChannelUpdated(this);
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("PConference is NULL!"));
|
|
|
|
}
|
|
}
|
|
DBGEXIT(CNmChannelData::NotifyChannelConnected);
|
|
}
|
|
|
|
|
|
/* N M G C C M S G H A N D L E R */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: NmGccMsgHandler
|
|
|
|
-------------------------------------------------------------------------*/
|
|
void CALLBACK NmGccMsgHandler(GCCAppSapMsg * pMsg)
|
|
{
|
|
TRACE_OUT(("NmGccMsgHandler: [%d]", pMsg->eMsgType));
|
|
|
|
CNmChannelData * psc = (CNmChannelData *) (pMsg->pAppData);
|
|
ASSERT(NULL != psc);
|
|
psc->AddRef();
|
|
|
|
switch (pMsg->eMsgType)
|
|
{
|
|
case GCC_PERMIT_TO_ENROLL_INDICATION:
|
|
TRACE_OUT((" m_conference_id = %X", pMsg->AppPermissionToEnrollInd.nConfID));
|
|
TRACE_OUT((" permission = %X", pMsg->AppPermissionToEnrollInd.fPermissionGranted));
|
|
if ((SCS_CONNECTED == psc->m_scs) &&
|
|
(0 == pMsg->AppPermissionToEnrollInd.fPermissionGranted))
|
|
{
|
|
psc->CloseConnection();
|
|
break;
|
|
}
|
|
|
|
if (SCS_CREATESAP != psc->m_scs)
|
|
{
|
|
TRACE_OUT((" ignoring Enroll Indication"));
|
|
break;
|
|
}
|
|
psc->m_gcc_conference_id = pMsg->AppPermissionToEnrollInd.nConfID;
|
|
psc->UpdateScState(SCS_CREATESAP, !pMsg->AppPermissionToEnrollInd.fPermissionGranted);
|
|
break;
|
|
|
|
case GCC_ENROLL_CONFIRM:
|
|
TRACE_OUT((" result = %s", GetGccResultString(pMsg->AppEnrollConfirm.nResult)));
|
|
|
|
if (GCC_RESULT_SUCCESSFUL == pMsg->AppEnrollConfirm.nResult)
|
|
{
|
|
TRACE_OUT((" m_conference_id = %X", pMsg->AppEnrollConfirm.nConfID));
|
|
TRACE_OUT((" entity_id = %X", pMsg->AppEnrollConfirm.eidMyself));
|
|
TRACE_OUT((" node_id = %X", pMsg->AppEnrollConfirm.nidMyself));
|
|
psc->m_gcc_node_id = pMsg->AppEnrollConfirm.nidMyself;
|
|
}
|
|
break;
|
|
|
|
case GCC_APP_ROSTER_REPORT_INDICATION:
|
|
if(psc->UpdateRoster(pMsg) && psc->m_scs == SCS_ENROLL)
|
|
{
|
|
psc->UpdateScState(SCS_ENROLL, GCC_RESULT_SUCCESSFUL);
|
|
}
|
|
break;
|
|
|
|
case GCC_REGISTER_CHANNEL_CONFIRM:
|
|
DbgMsgDc("GCC_REGISTER_CHANNEL_CONFIRM: channel id = %04X result = %s",
|
|
pMsg->RegistryConfirm.pRegItem->channel_id,
|
|
GetGccResultString(pMsg->RegistryConfirm.nResult));
|
|
if (GCC_RESULT_SUCCESSFUL == pMsg->RegistryConfirm.nResult)
|
|
{
|
|
if (psc->GetMcsChannelId() ==
|
|
pMsg->RegistryConfirm.pRegItem->channel_id)
|
|
{
|
|
ASSERT((0 == psc->m_gcc_registry_item.item_type) ||
|
|
(GCC_REGISTRY_NONE == psc->m_gcc_registry_item.item_type));
|
|
|
|
ASSERT(sizeof(psc->m_gcc_registry_item) == sizeof(*(pMsg->RegistryConfirm.pRegItem)));
|
|
CopyMemory(&psc->m_gcc_registry_item, pMsg->RegistryConfirm.pRegItem,
|
|
sizeof(psc->m_gcc_registry_item));
|
|
}
|
|
else
|
|
{
|
|
ASSERT(psc->SenderChannelId() ==
|
|
pMsg->RegistryConfirm.pRegItem->channel_id);
|
|
ASSERT(0 == psc->m_registry_item_Private.item_type);
|
|
|
|
ASSERT(sizeof(psc->m_registry_item_Private) == sizeof(*(pMsg->RegistryConfirm.pRegItem)));
|
|
CopyMemory(&psc->m_registry_item_Private, pMsg->RegistryConfirm.pRegItem,
|
|
sizeof(psc->m_registry_item_Private));
|
|
}
|
|
}
|
|
ASSERT((SCS_REGCHANNEL == psc->m_scs) || (SCS_REGPRIVATE == psc->m_scs));
|
|
psc->UpdateScState(psc->m_scs, pMsg->RegistryConfirm.nResult);
|
|
break;
|
|
|
|
case GCC_RETRIEVE_ENTRY_CONFIRM:
|
|
psc->ProcessEntryConfirm(pMsg);
|
|
break;
|
|
|
|
case GCC_ALLOCATE_HANDLE_CONFIRM:
|
|
psc->ProcessHandleConfirm(pMsg);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
psc->Release();
|
|
}
|
|
|
|
|
|
|
|
/* N M M C S M S G H A N D L E R */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: NmMcsMsgHandler
|
|
|
|
-------------------------------------------------------------------------*/
|
|
void CALLBACK NmMcsMsgHandler(unsigned int uMsg, LPARAM lParam, PVOID pv)
|
|
{
|
|
CNmChannelData * psc = (CNmChannelData *) pv;
|
|
ASSERT(NULL != psc);
|
|
// TRACE_OUT(("[%s]", GetMcsMsgString(uMsg)));
|
|
psc->AddRef();
|
|
|
|
switch (uMsg)
|
|
{
|
|
case MCS_ATTACH_USER_CONFIRM:
|
|
{
|
|
DbgMsgDc("MCS_ATTACH_USER_CONFIRM channelId=%04X result=%s",
|
|
LOWORD(lParam), GetMcsResultString(HIWORD(lParam) ));
|
|
if (RESULT_SUCCESSFUL == HIWORD(lParam))
|
|
{
|
|
DbgMsgDc(" Local m_mcs_sender_id = %04X", LOWORD(lParam));
|
|
psc->m_mcs_sender_id = LOWORD(lParam);
|
|
}
|
|
psc->UpdateScState(SCS_ATTACH, (DWORD) HIWORD(lParam));
|
|
break;
|
|
}
|
|
|
|
case MCS_CHANNEL_JOIN_CONFIRM:
|
|
{
|
|
DbgMsgDc("MCS_CHANNEL_JOIN_CONFIRM channelId=%04X result=%s",
|
|
LOWORD(lParam), GetMcsResultString(HIWORD(lParam) ));
|
|
if (RESULT_SUCCESSFUL == HIWORD(lParam))
|
|
{
|
|
if (psc->m_mcs_sender_id == LOWORD(lParam))
|
|
{
|
|
ASSERT(SCS_JOIN_PRIVATE == psc->m_scs);
|
|
}
|
|
else
|
|
{
|
|
ASSERT((0 == psc->m_mcs_channel_id) ||
|
|
(psc->m_mcs_channel_id == LOWORD(lParam)));
|
|
|
|
psc->m_mcs_channel_id = LOWORD(lParam);
|
|
}
|
|
}
|
|
ASSERT((SCS_JOIN_NEW == psc->m_scs) ||
|
|
(SCS_JOIN_OLD == psc->m_scs) ||
|
|
(SCS_JOIN_PRIVATE == psc->m_scs) ||
|
|
(SCS_CONNECTED == psc->m_scs)||
|
|
(SCS_JOIN_STATIC_CHANNEL == psc->m_scs));
|
|
|
|
psc->UpdateScState(psc->m_scs, (DWORD) HIWORD(lParam));
|
|
break;
|
|
}
|
|
|
|
case MCS_UNIFORM_SEND_DATA_INDICATION:
|
|
case MCS_SEND_DATA_INDICATION: // lParam == SendData *
|
|
{
|
|
SendData * pSendData = (SendData *) lParam;
|
|
ASSERT(NULL != pSendData);
|
|
CNmMember * pMember = psc->PMemberFromSenderId(pSendData->initiator);
|
|
|
|
if (NULL != pMember)
|
|
{
|
|
if (uMsg == MCS_UNIFORM_SEND_DATA_INDICATION)
|
|
{
|
|
//
|
|
// Skip UNIFORM notifications that came from us
|
|
//
|
|
|
|
ULONG memberID;
|
|
pMember->GetID(&memberID);
|
|
|
|
if (memberID == psc->m_gcc_node_id)
|
|
{
|
|
// We sent this, skip it.
|
|
goto RelMember;
|
|
}
|
|
}
|
|
|
|
ASSERT (pSendData->segmentation == (SEGMENTATION_BEGIN | SEGMENTATION_END));
|
|
|
|
NMN_DATA_XFER nmnData;
|
|
nmnData.pMember =(INmMember *) pMember;
|
|
nmnData.pb = pSendData->user_data.value;
|
|
nmnData.cb = pSendData->user_data.length;
|
|
nmnData.dwFlags = (ULONG)
|
|
(NM_DF_SEGMENT_BEGIN | NM_DF_SEGMENT_END) |
|
|
((psc->GetMcsChannelId() == pSendData->channel_id) ?
|
|
NM_DF_BROADCAST : NM_DF_PRIVATE);
|
|
|
|
psc->NotifySink((PVOID) &nmnData, OnNmDataReceived);
|
|
|
|
RelMember:
|
|
pMember->Release();
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
psc->Release();
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// CNmMemberId
|
|
//
|
|
|
|
CNmMemberId::CNmMemberId(CNmMember *pMember, UCID * pucid) :
|
|
m_channelId(pucid->channelId),
|
|
m_sender_id_public(pucid->sender_id_public),
|
|
m_sender_id_private(pucid->sender_id_private),
|
|
m_cCheckId(0),
|
|
m_pMember(pMember)
|
|
{
|
|
}
|
|
|
|
VOID CNmMemberId::UpdateRosterInfo(UCID * pucid)
|
|
{
|
|
if (0 == m_channelId)
|
|
m_channelId = pucid->channelId;
|
|
if (0 == m_sender_id_private)
|
|
m_sender_id_private = pucid->sender_id_private;
|
|
if (0 == m_sender_id_public)
|
|
m_sender_id_public = pucid->sender_id_public;
|
|
}
|
|
|
|
//
|
|
// CNmChannelData
|
|
//
|
|
|
|
CNmChannelData::CNmChannelData(CConfObject * pConference, REFGUID rguid, PGCCEnrollRequest pER) :
|
|
CConnectionPointContainer(g_apiidCP, ARRAY_ELEMENTS(g_apiidCP)),
|
|
m_pConference(pConference),
|
|
m_fClosed(TRUE),
|
|
m_fActive(FALSE),
|
|
m_cMember(0),
|
|
m_pListMemberId(NULL),
|
|
m_pListMember(NULL),
|
|
m_pGCCER(pER)
|
|
{
|
|
m_guid = rguid;
|
|
ASSERT(GUID_NULL != rguid);
|
|
|
|
m_dwUserIdLocal = pConference->GetDwUserIdLocal();
|
|
ASSERT(INVALID_GCCID != m_dwUserIdLocal);
|
|
|
|
DbgMsg(iZONE_OBJECTS, "Obj: %08X created CNmChannelData", this);
|
|
}
|
|
|
|
|
|
CNmChannelData::~CNmChannelData(void)
|
|
{
|
|
DBGENTRY(CNmChannelData::~CNmChannelData);
|
|
|
|
// This will keep us from being deleted again...
|
|
++m_ulcRef;
|
|
|
|
CloseConnection();
|
|
|
|
FreeMemberIdList(&m_pListMemberId);
|
|
delete m_pListMember;
|
|
|
|
if(m_pConference)
|
|
{
|
|
m_pConference->RemoveDataChannelGUID(m_guid);
|
|
}
|
|
|
|
DbgMsg(iZONE_OBJECTS, "Obj: %08X destroyed CNmChannelData", this);
|
|
|
|
DBGEXIT(CNmChannelData::~CNmChannelData);
|
|
}
|
|
|
|
|
|
/* A D D M E M B E R */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: AddMember
|
|
|
|
-------------------------------------------------------------------------*/
|
|
VOID CNmChannelData::AddMember(CNmMember * pMember)
|
|
{
|
|
DbgMsgDc("CNmChannelData::AddMember [%ls] id=%08X",
|
|
pMember->GetName(), pMember->GetGCCID());
|
|
|
|
m_cMember++;
|
|
pMember->AddRef();
|
|
AddNode(pMember, &m_pListMember);
|
|
|
|
INmMember * pNmMember = (INmMember *) pMember;
|
|
NotifySink(pNmMember, OnNotifyChannelMemberAdded);
|
|
}
|
|
|
|
|
|
/* R E M O V E M E M B E R */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: RemoveMember
|
|
|
|
-------------------------------------------------------------------------*/
|
|
VOID CNmChannelData::RemoveMember(CNmMember * pMember)
|
|
{
|
|
DbgMsgDc("CNmChannelData::RemoveMember [%ls] id=%08X",
|
|
pMember->GetName(), pMember->GetGCCID());
|
|
|
|
m_cMember--;
|
|
ASSERT((int)m_cMember >= 0);
|
|
RemoveNode(pMember, m_pListMember);
|
|
|
|
INmMember * pNmMember = (INmMember *) pMember;
|
|
NotifySink(pNmMember, OnNotifyChannelMemberRemoved);
|
|
|
|
pMember->Release(); // Release AFTER notifying everyone
|
|
}
|
|
|
|
|
|
/* O P E N C O N N E C T I O N */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: OpenConnection
|
|
|
|
Open a T.120 data connection (init both public and private channels)
|
|
-------------------------------------------------------------------------*/
|
|
HRESULT CNmChannelData::OpenConnection(void)
|
|
{
|
|
TRACE_OUT(("CNmChannelData::OpenConection()"));
|
|
|
|
if (!m_fClosed)
|
|
return E_FAIL; // already open
|
|
m_fClosed = FALSE; // need to call CloseConnection after this
|
|
|
|
if (FAILED(PFNT120::Init()))
|
|
return E_FAIL;
|
|
|
|
InitCT120Channel(m_dwUserIdLocal);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* C L O S E C O N N E C T I O N */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: CloseConnection
|
|
|
|
Close the data channel - this matches what is done in OpenConnection
|
|
-------------------------------------------------------------------------*/
|
|
HRESULT CNmChannelData::CloseConnection(void)
|
|
{
|
|
DBGENTRY(CNmChannelData::CloseConnection);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_fClosed)
|
|
{
|
|
m_fClosed = TRUE;
|
|
|
|
// Close any open T.120 channels
|
|
CloseChannel();
|
|
|
|
if (0 != m_cMember)
|
|
{
|
|
// force roster update with no peers
|
|
DbgMsgDc("CloseConnection: %d members left", m_cMember);
|
|
UpdateRoster(NULL, 0, FALSE, TRUE /* fRemove */);
|
|
ASSERT(IsEmpty());
|
|
}
|
|
|
|
CConfObject * pConference = PConference();
|
|
if (NULL != pConference)
|
|
{
|
|
m_fActive = FALSE;
|
|
// The channel is now officially inactive
|
|
pConference->OnChannelUpdated(this);
|
|
}
|
|
}
|
|
|
|
DBGEXIT_HR(CNmChannelData::CloseConnection, hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* U P D A T E P E E R */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: UpdatePeer
|
|
|
|
-------------------------------------------------------------------------*/
|
|
VOID CNmChannelData::UpdatePeer(CNmMember * pMember, UCID *pucid, BOOL fAdd)
|
|
{
|
|
#ifdef DEBUG
|
|
DbgMsgDc("UpdatePeer (%08X) fAdd=%d fLocal=%d", pMember, fAdd, pMember->FLocal());
|
|
if (NULL != pucid)
|
|
{
|
|
DbgMsgDc(" channelId=(%04X) dwUserId=%08X", pucid->channelId, pucid->dwUserId);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
if (fAdd)
|
|
{
|
|
CNmMemberId *pMemberId = new CNmMemberId(pMember, pucid);
|
|
if (NULL != pMemberId)
|
|
{
|
|
AddNode(pMemberId, &m_pListMemberId);
|
|
AddMember(pMember);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CNmMemberId *pMemberId = GetMemberId(pMember);
|
|
if (NULL != pMemberId)
|
|
{
|
|
RemoveNode(pMemberId, m_pListMemberId);
|
|
delete pMemberId;
|
|
RemoveMember(pMember);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* U P D A T E R O S T E R */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: UpdateRoster
|
|
|
|
Update the local peer list based on the new roster data
|
|
-------------------------------------------------------------------------*/
|
|
VOID CNmChannelData::UpdateRoster(UCID * rgPeer, int cPeer, BOOL fAdd, BOOL fRemove)
|
|
{
|
|
int iPeer;
|
|
DWORD dwUserId;
|
|
CNmMember * pMember;
|
|
COBLIST * pList;
|
|
|
|
DbgMsgDc("CNmChannelData::UpdateRoster: %d peers, fAdd=%d, fRemove=%d",
|
|
cPeer, fAdd, fRemove);
|
|
|
|
if (NULL != m_pListMemberId)
|
|
{
|
|
for (POSITION pos = m_pListMemberId->GetHeadPosition(); NULL != pos; )
|
|
{
|
|
BOOL fFound = FALSE;
|
|
CNmMemberId *pMemberId = (CNmMemberId *) m_pListMemberId->GetNext(pos);
|
|
ASSERT(NULL != pMemberId);
|
|
pMember = pMemberId->GetMember();
|
|
ASSERT(NULL != pMember);
|
|
dwUserId = pMember->GetGCCID();
|
|
|
|
if (0 != dwUserId)
|
|
{
|
|
for (iPeer = 0; iPeer < cPeer; iPeer++)
|
|
{
|
|
if (dwUserId == rgPeer[iPeer].dwUserId)
|
|
{
|
|
fFound = TRUE;
|
|
// remove from the new list
|
|
// so that the peer will not be added below
|
|
rgPeer[iPeer].dwUserId = 0;
|
|
|
|
// no change, but make sure we know sender_ids
|
|
pMemberId->UpdateRosterInfo(&rgPeer[iPeer]);
|
|
|
|
// try to find channel id, if necessary
|
|
if ((0 == pMemberId->GetChannelId()) &&
|
|
(0 == pMemberId->GetCheckIdCount())
|
|
&& !pMember->FLocal())
|
|
{
|
|
pMemberId->SetCheckIdCount(MAX_CHECKID_COUNT);
|
|
RequestChannelId(dwUserId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fFound && fRemove)
|
|
{
|
|
pMember->AddRef();
|
|
|
|
// Unable to find old peer in new list - delete it
|
|
UpdatePeer(pMember, NULL, FALSE /* fAdd */ );
|
|
|
|
pMember->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fAdd)
|
|
return;
|
|
|
|
|
|
// Use the conference list to find member data
|
|
pList = PConference()->GetMemberList();
|
|
/* Add new peers */
|
|
for (iPeer = 0; iPeer < cPeer; iPeer++)
|
|
{
|
|
dwUserId = rgPeer[iPeer].dwUserId;
|
|
if (0 == dwUserId)
|
|
continue;
|
|
|
|
// PMemberFromDwUserId returns AddRef'd member
|
|
pMember = PMemberFromDwUserId(dwUserId, pList);
|
|
|
|
if (NULL == pMember)
|
|
{
|
|
WARNING_OUT(("UpdateRoster: Member not found! dwUserId=%08X", dwUserId));
|
|
}
|
|
else
|
|
{
|
|
UpdatePeer(pMember, &rgPeer[iPeer], TRUE /* fAdd */);
|
|
pMember->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* U P D A T E M E M B E R C H A N N E L I D */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: UpdateMemberChannelId
|
|
|
|
-------------------------------------------------------------------------*/
|
|
VOID CNmChannelData::UpdateMemberChannelId(DWORD dwUserId, ChannelID channelId)
|
|
{
|
|
// PMemberFromDwUserId returns AddRef'd member
|
|
CNmMember * pMember = PMemberFromDwUserId(dwUserId, PConference()->GetMemberList());
|
|
TRACE_OUT(("Member (%08X) private channelId=(%04X)", pMember, channelId));
|
|
if (NULL != pMember)
|
|
{
|
|
UCID ucid;
|
|
ClearStruct(&ucid);
|
|
ucid.channelId = channelId;
|
|
UpdateRosterInfo(pMember, &ucid);
|
|
pMember->Release();
|
|
}
|
|
}
|
|
|
|
|
|
/* G E T M E M B E R I D */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: GetMemberId
|
|
|
|
-------------------------------------------------------------------------*/
|
|
CNmMemberId * CNmChannelData::GetMemberId(CNmMember *pMember)
|
|
{
|
|
if (NULL != m_pListMemberId)
|
|
{
|
|
POSITION pos = m_pListMemberId->GetHeadPosition();
|
|
while (NULL != pos)
|
|
{
|
|
CNmMemberId *pMemberId = (CNmMemberId *) m_pListMemberId->GetNext(pos);
|
|
ASSERT(NULL != pMemberId);
|
|
if (pMemberId->GetMember() == pMember)
|
|
{
|
|
return pMemberId;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* G E T M E M B E R I D */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: GetMemberId
|
|
|
|
-------------------------------------------------------------------------*/
|
|
CNmMemberId * CNmChannelData::GetMemberId(DWORD dwUserId)
|
|
{
|
|
if (NULL != m_pListMemberId)
|
|
{
|
|
POSITION pos = m_pListMemberId->GetHeadPosition();
|
|
while (NULL != pos)
|
|
{
|
|
CNmMemberId *pMemberId = (CNmMemberId *) m_pListMemberId->GetNext(pos);
|
|
ASSERT(NULL != pMemberId);
|
|
CNmMember *pMember = pMemberId->GetMember();
|
|
ASSERT(NULL != pMember);
|
|
if (pMember->GetGCCID() == dwUserId)
|
|
{
|
|
return pMemberId;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* U P D A T E R O S T E R I N F O */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: UpdateRosterInfo
|
|
|
|
-------------------------------------------------------------------------*/
|
|
VOID CNmChannelData::UpdateRosterInfo(CNmMember *pMember, UCID * pucid)
|
|
{
|
|
CNmMemberId *pMemberId = GetMemberId(pMember);
|
|
if (NULL != pMemberId)
|
|
{
|
|
pMemberId->UpdateRosterInfo(pucid);
|
|
}
|
|
}
|
|
|
|
/* G E T C H A N N E L I D */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: GetChannelId
|
|
|
|
-------------------------------------------------------------------------*/
|
|
ChannelID CNmChannelData::GetChannelId(CNmMember *pMember)
|
|
{
|
|
CNmMemberId *pMemberId = GetMemberId(pMember);
|
|
if (NULL != pMemberId)
|
|
{
|
|
return pMemberId->GetChannelId();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* P M E M B E R F R O M S E N D E R I D */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: PMemberFromSenderId
|
|
|
|
-------------------------------------------------------------------------*/
|
|
CNmMember * CNmChannelData::PMemberFromSenderId(UserID id)
|
|
{
|
|
if (NULL != m_pListMemberId)
|
|
{
|
|
POSITION pos = m_pListMemberId->GetHeadPosition();
|
|
while (NULL != pos)
|
|
{
|
|
CNmMemberId * pMemberId = (CNmMemberId *) m_pListMemberId->GetNext(pos);
|
|
ASSERT(NULL != pMemberId);
|
|
if (pMemberId->FSenderId(id))
|
|
{
|
|
CNmMember* pMember = pMemberId->GetMember();
|
|
ASSERT(NULL != pMember);
|
|
pMember->AddRef();
|
|
return pMember;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
///////////////////////////
|
|
// CNmChannelData:IUknown
|
|
|
|
ULONG STDMETHODCALLTYPE CNmChannelData::AddRef(void)
|
|
{
|
|
TRACE_OUT(("CNmChannelData::AddRef this = 0x%X", this));
|
|
return RefCount::AddRef();
|
|
}
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE CNmChannelData::Release(void)
|
|
{
|
|
TRACE_OUT(("CNmChannelData::Release this = 0x%X", this));
|
|
return RefCount::Release();
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::QueryInterface(REFIID riid, PVOID *ppv)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ((riid == IID_IUnknown) || (riid == IID_INmChannelData2) || (riid == IID_INmChannelData) || (riid == IID_INmChannel))
|
|
{
|
|
*ppv = (INmChannelData2 *)this;
|
|
TRACE_OUT(("CNmChannel::QueryInterface(): Returning INmChannelData."));
|
|
}
|
|
else if (riid == IID_IConnectionPointContainer)
|
|
{
|
|
*ppv = (IConnectionPointContainer *) this;
|
|
TRACE_OUT(("CNmChannel::QueryInterface(): Returning IConnectionPointContainer."));
|
|
}
|
|
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
*ppv = NULL;
|
|
TRACE_OUT(("CNmChannel::QueryInterface(): Called on unknown interface."));
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
AddRef();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////
|
|
// INmChannelData
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::GetGuid(GUID *pGuid)
|
|
{
|
|
if (NULL == pGuid)
|
|
return E_POINTER;
|
|
|
|
*pGuid = m_guid;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::SendData(INmMember *pMember, ULONG cb, LPBYTE pv, ULONG uOptions)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_fActive)
|
|
{
|
|
// No active Channels, yet
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ((NULL == pv) || (0 == cb))
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
if (IsBadReadPtr(pv, cb))
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
CNmMember * pDest = (CNmMember *) pMember;
|
|
COBLIST * pList = GetMemberList();
|
|
if (NULL == pMember)
|
|
{
|
|
hr = HrSendData(GetMcsChannelId(), 0, pv, cb, uOptions);
|
|
}
|
|
else if ((NULL == pList) || (NULL == pList->Lookup(pDest)) )
|
|
{
|
|
// Destination is not in list
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
ChannelID channel_id = GetChannelId(pDest);
|
|
if (0 == channel_id)
|
|
{
|
|
WARNING_OUT(("Unable to find user destination channel?"));
|
|
|
|
CNmMemberId *pMemberId = GetMemberId(pDest);
|
|
if (NULL == pMemberId)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
channel_id = pMemberId->SenderId();
|
|
hr = (0 == channel_id) ? E_FAIL : S_OK;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrSendData(channel_id, pDest->GetGCCID(), pv, cb, uOptions);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::RegistryAllocateHandle(ULONG numberOfHandlesRequested)
|
|
{
|
|
if (!m_fActive)
|
|
{
|
|
// No active Channels, yet
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(numberOfHandlesRequested == 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Request handles from gcc
|
|
//
|
|
GCCError gccError = m_gcc_pIAppSap->RegistryAllocateHandle(m_gcc_conference_id, numberOfHandlesRequested);
|
|
|
|
if(gccError == GCC_NO_ERROR)
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
///////////////
|
|
// INmChannel
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::IsSameAs(INmChannel *pChannel)
|
|
{
|
|
HRESULT hr;
|
|
PVOID pv;
|
|
|
|
if (pChannel == NULL)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
hr = pChannel->QueryInterface(IID_INmChannelData, &pv);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = (this == (PVOID) ((CNmChannelData *)(INmChannelData *)pv)) ? S_OK : S_FALSE;
|
|
((IUnknown *) pv)->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::IsActive(void)
|
|
{
|
|
return m_fActive ? S_OK : S_FALSE;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::SetActive(BOOL fActive)
|
|
{
|
|
TRACE_OUT(("CNmChannelData::SetActive(%d)", fActive));
|
|
|
|
NM_CONFERENCE_STATE state;
|
|
// Must be in a non-idle conference
|
|
CConfObject * pConference = PConference();
|
|
pConference->GetState(&state);
|
|
if ((NULL == pConference) || state == NM_CONFERENCE_IDLE)
|
|
return E_FAIL;
|
|
|
|
if (fActive)
|
|
{
|
|
if (S_OK == IsActive())
|
|
return S_OK;
|
|
return OpenConnection();
|
|
}
|
|
else
|
|
{
|
|
if (S_FALSE == IsActive())
|
|
return S_OK;
|
|
return CloseConnection();
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::GetConference(INmConference **ppConference)
|
|
{
|
|
return ::GetConference(ppConference);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::GetInterface(IID *piid)
|
|
{
|
|
HRESULT hr = E_POINTER;
|
|
if (NULL != piid)
|
|
{
|
|
*piid = IID_INmChannelData;
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::GetNmch(ULONG *puch)
|
|
{
|
|
HRESULT hr = E_POINTER;
|
|
|
|
if (NULL != puch)
|
|
{
|
|
*puch = NMCH_DATA;
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::EnumMember(IEnumNmMember **ppEnum)
|
|
{
|
|
HRESULT hr = E_POINTER;
|
|
if (NULL != ppEnum)
|
|
{
|
|
*ppEnum = new CEnumNmMember( GetMemberList(), m_cMember);
|
|
|
|
hr = (NULL != *ppEnum)? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNmChannelData::GetMemberCount(ULONG *puCount)
|
|
{
|
|
HRESULT hr = E_POINTER;
|
|
|
|
if (NULL != puCount)
|
|
{
|
|
*puCount = m_cMember;
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Utility Functions
|
|
|
|
HRESULT OnNmDataSent(IUnknown *pChannelDataNotify, void *pv, REFIID riid)
|
|
{
|
|
NMN_DATA_XFER * pData = (NMN_DATA_XFER *) pv;
|
|
|
|
if (IID_INmChannelDataNotify.Data1 == riid.Data1 || IID_INmChannelDataNotify2.Data1 == riid.Data1)
|
|
{
|
|
((INmChannelDataNotify2*)pChannelDataNotify)->DataSent(
|
|
pData->pMember, pData->cb, pData->pb);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT OnNmDataReceived(IUnknown *pChannelDataNotify, void *pv, REFIID riid)
|
|
{
|
|
NMN_DATA_XFER * pData = (NMN_DATA_XFER *) pv;
|
|
|
|
if (IID_INmChannelDataNotify.Data1 == riid.Data1 || IID_INmChannelDataNotify2.Data1 == riid.Data1)
|
|
{
|
|
((INmChannelDataNotify2*)pChannelDataNotify)->DataReceived(
|
|
pData->pMember, pData->cb, pData->pb, pData->dwFlags);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT OnAllocateHandleConfirm(IUnknown *pChannelDataNotify, void *pv, REFIID riid)
|
|
{
|
|
|
|
|
|
if(IID_INmChannelDataNotify2.Data1 == riid.Data1)
|
|
{
|
|
GCCRegAllocateHandleConfirm *pConfirm = (GCCRegAllocateHandleConfirm *)pv;
|
|
|
|
((INmChannelDataNotify2*)pChannelDataNotify)->AllocateHandleConfirm(pConfirm->nFirstHandle,
|
|
pConfirm->cHandles);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Utility Functions
|
|
|
|
/* F R E E M E M B E R ID L I S T */
|
|
/*-------------------------------------------------------------------------
|
|
%%Function: FreeMemberIdList
|
|
|
|
-------------------------------------------------------------------------*/
|
|
VOID FreeMemberIdList(COBLIST ** ppList)
|
|
{
|
|
DBGENTRY(FreeMemberIdList);
|
|
|
|
ASSERT(NULL != ppList);
|
|
if (NULL != *ppList)
|
|
{
|
|
while (!(*ppList)->IsEmpty())
|
|
{
|
|
CNmMemberId * pMemberId = (CNmMemberId *) (*ppList)->RemoveHead();
|
|
delete pMemberId;
|
|
}
|
|
delete *ppList;
|
|
*ppList = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GCC / MCS Errors
|
|
|
|
#ifdef DEBUG
|
|
LPCTSTR _FormatSzErr(LPTSTR psz, UINT uErr)
|
|
{
|
|
static char szErr[MAX_PATH];
|
|
wsprintf(szErr, "%s 0x%08X (%d)", psz, uErr, uErr);
|
|
return szErr;
|
|
}
|
|
|
|
#define STRING_CASE(val) case val: pcsz = #val; break
|
|
|
|
LPCTSTR GetGccErrorString(GCCError uErr)
|
|
{
|
|
LPCTSTR pcsz;
|
|
|
|
switch (uErr)
|
|
{
|
|
STRING_CASE(GCC_NO_ERROR);
|
|
STRING_CASE(GCC_RESULT_ENTRY_DOES_NOT_EXIST);
|
|
STRING_CASE(GCC_NOT_INITIALIZED);
|
|
STRING_CASE(GCC_ALREADY_INITIALIZED);
|
|
STRING_CASE(GCC_ALLOCATION_FAILURE);
|
|
STRING_CASE(GCC_NO_SUCH_APPLICATION);
|
|
STRING_CASE(GCC_INVALID_CONFERENCE);
|
|
|
|
default:
|
|
pcsz = _FormatSzErr("GccError", uErr);
|
|
break;
|
|
}
|
|
|
|
return pcsz;
|
|
}
|
|
|
|
LPCTSTR GetMcsErrorString(MCSError uErr)
|
|
{
|
|
LPCTSTR pcsz;
|
|
|
|
switch (uErr)
|
|
{
|
|
STRING_CASE(MCS_NO_ERROR);
|
|
STRING_CASE(MCS_USER_NOT_ATTACHED);
|
|
STRING_CASE(MCS_NO_SUCH_USER);
|
|
STRING_CASE(MCS_TRANSMIT_BUFFER_FULL);
|
|
STRING_CASE(MCS_NO_SUCH_CONNECTION);
|
|
|
|
default:
|
|
pcsz = _FormatSzErr("McsError", uErr);
|
|
break;
|
|
}
|
|
|
|
return pcsz;
|
|
}
|
|
|
|
LPCTSTR GetGccResultString(UINT uErr)
|
|
{
|
|
LPCTSTR pcsz;
|
|
|
|
switch (uErr)
|
|
{
|
|
STRING_CASE(GCC_RESULT_ENTRY_DOES_NOT_EXIST);
|
|
default:
|
|
pcsz = _FormatSzErr("GccResult", uErr);
|
|
break;
|
|
}
|
|
|
|
return pcsz;
|
|
}
|
|
|
|
LPCTSTR GetMcsResultString(UINT uErr)
|
|
{
|
|
return _FormatSzErr("McsResult", uErr);
|
|
}
|
|
#endif /* DEBUG (T.120 Error routines) */
|
|
|
|
|
|
|