Windows2003-3790/enduser/netmeeting/core/ichnldat.cpp

1867 lines
48 KiB
C++
Raw Normal View History

2001-01-01 00:00:00 +01:00
// 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(&registry_key.session_key, &m_gcc_session_key);
CreateAppKey(keyChannel, m_pGuid, dwUserId);
SetAppKey(&registry_key.resource_id, keyChannel);
GCCError gccError = m_gcc_pIAppSap->RegistryRetrieveEntry(
m_gcc_conference_id, &registry_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) */