windows-nt/Source/XPSP1/NT/enduser/netmeeting/ui/wb/nmwbobj.cpp
2020-09-26 16:20:57 +08:00

1075 lines
25 KiB
C++

// NMWbObj.cpp : Implementation of CNMWbObj
#include "precomp.h"
#include <wbguid.h>
#include "wbcaps.h"
#include "NMWbObj.h"
#include <iappldr.h>
// Local prototypes
void CALLBACK T120AppletCallbackProc(T120AppletMsg *pMsg);
void CALLBACK T120SessionCallbackProc(T120AppletSessionMsg *pMsg);
/////////////////////////////////////////////////////////////////////////////////////////////////////
// CNMWbObj Construction and initialization
///////////////////////////////////////////////////////////////////////////////////////////////////////
CNMWbObj* g_pNMWBOBJ;
UINT g_numberOfWorkspaces;
UINT g_numberOfObjects;
CWBOBLIST* g_pListOfWorkspaces;
BOOL g_fWaitingForBufferAvailable;
CWBOBLIST* g_pListOfObjectsThatRequestedHandles;
CWBOBLIST* g_pRetrySendList;
CWBOBLIST* g_pTrash;
ULONG g_MyMemberID;
ULONG g_RefresherID;
UINT g_MyIndex;
BOOL g_bSavingFile;
BOOL g_bContentsChanged;
GCCPREALOC g_GCCPreallocHandles[PREALLOC_GCC_BUFFERS];
UINT g_iGCCHandleIndex;
BOOL g_WaitingForGCCHandles;
//
// T.126 protocol related
//
static const ULONG g_T126KeyNodes[] = {0,0,20,126,0,1};
static const T120ChannelID g_aStaticChannels[] = { _SI_CHANNEL_0 };
//
// T.120 capabilities
//
static GCCAppCap *g_CapPtrList[_iT126_MAX_COLLAPSING_CAPABILITIES];
static GCCAppCap g_CapArray[_iT126_MAX_COLLAPSING_CAPABILITIES];
//
// T.120 non-collapsing capabilities
//
#define MY_APP_STR "_MSWB"
#define T126_TEXT_STRING "NM 3 Text"
#define T126_24BIT_STRING "NM 3 24BitMap"
static const OSTR s_AppData[_iT126_LAST_NON_COLLAPSING_CAPABILITIES] =
{
{
sizeof(T126_TEXT_STRING),
(LPBYTE) T126_TEXT_STRING
},
{
sizeof(T126_24BIT_STRING),
(LPBYTE) T126_24BIT_STRING
},
};
static GCCNonCollCap g_NCCapArray[2];
static const GCCNonCollCap *g_NCCapPtrList[2] = { &g_NCCapArray[0], &g_NCCapArray[1] };
//
// Member ID arrays, assuming 64 members
//
#define MAX_MEMBERS 128
static MEMBER_ID g_aMembers[MAX_MEMBERS];
CNMWbObj::CNMWbObj( void ) :
// T.120 applet SAP
m_pApplet(NULL),
m_aMembers(&g_aMembers[0])
{
DBGENTRY(CNMWbObj::CNMWbObj);
DBG_SAVE_FILE_LINE
g_pListOfWorkspaces = new CWBOBLIST();
DBG_SAVE_FILE_LINE
g_pListOfObjectsThatRequestedHandles = new CWBOBLIST();
DBG_SAVE_FILE_LINE
g_pTrash = new CWBOBLIST();
DBG_SAVE_FILE_LINE
g_pRetrySendList = new CWBOBLIST();
g_pListOfWorkspaces->EmptyList();
g_pListOfObjectsThatRequestedHandles->EmptyList();
g_pRetrySendList->EmptyList();
g_pTrash->EmptyList();
g_numberOfWorkspaces = 0;
g_numberOfObjects = 0;
g_MyIndex = 0;
g_bSavingFile = FALSE;
g_bContentsChanged = FALSE;
g_iGCCHandleIndex = 0;
g_fWaitingForBufferAvailable = FALSE;
g_WaitingForGCCHandles = FALSE;
::ZeroMemory(&g_GCCPreallocHandles, sizeof(g_GCCPreallocHandles));
m_instanceNumber = 0;
m_bConferenceOnlyNetmeetingNodes = TRUE;
g_pNMWBOBJ = this;
// Cleanup per-conference T.120 info
CleanupPerConf();
// T.120 Applet
T120Error rc = ::T120_CreateAppletSAP(&m_pApplet);
if (T120_NO_ERROR != rc)
{
ERROR_OUT(("CNMWbObj::CNMWbObj: cannot create applet SAP"));
return;
}
ASSERT(NULL != m_pApplet);
m_pApplet->Advise(T120AppletCallbackProc, this);
//
// Fill in the capabilities
//
BuildCaps();
//
// Load IMM32 if this is FE
//
ASSERT(!g_hImmLib);
ASSERT(!g_fnImmGetContext);
ASSERT(!g_fnImmNotifyIME);
if (GetSystemMetrics(SM_DBCSENABLED))
{
g_hImmLib = LoadLibrary("imm32.dll");
if (!g_hImmLib)
{
ERROR_OUT(("Failed to load imm32.dll"));
}
else
{
g_fnImmGetContext = (IGC_PROC)GetProcAddress(g_hImmLib, "ImmGetContext");
if (!g_fnImmGetContext)
{
ERROR_OUT(("Failed to get ImmGetContext pointer"));
}
g_fnImmNotifyIME = (INI_PROC)GetProcAddress(g_hImmLib, "ImmNotifyIME");
if (!g_fnImmNotifyIME)
{
ERROR_OUT(("Failed to get ImmNotifyIME pointer"));
}
}
}
DBG_SAVE_FILE_LINE
g_pMain = new WbMainWindow();
if (!g_pMain)
{
ERROR_OUT(("Can't create WbMainWindow"));
}
else
{
//
// OK, now we're ready to create our HWND
//
if (!g_pMain->Open(SW_SHOWDEFAULT))
{
ERROR_OUT(("Can't create WB windows"));
}
}
DBGEXIT(CNMWbObj::CNMWbObj);
}
CNMWbObj::~CNMWbObj( void )
{
DBGENTRY(CNMWbObj::~CNMWbObj);
//
// If i'm the refresher, I have to release the token
// And send an workspace refresh status pdu
//
if(m_bImTheT126Refresher)
{
::ZeroMemory(&m_tokenRequest, sizeof(m_tokenRequest));
m_tokenRequest.eCommand = APPLET_RELEASE_TOKEN;
m_tokenRequest.nTokenID = _SI_WORKSPACE_REFRESH_TOKEN;
T120Error rc = m_pAppletSession->TokenRequest(&m_tokenRequest);
SendWorkspaceRefreshPDU(FALSE);
}
// no more T.120
if (NULL != m_pAppletSession)
{
m_pAppletSession->ReleaseInterface();
CleanupPerConf();
}
if (NULL != m_pApplet)
{
m_pApplet->ReleaseInterface();
m_pApplet = NULL;
}
if(g_pMain)
{
delete g_pMain;
g_pMain = NULL;
}
//
// Delete all the global lists
//
DeleteAllWorkspaces(FALSE);
g_pListOfWorkspaces->EmptyList();
g_pListOfObjectsThatRequestedHandles->EmptyList();
g_numberOfWorkspaces = 0;
T126Obj* pGraphic;
//
// Burn trash
//
pGraphic = (T126Obj *)g_pTrash->RemoveTail();
while (pGraphic != NULL)
{
delete pGraphic;
pGraphic = (T126Obj *) g_pTrash->RemoveTail();
}
if(g_pTrash)
{
delete g_pTrash;
g_pTrash = NULL;
}
if(g_pListOfWorkspaces)
{
delete g_pListOfWorkspaces;
g_pListOfWorkspaces = NULL;
}
if(g_pListOfObjectsThatRequestedHandles)
{
delete g_pListOfObjectsThatRequestedHandles;
g_pListOfObjectsThatRequestedHandles = NULL;
}
if(g_pRetrySendList)
{
delete g_pRetrySendList;
g_pRetrySendList = NULL;
}
g_fnImmNotifyIME = NULL;
g_fnImmGetContext = NULL;
if (g_hImmLib)
{
FreeLibrary(g_hImmLib);
g_hImmLib = NULL;
}
DBGEXIT(CNMWbObj::~CNMWbObj);
}
void CNMWbObj::BuildCaps(void)
{
// Fill in the caps we support
int i;
for(i=0;i<_iT126_MAX_COLLAPSING_CAPABILITIES;i++)
{
g_CapArray[i].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
g_CapArray[i].capability_id.standard_capability = GCCCaps[i].CapValue;
g_CapArray[i].capability_class.eType = GCCCaps[i].Type;
if( GCCCaps[i].CapValue == Soft_Copy_Workspace_Max_Width)
{
GCCCaps[i].MinValue = DRAW_WIDTH + 1;
GCCCaps[i].MaxValue = DRAW_WIDTH - 1;
}
if(GCCCaps[i].CapValue == Soft_Copy_Workspace_Max_Height)
{
GCCCaps[i].MinValue = DRAW_HEIGHT + 1;
GCCCaps[i].MaxValue = DRAW_HEIGHT - 1;
}
if(GCCCaps[i].CapValue == Soft_Copy_Workspace_Max_Planes)
{
GCCCaps[i].MinValue = WB_MAX_WORKSPACES + 1;
GCCCaps[i].MaxValue = WB_MAX_WORKSPACES - 1;
}
if(GCCCaps[i].Type == GCC_UNSIGNED_MINIMUM_CAPABILITY)
{
g_CapArray[i].capability_class.nMinOrMax = GCCCaps[i].MinValue - 1;
}
else if ((GCCCaps[i].Type == GCC_UNSIGNED_MAXIMUM_CAPABILITY))
{
g_CapArray[i].capability_class.nMinOrMax = GCCCaps[i].MaxValue + 1;
}
else
{
g_CapArray[i].capability_class.nMinOrMax = 0;
}
g_CapArray[i].number_of_entities = 0;
g_CapPtrList[i] = &g_CapArray[i];
}
//
// Non-Collapsed Capabilities
//
g_NCCapArray[0].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
g_NCCapArray[0].capability_id.standard_capability = _iT126_TEXT_CAPABILITY_ID;
g_NCCapArray[0].application_data = (OSTR *) &s_AppData[0];
//
// How many bits per pixel can we handle?
//
HDC hDC = CreateCompatibleDC(NULL);
if((GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)) >= 24)
{
m_bICanDo24BitBitmaps = TRUE;
g_NCCapArray[1].capability_id.capability_id_type = GCC_STANDARD_CAPABILITY;
g_NCCapArray[1].capability_id.standard_capability = _iT126_24BIT_BITMAP_ID;
g_NCCapArray[1].application_data = (OSTR *) &s_AppData[1];
}
else
{
m_bICanDo24BitBitmaps = FALSE;
}
if (hDC)
{
DeleteDC(hDC);
}
}
//
// T120 Applet Functions
//
void CALLBACK T120AppletCallbackProc
(
T120AppletMsg *pMsg
)
{
CNMWbObj *pWBOBJ = (CNMWbObj *) pMsg->pAppletContext;
if (pWBOBJ == g_pNMWBOBJ)
{
switch (pMsg->eMsgType)
{
case GCC_PERMIT_TO_ENROLL_INDICATION:
pWBOBJ->OnPermitToEnroll(pMsg->PermitToEnrollInd.nConfID,
pMsg->PermitToEnrollInd.fPermissionGranted);
break;
case T120_JOIN_SESSION_CONFIRM:
default:
break;
}
}
}
void CALLBACK T120SessionCallbackProc
(
T120AppletSessionMsg *pMsg
)
{
if(g_pNMWBOBJ == NULL)
{
return;
}
CNMWbObj *pSession = (CNMWbObj *) pMsg->pSessionContext;
ASSERT(pMsg->pAppletContext == pMsg->pSessionContext);
if (pSession == g_pNMWBOBJ)
{
ASSERT(pMsg->nConfID == pSession->GetConfID());
switch (pMsg->eMsgType)
{
case MCS_UNIFORM_SEND_DATA_INDICATION:
//
// Check if we are receiving a indication from owrself
//
if(pMsg->SendDataInd.initiator == GET_USER_ID_FROM_MEMBER_ID(g_MyMemberID))
{
return;
}
case MCS_SEND_DATA_INDICATION:
::T126_MCSSendDataIndication(
pMsg->SendDataInd.user_data.length,
pMsg->SendDataInd.user_data.value,
pMsg->SendDataInd.initiator,
FALSE);
break;
case MCS_TRANSMIT_BUFFER_AVAILABLE_INDICATION:
g_fWaitingForBufferAvailable = FALSE;
RetrySend();
break;
case GCC_APP_ROSTER_REPORT_INDICATION:
pSession->OnRosterIndication((ULONG) pMsg->AppRosterReportInd.cRosters,
pMsg->AppRosterReportInd.apAppRosters);
break;
case GCC_ALLOCATE_HANDLE_CONFIRM:
pSession->OnAllocateHandleConfirm(&pMsg->RegAllocHandleConfirm);
break;
case T120_JOIN_SESSION_CONFIRM:
pSession->OnJoinSessionConfirm(&pMsg->JoinSessionConfirm);
break;
case MCS_TOKEN_GRAB_CONFIRM:
TRACE_DEBUG(("MCS_TOKEN_GRAB_CONFIRM result = %d",pMsg->TokenConfirm.eResult));
if(pMsg->TokenConfirm.eResult == T120_RESULT_SUCCESSFUL)
{
TRACE_DEBUG((">>> I'm the T126 REFRESHER <<<"));
g_pNMWBOBJ->m_bImTheT126Refresher = TRUE;
//
// Tell everybody I'm the refresher
//
SendWorkspaceRefreshPDU(TRUE);
g_RefresherID = g_MyMemberID;
}
else
{
TRACE_DEBUG((">>> I'm NOT the T126 REFRESHER <<<"));
// if we are not the t126 refresher, we should save the previous work
if (!g_pNMWBOBJ->m_bImTheT126Refresher)
{
if(!g_pNMWBOBJ->IsInConference())
{
if (g_pMain && (g_pMain->QuerySaveRequired(FALSE) == IDYES))
{
g_pMain->OnSave(FALSE);
}
//
// If we were waiting on the save contents <yes> <no> dialog
// and the whole conference and UI are exiting, g_pMain could be NULL
// Or if we are not in a call anymore, we don't need to delete all the local workspaces.
//
if(g_pMain == NULL || !g_pNMWBOBJ->IsInConference())
{
return;
}
::InvalidateRect(g_pDraw->m_hwnd, NULL, TRUE);
DeleteAllWorkspaces(FALSE);
//
// Fill up the GCC tank
//
TimeToGetGCCHandles(PREALLOC_GCC_HANDLES);
}
// ELSE
// If we got here and we are in a call don't do a thing.
// We just got here because the refresher went away. We tried
// to grab the token and we lost it to a faster node.
//
}
}
break;
default:
break;
}
}
}
void CNMWbObj::OnPermitToEnroll
(
T120ConfID nConfID,
BOOL fPermissionGranted
)
{
if (fPermissionGranted)
{
// We are not in a conference, right?
ASSERT(NULL == m_pAppletSession);
m_bConferenceOnlyNetmeetingNodes = TRUE;
// Create an applet session
T120Error rc = m_pApplet->CreateSession(&m_pAppletSession, nConfID);
if (T120_NO_ERROR == rc)
{
ASSERT(NULL != m_pAppletSession);
m_pAppletSession->Advise(T120SessionCallbackProc, this, this);
// get top provider information
m_bImTheTopProvider = m_pAppletSession->IsThisNodeTopProvider();
// Build join-sesion request
::ZeroMemory(&m_JoinSessionReq, sizeof(m_JoinSessionReq));
m_JoinSessionReq.dwAttachmentFlags = ATTACHMENT_DISCONNECT_IN_DATA_LOSS | ATTACHMENT_MCS_FREES_DATA_IND_BUFFER;
m_JoinSessionReq.SessionKey.application_protocol_key.key_type = GCC_OBJECT_KEY;
m_JoinSessionReq.SessionKey.application_protocol_key.object_id.long_string = (ULONG *) g_T126KeyNodes;
m_JoinSessionReq.SessionKey.application_protocol_key.object_id.long_string_length = sizeof(g_T126KeyNodes) / sizeof(g_T126KeyNodes[0]);
m_JoinSessionReq.SessionKey.session_id = _SI_CHANNEL_0;
m_JoinSessionReq.fConductingCapable = FALSE;
m_JoinSessionReq.nStartupChannelType =MCS_STATIC_CHANNEL;
m_JoinSessionReq.cNonCollapsedCaps =1 + (m_bICanDo24BitBitmaps ? 1 : 0);
m_JoinSessionReq.apNonCollapsedCaps = (GCCNonCollCap **) g_NCCapPtrList;
m_JoinSessionReq.cCollapsedCaps = sizeof(g_CapPtrList) / sizeof(g_CapPtrList[0]);
ASSERT(_iT126_MAX_COLLAPSING_CAPABILITIES == sizeof(g_CapPtrList) / sizeof(g_CapPtrList[0]));
m_JoinSessionReq.apCollapsedCaps = g_CapPtrList;
m_JoinSessionReq.cStaticChannels = sizeof(g_aStaticChannels) / sizeof(g_aStaticChannels[0]);
m_JoinSessionReq.aStaticChannels = (T120ChannelID *) g_aStaticChannels;
//
// Token to grab
//
::ZeroMemory(&m_tokenResourceRequest, sizeof(m_tokenResourceRequest));
m_tokenResourceRequest.eCommand = APPLET_GRAB_TOKEN_REQUEST;
// m_tokenRequest.nChannelID = _SI_CHANNEL_0;
m_tokenResourceRequest.nTokenID = _SI_WORKSPACE_REFRESH_TOKEN;
m_tokenResourceRequest.fImmediateNotification = TRUE;
m_JoinSessionReq.cResourceReqs = 1;
m_JoinSessionReq.aResourceReqs = &m_tokenResourceRequest;
// Join now
rc = m_pAppletSession->Join(&m_JoinSessionReq);
if (T120_NO_ERROR == rc)
{
m_nConfID = nConfID;
//
// JOSEF NOW SET THE MAIN WINDOW STATUS
}
else
{
WARNING_OUT(("CNMWbObj::OnPermitToEnroll: cannot join conf=%u, rc=%u", nConfID, rc));
}
}
}
else
{
if (NULL != m_pAppletSession)
{
m_pAppletSession->ReleaseInterface();
CleanupPerConf();
}
}
}
void CNMWbObj::OnJoinSessionConfirm
(
T120JoinSessionConfirm *pConfirm
)
{
if (NULL != m_pAppletSession)
{
ASSERT(m_pAppletSession == pConfirm->pIAppletSession);
if (T120_RESULT_SUCCESSFUL == pConfirm->eResult)
{
m_uidMyself = pConfirm->uidMyself;
m_sidMyself = pConfirm->sidMyself;
m_eidMyself = pConfirm->eidMyself;
m_nidMyself = pConfirm->nidMyself;
// create member ID
g_MyMemberID = MAKE_MEMBER_ID(m_nidMyself, m_uidMyself);
if(g_pDraw && g_pDraw->IsLocked())
{
m_LockerID = g_MyMemberID;
}
// regardless, update the index anyway
g_MyIndex = (m_uidMyself + NUMCOLS) % NUMCLRPANES;
// we are now in the conference
m_fInConference = TRUE;
// allocate handles for all objects
if (m_bImTheT126Refresher)
{
g_RefresherID = g_MyMemberID;
//
// Resend all objects
//
WBPOSITION pos;
WBPOSITION posObj;
WorkspaceObj* pWorkspace;
T126Obj* pObj;
pos = g_pListOfWorkspaces->GetHeadPosition();
while(pos)
{
pWorkspace = (WorkspaceObj*)g_pListOfWorkspaces->GetNext(pos);
g_pListOfObjectsThatRequestedHandles->AddHead(pWorkspace);
posObj = pWorkspace->GetHeadPosition();
while(posObj)
{
pObj = pWorkspace->GetNextObject(posObj);
if(pObj)
{
g_pListOfObjectsThatRequestedHandles->AddHead(pObj);
}
}
}
//
// Delete the fake handles we had
//
g_WaitingForGCCHandles = FALSE;
g_GCCPreallocHandles[0].GccHandleCount = 0;
g_GCCPreallocHandles[1].GccHandleCount = 0;
TimeToGetGCCHandles(g_numberOfObjects + g_numberOfWorkspaces + PREALLOC_GCC_HANDLES);
}
else
{
::InvalidateRect(g_pDraw->m_hwnd, NULL, TRUE);
DeleteAllWorkspaces(FALSE);
}
}
else
{
WARNING_OUT(("CNMWbObj::OnJoinSessionConfirm: failed to join conference, result=%u. error=%u",
pConfirm->eResult, pConfirm->eError));
ASSERT(GCC_CONFERENCE_NOT_ESTABLISHED == pConfirm->eError);
m_pAppletSession->ReleaseInterface();
CleanupPerConf();
}
}
}
void CNMWbObj::OnAllocateHandleConfirm
(
GCCRegAllocateHandleConfirm *pConfirm
)
{
if (T120_RESULT_SUCCESSFUL == pConfirm->nResult)
{
::T126_GCCAllocateHandleConfirm(pConfirm->nFirstHandle, pConfirm->cHandles);
}
else
{
ERROR_OUT(("CNMWbObj::OnAllocateHandleConfirm: failed to allocate %u handles, result=%u",
pConfirm->cHandles, pConfirm->nResult));
}
}
void CNMWbObj::OnRosterIndication
(
ULONG cRosters,
GCCAppRoster *apRosters[]
)
{
if (IsInConference())
{
BOOL fAdded = FALSE;
BOOL fRemoved = FALSE;
ULONG cOtherMembers = 0;
ULONG i, j, k;
// Caculate how many members in this session
for (i = 0; i < cRosters; i++)
{
GCCAppRoster *pRoster = apRosters[i];
// bail out if this roster is not for this session
if (pRoster->session_key.session_id != m_sidMyself)
{
continue;
}
// node added or removed?
fAdded |= pRoster->nodes_were_added;
fRemoved |= pRoster->nodes_were_removed;
BOOL conferenceCanDo24BitBitmap = TRUE;
BOOL conferenceCanDoText = TRUE;
// parse the roster records
for (j = 0; j < pRoster->number_of_records; j++)
{
GCCAppRecord *pRecord = pRoster->application_record_list[j];
if (pRecord->is_enrolled_actively)
{
MEMBER_ID nMemberID = MAKE_MEMBER_ID(pRecord->node_id, pRecord->application_user_id);
if (nMemberID != g_MyMemberID)
{
//
// Only count T126 apps
//
if((pRoster->session_key.application_protocol_key.key_type == GCC_OBJECT_KEY &&
pRoster->session_key.application_protocol_key.object_id.long_string_length == sizeof(g_T126KeyNodes) / sizeof(g_T126KeyNodes[0]) &&
!memcmp (pRoster->session_key.application_protocol_key.object_id.long_string, g_T126KeyNodes, sizeof(g_T126KeyNodes))))
{
cOtherMembers++;
m_instanceNumber = pRoster->instance_number;
if(T120_GetNodeVersion(m_nConfID, pRecord->node_id) < 0x404)
{
m_bConferenceOnlyNetmeetingNodes = FALSE;
}
}
}
//
// Can we do 24 color bitmap
//
BOOL nodeCanDo24BitBitmap = FALSE;
BOOL nodeCanDoText = FALSE;
for (k = 0; k < pRecord->number_of_non_collapsed_caps; k++)
{
//
// Check if the node handles 24 bit bitmaps
//
if(pRecord->non_collapsed_caps_list[k]->application_data->length == sizeof(T126_24BIT_STRING))
{
if(!memcmp(pRecord->non_collapsed_caps_list[k]->application_data->value, T126_24BIT_STRING ,sizeof(T126_24BIT_STRING)))
{
nodeCanDo24BitBitmap = TRUE;
}
}
//
// Check if the node handles text
//
if(pRecord->non_collapsed_caps_list[k]->application_data->length == sizeof(T126_TEXT_STRING))
{
if(!memcmp(pRecord->non_collapsed_caps_list[k]->application_data->value, T126_TEXT_STRING ,sizeof(T126_TEXT_STRING)))
{
nodeCanDoText = TRUE;
}
}
}
conferenceCanDo24BitBitmap &= nodeCanDo24BitBitmap;
conferenceCanDoText &= nodeCanDoText;
}
} // for
m_bConferenceCanDo24BitBitmaps = conferenceCanDo24BitBitmap;
m_bConferenceCanDoText = conferenceCanDoText;
} // for
// If there are changes, we then do the update
if (fAdded || fRemoved || cOtherMembers != m_cOtherMembers)
{
MEMBER_ID aTempMembers[MAX_MEMBERS]; // scratch copy
// make sure we are able to handle it
if (cOtherMembers >= MAX_MEMBERS)
{
ERROR_OUT(("CNMWbObj::OnRosterIndication: we hit the max members limit, cOtherMembers=%u, max-members=%u",
cOtherMembers, MAX_MEMBERS));
cOtherMembers = MAX_MEMBERS;
}
// reset the flags for members added and removed
fAdded = FALSE;
fRemoved = FALSE;
// copy the members
ULONG idxTempMember = 0;
for (i = 0; i < cRosters; i++)
{
GCCAppRoster *pRoster = apRosters[i];
// bail out if this roster is not for this session
if (pRoster->session_key.session_id != m_sidMyself)
{
continue;
}
// parse the roster records
for (j = 0; j < pRoster->number_of_records; j++)
{
GCCAppRecord *pRecord = pRoster->application_record_list[j];
if (pRecord->is_enrolled_actively)
{
MEMBER_ID nMemberID = MAKE_MEMBER_ID(pRecord->node_id, pRecord->application_user_id);
if (nMemberID != g_MyMemberID && idxTempMember < cOtherMembers)
{
aTempMembers[idxTempMember++] = nMemberID;
// let's see if it is an 'add' or a 'delete'
for (k = 0; k < m_cOtherMembers; k++)
{
if (m_aMembers[k] == nMemberID)
{
m_aMembers[k] = 0;
break;
}
}
fAdded |= (k >= m_cOtherMembers); // not found, must be new
}
}
} // for
} // for
// sanity check
ASSERT(idxTempMember == cOtherMembers);
// see if there are ones that are not in the new roster.
// if so, they must be removed.
for (k = 0; k < m_cOtherMembers; k++)
{
if (m_aMembers[k])
{
fRemoved = TRUE;
ULONG memberID = GET_USER_ID_FROM_MEMBER_ID(m_aMembers[k]);
TRACE_DEBUG(("OnRosterIndication removing RemotePointer from member =%x", memberID));
RemoveRemotePointer(memberID);
//
// if the refresher went away
//
if(g_RefresherID == memberID)
{
GrabRefresherToken();
}
//
// if node locking went away
//
if(m_LockerID == memberID)
{
TogleLockInAllWorkspaces(FALSE, FALSE); // Not locked, don't send updates
g_pMain->UnlockDrawingArea();
g_pMain->m_TB.PopUp(IDM_LOCK);
g_pMain->UncheckMenuItem(IDM_LOCK);
m_LockerID = 0;
}
}
}
// now, update the member array
m_cOtherMembers = cOtherMembers;
if (m_cOtherMembers)
{
ASSERT(sizeof(m_aMembers[0]) == sizeof(aTempMembers[0]));
::CopyMemory(&m_aMembers[0], &aTempMembers[0], m_cOtherMembers * sizeof(m_aMembers[0]));
}
// if added, resend all objects
if (fAdded && (m_bImTheT126Refresher))
{
//
// Tell the new node that I'm the refresher
//
SendWorkspaceRefreshPDU(TRUE);
//
// Refresh the new node
//
ResendAllObjects();
//
// if node locking everybody went away
//
if(m_LockerID == g_MyMemberID)
{
TogleLockInAllWorkspaces(TRUE, TRUE); // Locked, send updates
}
//
// Syncronize it
//
if(g_pCurrentWorkspace)
{
g_pCurrentWorkspace->OnObjectEdit();
}
}
// finally, update the caption
if(g_pMain)
{
g_pMain->UpdateWindowTitle();
}
} // if any change
} // if is in conf
}
void CNMWbObj::CleanupPerConf(void)
{
m_fInConference = FALSE;
m_pAppletSession = NULL;
g_MyMemberID = 0;
g_RefresherID = 0;
m_nConfID = 0; // Conf ID
m_uidMyself = 0; // User ID
m_sidMyself = 0; // Session ID
m_eidMyself = 0; // Entity ID
m_nidMyself = 0; // Node ID
m_bImTheTopProvider = FALSE;
m_bImTheT126Refresher = FALSE;
m_bConferenceOnlyNetmeetingNodes = TRUE;
m_cOtherMembers = 0;
if(g_pMain)
{
g_pMain->UpdateWindowTitle();
RemoveRemotePointer(0);
DeleteAllRetryPDUS();
g_pListOfObjectsThatRequestedHandles->EmptyList();
ASSERT(g_pDraw);
//
// If we were locked
//
if(g_pDraw->IsLocked())
{
m_LockerID = g_MyMemberID;
TogleLockInAllWorkspaces(FALSE, FALSE); // Not locked, don't send updates
g_pMain->UnlockDrawingArea();
g_pMain->m_TB.PopUp(IDM_LOCK);
g_pMain->UncheckMenuItem(IDM_LOCK);
}
}
m_LockerID = 0;
}
T120Error CNMWbObj::SendData
(
T120Priority ePriority,
ULONG cbDataSize,
PBYTE pbData
)
{
T120Error rc;
if (IsInConference())
{
rc = m_pAppletSession->SendData(
UNIFORM_SEND_DATA,
_SI_CHANNEL_0,
ePriority,
pbData,
cbDataSize,
APP_ALLOCATION);
}
else
{
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
}
return rc;
}
T120Error CNMWbObj::GrabRefresherToken(void)
{
T120Error rc;
if (IsInConference())
{
T120TokenRequest Req;
Req.eCommand = APPLET_GRAB_TOKEN;
Req.nTokenID = _SI_WORKSPACE_REFRESH_TOKEN;
Req.uidGiveTo = m_uidMyself;
Req.eGiveResponse = T120_RESULT_SUCCESSFUL;
rc = m_pAppletSession->TokenRequest(&Req);
if (T120_NO_ERROR != rc)
{
WARNING_OUT(("CNMWbObj::AllocateHandles: TokenRequest"));
}
}
else
{
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
}
return rc;
}
T120Error CNMWbObj::AllocateHandles
(
ULONG cHandles
)
{
T120Error rc;
if ( cHandles > 0 && IsInConference())
{
T120RegistryRequest Req;
Req.eCommand = APPLET_ALLOCATE_HANDLE;
Req.pRegistryKey = NULL;
Req.cHandles = cHandles;
rc = m_pAppletSession->RegistryRequest(&Req);
if (T120_NO_ERROR != rc)
{
ERROR_OUT(("CNMWbObj::AllocateHandles: RegistryRequest(cHandles=%u), rc=%u", cHandles, rc));
}
}
else
{
rc = GCC_CONFERENCE_NOT_ESTABLISHED;
}
return rc;
}