Source code of Windows XP (NT5)
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.

2397 lines
81 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* ERNCCM.CPP */
  4. /* */
  5. /* Conference Manager class for the Reference System Node Controller. */
  6. /* */
  7. /* Copyright Data Connection Ltd. 1995 */
  8. /* */
  9. /****************************************************************************/
  10. /* Changes: */
  11. /* */
  12. /* 07Jul95 NFC Created. */
  13. /* 23Aug95 NFC Bad trace in StartConference(). */
  14. /* 05Sep95 NFC Integration with CMP_Notify* API. */
  15. /* 13Sep95 NFC Added handler for GCC_EJECT_USER_INDICATION */
  16. /* 19Sep95 NFC Missing break in GetConfIDFromMessage(). */
  17. /****************************************************************************/
  18. #include "precomp.h"
  19. DEBUG_FILEZONE(ZONE_GCC_NC);
  20. #include "ernccons.h"
  21. #include "nccglbl.hpp"
  22. #include "erncvrsn.hpp"
  23. #include "t120app.h"
  24. #include <cuserdta.hpp>
  25. #include <confcli.h>
  26. #include <confreg.h>
  27. #include "erncconf.hpp"
  28. #include "ernccm.hpp"
  29. #include "ernctrc.h"
  30. #include <iappldr.h>
  31. #include "appldr.h"
  32. #include <time.h>
  33. #include <string.h>
  34. #include "plgxprt.h"
  35. #ifdef _DEBUG
  36. BOOL g_fInterfaceBreak = FALSE;
  37. #endif
  38. #define MAX_INVALID_PASSWORDS 5
  39. // Global data structures.
  40. DCRNCConferenceManager *g_pNCConfMgr = NULL;
  41. CQueryRemoteWorkList *g_pQueryRemoteList = NULL;
  42. INodeControllerEvents *g_pCallbackInterface = NULL;
  43. HINSTANCE g_hDllInst = NULL;
  44. IT120ControlSAP *g_pIT120ControlSap = NULL;
  45. BOOL g_bRDS = FALSE;
  46. extern PController g_pMCSController;
  47. // Private function prototypes.
  48. void HandleAddInd(AddIndicationMessage * pAddInd);
  49. void HandleQueryConfirmation(QueryConfirmMessage * pQueryMessage);
  50. void HandleQueryIndication(QueryIndicationMessage * pQueryMessage);
  51. void HandleConductGiveInd(ConductGiveIndicationMessage * pConductGiveInd);
  52. void HandleLockIndication(LockIndicationMessage * pLockInd);
  53. void HandleUnlockIndication(UnlockIndicationMessage * pUnlockInd);
  54. void HandleSubInitializedInd(SubInitializedIndicationMessage * pSubInitInd);
  55. void HandleTimeInquireIndication(TimeInquireIndicationMessage * pTimeInquireInd);
  56. void HandleApplicationInvokeIndication(ApplicationInvokeIndicationMessage * pInvokeMessage);
  57. BOOL InitializePluggableTransport(void);
  58. void CleanupPluggableTransport(void);
  59. BOOL WINAPI DllMain(HINSTANCE hDllInst, DWORD fdwReason, LPVOID)
  60. {
  61. switch (fdwReason)
  62. {
  63. case DLL_PROCESS_ATTACH:
  64. {
  65. g_hDllInst = hDllInst;
  66. ASSERT (g_hDllInst != NULL);
  67. DisableThreadLibraryCalls (hDllInst);
  68. DBG_INIT_MEMORY_TRACKING(hDllInst);
  69. ::InitializeCriticalSection(&g_csTransport);
  70. T120DiagnosticCreate();
  71. g_bRDS = ( NULL != ::FindAtomA("NMSRV_ATOM"));
  72. break;
  73. }
  74. case DLL_PROCESS_DETACH:
  75. {
  76. g_hDllInst = NULL;
  77. /*
  78. * Go cleanup all resources on behalf of the process that is
  79. * detaching from this DLL.
  80. */
  81. T120DiagnosticDestroy ();
  82. ::DeleteCriticalSection(&g_csTransport);
  83. DBG_CHECK_MEMORY_TRACKING(hDllInst);
  84. break;
  85. }
  86. }
  87. return (TRUE);
  88. }
  89. HRESULT WINAPI
  90. T120_CreateNodeController
  91. (
  92. INodeController **ppNodeCtrlIntf,
  93. INodeControllerEvents *pEventsCallback
  94. )
  95. {
  96. DebugEntry(T120_CreateNodeController);
  97. HRESULT hr;
  98. if (NULL == g_pNCConfMgr)
  99. {
  100. if (NULL != ppNodeCtrlIntf && NULL != pEventsCallback)
  101. {
  102. *ppNodeCtrlIntf = NULL;
  103. DBG_SAVE_FILE_LINE
  104. if (NULL != (g_pNCConfMgr = new DCRNCConferenceManager(pEventsCallback, &hr)))
  105. {
  106. if (S_OK == hr)
  107. {
  108. *ppNodeCtrlIntf = (INodeController*) g_pNCConfMgr;
  109. }
  110. else
  111. {
  112. g_pNCConfMgr->Release();
  113. }
  114. }
  115. else
  116. {
  117. hr = E_OUTOFMEMORY;
  118. }
  119. }
  120. else
  121. {
  122. hr = E_INVALIDARG;
  123. }
  124. }
  125. else
  126. {
  127. hr = UI_RC_T120_ALREADY_INITIALIZED;
  128. }
  129. DebugExitHRESULT(T120_CreateNodeController, hr);
  130. return hr;
  131. }
  132. /****************************************************************************/
  133. /* Constructor - see ernccm.hpp */
  134. /****************************************************************************/
  135. DCRNCConferenceManager::
  136. DCRNCConferenceManager
  137. (
  138. INodeControllerEvents *pCallback,
  139. HRESULT *pRetCode
  140. )
  141. :
  142. CRefCount(MAKE_STAMP_ID('N', 'C', 'C', 'M')),
  143. m_eState(CM_ST_UNINITIALIZED)
  144. {
  145. GCCError GCCrc;
  146. HRESULT hr = NO_ERROR;
  147. DebugEntry(DCRNCConferenceManager::DCRNCConferenceManager);
  148. ::InitializePluggableTransport();
  149. //
  150. // There should be only one NC conference manager in the system.
  151. //
  152. ASSERT(NULL == g_pNCConfMgr);
  153. ASSERT(pRetCode);
  154. // initialize applet loader structure
  155. ::AppLdr_Initialize();
  156. //
  157. // Save the callback interface to nmcom.dll
  158. //
  159. g_pCallbackInterface = pCallback;
  160. //
  161. // Validate that there is a node name.
  162. //
  163. LPWSTR pwszNodeName;
  164. if (NULL != (pwszNodeName = ::GetNodeName()))
  165. {
  166. delete pwszNodeName;
  167. }
  168. else
  169. {
  170. ERROR_OUT(("Failed to obtain node name"));
  171. hr = UI_RC_NO_NODE_NAME;
  172. goto MyExit;
  173. }
  174. //
  175. // Load versioning information.
  176. //
  177. hr = ::InitOurVersion();
  178. if (NO_ERROR != hr)
  179. {
  180. ERROR_OUT(("Failed to load version info"));
  181. goto MyExit;
  182. }
  183. //
  184. // Create the query-remote list.
  185. //
  186. ASSERT(NULL == g_pQueryRemoteList);
  187. DBG_SAVE_FILE_LINE
  188. g_pQueryRemoteList = new CQueryRemoteWorkList();
  189. if (g_pQueryRemoteList == NULL)
  190. {
  191. ERROR_OUT(("Failed to create Query Remote List"));
  192. hr = UI_RC_OUT_OF_MEMORY;
  193. goto MyExit;
  194. }
  195. /************************************************************************/
  196. /* For GCCInitialize: */
  197. /* */
  198. /* - pass in a pointer to CM as the user defined data, allowing */
  199. /* GCCCallBackHandler to call back into CM to handle GCC callbacks. */
  200. /************************************************************************/
  201. GCCrc = ::T120_CreateControlSAP(&g_pIT120ControlSap, this, GCCCallBackHandler);
  202. if (GCCrc == GCC_NO_ERROR)
  203. {
  204. m_eState = CM_ST_GCC_INITIALIZED;
  205. hr = NO_ERROR;
  206. }
  207. else
  208. {
  209. ERROR_OUT(("Failed to initializeGCC, GCC error %d", GCCrc));
  210. hr = ::GetGCCRCDetails(GCCrc);
  211. }
  212. MyExit:
  213. *pRetCode = hr;
  214. DebugExitHRESULT(DCRNCConferenceManager::DCRNCConferenceManager, hr);
  215. }
  216. /****************************************************************************/
  217. /* Destructor - see ernccm.hpp */
  218. /****************************************************************************/
  219. DCRNCConferenceManager::
  220. ~DCRNCConferenceManager(void)
  221. {
  222. DebugEntry(DCRNCConferenceManager::~DCRNCConferenceManager);
  223. //
  224. // Make sure no one can use this global pointer any more since
  225. // we are deleting this object.
  226. //
  227. g_pNCConfMgr = NULL;
  228. g_pCallbackInterface = NULL;
  229. //
  230. // Release cached version
  231. //
  232. ::ReleaseOurVersion();
  233. //
  234. // Clean up the query-remote list
  235. //
  236. delete g_pQueryRemoteList;
  237. g_pQueryRemoteList = NULL;
  238. //
  239. // If we have initialized GCC, uninitialize it.
  240. //
  241. if (NULL != g_pIT120ControlSap)
  242. {
  243. ASSERT(CM_ST_GCC_INITIALIZED == m_eState);
  244. g_pIT120ControlSap->ReleaseInterface();
  245. g_pIT120ControlSap = NULL;
  246. }
  247. m_eState = CM_ST_UNINITIALIZED;
  248. ::CleanupPluggableTransport();
  249. DebugExitVOID(DCRNCConferenceManager::~DCRNCConferenceManager);
  250. }
  251. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  252. //
  253. // Implementation of INodeController interface
  254. //
  255. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  256. STDMETHODIMP_(void) DCRNCConferenceManager::
  257. ReleaseInterface ( void )
  258. {
  259. DebugEntry(DCRNCConferenceManager::ReleaseInterface);
  260. InterfaceEntry();
  261. // de-initialize applet loader structure
  262. ::AppLdr_Shutdown();
  263. //
  264. // End and delete all the conferences.
  265. //
  266. PCONFERENCE pConf;
  267. while (NULL != (pConf = m_ConfList.Get()))
  268. {
  269. RemoveConference(pConf, TRUE, TRUE);
  270. }
  271. //
  272. // Free the query remote list
  273. //
  274. g_pQueryRemoteList->DeleteList();
  275. //
  276. // Empty our sequential lists of entries without owners.
  277. //
  278. m_InviteIndWorkList.DeleteList();
  279. m_JoinIndWorkList.DeleteList();
  280. //
  281. // Reset the NC related data
  282. //
  283. g_pCallbackInterface = NULL;
  284. //
  285. // Release this object now.
  286. //
  287. Release();
  288. DebugExitVOID(DCRNCConferenceManager::ReleaseInterface);
  289. }
  290. STDMETHODIMP DCRNCConferenceManager::
  291. QueryRemote
  292. (
  293. LPVOID pCallerContext,
  294. LPCSTR pcszNodeAddress,
  295. BOOL fSecure,
  296. BOOL bIsConferenceActive
  297. )
  298. {
  299. DebugEntry(DCRNCConferenceManager::QueryRemote);
  300. InterfaceEntry();
  301. HRESULT hr;
  302. #if defined(TEST_PLUGGABLE) && defined(_DEBUG)
  303. if (g_fWinsockDisabled)
  304. {
  305. pcszNodeAddress = ::FakeNodeAddress(pcszNodeAddress);
  306. }
  307. #endif
  308. if (NULL != pcszNodeAddress)
  309. {
  310. // if winsock is disabled, block any IP address or machine name
  311. if (g_fWinsockDisabled)
  312. {
  313. if (! IsValidPluggableTransportName(pcszNodeAddress))
  314. {
  315. return UI_RC_NO_WINSOCK;
  316. }
  317. }
  318. // Construct context for the life of the request.
  319. DBG_SAVE_FILE_LINE
  320. CQueryRemoteWork *pQueryRemote;
  321. DBG_SAVE_FILE_LINE
  322. pQueryRemote = new CQueryRemoteWork(pCallerContext,
  323. bIsConferenceActive ? GCC_ASYMMETRY_CALLER : GCC_ASYMMETRY_UNKNOWN,
  324. // GCC_ASYMMETRY_CALLER, // lonchanc: always want to be the caller
  325. pcszNodeAddress,
  326. fSecure,
  327. &hr);
  328. if (NULL != pQueryRemote && NO_ERROR == hr)
  329. {
  330. //
  331. // LONCHANC: The following call is to put this query remote work item
  332. // to the global list, and do the work. We have to do this because
  333. // we removed the physical connection.
  334. //
  335. pQueryRemote->SetHr(NO_ERROR);
  336. // Put entry in list of pending query requests to
  337. // issue GCCConferenceQuery on connection.
  338. g_pQueryRemoteList->AddWorkItem(pQueryRemote);
  339. hr = NO_ERROR;
  340. }
  341. else
  342. {
  343. ERROR_OUT(("DCRNCConferenceManager::QueryRemote:: can't allocate query remote work item"));
  344. delete pQueryRemote;
  345. hr = UI_RC_OUT_OF_MEMORY;
  346. }
  347. }
  348. else
  349. {
  350. ERROR_OUT(("DCRNCConferenceManager::QueryRemote:: null pcszAddress"));
  351. hr = UI_RC_NO_ADDRESS;
  352. }
  353. DebugExitHRESULT(DCRNCConferenceManager::QueryRemote, hr);
  354. return hr;
  355. }
  356. STDMETHODIMP DCRNCConferenceManager::
  357. CancelQueryRemote ( LPVOID pCallerContext )
  358. {
  359. DebugEntry(DCRNCConferenceManager::CancelQueryRemote);
  360. InterfaceEntry();
  361. HRESULT hr = g_pQueryRemoteList->Cancel(pCallerContext);
  362. DebugExitHRESULT(DCRNCConferenceManager::CancelQueryRemote, hr);
  363. return hr;
  364. }
  365. STDMETHODIMP DCRNCConferenceManager::
  366. CreateConference
  367. (
  368. LPCWSTR pcwszConfName,
  369. LPCWSTR pcwszPassword,
  370. PBYTE pbHashedPassword,
  371. DWORD cbHashedPassword,
  372. BOOL fSecure,
  373. CONF_HANDLE *phConf
  374. )
  375. {
  376. DebugEntry(DCRNCConferenceManager::CreateConference);
  377. InterfaceEntry();
  378. HRESULT hr;
  379. if (NULL != phConf)
  380. {
  381. *phConf = NULL;
  382. if (! ::IsEmptyStringW(pcwszConfName))
  383. {
  384. PCONFERENCE pNewConf;
  385. /************************************************************************/
  386. /* Create a new conference. */
  387. /************************************************************************/
  388. hr = CreateNewConference(pcwszConfName, NULL, &pNewConf, FALSE, fSecure);
  389. if (NO_ERROR == hr)
  390. {
  391. ASSERT(NULL != pNewConf);
  392. /****************************************************************/
  393. /* Only need the name for a new local conference. */
  394. /****************************************************************/
  395. hr = pNewConf->StartLocal(pcwszPassword, pbHashedPassword, cbHashedPassword);
  396. if (NO_ERROR == hr)
  397. {
  398. pNewConf->SetNotifyToDo(TRUE);
  399. *phConf = (CONF_HANDLE) pNewConf;
  400. }
  401. else
  402. {
  403. ERROR_OUT(("DCRNCConferenceManager::CreateConference: can't start local conference, hr=0x%x", (UINT) hr));
  404. if (hr != UI_RC_CONFERENCE_ALREADY_EXISTS)
  405. {
  406. RemoveConference(pNewConf);
  407. }
  408. }
  409. }
  410. else
  411. {
  412. ERROR_OUT(("DCRNCConferenceManager::CreateConference: failed to create new conference, hr=0x%x", (UINT) hr));
  413. }
  414. }
  415. else
  416. {
  417. ERROR_OUT(("DCRNCConferenceManager::CreateConference: invalid conference name"));
  418. hr = UI_RC_NO_CONFERENCE_NAME;
  419. }
  420. }
  421. else
  422. {
  423. ERROR_OUT(("DCRNCConferenceManager::CreateConference: null phConf"));
  424. hr = UI_RC_BAD_PARAMETER;
  425. }
  426. DebugExitHRESULT(DCRNCConferenceManager::CreateConference, hr);
  427. return hr;
  428. }
  429. STDMETHODIMP DCRNCConferenceManager::
  430. JoinConference
  431. (
  432. LPCWSTR pcwszConfName,
  433. LPCWSTR pcwszPassword,
  434. LPCSTR pcszNodeAddress,
  435. BOOL fSecure,
  436. USERDATAINFO *pUserDataInfoEntries,
  437. UINT cUserDataEntries,
  438. CONF_HANDLE *phConf
  439. )
  440. {
  441. DebugEntry(DCRNCConferenceManager::JoinConference);
  442. InterfaceEntry();
  443. HRESULT hr;
  444. #if defined(TEST_PLUGGABLE) && defined(_DEBUG)
  445. if (g_fWinsockDisabled)
  446. {
  447. pcszNodeAddress = ::FakeNodeAddress(pcszNodeAddress);
  448. }
  449. #endif
  450. if (NULL != phConf)
  451. {
  452. *phConf = NULL;
  453. if (! ::IsEmptyStringW(pcwszConfName) && NULL != pcszNodeAddress)
  454. {
  455. // if winsock is disabled, block any IP address or machine name
  456. if (g_fWinsockDisabled)
  457. {
  458. if (! IsValidPluggableTransportName(pcszNodeAddress))
  459. {
  460. return UI_RC_NO_WINSOCK;
  461. }
  462. }
  463. PCONFERENCE pNewConf;
  464. // Create a new conference, or find a new conference that
  465. // has just rejected a join because of an invalid password,
  466. // and call its Join() entry point.
  467. hr = CreateNewConference(pcwszConfName, NULL, &pNewConf, TRUE, fSecure);
  468. if (NO_ERROR == hr)
  469. {
  470. // First join attempt. Do all of the start connection.
  471. hr = pNewConf->Join((LPSTR) pcszNodeAddress,
  472. pUserDataInfoEntries,
  473. cUserDataEntries,
  474. pcwszPassword);
  475. }
  476. else
  477. if (hr == UI_RC_CONFERENCE_ALREADY_EXISTS)
  478. {
  479. // Conference already exists.
  480. // Look to see if it is awaiting a join with a password.
  481. // If so, then retry the join.
  482. // Otherwise drop through to return an error.
  483. // Note that we walk the list here again to find the existing
  484. // conference rather than pass back from CreateNewConference(),
  485. // because that would be a side effect behavior that can (and has!)
  486. // introduce obscure bugs in unrelated code.
  487. hr = NO_ERROR;
  488. pNewConf = GetConferenceFromName(pcwszConfName);
  489. ASSERT(NULL != pNewConf);
  490. if (! pNewConf->IsConnListEmpty())
  491. {
  492. CLogicalConnection *pConEntry = pNewConf->PeekConnListHead();
  493. if (pConEntry->GetState() == CONF_CON_PENDING_PASSWORD)
  494. {
  495. hr = pNewConf->JoinWrapper(pConEntry, pcwszPassword);
  496. }
  497. }
  498. }
  499. // Delete the conference if the join fails
  500. // for any reason other than trying to join
  501. // a local conference.
  502. if (NO_ERROR == hr)
  503. {
  504. pNewConf->SetNotifyToDo(TRUE);
  505. *phConf = (CONF_HANDLE) pNewConf;
  506. }
  507. else
  508. {
  509. if (hr != UI_RC_CONFERENCE_ALREADY_EXISTS)
  510. {
  511. ERROR_OUT(("DCRNCConferenceManager::JoinConference: Failed to create new conference, hr=0x%x", (UINT) hr));
  512. }
  513. RemoveConference(pNewConf);
  514. }
  515. }
  516. else
  517. {
  518. hr = (pcszNodeAddress == NULL) ? UI_RC_NO_ADDRESS : UI_RC_NO_CONFERENCE_NAME;
  519. ERROR_OUT(("DCRNCConferenceManager::JoinConference: invalid parameters, hr=0x%x", (UINT) hr));
  520. }
  521. }
  522. else
  523. {
  524. ERROR_OUT(("DCRNCConferenceManager::JoinConference: null phConf"));
  525. hr = UI_RC_BAD_PARAMETER;
  526. }
  527. DebugExitHRESULT(DCRNCConferenceManager::JoinConference, hr);
  528. return hr;
  529. }
  530. STDMETHODIMP DCRNCConferenceManager::
  531. GetUserData
  532. (
  533. ROSTER_DATA_HANDLE hUserData,
  534. const GUID *pcGUID,
  535. UINT *pcbData,
  536. LPVOID *ppvData
  537. )
  538. {
  539. DebugEntry(DCRNCConferenceManager::GetUserData);
  540. InterfaceEntry();
  541. HRESULT hr;
  542. GCCNodeRecord * pRosterEntry = (GCCNodeRecord *) hUserData;
  543. if (NULL != pRosterEntry)
  544. {
  545. ASSERT(NULL != pcbData);
  546. hr = ::GetUserData(pRosterEntry->number_of_user_data_members,
  547. pRosterEntry->user_data_list,
  548. (GUID*) pcGUID,
  549. pcbData,
  550. ppvData);
  551. if (NO_ERROR != hr && UI_RC_NO_SUCH_USER_DATA != hr)
  552. {
  553. ERROR_OUT(("DCRNCConferenceManager::GetUserData: GetUserData failed, hr=0x%x", (UINT) hr));
  554. }
  555. }
  556. else
  557. {
  558. hr = UI_RC_BAD_ADDRESS;
  559. ERROR_OUT(("DCRNCConferenceManager::GetUserData: null pRosterEntry"));
  560. }
  561. DebugExitHRESULT(DCRNCConferenceManager::GetUserData, hr);
  562. return hr;
  563. }
  564. STDMETHODIMP_(UINT) DCRNCConferenceManager::
  565. GetPluggableConnID
  566. (
  567. LPCSTR pcszNodeAddress
  568. )
  569. {
  570. return ::GetPluggableTransportConnID(pcszNodeAddress);
  571. }
  572. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  573. //
  574. // Implementation of Methods for DCRNCConferenceManager
  575. //
  576. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  577. void DCRNCConferenceManager::
  578. WndMsgHandler(UINT uMsg, LPARAM lParam)
  579. {
  580. DebugEntry(DCRNCConferenceManager::WndMsgHandler);
  581. TRACE_OUT(("DCRNCConferenceManager::WndMsgHandler: uMsg=%u, lParam=0x%x", (UINT) uMsg, (UINT) lParam));
  582. switch (uMsg)
  583. {
  584. case NCMSG_FIRST_ROSTER_RECVD:
  585. {
  586. PCONFERENCE pConf = (PCONFERENCE) lParam;
  587. if (NULL != pConf)
  588. {
  589. pConf->FirstRoster();
  590. }
  591. }
  592. break;
  593. case NCMSG_QUERY_REMOTE_FAILURE:
  594. {
  595. CQueryRemoteWork *pWork = (CQueryRemoteWork *) lParam;
  596. if (NULL != pWork)
  597. {
  598. pWork->SyncQueryRemoteResult();
  599. }
  600. }
  601. break;
  602. default:
  603. ERROR_OUT(("DCRNCConferenceManager::WndMsgHandler: unknown msg=%u, lParam=0x%x", uMsg, (UINT) lParam));
  604. break;
  605. }
  606. DebugExitVOID(DCRNCConferenceManager::WndMsgHandler);
  607. }
  608. /****************************************************************************/
  609. /* CreateNewConference - create a new instance of DCRNCConference and add */
  610. /* it to the conference list. */
  611. /****************************************************************************/
  612. HRESULT DCRNCConferenceManager::
  613. CreateNewConference
  614. (
  615. LPCWSTR pcwszConfName,
  616. GCCConfID nConfID,
  617. PCONFERENCE *ppConf,
  618. BOOL fFindExistingConf,
  619. BOOL fSecure
  620. )
  621. {
  622. HRESULT hr;
  623. DebugEntry(DCRNCConferenceManager::CreateNewConference);
  624. ASSERT(ppConf);
  625. // Make sure there is not already an active conference of the same name.
  626. PCONFERENCE pConf = GetConferenceFromName(pcwszConfName);
  627. if (NULL == pConf)
  628. {
  629. // Add new conference
  630. DBG_SAVE_FILE_LINE
  631. pConf = new DCRNCConference(pcwszConfName, nConfID, fSecure, &hr);
  632. if (NULL != pConf && NO_ERROR == hr)
  633. {
  634. // Conference added, so include in list.
  635. m_ConfList.Append(pConf);
  636. #ifdef _DEBUG
  637. pConf->OnAppended();
  638. #endif
  639. // This reference is for nmcom.dll so that ReleaseInterface will do
  640. // the right thing.
  641. pConf->AddRef();
  642. }
  643. else
  644. {
  645. ERROR_OUT(("DCRNCConferenceManager::CreateNewConference: can't create conf, hr=0x%x, pConf=0x%p", (UINT) hr, pConf));
  646. if (pConf == NULL)
  647. {
  648. hr = UI_RC_OUT_OF_MEMORY;
  649. }
  650. else
  651. {
  652. pConf->Release();
  653. pConf = NULL;
  654. }
  655. }
  656. *ppConf = pConf;
  657. }
  658. else
  659. {
  660. WARNING_OUT(("DCRNCConferenceManager::CreateNewConference: conf already exists"));
  661. hr = UI_RC_CONFERENCE_ALREADY_EXISTS;
  662. *ppConf = fFindExistingConf ? pConf : NULL;
  663. }
  664. DebugExitHRESULT(DCRNCConferenceManager::CreateNewConference, hr);
  665. return hr;
  666. }
  667. /***************************************************************************/
  668. /* GetConfIDFromMessage() - Get the conference ID from the message. */
  669. /***************************************************************************/
  670. GCCConfID GetConfIDFromMessage ( GCCMessage * pGCCMessage )
  671. {
  672. GCCConfID nConfID = pGCCMessage->nConfID;
  673. #ifdef _DEBUG
  674. /************************************************************************/
  675. /* Dig the conference ID out of the message. */
  676. /************************************************************************/
  677. switch (pGCCMessage->message_type)
  678. {
  679. case GCC_CREATE_INDICATION:
  680. // nConfID = pGCCMessage->u.create_indication.conference_id;
  681. break;
  682. case GCC_CREATE_CONFIRM:
  683. // nConfID = pGCCMessage->u.create_confirm.conference_id;
  684. break;
  685. case GCC_JOIN_CONFIRM:
  686. // nConfID = pGCCMessage->u.join_confirm.conference_id;
  687. break;
  688. case GCC_INVITE_CONFIRM:
  689. // nConfID = pGCCMessage->u.invite_confirm.conference_id;
  690. break;
  691. case GCC_ADD_CONFIRM:
  692. // nConfID = pGCCMessage->u.add_confirm.conference_id;
  693. break;
  694. case GCC_DISCONNECT_INDICATION:
  695. // nConfID = pGCCMessage->u.disconnect_indication.conference_id;
  696. break;
  697. case GCC_DISCONNECT_CONFIRM:
  698. // nConfID = pGCCMessage->u.disconnect_confirm.conference_id;
  699. break;
  700. case GCC_TERMINATE_INDICATION:
  701. // nConfID = pGCCMessage->u.terminate_indication.conference_id;
  702. break;
  703. case GCC_TERMINATE_CONFIRM:
  704. // nConfID = pGCCMessage->u.terminate_confirm.conference_id;
  705. break;
  706. case GCC_ANNOUNCE_PRESENCE_CONFIRM:
  707. // nConfID = pGCCMessage->u.announce_presence_confirm.conference_id;
  708. break;
  709. case GCC_ROSTER_REPORT_INDICATION:
  710. // nConfID = pGCCMessage->u.conf_roster_report_indication.conference_id;
  711. break;
  712. case GCC_ROSTER_INQUIRE_CONFIRM:
  713. // nConfID = pGCCMessage->u.conf_roster_inquire_confirm.conference_id;
  714. break;
  715. case GCC_PERMIT_TO_ANNOUNCE_PRESENCE:
  716. // nConfID = pGCCMessage->u.permit_to_announce_presence.conference_id;
  717. break;
  718. case GCC_EJECT_USER_INDICATION:
  719. // nConfID = pGCCMessage->u.eject_user_indication.conference_id;
  720. break;
  721. default :
  722. // nConfID = 0;
  723. ERROR_OUT(("Unknown message"));
  724. break;
  725. }
  726. #endif // _DEBUG
  727. return nConfID;
  728. }
  729. PCONFERENCE DCRNCConferenceManager::
  730. GetConferenceFromID ( GCCConfID conferenceID )
  731. {
  732. PCONFERENCE pConf = NULL;
  733. m_ConfList.Reset();
  734. while (NULL != (pConf = m_ConfList.Iterate()))
  735. {
  736. if (pConf->GetID() == conferenceID)
  737. {
  738. break;
  739. }
  740. }
  741. return pConf;
  742. }
  743. PCONFERENCE DCRNCConferenceManager::
  744. GetConferenceFromName ( LPCWSTR pcwszConfName )
  745. {
  746. PCONFERENCE pConf = NULL;
  747. if (! ::IsEmptyStringW(pcwszConfName))
  748. {
  749. m_ConfList.Reset();
  750. while (NULL != (pConf = m_ConfList.Iterate()))
  751. {
  752. if ((0 == ::My_strcmpW(pConf->GetName(), pcwszConfName)) &&
  753. (pConf->IsActive()))
  754. {
  755. break;
  756. }
  757. }
  758. }
  759. return pConf;
  760. }
  761. // GetConferenceFromNumber - get the T120 conference with the specified number.
  762. PCONFERENCE DCRNCConferenceManager::
  763. GetConferenceFromNumber ( GCCNumericString NumericName )
  764. {
  765. PCONFERENCE pConf = NULL;
  766. if (! ::IsEmptyStringA(NumericName))
  767. {
  768. m_ConfList.Reset();
  769. while (NULL != (pConf = m_ConfList.Iterate()))
  770. {
  771. LPSTR pszConfNumericName = pConf->GetNumericName();
  772. if (NULL != pszConfNumericName &&
  773. 0 == ::lstrcmpA(pszConfNumericName, NumericName))
  774. {
  775. break;
  776. }
  777. }
  778. }
  779. return pConf;
  780. }
  781. /****************************************************************************/
  782. /* Handle a GCC callback. */
  783. /****************************************************************************/
  784. void DCRNCConferenceManager::
  785. HandleGCCCallback ( GCCMessage * pGCCMessage )
  786. {
  787. DebugEntry(DCRNCConferenceManager::HandleGCCCallback);
  788. TRACE_OUT(("DCRNCConferenceManager::HandleGCCCallback: msg_type=%u", (UINT) pGCCMessage->message_type));
  789. switch (pGCCMessage->message_type)
  790. {
  791. case GCC_CREATE_CONFIRM:
  792. {
  793. PCONFERENCE pConf;
  794. LPWSTR pwszConfName;
  795. // For create confirm, the conference won't
  796. // know its ID yet (it is contained in this message), so get
  797. // the conference by name.
  798. if (NO_ERROR == ::GetUnicodeFromGCC(
  799. pGCCMessage->u.create_confirm.conference_name.numeric_string,
  800. pGCCMessage->u.create_confirm.conference_name.text_string,
  801. &pwszConfName))
  802. {
  803. pConf = GetConferenceFromName(pwszConfName);
  804. if (NULL != pConf)
  805. {
  806. pConf->HandleGCCCallback(pGCCMessage);
  807. }
  808. delete pwszConfName;
  809. }
  810. }
  811. break;
  812. case GCC_JOIN_CONFIRM:
  813. HandleJoinConfirm(&(pGCCMessage->u.join_confirm));
  814. break;
  815. case GCC_CONDUCT_GIVE_INDICATION:
  816. HandleConductGiveInd(&(pGCCMessage->u.conduct_give_indication));
  817. break;
  818. case GCC_JOIN_INDICATION:
  819. HandleJoinInd(&(pGCCMessage->u.join_indication));
  820. break;
  821. case GCC_ADD_INDICATION:
  822. HandleAddInd(&(pGCCMessage->u.add_indication));
  823. break;
  824. case GCC_SUB_INITIALIZED_INDICATION:
  825. HandleSubInitializedInd(&(pGCCMessage->u.conf_sub_initialized_indication));
  826. break;
  827. case GCC_ROSTER_REPORT_INDICATION:
  828. // update the (node id, name) list and user data
  829. UpdateNodeIdNameListAndUserData(pGCCMessage);
  830. // fall through
  831. case GCC_INVITE_CONFIRM:
  832. case GCC_ADD_CONFIRM:
  833. case GCC_DISCONNECT_INDICATION:
  834. case GCC_DISCONNECT_CONFIRM:
  835. case GCC_TERMINATE_INDICATION:
  836. case GCC_TERMINATE_CONFIRM:
  837. case GCC_ANNOUNCE_PRESENCE_CONFIRM:
  838. case GCC_ROSTER_INQUIRE_CONFIRM:
  839. case GCC_PERMIT_TO_ANNOUNCE_PRESENCE:
  840. case GCC_EJECT_USER_INDICATION:
  841. {
  842. /****************************************************************/
  843. /* All these events are passed straight onto one of our */
  844. /* conferences. */
  845. /****************************************************************/
  846. /****************************************************************/
  847. /* Get the conference ID from the message */
  848. /****************************************************************/
  849. GCCConfID nConfID = ::GetConfIDFromMessage(pGCCMessage);
  850. /****************************************************************/
  851. /* See whether we have a conference with this ID; */
  852. /****************************************************************/
  853. PCONFERENCE pConf = GetConferenceFromID(nConfID);
  854. if (NULL != pConf)
  855. {
  856. /****************************************************************/
  857. /* Pass the event onto the conference. */
  858. /****************************************************************/
  859. pConf->HandleGCCCallback(pGCCMessage);
  860. }
  861. else
  862. {
  863. // bugbug: should still reply to indications that require a response.
  864. TRACE_OUT(("DCRNCConferenceManager::HandleGCCCallback: No conference found with ID %d", nConfID));
  865. }
  866. }
  867. break;
  868. #ifdef TSTATUS_INDICATION
  869. case GCC_TRANSPORT_STATUS_INDICATION:
  870. {
  871. WORD state = 0;
  872. TRACE_OUT(("DCRNCConferenceManager::HandleGCCCallback: GCC msg type GCC_TRANSPORT_STATUS_INDICATION"));
  873. TRACE_OUT(("Device identifier '%s'",
  874. pGCCMessage->u.transport_status.device_identifier));
  875. TRACE_OUT(("Remote address '%s'",
  876. pGCCMessage->u.transport_status.remote_address));
  877. TRACE_OUT(("Message '%s'",
  878. pGCCMessage->u.transport_status.message));
  879. state = pGCCMessage->u.transport_status.state;
  880. #ifdef DEBUG
  881. LPSTR stateString =
  882. (state == TSTATE_NOT_READY ? "TSTATE_NOT_READY" :
  883. (state == TSTATE_NOT_CONNECTED ? "TSTATE_NOT_CONNECTED" :
  884. (state == TSTATE_CONNECT_PENDING ? "TSTATE_CONNECT_PENDING" :
  885. (state == TSTATE_CONNECTED ? "TSTATE_CONNECTED" :
  886. (state == TSTATE_REMOVED ? "TSTATE_REMOVED" :
  887. ("UNKNOWN STATE"))))));
  888. TRACE_OUT(("DCRNCConferenceManager::HandleGCCCallback: Transport state %d (%s)",
  889. pGCCMessage->u.transport_status.state,
  890. (const char *)stateString));
  891. #endif // DEBUG
  892. }
  893. break;
  894. case GCC_STATUS_INDICATION:
  895. {
  896. WORD state = 0;
  897. #ifdef DEBUG
  898. LPSTR stateString =
  899. (state == GCC_STATUS_PACKET_RESOURCE_FAILURE ? "GCC_STATUS_PACKET_RESOURCE_FAILURE " :
  900. (state == GCC_STATUS_PACKET_LENGTH_EXCEEDED ? "GCC_STATUS_PACKET_LENGTH_EXCEEDED " :
  901. (state == GCC_STATUS_CTL_SAP_RESOURCE_ERROR ? "GCC_STATUS_CTL_SAP_RESOURCE_ERROR " :
  902. (state == GCC_STATUS_APP_SAP_RESOURCE_ERROR ? "GCC_STATUS_APP_SAP_RESOURCE_ERROR " :
  903. (state == GCC_STATUS_CONF_RESOURCE_ERROR ? "GCC_STATUS_CONF_RESOURCE_ERROR " :
  904. (state == GCC_STATUS_INCOMPATIBLE_PROTOCOL ? "GCC_STATUS_INCOMPATIBLE_PROTOCOL " :
  905. (state == GCC_STATUS_JOIN_FAILED_BAD_CONF_NAME ? "GCC_STATUS_JOIN_FAILED_BAD_CONF_NAME" :
  906. (state == GCC_STATUS_JOIN_FAILED_BAD_CONVENER ? "GCC_STATUS_JOIN_FAILED_BAD_CONVENER " :
  907. (state == GCC_STATUS_JOIN_FAILED_LOCKED ? "GCC_STATUS_JOIN_FAILED_LOCKED " :
  908. ("UNKNOWN STATUS"))))))))));
  909. TRACE_OUT(("DCRNCConferenceManager::HandleGCCCallback: GCC_STATUS_INDICATION, type %d (%s)",
  910. pGCCMessage->u.status_indication.status_message_type,
  911. (const char *)stateString));
  912. #endif // DEBUG
  913. }
  914. break;
  915. #endif // TSTATUS_INDICATION
  916. case GCC_INVITE_INDICATION:
  917. /****************************************************************/
  918. /* We have been invited into a conference: Create a new */
  919. /* (incoming) conference. */
  920. /****************************************************************/
  921. HandleInviteIndication(&(pGCCMessage->u.invite_indication));
  922. break;
  923. case GCC_CREATE_INDICATION:
  924. /****************************************************************/
  925. /* A new conference has been created. */
  926. /****************************************************************/
  927. HandleCreateIndication(&(pGCCMessage->u.create_indication));
  928. break;
  929. case GCC_QUERY_CONFIRM:
  930. HandleQueryConfirmation(&(pGCCMessage->u.query_confirm));
  931. break;
  932. case GCC_QUERY_INDICATION:
  933. HandleQueryIndication(&(pGCCMessage->u.query_indication));
  934. break;
  935. case GCC_CONNECTION_BROKEN_INDICATION:
  936. BroadcastGCCCallback(pGCCMessage);
  937. break;
  938. case GCC_LOCK_INDICATION:
  939. HandleLockIndication(&(pGCCMessage->u.lock_indication));
  940. break;
  941. // case GCC_APPLICATION_INVOKE_CONFIRM:
  942. // This just indicates the g_pIT120ControlSap->AppletInvokeRequest succeeded.
  943. // There is no official confirmation from the remote machine.
  944. // FUTURE: Add protocol + code to respond to the launch request.
  945. // break;
  946. case GCC_APPLICATION_INVOKE_INDICATION:
  947. HandleApplicationInvokeIndication(&(pGCCMessage->u.application_invoke_indication));
  948. break;
  949. case GCC_UNLOCK_INDICATION:
  950. HandleUnlockIndication(&(pGCCMessage->u.unlock_indication));
  951. break;
  952. case GCC_TIME_INQUIRE_INDICATION:
  953. HandleTimeInquireIndication(&(pGCCMessage->u.time_inquire_indication));
  954. break;
  955. #ifdef DEBUG
  956. case GCC_APP_ROSTER_REPORT_INDICATION:
  957. TRACE_OUT(("DCRNCConferenceManager::HandleGCCCallback: GCC msg type GCC_APP_ROSTER_REPORT_INDICATION"));
  958. break;
  959. #endif /* DEBUG */
  960. default :
  961. /****************************************************************/
  962. /* This should be an exhaustive list of all the events we dont */
  963. /* handle: */
  964. /* */
  965. /* GCC_TEXT_MESSAGE_INDICATION */
  966. /* GCC_TIME_REMAINING_INDICATION */
  967. /* */
  968. /* GCC_ALLOCATE_HANDLE_CONFIRM */
  969. /* GCC_APP_ROSTER_INQUIRE_CONFIRM */
  970. /* GCC_ASSIGN_TOKEN_CONFIRM */
  971. /* GCC_ASSISTANCE_CONFIRM */
  972. /* GCC_ASSISTANCE_INDICATION */
  973. /* GCC_CONDUCT_ASK_CONFIRM */
  974. /* GCC_CONDUCT_ASK_INDICATION */
  975. /* GCC_CONDUCT_ASSIGN_CONFIRM */
  976. /* GCC_CONDUCT_ASSIGN_INDICATION */
  977. /* GCC_CONDUCT_GIVE_CONFIRM */
  978. /* GCC_CONDUCT_GRANT_CONFIRM */
  979. /* GCC_CONDUCT_GRANT_INDICATION */
  980. /* GCC_CONDUCT_INQUIRE_CONFIRM */
  981. /* GCC_CONDUCT_PLEASE_CONFIRM */
  982. /* GCC_CONDUCT_PLEASE_INDICATION */
  983. /* GCC_CONDUCT_RELEASE_CONFIRM */
  984. /* GCC_CONDUCT_RELEASE_INDICATION */
  985. /* GCC_CONFERENCE_EXTEND_CONFIRM */
  986. /* GCC_CONFERENCE_EXTEND_INDICATION */
  987. /* GCC_DELETE_ENTRY_CONFIRM */
  988. /* GCC_EJECT_USER_CONFIRM */
  989. /* GCC_ENROLL_CONFIRM */
  990. /* GCC_LOCK_CONFIRM */
  991. /* GCC_LOCK_REPORT_INDICATION */
  992. /* GCC_MONITOR_CONFIRM */
  993. /* GCC_MONITOR_INDICATION */
  994. /* GCC_PERMIT_TO_ENROLL_INDICATION: */
  995. /* GCC_REGISTER_CHANNEL_CONFIRM */
  996. /* GCC_RETRIEVE_ENTRY_CONFIRM */
  997. /* GCC_SET_PARAMETER_CONFIRM */
  998. /* GCC_TEXT_MESSAGE_CONFIRM */
  999. /* GCC_TIME_INQUIRE_CONFIRM */
  1000. /* GCC_TIME_REMAINING_CONFIRM */
  1001. /* GCC_TRANSFER_CONFIRM */
  1002. /* GCC_TRANSFER_INDICATION */
  1003. /* GCC_UNLOCK_CONFIRM */
  1004. /****************************************************************/
  1005. TRACE_OUT(("DCRNCConferenceManager::HandleGCCCallback: Ignoring msg_type=%u", pGCCMessage->message_type));
  1006. break;
  1007. }
  1008. DebugExitVOID(DCRNCConferenceManager::HandleGCCCallback);
  1009. }
  1010. void DCRNCConferenceManager::
  1011. BroadcastGCCCallback ( GCCMessage *pGCCMessage )
  1012. {
  1013. DebugEntry(DCRNCConferenceManager::BroadcastGCCCallback);
  1014. // An event has come in that is of potential interest to all
  1015. // conferences, so pass it on to them.
  1016. // Note that this is currently only used for broken logical
  1017. // connections that are actually on a single conference because
  1018. // T120 maps logical connections to conferences.
  1019. PCONFERENCE pConf;
  1020. m_ConfList.Reset();
  1021. while (NULL != (pConf = m_ConfList.Iterate()))
  1022. {
  1023. pConf->HandleGCCCallback(pGCCMessage);
  1024. }
  1025. DebugExitVOID(DCRNCConferenceManager::BroadcastGCCCallback);
  1026. }
  1027. // HandleJoinConfirm - handle a GCC_JOIN_CONFIRM message.
  1028. void DCRNCConferenceManager::
  1029. HandleJoinConfirm ( JoinConfirmMessage * pJoinConfirm )
  1030. {
  1031. PCONFERENCE pConf = NULL;
  1032. LPWSTR pwszConfName;
  1033. DebugEntry(DCRNCConferenceManager::HandleJoinConfirm);
  1034. // For join confirm, the conference won't know its ID yet
  1035. // (it is contained in this message),
  1036. // so get the conference by name.
  1037. HRESULT hr = GetUnicodeFromGCC((PCSTR)pJoinConfirm->conference_name.numeric_string,
  1038. pJoinConfirm->conference_name.text_string,
  1039. &pwszConfName);
  1040. if (NO_ERROR == hr)
  1041. {
  1042. pConf = GetConferenceFromName(pwszConfName);
  1043. delete pwszConfName;
  1044. }
  1045. if (pConf == NULL)
  1046. {
  1047. pConf = GetConferenceFromNumber(pJoinConfirm->conference_name.numeric_string);
  1048. }
  1049. if (pConf != NULL)
  1050. {
  1051. pConf->HandleJoinConfirm(pJoinConfirm);
  1052. }
  1053. DebugExitVOID(DCRNCConferenceManager::HandleJoinConfirm);
  1054. }
  1055. #ifdef ENABLE_START_REMOTE
  1056. // HandleCreateIndication - handle a GCC_CREATE_INDICATION message.
  1057. void DCRNCConferenceManager::
  1058. HandleCreateIndication ( CreateIndicationMessage * pCreateMessage )
  1059. {
  1060. PCONFERENCE pNewConference = NULL;
  1061. HRESULT hr = UI_RC_USER_REJECTED;
  1062. LPWSTR name;
  1063. DebugEntry(DCRNCConferenceManager::HandleCreateIndication);
  1064. TRACE_OUT(("GCC event: GCC_CREATE_INDICATION"));
  1065. TRACE_OUT(("Conference ID %ld", pCreateMessage->conference_id));
  1066. if (pCreateMessage->conductor_privilege_list == NULL)
  1067. {
  1068. TRACE_OUT(("Conductor privilege list is NULL"));
  1069. }
  1070. else
  1071. {
  1072. TRACE_OUT(("Conductor priv, terminate allowed %d",
  1073. pCreateMessage->conductor_privilege_list->terminate_is_allowed));
  1074. }
  1075. if (pCreateMessage->conducted_mode_privilege_list == NULL)
  1076. {
  1077. TRACE_OUT(("Conducted mode privilege list is NULL"));
  1078. }
  1079. else
  1080. {
  1081. TRACE_OUT(("Conducted mode priv, terminate allowed %d",
  1082. pCreateMessage->conducted_mode_privilege_list->terminate_is_allowed));
  1083. }
  1084. if (pCreateMessage->non_conducted_privilege_list == NULL)
  1085. {
  1086. TRACE_OUT(("Non-conducted mode privilege list is NULL"));
  1087. }
  1088. else
  1089. {
  1090. TRACE_OUT(("non-conducted priv, terminate allowed %d",
  1091. pCreateMessage->non_conducted_privilege_list->terminate_is_allowed));
  1092. }
  1093. hr = ::GetUnicodeFromGCC((PCSTR)pCreateMessage->conference_name.numeric_string,
  1094. (PWSTR)pCreateMessage->conference_name.text_string,
  1095. &name);
  1096. if (NO_ERROR == hr)
  1097. {
  1098. hr = CreateNewConference(name,
  1099. pCreateMessage->conference_id,
  1100. &pNewConference);
  1101. delete name;
  1102. }
  1103. if (NO_ERROR == hr)
  1104. {
  1105. hr = pNewConference->StartIncoming();
  1106. if (NO_ERROR == hr)
  1107. {
  1108. g_pNCConfMgr->CreateConferenceRequest(pNewConference);
  1109. return;
  1110. }
  1111. }
  1112. ERROR_OUT(("Failed to create incoming conference"));
  1113. GCCCreateResponse(hr, pMsg->conference_id, &pMsg->conference_name);
  1114. DebugExitVOID(DCRNCConferenceManager::HandleCreateIndication);
  1115. }
  1116. #endif // ENABLE_START_REMOTE
  1117. void DCRNCConferenceManager::
  1118. GCCCreateResponse
  1119. (
  1120. HRESULT hr,
  1121. GCCConfID conference_id,
  1122. GCCConferenceName * pGCCName
  1123. )
  1124. {
  1125. DebugEntry(DCRNCConferenceManager::GCCCreateResponse);
  1126. GCCError GCCrc = g_pIT120ControlSap->ConfCreateResponse(
  1127. NULL,
  1128. conference_id,
  1129. 0,
  1130. NULL, /* domain_parameters */
  1131. 0, /* number_of_network_addresses */
  1132. NULL, /* local_network_address_list */
  1133. 0, /* number_of_user_data_members */
  1134. NULL, /* user_data_list */
  1135. ::MapRCToGCCResult(hr));
  1136. TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfCreateResponse, rc=%d", GCCrc));
  1137. DebugExitVOID(DCRNCConferenceManager::GCCCreateResponse);
  1138. }
  1139. /****************************************************************************/
  1140. /* HandleInviteIndication - handle a GCC_INVITE_INDICATION message. */
  1141. /****************************************************************************/
  1142. void DCRNCConferenceManager::
  1143. HandleInviteIndication ( InviteIndicationMessage * pInviteMessage )
  1144. {
  1145. LPWSTR pwszConfName;
  1146. PCONFERENCE pNewConference = NULL;
  1147. HRESULT hr;
  1148. CLogicalConnection *pConEntry;
  1149. CInviteIndWork *pInviteUI;
  1150. PT120PRODUCTVERSION pVersion;
  1151. DebugEntry(DCRNCConferenceManager::HandleInviteIndication);
  1152. TRACE_OUT(("GCC event: GCC_INVITE_INDICATION"));
  1153. TRACE_OUT(("Invited into conference ID %ld", pInviteMessage->conference_id));
  1154. // Create a new conference, using the constructor for an incoming T120
  1155. // conference.
  1156. hr = GetUnicodeFromGCC((PCSTR)pInviteMessage->conference_name.numeric_string,
  1157. (PWSTR)pInviteMessage->conference_name.text_string,
  1158. &pwszConfName);
  1159. //
  1160. // Check to see if we're allowed to be invited. We may never get here
  1161. // if we properly signal callers that we won't accept a nonsecure
  1162. // Invite, but if they do it anyway or lead with T.120 we will enforce
  1163. // the registry setting here.
  1164. //
  1165. RegEntry re(CONFERENCING_KEY, HKEY_CURRENT_USER);
  1166. if ( re.GetNumber(REGVAL_SECURITY_INCOMING_REQUIRED,
  1167. DEFAULT_SECURITY_INCOMING_REQUIRED ))
  1168. {
  1169. if ( !pInviteMessage->fSecure )
  1170. {
  1171. WARNING_OUT(("HandleInviteIndication: CONNECTION is NOT SECURE"));
  1172. hr = UI_RC_T120_SECURITY_FAILED;
  1173. }
  1174. }
  1175. if (NO_ERROR == hr)
  1176. {
  1177. hr = CreateNewConference(pwszConfName,
  1178. pInviteMessage->conference_id,
  1179. &pNewConference,
  1180. FALSE,
  1181. pInviteMessage->fSecure);
  1182. delete pwszConfName;
  1183. if (NO_ERROR == hr)
  1184. {
  1185. // Make sure the conference object does not go away randomly.
  1186. pNewConference->AddRef();
  1187. pNewConference->SetActive(FALSE);
  1188. DBG_SAVE_FILE_LINE
  1189. pConEntry = pNewConference->NewLogicalConnection(CONF_CON_INVITED,
  1190. pInviteMessage->connection_handle,
  1191. NULL,
  1192. 0,
  1193. pInviteMessage->fSecure);
  1194. if (NULL != pConEntry)
  1195. {
  1196. // Save the T120 connection handle in the connection record
  1197. // so that disconnect indications take down the conference.
  1198. pConEntry->SetInviteReqConnHandle(pInviteMessage->connection_handle);
  1199. hr = pNewConference->StartIncoming();
  1200. // Linearize the invite requests so that two invites don't fight each other
  1201. // for attention, and so that the second invite has a conference to see in
  1202. // rosters and join if the first invite gets accepted.
  1203. if (NO_ERROR == hr)
  1204. {
  1205. pVersion = ::GetVersionData(pInviteMessage->number_of_user_data_members,
  1206. pInviteMessage->user_data_list);
  1207. DBG_SAVE_FILE_LINE
  1208. pInviteUI = new CInviteIndWork(pNewConference,
  1209. (LPCWSTR)(pInviteMessage->caller_identifier),
  1210. pVersion,
  1211. pInviteMessage->user_data_list,
  1212. pInviteMessage->number_of_user_data_members,
  1213. pConEntry);
  1214. if (pInviteUI)
  1215. {
  1216. pNewConference->SetInviteIndWork(pInviteUI);
  1217. m_InviteIndWorkList.AddWorkItem(pInviteUI);
  1218. hr = NO_ERROR;
  1219. }
  1220. else
  1221. {
  1222. hr = UI_RC_OUT_OF_MEMORY;
  1223. }
  1224. }
  1225. }
  1226. else
  1227. {
  1228. hr = UI_RC_OUT_OF_MEMORY;
  1229. }
  1230. // This Release corresponds to the above AddRef.
  1231. if (0 == pNewConference->Release())
  1232. {
  1233. // Make sure no one will use it any more.
  1234. pNewConference = NULL;
  1235. }
  1236. }
  1237. }
  1238. if (NO_ERROR != hr)
  1239. {
  1240. if (NULL != pNewConference)
  1241. {
  1242. pNewConference->InviteResponse(hr);
  1243. }
  1244. else
  1245. {
  1246. // LONCHANC: we have to somehow send a response PDU out.
  1247. g_pIT120ControlSap->ConfInviteResponse(
  1248. pInviteMessage->conference_id,
  1249. NULL,
  1250. pInviteMessage->fSecure,
  1251. NULL, // domain parms
  1252. 0, // number_of_network_addresses
  1253. NULL, // local_network_address_list
  1254. g_nVersionRecords, // number_of_user_data_members
  1255. g_ppVersionUserData,// user_data_list
  1256. GCC_RESULT_ENTRY_ALREADY_EXISTS);
  1257. }
  1258. }
  1259. DebugExitHRESULT(DCRNCConferenceManager::HandleInviteIndication, hr);
  1260. }
  1261. /****************************************************************************/
  1262. /* HandleJoinInd - handle a GCC_JOIN_INDICATION message. */
  1263. /****************************************************************************/
  1264. void DCRNCConferenceManager::
  1265. HandleJoinInd ( JoinIndicationMessage * pJoinInd )
  1266. {
  1267. DebugEntry(DCRNCConferenceManager::HandleJoinInd);
  1268. GCCResult Result = GCC_RESULT_SUCCESSFUL;
  1269. // Look up conference ID, and if not found, dismiss request.
  1270. CJoinIndWork *pJoinUI;
  1271. CLogicalConnection *pConEntry;
  1272. PT120PRODUCTVERSION pVersion;
  1273. PCONFERENCE pConf = GetConferenceFromID(pJoinInd->conference_id);
  1274. if (NULL != pConf)
  1275. {
  1276. //
  1277. // Under RDS, if this conference has been hit with bad passwords
  1278. // too many times, everyone is out of luck and we will not accept
  1279. // anyone into this conference anymore.
  1280. //
  1281. if (g_bRDS && ( pConf->InvalidPwdCount() >= MAX_INVALID_PASSWORDS ))
  1282. {
  1283. WARNING_OUT(("RDS: locked out by too many bad pwd attempts"));
  1284. Result = GCC_RESULT_USER_REJECTED;
  1285. }
  1286. // Validate conference password, if required.
  1287. else if (!pConf->ValidatePassword(pJoinInd->password_challenge))
  1288. {
  1289. //
  1290. // Only increment the wrong password count if one was
  1291. // supplied
  1292. //
  1293. if ( pJoinInd->password_challenge )
  1294. pConf->IncInvalidPwdCount();
  1295. if ( g_bRDS &&
  1296. ( pConf->InvalidPwdCount() >= MAX_INVALID_PASSWORDS ))
  1297. {
  1298. Result = GCC_RESULT_USER_REJECTED;
  1299. }
  1300. else
  1301. {
  1302. Result = GCC_RESULT_INVALID_PASSWORD;
  1303. }
  1304. }
  1305. else
  1306. pConf->ResetInvalidPwdCount();
  1307. }
  1308. else
  1309. {
  1310. Result = GCC_RESULT_INVALID_CONFERENCE;
  1311. }
  1312. if (Result == GCC_RESULT_SUCCESSFUL)
  1313. {
  1314. DBG_SAVE_FILE_LINE
  1315. pConEntry = pConf->NewLogicalConnection(
  1316. CONF_CON_JOINED,
  1317. pJoinInd->connection_handle,
  1318. NULL,
  1319. 0,
  1320. pConf->IsSecure());
  1321. if (NULL != pConEntry)
  1322. {
  1323. HRESULT hr;
  1324. pVersion = ::GetVersionData(pJoinInd->number_of_user_data_members,
  1325. pJoinInd->user_data_list);
  1326. DBG_SAVE_FILE_LINE
  1327. pJoinUI = new CJoinIndWork(pJoinInd->join_response_tag,
  1328. pConf,
  1329. pJoinInd->caller_identifier,
  1330. pConEntry,
  1331. pVersion,
  1332. pJoinInd->number_of_user_data_members,
  1333. pJoinInd->user_data_list,
  1334. &hr);
  1335. if (NULL != pJoinUI && NO_ERROR == hr)
  1336. {
  1337. m_JoinIndWorkList.AddWorkItem(pJoinUI);
  1338. return;
  1339. }
  1340. // Handle failure
  1341. delete pJoinUI;
  1342. pConEntry->Delete(UI_RC_OUT_OF_MEMORY);
  1343. }
  1344. Result = GCC_RESULT_RESOURCES_UNAVAILABLE;
  1345. }
  1346. ::GCCJoinResponseWrapper(pJoinInd->join_response_tag,
  1347. NULL,
  1348. Result,
  1349. pJoinInd->conference_id);
  1350. DebugExitVOID(DCRNCConferenceManager::HandleJoinInd);
  1351. }
  1352. void HandleQueryConfirmation ( QueryConfirmMessage * pQueryMessage )
  1353. {
  1354. DebugEntry(HandleQueryConfirmation);
  1355. ASSERT(g_pQueryRemoteList);
  1356. CQueryRemoteWork *pQueryRemote;
  1357. // Must have a pending query and it must be first in
  1358. // sequential work list.
  1359. g_pQueryRemoteList->Reset();
  1360. while (NULL != (pQueryRemote = g_pQueryRemoteList->Iterate()))
  1361. {
  1362. if (pQueryRemote->GetConnectionHandle() == pQueryMessage->connection_handle)
  1363. {
  1364. // GCC has given us a valid query response, so handle it.
  1365. pQueryRemote->HandleQueryConfirmation(pQueryMessage);
  1366. break;
  1367. }
  1368. }
  1369. if (NULL == pQueryRemote)
  1370. {
  1371. // Unexpected GCC Query Confirmation.
  1372. WARNING_OUT(("HandleQueryConfirmation: Unmatched GCCQueryConfirm"));
  1373. }
  1374. DebugExitVOID(HandleQueryConfirmation);
  1375. }
  1376. /****************************************************************************/
  1377. /* NotifyConferenceComplete() - see ernccm.hpp */
  1378. /****************************************************************************/
  1379. void DCRNCConferenceManager::
  1380. NotifyConferenceComplete
  1381. (
  1382. PCONFERENCE pConf,
  1383. BOOL bIncoming,
  1384. HRESULT result
  1385. )
  1386. {
  1387. DebugEntry(DCRNCConferenceManager::NotifyConferenceComplete);
  1388. ASSERT(NULL != pConf);
  1389. // If the new conference was successfully added, then ensure that it
  1390. // is marked as active. This is for the invite case, and is done before
  1391. // telling the UI about the conference.
  1392. HRESULT hr = result;
  1393. if (NO_ERROR == hr)
  1394. {
  1395. pConf->SetActive(TRUE);
  1396. }
  1397. // If the conference failed to start, tell the UI so that
  1398. // it can display a pop-up.
  1399. // Note this this allows message pre-emption which can cause GCC to give back a GCC event.
  1400. // In particular, a JoinRequest completion event, which must be ignored.
  1401. // The following is a guard because NotifyConferenceComplete is called all
  1402. // over the place and we do not want the user notified through callbacks
  1403. // for inline errors. All inline errors are meant to trickle back through the
  1404. // originating API, so these callbacks are only enabled once the user is returned
  1405. // success.
  1406. if (pConf->GetNotifyToDo())
  1407. {
  1408. pConf->SetNotifyToDo(FALSE);
  1409. //
  1410. // LONCHANC: This function may be called inside
  1411. // ConfMgr::ReleaseInterface(). As a result, the global pointer
  1412. // to the callback interface may already be nulled out.
  1413. // Check it before use it.
  1414. //
  1415. if (NULL != g_pCallbackInterface)
  1416. {
  1417. g_pCallbackInterface->OnConferenceStarted(pConf, hr);
  1418. }
  1419. }
  1420. if (NO_ERROR == hr)
  1421. {
  1422. // If the conference is new as the result of an invite, then it has an entry
  1423. // at the start of the sequential work item list. Now that the conference is up
  1424. // and the UI has been told, this entry is removed to allow other invite
  1425. // requests to be processed.
  1426. m_InviteIndWorkList.RemoveWorkItem(pConf->GetInviteIndWork());
  1427. pConf->SetInviteIndWork(NULL);
  1428. }
  1429. else
  1430. {
  1431. RemoveConference(pConf);
  1432. }
  1433. DebugExitVOID(DCRNCConferenceManager::NotifyConferenceComplete);
  1434. }
  1435. /****************************************************************************/
  1436. /* NotifyRosterChanged() - see ernccm.hpp */
  1437. /****************************************************************************/
  1438. // RemoveConference() - remove the conference from the conference list,
  1439. // and destroy the conference.
  1440. void DCRNCConferenceManager::
  1441. RemoveConference ( PCONFERENCE pConf, BOOL fDontCheckList, BOOL fReleaseNow )
  1442. {
  1443. DebugEntry(DCRNCConferenceManager::RemoveConference);
  1444. if (pConf != NULL)
  1445. {
  1446. if (m_ConfList.Remove(pConf) || fDontCheckList)
  1447. {
  1448. pConf->OnRemoved(fReleaseNow);
  1449. m_InviteIndWorkList.PurgeListEntriesByOwner(pConf);
  1450. m_JoinIndWorkList.PurgeListEntriesByOwner(pConf);
  1451. }
  1452. else
  1453. {
  1454. // If we get here, we haven't found the conference.
  1455. // This actually happens because when a conference is being
  1456. // terminated, its destructor calls DCRNCConference::Leave()
  1457. // to ensure a speedy exit, if required. However, if the
  1458. // conference is currently not yet active (e.g. waiting for
  1459. // the user to supply a password), calling Leave() causes
  1460. // RemoveConference() to be called back. In this case,
  1461. // because the conference has already been removed from the
  1462. // list, this function does nothing.
  1463. }
  1464. }
  1465. DebugExitVOID(DCRNCConferenceManager::RemoveConference);
  1466. }
  1467. /****************************************************************************/
  1468. /* EjectUserFromConference() - see ernccm.hpp */
  1469. /****************************************************************************/
  1470. /****************************************************************************/
  1471. /* SendUserTextMessage() - see ernccm.hpp */
  1472. /****************************************************************************/
  1473. /****************************************************************************/
  1474. /* TimeRemainingInConference() - see ernccm.hpp */
  1475. /****************************************************************************/
  1476. /****************************************************************************/
  1477. /* GCC callback function. */
  1478. /****************************************************************************/
  1479. void CALLBACK DCRNCConferenceManager::
  1480. GCCCallBackHandler ( GCCMessage * pGCCMessage )
  1481. {
  1482. DCRNCConferenceManager *pConfManager;
  1483. /************************************************************************/
  1484. /* The message has a user defined field which we use to store a pointer */
  1485. /* to the CM class. Use it to pass the message onto CM. */
  1486. /************************************************************************/
  1487. pConfManager = (DCRNCConferenceManager *) pGCCMessage->user_defined;
  1488. //
  1489. // Check the pointer isnt completely daft,
  1490. // and guard against getting events after shutting down
  1491. // (a current bug in GCC/MCS).
  1492. if (pConfManager == g_pNCConfMgr)
  1493. {
  1494. /************************************************************************/
  1495. /* Pass the message onto CM and return the returned code. */
  1496. /************************************************************************/
  1497. g_pNCConfMgr->HandleGCCCallback(pGCCMessage);
  1498. }
  1499. else
  1500. {
  1501. WARNING_OUT(("Dud user_defined field, pConfMgr=%p, g_pNCConfMgr=%p",
  1502. pConfManager, g_pNCConfMgr));
  1503. }
  1504. }
  1505. HRESULT GCCJoinResponseWrapper
  1506. (
  1507. GCCResponseTag join_response_tag,
  1508. GCCChallengeRequestResponse *password_challenge,
  1509. GCCResult result,
  1510. GCCConferenceID conferenceID,
  1511. UINT nUserData,
  1512. GCCUserData **ppUserData
  1513. )
  1514. {
  1515. HRESULT hr;
  1516. GCCError GCCrc;
  1517. DebugEntry(GCCJoinResponseWrapper);
  1518. TRACE_OUT(("GCC event: GCC_JOIN_INDICATION"));
  1519. TRACE_OUT(("Response tag %d", join_response_tag));
  1520. if (g_pControlSap->IsThisNodeTopProvider(conferenceID) == FALSE)
  1521. {
  1522. GCCrc = g_pIT120ControlSap->ConfJoinResponse(join_response_tag,
  1523. password_challenge,
  1524. nUserData,
  1525. ppUserData,
  1526. result);
  1527. }
  1528. else
  1529. {
  1530. GCCrc = g_pIT120ControlSap->ConfJoinResponse(join_response_tag,
  1531. password_challenge,
  1532. g_nVersionRecords,
  1533. g_ppVersionUserData,
  1534. result);
  1535. }
  1536. hr = ::GetGCCRCDetails(GCCrc);
  1537. TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfJoinResponse, rc=%d", GCCrc));
  1538. if ((GCCrc != GCC_NO_ERROR) &&
  1539. (result != GCC_RESULT_USER_REJECTED))
  1540. {
  1541. /********************************************************************/
  1542. /* If the call to join response fails, we must try again to reject */
  1543. /* the join request. */
  1544. /********************************************************************/
  1545. ERROR_OUT(("GCCJoinResponseWrapper: GCC error %d responding to join ind", GCCrc));
  1546. GCCrc = g_pIT120ControlSap->ConfJoinResponse(join_response_tag,
  1547. password_challenge,
  1548. g_nVersionRecords,
  1549. g_ppVersionUserData,
  1550. GCC_RESULT_USER_REJECTED);
  1551. TRACE_OUT(("GCC call: g_pIT120ControlSap->ConfJoinResponse (again), rc=%d", GCCrc));
  1552. if (GCCrc != GCC_NO_ERROR)
  1553. {
  1554. /****************************************************************/
  1555. /* If it fails a second time we really are in deep doggy-do. */
  1556. /****************************************************************/
  1557. ERROR_OUT(("GCCJoinResponseWrapper: g_pIT120ControlSap->ConfJoinResponse failed again..."));
  1558. }
  1559. }
  1560. DebugExitHRESULT(GCCJoinResponseWrapper, hr);
  1561. return hr;
  1562. }
  1563. void HandleQueryIndication ( QueryIndicationMessage * pQueryMessage )
  1564. {
  1565. DebugEntry(HandleQueryIndication);
  1566. GCCAsymmetryIndicator ai, ai2;
  1567. GCCNodeType node_type;
  1568. GCCError GCCrc;
  1569. CQueryRemoteWork *pQueryRemote = NULL;
  1570. GCCResult result = GCC_RESULT_SUCCESSFUL;
  1571. OSVERSIONINFO osvi;
  1572. osvi.dwOSVersionInfoSize = sizeof(osvi);
  1573. if (FALSE == ::GetVersionEx (&osvi))
  1574. {
  1575. ERROR_OUT(("GetVersionEx() failed!"));
  1576. }
  1577. if ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && g_bRDS )
  1578. {
  1579. SOCKET socket_number;
  1580. if (g_pMCSController->FindSocketNumber(pQueryMessage->connection_handle, &socket_number))
  1581. {
  1582. TransportConnection XprtConn;
  1583. SET_SOCKET_CONNECTION(XprtConn, socket_number);
  1584. PSocket pSocket = g_pSocketList->FindByTransportConnection(XprtConn);
  1585. ASSERT(NULL != pSocket);
  1586. if (NULL != pSocket)
  1587. {
  1588. AddToMessageLog(EVENTLOG_INFORMATION_TYPE,
  1589. 0,
  1590. MSG_INF_ACCESS,
  1591. pSocket->Remote_Address);
  1592. pSocket->Release();
  1593. }
  1594. }
  1595. }
  1596. // If the caller did not pass in the protocol for deciding who is caller
  1597. // then fabricate something for him and make him the caller.
  1598. if (pQueryMessage->asymmetry_indicator)
  1599. {
  1600. ai = *pQueryMessage->asymmetry_indicator;
  1601. }
  1602. else
  1603. {
  1604. ai.asymmetry_type = GCC_ASYMMETRY_CALLER;
  1605. ai.random_number = 0;
  1606. }
  1607. // let's set default random number, which will be read only in the "unknown" case.
  1608. ai2.random_number = ai.random_number;
  1609. // prepare the query respone
  1610. switch (ai.asymmetry_type)
  1611. {
  1612. case GCC_ASYMMETRY_CALLED:
  1613. ai2.asymmetry_type = GCC_ASYMMETRY_CALLER;
  1614. break;
  1615. case GCC_ASYMMETRY_CALLER:
  1616. ai2.asymmetry_type = GCC_ASYMMETRY_CALLED;
  1617. break;
  1618. case GCC_ASYMMETRY_UNKNOWN:
  1619. // Check if we are not in a pending query
  1620. ASSERT(g_pQueryRemoteList);
  1621. if (! g_pQueryRemoteList->IsEmpty())
  1622. {
  1623. pQueryRemote = g_pQueryRemoteList->PeekHead();
  1624. }
  1625. // If we queryed as unknown
  1626. if (pQueryRemote && pQueryRemote->IsInUnknownQueryRequest())
  1627. {
  1628. pQueryRemote->GetAsymIndicator(&ai2);
  1629. if (ai2.asymmetry_type == GCC_ASYMMETRY_UNKNOWN &&
  1630. ai2.random_number > ai.random_number)
  1631. {
  1632. result = GCC_RESULT_USER_REJECTED;
  1633. }
  1634. }
  1635. else
  1636. {
  1637. ai2.asymmetry_type = GCC_ASYMMETRY_UNKNOWN;
  1638. // ai2.random_number = ~ ai.random_number;
  1639. ai2.random_number--; // lonchanc: we should always be the callee in this case.
  1640. }
  1641. break;
  1642. default:
  1643. result = GCC_RESULT_USER_REJECTED;
  1644. break;
  1645. }
  1646. // Figure out my node type.
  1647. LoadAnnouncePresenceParameters(&node_type, NULL, NULL, NULL);
  1648. // Issue reply.
  1649. GCCrc = g_pIT120ControlSap->ConfQueryResponse(
  1650. pQueryMessage->query_response_tag,
  1651. node_type,
  1652. &ai2,
  1653. g_nVersionRecords,
  1654. g_ppVersionUserData,
  1655. result);
  1656. if (GCCrc)
  1657. {
  1658. TRACE_OUT(("HandleQueryIndication: g_pIT120ControlSap->ConfQueryResponse failed, rc=%d", GCCrc));
  1659. }
  1660. DebugExitVOID(HandleQueryIndication);
  1661. }
  1662. void HandleConductGiveInd ( ConductGiveIndicationMessage * pConductGiveInd )
  1663. {
  1664. DebugEntry(HandleConductGiveInd);
  1665. // Node controller does not accept conductorship being handed over
  1666. // from another node, so reject request.
  1667. GCCError GCCrc = g_pIT120ControlSap->ConductorGiveResponse(pConductGiveInd->conference_id,
  1668. GCC_RESULT_USER_REJECTED);
  1669. TRACE_OUT(("HandleConductGiveInd: Failed to reject ConductGiveIndication, gcc_rc=%u", (UINT) GCCrc));
  1670. DebugExitVOID(HandleConductGiveInd);
  1671. }
  1672. void HandleAddInd ( AddIndicationMessage * pAddInd )
  1673. {
  1674. DebugEntry(HandleAddInd);
  1675. // Just reject the request because we don't do adds on behalf of someone else.
  1676. GCCError GCCrc = g_pIT120ControlSap->ConfAddResponse(
  1677. pAddInd->add_response_tag, // add_response_tag
  1678. pAddInd->conference_id, // conference_id
  1679. pAddInd->requesting_node_id, // requesting_node
  1680. 0, // number_of_user_data_members
  1681. NULL, // user_data_list
  1682. GCC_RESULT_USER_REJECTED); // result
  1683. TRACE_OUT(("HandleAddInd: Failed to reject AddIndication, gcc_rc=%u", (UINT) GCCrc));
  1684. DebugExitVOID(HandleAddInd);
  1685. }
  1686. void HandleLockIndication ( LockIndicationMessage * pLockInd )
  1687. {
  1688. DebugEntry(HandleLockIndication);
  1689. // Just reject the request because we don't do locked conferences.
  1690. GCCError GCCrc = g_pIT120ControlSap->ConfLockResponse(
  1691. pLockInd->conference_id, // conference_id
  1692. pLockInd->requesting_node_id, // requesting_node
  1693. GCC_RESULT_USER_REJECTED); // result
  1694. TRACE_OUT(("HandleLockIndication: Failed to reject LockIndication, gcc_rc=%u", (UINT) GCCrc));
  1695. DebugExitVOID(HandleLockIndication);
  1696. }
  1697. void HandleUnlockIndication ( UnlockIndicationMessage * pUnlockInd )
  1698. {
  1699. DebugEntry(HandleUnlockIndication);
  1700. // Reject the request because we don't manage
  1701. // locking/unlocking of conferences.
  1702. GCCError GCCrc = g_pIT120ControlSap->ConfLockResponse(
  1703. pUnlockInd->conference_id, // conference_id
  1704. pUnlockInd->requesting_node_id, // requesting_node
  1705. GCC_RESULT_USER_REJECTED); // result
  1706. TRACE_OUT(("HandleUnlockIndication: Failed to reject UnlockIndication, gcc_rc=%u", (UINT) GCCrc));
  1707. DebugExitVOID(HandleUnlockIndication);
  1708. }
  1709. void HandleSubInitializedInd ( SubInitializedIndicationMessage * pSubInitInd )
  1710. {
  1711. DebugEntry(HandleSubInitializedInd);
  1712. CLogicalConnection *pConEntry = g_pNCConfMgr->GetConEntryFromConnectionHandle(
  1713. pSubInitInd->connection_handle);
  1714. if (NULL != pConEntry)
  1715. {
  1716. pConEntry->SetConnectionNodeID(pSubInitInd->subordinate_node_id);
  1717. }
  1718. DebugExitVOID(HandleSubInitializedInd);
  1719. }
  1720. // This function is used by the GCC_SUB_INITIALIZED_INDICATION handler.
  1721. // This handler was added to bind the request to enter someone into
  1722. // a conference to the resulting conference roster, so that you could
  1723. // tell which new entry in the roster was the one you requested in.
  1724. // Since the above handler only gets a connection handle (recast here to a
  1725. // request handle) and a userID, this means that the local GCC implementation
  1726. // is guarunteeing that connection handles are unique to a local machine
  1727. // and not duplicated in different conferences (this fact is also being used
  1728. // by the node controller to know when someone invited into a conference leaves).
  1729. CLogicalConnection * DCRNCConferenceManager::
  1730. GetConEntryFromConnectionHandle ( ConnectionHandle hInviteIndConn )
  1731. {
  1732. PCONFERENCE pConf;
  1733. CLogicalConnection *pConEntry;
  1734. m_ConfList.Reset();
  1735. while (NULL != (pConf = m_ConfList.Iterate()))
  1736. {
  1737. pConEntry = pConf->GetConEntry(hInviteIndConn);
  1738. if (NULL != pConEntry)
  1739. {
  1740. return(pConEntry);
  1741. }
  1742. }
  1743. return(NULL);
  1744. }
  1745. void HandleTimeInquireIndication ( TimeInquireIndicationMessage * pTimeInquireInd )
  1746. {
  1747. DebugEntry(HandleTimeInquireIndication);
  1748. // Since we don't currently time messages, and there is no mechanism to say this,
  1749. // or to even say that there is no such conference that we know about, just
  1750. // say that the conference has one hour remaining, with the same scope as the request.
  1751. UserID node_id = pTimeInquireInd->time_is_conference_wide ?
  1752. 0 : pTimeInquireInd->requesting_node_id;
  1753. GCCError GCCrc = g_pIT120ControlSap->ConfTimeRemainingRequest(
  1754. pTimeInquireInd->conference_id,
  1755. 60*60,
  1756. node_id);
  1757. TRACE_OUT(("HandleTimeInquireIndication: Failed to return Time Remaining, gcc_rc=%u", (UINT) GCCrc));
  1758. DebugExitVOID(HandleTimeInquireIndication);
  1759. }
  1760. BOOL DCRNCConferenceManager::
  1761. FindSocketNumber
  1762. (
  1763. GCCNodeID nid,
  1764. SOCKET *socket_number
  1765. )
  1766. {
  1767. // Currently we are relying on the fact there is only one conference at a time.
  1768. PCONFERENCE pConf = m_ConfList.PeekHead();
  1769. if (NULL != pConf)
  1770. {
  1771. return pConf->FindSocketNumber(nid, socket_number);
  1772. }
  1773. return FALSE;
  1774. }
  1775. /* H A N D L E A P P L I C A T I O N I N V O K E I N D I C A T I O N */
  1776. /*----------------------------------------------------------------------------
  1777. %%Function: HandleApplicationInvokeIndication
  1778. TODO: use GCC_OBJECT_KEY instead of GCC_H221_NONSTANDARD_KEY
  1779. ----------------------------------------------------------------------------*/
  1780. #define NUMBER_OF_INTERNAL_STD_APPLETS 2
  1781. typedef struct
  1782. {
  1783. ULONG cNodes;
  1784. const ULONG *aNodes;
  1785. APPLET_ID eAppletId;
  1786. }
  1787. INTERNAL_STD_INVOKE_APPLET;
  1788. static const ULONG c_T126ObjectID[] = {0,0,20,126,0,1}; // Whiteboard
  1789. static const ULONG c_T127ObjectID[] = {0,0,20,127,0,1}; // File Transfer
  1790. static INTERNAL_STD_INVOKE_APPLET s_aStdAppletInvokeInfo[NUMBER_OF_INTERNAL_STD_APPLETS] =
  1791. {
  1792. { // T.126 Whiteboard
  1793. sizeof(c_T126ObjectID) / sizeof(c_T126ObjectID[0]),
  1794. &c_T126ObjectID[0],
  1795. APPLET_ID_WB
  1796. },
  1797. { // T.127 File Transfer
  1798. sizeof(c_T127ObjectID) / sizeof(c_T127ObjectID[0]),
  1799. &c_T127ObjectID[0],
  1800. APPLET_ID_FT
  1801. },
  1802. };
  1803. void InvokeAppletEntity(GCCConfID, GCCNodeID, GCCAppProtocolEntity*);
  1804. int GetInternalStandardAppletInvokeFunction(ULONG, ULONG*);
  1805. void HandleApplicationInvokeIndication ( ApplicationInvokeIndicationMessage * pInvokeMessage )
  1806. {
  1807. DebugEntry(HandleApplicationInvokeIndication);
  1808. for (ULONG i = 0; i < pInvokeMessage->number_of_app_protocol_entities; i++)
  1809. {
  1810. InvokeAppletEntity(pInvokeMessage->conference_id,
  1811. pInvokeMessage->invoking_node_id,
  1812. pInvokeMessage->app_protocol_entity_list[i]);
  1813. }
  1814. DebugExitVOID(HandleApplicationInvokeIndication);
  1815. }
  1816. int GetInternalStandardAppletInvokeFunction(ULONG cNodes, ULONG aNodes[])
  1817. {
  1818. for (ULONG i = 0; i < sizeof(s_aStdAppletInvokeInfo) / sizeof(s_aStdAppletInvokeInfo[0]); i++)
  1819. {
  1820. INTERNAL_STD_INVOKE_APPLET *p = &s_aStdAppletInvokeInfo[i];
  1821. if (cNodes == p->cNodes)
  1822. {
  1823. if (0 == memcmp(aNodes, p->aNodes, cNodes * sizeof(ULONG)))
  1824. {
  1825. return (int)p->eAppletId;
  1826. }
  1827. }
  1828. }
  1829. return -1;
  1830. }
  1831. void InvokeAppletEntity
  1832. (
  1833. GCCConfID nConfID,
  1834. GCCNodeID nidInitiator,
  1835. GCCAppProtocolEntity *pAppEntity
  1836. )
  1837. {
  1838. DebugEntry(InvokeAppletEntity);
  1839. int iAppletId;
  1840. HKEY hkey;
  1841. ULONG cNodes, cbDataSize, i;
  1842. ULONG *pNodeID;
  1843. LPOSTR postrNonStdKey;
  1844. LPBYTE pbData;
  1845. GCCSessionID sidApplet = pAppEntity->session_key.session_id;
  1846. CApplet *pApplet;
  1847. char szGuid[LENGTH_SZGUID_FORMATTED];
  1848. char szKey[MAX_PATH];
  1849. szKey[0] = '\0'; // safety net
  1850. // if (!pAppEntity->must_be_invoked)
  1851. // return; // this is optional and can fail
  1852. switch (pAppEntity->session_key.application_protocol_key.key_type)
  1853. {
  1854. case GCC_OBJECT_KEY:
  1855. //
  1856. // Standard object key
  1857. //
  1858. cNodes = pAppEntity->session_key.application_protocol_key.object_id.long_string_length;
  1859. pNodeID = pAppEntity->session_key.application_protocol_key.object_id.long_string;
  1860. // check if it is an internal standard applet
  1861. iAppletId = GetInternalStandardAppletInvokeFunction(cNodes, pNodeID);
  1862. if (iAppletId >= 0)
  1863. {
  1864. // Invoke the internal applet
  1865. WARNING_OUT(("Find internal standard applet %s.\n",
  1866. iAppletId?"File Transfer":"White Board"));
  1867. T120_LoadApplet((APPLET_ID)iAppletId, FALSE, 0, FALSE, NULL);
  1868. return;
  1869. }
  1870. // ok, it is not an internal applet, convert it to hexa-dot string to look for
  1871. // a registered third-party applet
  1872. // Format: T120_APPLET_KEY\T120_STD_KEY\{hex-dot string} '\0'
  1873. if (0 < cNodes && NULL != pNodeID &&
  1874. (cNodes << 2) + sizeof(T120_APPLET_KEY) + sizeof(T120_STD_KEY) < MAX_PATH - 2)
  1875. {
  1876. ::wsprintfA(szKey, "%s\\%s\\%s", T120_APPLET_KEY, T120_STD_KEY, "{");
  1877. LPSTR pszKey = szKey + ::lstrlenA(szKey);
  1878. for (i = 0; i < cNodes; i++, pNodeID++)
  1879. {
  1880. ::wsprintf(pszKey, "%08X.", (UINT) *pNodeID);
  1881. pszKey += ::lstrlenA(pszKey);
  1882. }
  1883. ::wsprintfA(pszKey-1, "%s", "}"); // remove the last dot character
  1884. WARNING_OUT(("Find standard applet: %s\n", szKey));
  1885. }
  1886. else
  1887. {
  1888. ERROR_OUT(("InvokeAppletEntity: cannot handle standard key size=%u", cNodes));
  1889. return;
  1890. }
  1891. break;
  1892. case GCC_H221_NONSTANDARD_KEY:
  1893. //
  1894. // Non-standard object key
  1895. //
  1896. postrNonStdKey = &pAppEntity->session_key.application_protocol_key.h221_non_standard_id;
  1897. if (GetGuidFromH221AppKey(szGuid, postrNonStdKey))
  1898. {
  1899. //
  1900. // Microsoft non-standard object key
  1901. // NetMeeting's DataChannel
  1902. //
  1903. ::wsprintfA(szKey, "%s\\%s", GUID_KEY, szGuid);
  1904. WARNING_OUT(("Find Microsoft non-standard applet: %s\n", szKey));
  1905. }
  1906. else
  1907. {
  1908. //
  1909. // Non-Microsoft non-standard object key
  1910. //
  1911. // Third-party's non-standard object key.
  1912. // In this case, we convert the octet string into dotted decimal string,
  1913. // like an IP address.
  1914. // Each byte can take four characters in the dotted decimal string.
  1915. // Format: T120_APPLET_KEY\T120_NONSTD_KEY\{hex-dot string}'\0'
  1916. cbDataSize = postrNonStdKey->length;
  1917. pbData = postrNonStdKey->value;
  1918. if (0 < cbDataSize && NULL != pbData &&
  1919. (cbDataSize << 2) + sizeof(T120_APPLET_KEY) + sizeof(T120_NONSTD_KEY) < MAX_PATH - 2)
  1920. {
  1921. ::wsprintfA(szKey, "%s\\%s\\%s", T120_APPLET_KEY, T120_NONSTD_KEY, "{");
  1922. LPSTR pszKey = szKey + ::lstrlenA(szKey);
  1923. for (i = 0; i < cbDataSize; i++, pbData++)
  1924. {
  1925. ::wsprintfA(pszKey, "%02X.", (UINT) *pbData);
  1926. pszKey += ::lstrlenA(pszKey);
  1927. }
  1928. ::wsprintfA(pszKey-1, "%s", "}"); // remove the last dot character
  1929. WARNING_OUT(("Find third party non-standard applet: %s\n", szKey));
  1930. }
  1931. else
  1932. {
  1933. ERROR_OUT(("InvokeAppletEntity: cannot handle non-std key size=%u", cbDataSize));
  1934. return;
  1935. }
  1936. }
  1937. break;
  1938. default:
  1939. ERROR_OUT(("InvokeAppletEntity: invalid object key type=%u", pAppEntity->session_key.application_protocol_key.key_type));
  1940. return;
  1941. }
  1942. // Look for the registry key. open the registry now
  1943. RegEntry GuidKey(szKey, HKEY_LOCAL_MACHINE, FALSE, KEY_READ);
  1944. if (NO_ERROR == GuidKey.GetError())
  1945. {
  1946. LPSTR szAppName = ::My_strdupA(GuidKey.GetString(REGVAL_GUID_APPNAME));
  1947. LPSTR szCmdLine = ::My_strdupA(GuidKey.GetString(REGVAL_GUID_CMDLINE));
  1948. LPSTR szCurrDir = ::My_strdupA(GuidKey.GetString(REGVAL_GUID_CURRDIR));
  1949. if ((NULL != szAppName) || (NULL != szCmdLine))
  1950. {
  1951. LPSTR lpEnv;
  1952. STARTUPINFO startupInfo;
  1953. PROCESS_INFORMATION processInfo;
  1954. char szEnv[32];
  1955. ::ZeroMemory(&processInfo, sizeof(processInfo));
  1956. ::ZeroMemory(&startupInfo, sizeof(startupInfo));
  1957. startupInfo.cb = sizeof(startupInfo);
  1958. // set the special environment variables
  1959. ::wsprintfA(szEnv, "%u", nConfID);
  1960. SetEnvironmentVariable(ENV_CONFID, szEnv);
  1961. ::wsprintfA(szEnv, "%u", nidInitiator);
  1962. SetEnvironmentVariable(ENV_NODEID, szEnv);
  1963. lpEnv = ::GetEnvironmentStrings();
  1964. ::CreateProcess(
  1965. szAppName, // pointer to name of executable module
  1966. szCmdLine, // pointer to command line string
  1967. NULL, // pointer to process security attributes
  1968. NULL, // pointer to thread security attributes
  1969. FALSE, // handle inheritance flag
  1970. 0, // creation flags
  1971. lpEnv, // pointer to new environment block
  1972. szCurrDir, // pointer to current directory name
  1973. &startupInfo, // pointer to STARTUPINFO
  1974. &processInfo); // pointer to PROCESS_INFORMATION
  1975. if (NULL != lpEnv)
  1976. {
  1977. ::FreeEnvironmentStrings(lpEnv);
  1978. }
  1979. }
  1980. delete szAppName;
  1981. delete szCmdLine;
  1982. delete szCurrDir;
  1983. }
  1984. else
  1985. {
  1986. WARNING_OUT(("InvokeAppletEntity: no such registry=[%s]", szKey));
  1987. }
  1988. DebugExitVOID(InvokeAppletEntity);
  1989. }
  1990. LPWSTR GetNodeName(void)
  1991. {
  1992. LPWSTR pwszName;
  1993. LPSTR pszName;
  1994. RegEntry NameKey(ISAPI_KEY "\\" REGKEY_USERDETAILS);
  1995. if (g_bRDS) // Running as service?
  1996. {
  1997. char szName[MAX_COMPUTERNAME_LENGTH+2] = "";
  1998. DWORD dwBuf = sizeof(szName);
  1999. if ( !GetComputerName((LPSTR)&szName,&dwBuf) )
  2000. {
  2001. ERROR_OUT(("GetNameName: GetComputerName failed"));
  2002. }
  2003. pwszName = ::AnsiToUnicode(szName);
  2004. }
  2005. else
  2006. {
  2007. pszName = NameKey.GetString(REGVAL_ULS_NAME);
  2008. pwszName = ::AnsiToUnicode(pszName);
  2009. }
  2010. if (::IsEmptyStringW(pwszName))
  2011. {
  2012. WARNING_OUT(("GetNodeName: No node name"));
  2013. delete pwszName;
  2014. pwszName = NULL;
  2015. }
  2016. TRACE_OUT(("GetNodeName: pszName=%s", pszName));
  2017. return pwszName;
  2018. }
  2019. // Update <NodeId,Name> pair
  2020. void DCRNCConferenceManager::
  2021. UpdateNodeIdNameListAndUserData(GCCMessage * pGCCMessage)
  2022. {
  2023. GCCConfID ConfId = pGCCMessage->nConfID;
  2024. PCONFERENCE pConf = GetConferenceFromID(ConfId);
  2025. if (pConf)
  2026. pConf->UpdateNodeIdNameListAndUserData(pGCCMessage);
  2027. }
  2028. // Query node name
  2029. ULONG DCRNCConferenceManager::
  2030. GetNodeName(GCCConfID ConfId, GCCNodeID NodeId,
  2031. LPSTR pszBuffer, ULONG cbBufSize)
  2032. {
  2033. PCONFERENCE pConf = GetConferenceFromID(ConfId);
  2034. if (pConf)
  2035. return pConf->GetNodeName(NodeId, pszBuffer, cbBufSize);
  2036. return 0;
  2037. }
  2038. // Query user data
  2039. ULONG DCRNCConferenceManager::
  2040. GetUserGUIDData(GCCConfID ConfId, GCCNodeID NodeId,
  2041. GUID *pGuid, LPBYTE pbBuffer, ULONG cbBufSize)
  2042. {
  2043. PCONFERENCE pConf = GetConferenceFromID(ConfId);
  2044. if (pConf)
  2045. return pConf->GetUserGUIDData(NodeId, pGuid, pbBuffer, cbBufSize);
  2046. return 0;
  2047. }
  2048. ULONG WINAPI T120_GetNodeName(GCCConfID ConfId, GCCNodeID NodeId,
  2049. LPSTR pszBuffer, ULONG cbBufSize)
  2050. {
  2051. return g_pNCConfMgr->GetNodeName(ConfId, NodeId, pszBuffer, cbBufSize);
  2052. }
  2053. ULONG WINAPI T120_GetUserData(GCCConfID ConfId, GCCNodeID NodeId,
  2054. GUID *pGuid, LPBYTE pbBuffer,
  2055. ULONG cbBufSize)
  2056. {
  2057. return g_pNCConfMgr->GetUserGUIDData(ConfId, NodeId, pGuid, pbBuffer, cbBufSize);
  2058. }
  2059.