Leaked source code of windows server 2003
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.

1417 lines
34 KiB

  1. // File: imanager.cpp
  2. #include "precomp.h"
  3. extern "C"
  4. {
  5. #include "t120.h"
  6. }
  7. #include <version.h>
  8. #include <confcli.h>
  9. #include "icall.h"
  10. #include "icall_in.h"
  11. #include "imanager.h"
  12. #include "ichnlvid.h"
  13. #include "isysinfo.h"
  14. #include <tsecctrl.h>
  15. #include <imbft.h>
  16. #include <objbase.h>
  17. #include <regentry.h>
  18. #include <initguid.h>
  19. // GUID to receive userdata from "callto:" via INmCall::GetUserData
  20. //
  21. // {068B0780-718C-11d0-8B1A-00A0C91BC90E}
  22. DEFINE_GUID(GUID_CallToUserData,
  23. 0x068b0780, 0x718c, 0x11d0, 0x8b, 0x1a, 0x0, 0xa0, 0xc9, 0x1b, 0xc9, 0x0e);
  24. class CH323ChannelEvent
  25. {
  26. private:
  27. ICommChannel *m_pIChannel;
  28. IH323Endpoint *m_lpConnection;
  29. DWORD m_dwStatus;
  30. public:
  31. static DWORD ms_msgChannelEvent;
  32. CH323ChannelEvent(ICommChannel *pIChannel,
  33. IH323Endpoint *lpConnection,
  34. DWORD dwStatus):
  35. m_pIChannel(pIChannel),
  36. m_lpConnection(lpConnection),
  37. m_dwStatus(dwStatus)
  38. {
  39. if(!ms_msgChannelEvent)
  40. {
  41. ms_msgChannelEvent = RegisterWindowMessage(_TEXT("NetMeeting::H323ChannelEvent"));
  42. }
  43. m_pIChannel->AddRef();
  44. m_lpConnection->AddRef();
  45. }
  46. ~CH323ChannelEvent()
  47. {
  48. m_pIChannel->Release();
  49. m_lpConnection->Release();
  50. }
  51. ICommChannel* GetChannel() { return m_pIChannel; }
  52. IH323Endpoint* GetEndpoint() { return m_lpConnection; }
  53. DWORD GetStatus() { return m_dwStatus; }
  54. };
  55. //static
  56. DWORD CH323ChannelEvent::ms_msgChannelEvent = 0;
  57. static HRESULT OnNotifyConferenceCreated(IUnknown *pManagerNotify, PVOID pv, REFIID riid);
  58. static HRESULT OnNotifyCallCreated(IUnknown *pManagerNotify, PVOID pv, REFIID riid);
  59. GUID g_csguidRosterCaps = GUID_CAPS;
  60. GUID g_csguidSecurity = GUID_SECURITY;
  61. GUID g_csguidMeetingSettings = GUID_MTGSETTINGS;
  62. GUID g_csguidUserString = GUID_CallToUserData;
  63. GUID g_csguidNodeIdTag = GUID_NODEID;
  64. // this guid is dynamically created each time we start
  65. GUID g_guidLocalNodeId;
  66. CH323UI* g_pH323UI = NULL;
  67. INodeController* g_pNodeController = NULL;
  68. SOCKADDR_IN g_sinGateKeeper;
  69. const TCHAR cszDllHiddenWndClassName[] = _TEXT("OPNCUI_HiddenWindow");
  70. COprahNCUI *COprahNCUI::m_pOprahNCUI = NULL;
  71. static const IID * g_apiidCP_Manager[] =
  72. {
  73. {&IID_INmManagerNotify}
  74. };
  75. COprahNCUI::COprahNCUI(OBJECTDESTROYEDPROC ObjectDestroyed) :
  76. RefCount(ObjectDestroyed),
  77. CConnectionPointContainer(g_apiidCP_Manager, ARRAY_ELEMENTS(g_apiidCP_Manager)),
  78. m_uCaps(0),
  79. m_pQoS(NULL),
  80. m_pPreviewChannel(NULL),
  81. m_fAllowAV(TRUE),
  82. m_pAVConnection(NULL),
  83. m_hwnd(NULL),
  84. m_pSysInfo(NULL),
  85. m_pOutgoingCallManager(NULL),
  86. m_pIncomingCallManager(NULL),
  87. m_pConfObject(NULL)
  88. {
  89. DbgMsg(iZONE_OBJECTS, "Obj: %08X created CNmManager", this);
  90. // DllLock() is called by CClClassFactory::CreateInstance
  91. m_pOprahNCUI = this;
  92. ClearStruct(&g_sinGateKeeper);
  93. g_sinGateKeeper.sin_addr.s_addr = INADDR_NONE;
  94. m_pSysInfo = new CNmSysInfo();
  95. }
  96. COprahNCUI::~COprahNCUI()
  97. {
  98. // need to unregister the H323 callback
  99. // need to unregister the T120 callback
  100. delete m_pIncomingCallManager;
  101. m_pIncomingCallManager = NULL;
  102. delete m_pOutgoingCallManager;
  103. m_pOutgoingCallManager = NULL;
  104. if( m_pSysInfo )
  105. {
  106. m_pSysInfo->Release();
  107. m_pSysInfo = NULL;
  108. }
  109. if (m_pConfObject)
  110. {
  111. // turn off stream notifications
  112. if (g_pH323UI)
  113. {
  114. IMediaChannelBuilder *pStreamProvider = NULL;
  115. pStreamProvider = g_pH323UI->GetStreamProvider();
  116. if (pStreamProvider)
  117. {
  118. pStreamProvider->SetStreamEventObj(NULL);
  119. pStreamProvider->Release();
  120. }
  121. }
  122. m_pConfObject->Release();
  123. m_pConfObject = NULL;
  124. }
  125. if (NULL != m_pPreviewChannel)
  126. {
  127. m_pPreviewChannel->Release();
  128. m_pPreviewChannel = NULL;
  129. }
  130. // Shutdown H323
  131. delete g_pH323UI;
  132. g_pH323UI = NULL;
  133. if (NULL != m_hwnd)
  134. {
  135. HWND hwnd = m_hwnd;
  136. m_hwnd = NULL;
  137. #if 0 // if we start leaking th CH323ChannelEvents we may need to reenable this
  138. MSG msg;
  139. while (::PeekMessage(&msg, hwnd,
  140. CH323ChannelEvent::ms_msgChannelEvent,
  141. CH323ChannelEvent::ms_msgChannelEvent,
  142. PM_REMOVE))
  143. {
  144. CH323ChannelEvent *pEvent = reinterpret_cast<CH323ChannelEvent*>(msg.lParam);
  145. delete pEvent;
  146. }
  147. #endif
  148. ::DestroyWindow(hwnd);
  149. }
  150. if (0==UnregisterClass(cszDllHiddenWndClassName, GetInstanceHandle()))
  151. {
  152. ERROR_OUT(("COprahNCUI::~COprahNCUI - failed to unregister window class"));
  153. }
  154. // cleanup the node controller:
  155. if (NULL != g_pNodeController)
  156. {
  157. g_pNodeController->ReleaseInterface();
  158. g_pNodeController = NULL;
  159. }
  160. // Shutdown QoS
  161. delete m_pQoS;
  162. m_pQoS = NULL;
  163. m_pOprahNCUI = NULL;
  164. DbgMsg(iZONE_OBJECTS, "Obj: %08X destroyed CNmManager", this);
  165. }
  166. BSTR COprahNCUI::GetUserName()
  167. {
  168. return m_pSysInfo ? m_pSysInfo->GetUserName() : NULL;
  169. }
  170. UINT COprahNCUI::GetOutgoingCallCount()
  171. {
  172. return m_pOutgoingCallManager->GetCallCount();
  173. }
  174. VOID COprahNCUI::OnOutgoingCallCreated(INmCall* pCall)
  175. {
  176. // notify the UI about this outgoing call
  177. NotifySink(pCall, OnNotifyCallCreated);
  178. if (!m_pConfObject->IsConferenceCreated())
  179. {
  180. m_pConfObject->OnConferenceCreated();
  181. NotifySink((INmConference*) m_pConfObject, OnNotifyConferenceCreated);
  182. }
  183. }
  184. VOID COprahNCUI::OnOutgoingCallCanceled(COutgoingCall* pCall)
  185. {
  186. m_pOutgoingCallManager->RemoveFromList(pCall);
  187. }
  188. VOID COprahNCUI::OnIncomingCallAccepted()
  189. {
  190. if (!m_pConfObject->IsConferenceCreated())
  191. {
  192. m_pConfObject->OnConferenceCreated();
  193. NotifySink((INmConference*) m_pConfObject, OnNotifyConferenceCreated);
  194. }
  195. }
  196. VOID COprahNCUI::OnIncomingCallCreated(INmCall* pCall)
  197. {
  198. NotifySink(pCall, OnNotifyCallCreated);
  199. }
  200. VOID COprahNCUI::CancelCalls()
  201. {
  202. m_pOutgoingCallManager->CancelCalls();
  203. m_pIncomingCallManager->CancelCalls();
  204. }
  205. BOOL COprahNCUI::AcquireAV(IH323Endpoint* pConnection)
  206. {
  207. if (NULL == m_pAVConnection)
  208. {
  209. m_pAVConnection = pConnection;
  210. TRACE_OUT(("AV acquired"));
  211. return TRUE;
  212. }
  213. TRACE_OUT(("AV not acquired"));
  214. return FALSE;
  215. }
  216. BOOL COprahNCUI::ReleaseAV(IH323Endpoint* pConnection)
  217. {
  218. if (m_pAVConnection == pConnection)
  219. {
  220. m_pAVConnection = NULL;
  221. TRACE_OUT(("AV released"));
  222. return TRUE;
  223. }
  224. return FALSE;
  225. }
  226. HRESULT COprahNCUI::AllowH323(BOOL fAllowAV)
  227. {
  228. m_fAllowAV = fAllowAV;
  229. if (m_pConfObject->IsConferenceActive())
  230. {
  231. // Force a roster update
  232. CONF_HANDLE hConf = m_pConfObject->GetConfHandle();
  233. if (NULL != hConf)
  234. {
  235. ASSERT(g_pNodeController);
  236. hConf->UpdateUserData();
  237. }
  238. }
  239. return S_OK;
  240. }
  241. CREQ_RESPONSETYPE COprahNCUI::OnH323IncomingCall(IH323Endpoint* pConnection,
  242. P_APP_CALL_SETUP_DATA lpvMNMData)
  243. {
  244. CREQ_RESPONSETYPE resp = m_pIncomingCallManager->OnIncomingH323Call(this, pConnection, lpvMNMData);
  245. if ((CRR_REJECT == resp) ||
  246. (CRR_BUSY == resp) ||
  247. (CRR_SECURITY_DENIED == resp))
  248. {
  249. ReleaseAV(pConnection);
  250. }
  251. return resp;
  252. }
  253. VOID COprahNCUI::OnH323Connected(IH323Endpoint * lpConnection)
  254. {
  255. DebugEntry(COprahNCUI::OnH323Connected);
  256. if (!m_pOutgoingCallManager->OnH323Connected(lpConnection))
  257. {
  258. m_pIncomingCallManager->OnH323Connected(lpConnection);
  259. }
  260. DebugExitVOID(COprahNCUI::OnH323Connected);
  261. }
  262. VOID COprahNCUI::OnH323Disconnected(IH323Endpoint * lpConnection)
  263. {
  264. DebugEntry(COprahNCUI::OnH323Disconnected);
  265. if (!m_pOutgoingCallManager->OnH323Disconnected(lpConnection))
  266. {
  267. m_pIncomingCallManager->OnH323Disconnected(lpConnection);
  268. }
  269. m_pConfObject->OnH323Disconnected(lpConnection, IsOwnerOfAV(lpConnection));
  270. ReleaseAV(lpConnection);
  271. DebugExitVOID(COprahNCUI::OnH323Disconnected);
  272. }
  273. VOID COprahNCUI::OnT120ChannelOpen(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus)
  274. {
  275. DebugEntry(COprahNCUI::OnT120ChannelOpen);
  276. m_pOutgoingCallManager->OnT120ChannelOpen(pIChannel, lpConnection, dwStatus);
  277. DebugExitVOID(COprahNCUI::OnT120ChannelOpen);
  278. }
  279. VOID COprahNCUI::OnVideoChannelStatus(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus)
  280. {
  281. DebugEntry(COprahNCUI::OnVideoChannelStatus);
  282. m_pConfObject->OnVideoChannelStatus(pIChannel, lpConnection, dwStatus);
  283. DebugExitVOID(COprahNCUI::OnVideoChannelStatus);
  284. }
  285. VOID COprahNCUI::OnAudioChannelStatus(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus)
  286. {
  287. DebugEntry(COprahNCUI::OnAudioChannelStatus);
  288. m_pConfObject->OnAudioChannelStatus(pIChannel, lpConnection, dwStatus);
  289. DebugExitVOID(COprahNCUI::OnAudioChannelStatus);
  290. }
  291. BOOL COprahNCUI::GetULSName(CRosterInfo *pri)
  292. {
  293. if (FIsLoggedOn())
  294. {
  295. RegEntry reULS( ISAPI_KEY _TEXT("\\") REGKEY_USERDETAILS,
  296. HKEY_CURRENT_USER);
  297. CUSTRING custrULSName(reULS.GetString(REGVAL_ULS_RES_NAME));
  298. if ((NULL != (PWSTR)custrULSName) &&
  299. (L'\0' != ((PWSTR)custrULSName)[0]))
  300. {
  301. pri->AddItem(g_cwszULSTag, (PWSTR)custrULSName);
  302. return TRUE;
  303. }
  304. }
  305. return FALSE;
  306. }
  307. VOID COprahNCUI::GetRosterInfo(CRosterInfo *pri)
  308. {
  309. RegEntry reULS( ISAPI_KEY _TEXT("\\") REGKEY_USERDETAILS,
  310. HKEY_CURRENT_USER);
  311. // This code is here in addition to the code above to fix bug 3367.
  312. // Add the single IP address to the list that is obtained by calling
  313. // gethostname() and then gethostbyname().
  314. // This shouldn't be detrimental, even though we may end up adding the
  315. // same IP address that has already been added by the code above.
  316. // This is because the code that looks for matching IP addresses searches
  317. // through all of them until it finds a match.
  318. CHAR szHostName[MAX_PATH];
  319. if (SOCKET_ERROR != gethostname(szHostName, CCHMAX(szHostName)))
  320. {
  321. HOSTENT* phe = gethostbyname(szHostName);
  322. if (NULL != phe)
  323. {
  324. ASSERT(phe->h_addrtype == AF_INET);
  325. ASSERT(phe->h_length == sizeof(DWORD));
  326. struct in_addr in;
  327. in.s_addr = *((DWORD *)phe->h_addr);
  328. CHAR szIPAddress[MAX_PATH];
  329. lstrcpyn(szIPAddress, inet_ntoa(in), CCHMAX(szIPAddress));
  330. pri->AddItem( g_cwszIPTag, CUSTRING(szIPAddress));
  331. }
  332. }
  333. // Add the build/version string
  334. pri->AddItem(g_cwszVerTag, (PWSTR)VER_PRODUCTVERSION_DWSTR);
  335. if (FIsLoggedOn())
  336. {
  337. CUSTRING custrULSName(reULS.GetString(REGVAL_ULS_RES_NAME));
  338. if ((NULL != (PWSTR)custrULSName) &&
  339. (L'\0' != ((PWSTR)custrULSName)[0]))
  340. {
  341. pri->AddItem(g_cwszULSTag, (PWSTR)custrULSName);
  342. }
  343. }
  344. CUSTRING custrULSEmail(reULS.GetString(REGVAL_ULS_EMAIL_NAME));
  345. if ((NULL != (PWSTR)custrULSEmail) &&
  346. (L'\0' != ((PWSTR)custrULSEmail)[0]))
  347. {
  348. pri->AddItem(g_cwszULS_EmailTag, (PWSTR)custrULSEmail);
  349. }
  350. CUSTRING custrULSLocation(reULS.GetString(REGVAL_ULS_LOCATION_NAME));
  351. if ((NULL != (PWSTR)custrULSLocation) &&
  352. (L'\0' != ((PWSTR)custrULSLocation)[0]))
  353. {
  354. pri->AddItem(g_cwszULS_LocationTag, (PWSTR)custrULSLocation);
  355. }
  356. CUSTRING custrULSPhoneNum(reULS.GetString(REGVAL_ULS_PHONENUM_NAME));
  357. if ((NULL != (PWSTR)custrULSPhoneNum) &&
  358. (L'\0' != ((PWSTR)custrULSPhoneNum)[0]))
  359. {
  360. pri->AddItem(g_cwszULS_PhoneNumTag, (PWSTR)custrULSPhoneNum);
  361. }
  362. }
  363. ULONG COprahNCUI::GetRosterCaps()
  364. {
  365. ULONG uCaps = m_uCaps;
  366. CNmMember * pMember = m_pConfObject->GetLocalMember();
  367. if (NULL != pMember)
  368. {
  369. DWORD dwFlags = pMember->GetDwFlags();
  370. if (dwFlags & PF_MEDIA_VIDEO)
  371. {
  372. uCaps |= CAPFLAG_VIDEO_IN_USE;
  373. }
  374. if (dwFlags & PF_MEDIA_AUDIO)
  375. {
  376. uCaps |= CAPFLAG_AUDIO_IN_USE;
  377. }
  378. if (dwFlags & PF_MEDIA_DATA)
  379. {
  380. uCaps |= CAPFLAG_DATA_IN_USE;
  381. }
  382. if (dwFlags & PF_H323)
  383. {
  384. uCaps |= CAPFLAG_H323_IN_USE;
  385. }
  386. }
  387. if (!m_fAllowAV)
  388. {
  389. uCaps &= ~(CAPFLAGS_AV_ALL);
  390. }
  391. return uCaps;
  392. }
  393. ULONG COprahNCUI::GetAuthenticatedName(PBYTE * ppb)
  394. {
  395. // Buffer created here should be freed by caller.
  396. ULONG cb;
  397. if (::T120_GetSecurityInfoFromGCCID(0,NULL,&cb)) {
  398. (*ppb) = new BYTE[cb];
  399. if ((*ppb) != NULL) {
  400. ::T120_GetSecurityInfoFromGCCID(0,*ppb,&cb);
  401. return cb;
  402. }
  403. }
  404. (* ppb) = NULL;
  405. return 0;
  406. }
  407. HRESULT COprahNCUI::OnUpdateUserData(CONF_HANDLE hConference)
  408. {
  409. CRosterInfo ri;
  410. // This string will contain addresses in the form:
  411. // L"TCP:157.55.143.3\0TCP:157.55.143.4\0\0" - 512 character max for now
  412. WCHAR wszAddresses[512];
  413. ASSERT(g_pNodeController);
  414. ASSERT(hConference);
  415. if (NOERROR == hConference->GetLocalAddressList(wszAddresses,
  416. CCHMAX(wszAddresses)))
  417. {
  418. ri.Load(wszAddresses);
  419. }
  420. // First, handle roster information
  421. GetRosterInfo(&ri);
  422. PVOID pvData;
  423. UINT cbDataLen;
  424. if (SUCCEEDED(ri.Save(&pvData, &cbDataLen)))
  425. {
  426. ASSERT(g_pNodeController);
  427. ASSERT(hConference);
  428. hConference->SetUserData(&g_csguidRostInfo,
  429. cbDataLen,
  430. pvData);
  431. }
  432. // Next, handle caps information
  433. ULONG uCaps = GetRosterCaps();
  434. ASSERT(g_pNodeController);
  435. ASSERT(hConference);
  436. hConference->SetUserData(&g_csguidRosterCaps, sizeof(uCaps), &uCaps);
  437. // Next, handle credentials
  438. if ( hConference->IsSecure() )
  439. {
  440. BYTE * pb = NULL;
  441. ULONG cb = GetAuthenticatedName(&pb);
  442. if (cb > 0) {
  443. ASSERT(g_pNodeController);
  444. ASSERT(hConference);
  445. TRACE_OUT(("COprahNCUI::OnUpdateUserData: adding %d bytes SECURITY data", cb));
  446. hConference->SetUserData(&g_csguidSecurity, cb, pb);
  447. }
  448. else
  449. {
  450. WARNING_OUT(("OnUpdateUserData: 0 bytes security data?"));
  451. }
  452. delete [] pb;
  453. }
  454. // Next, set meeting settings if we hosted the meeting
  455. ASSERT(m_pConfObject);
  456. if (m_pConfObject->IsHosting() == S_OK)
  457. {
  458. NM30_MTG_PERMISSIONS attendeePermissions = m_pConfObject->GetConfAttendeePermissions();
  459. WARNING_OUT(("Hosted Meeting Settings 0x%08lx", attendeePermissions));
  460. hConference->SetUserData(&g_csguidMeetingSettings,
  461. sizeof(attendeePermissions), &attendeePermissions);
  462. }
  463. ULONG nRecords;
  464. GCCUserData ** ppUserData = NULL;
  465. if (m_pSysInfo)
  466. {
  467. m_pSysInfo->GetUserDataList(&nRecords,&ppUserData);
  468. for (unsigned int i = 0; i < nRecords; i++) {
  469. // Do not add user data that was already set above.
  470. if (memcmp(ppUserData[i]->octet_string->value,(PVOID)&g_csguidRostInfo,sizeof(GUID)) == 0)
  471. continue;
  472. if (memcmp(ppUserData[i]->octet_string->value,(PVOID)&g_csguidRosterCaps,sizeof(GUID)) == 0)
  473. continue;
  474. if (memcmp(ppUserData[i]->octet_string->value,(PVOID)&g_csguidSecurity,sizeof(GUID)) == 0)
  475. continue;
  476. if (memcmp(ppUserData[i]->octet_string->value,(PVOID)&g_csguidMeetingSettings,sizeof(GUID)) == 0)
  477. continue;
  478. ASSERT(g_pNodeController);
  479. ASSERT(hConference);
  480. hConference->SetUserData((GUID *)(ppUserData[i]->octet_string->value),
  481. ppUserData[i]->octet_string->length - sizeof(GUID), ppUserData[i]->octet_string->value + sizeof(GUID));
  482. }
  483. }
  484. // only add the LocalNodeId to the roster if H323 is enabled
  485. if (IsH323Enabled())
  486. {
  487. hConference->SetUserData((GUID *)(&g_csguidNodeIdTag), sizeof(GUID), (PVOID)&g_guidLocalNodeId);
  488. }
  489. return S_OK;
  490. }
  491. HRESULT COprahNCUI::OnIncomingInviteRequest(CONF_HANDLE hConference,
  492. PCWSTR pcwszNodeName,
  493. PT120PRODUCTVERSION pRequestorVersion,
  494. PUSERDATAINFO pUserDataInfoEntries,
  495. UINT cUserDataEntries,
  496. BOOL fSecure)
  497. {
  498. DebugEntry(COprahNCUI::OnIncomingInviteRequest);
  499. // Fix an AV problem ONLY for RTC client
  500. if (m_pConfObject == NULL)
  501. {
  502. return S_OK;
  503. }
  504. if (!m_pConfObject->OnT120Invite(hConference, fSecure))
  505. {
  506. // Respond negatively - already in a call
  507. TRACE_OUT(("Rejecting invite - already in a call"));
  508. ASSERT(g_pNodeController);
  509. ASSERT(hConference);
  510. hConference->InviteResponse(FALSE);
  511. }
  512. else
  513. {
  514. m_pIncomingCallManager->OnIncomingT120Call( this,
  515. TRUE,
  516. hConference,
  517. pcwszNodeName,
  518. pUserDataInfoEntries,
  519. cUserDataEntries,
  520. fSecure);
  521. //
  522. // This will simply notify the UI about the call state.
  523. //
  524. m_pConfObject->SetConfSecurity(fSecure);
  525. }
  526. DebugExitHRESULT(COprahNCUI::OnIncomingInviteRequest, S_OK);
  527. return S_OK;
  528. }
  529. HRESULT COprahNCUI::OnIncomingJoinRequest( CONF_HANDLE hConference,
  530. PCWSTR pcwszNodeName,
  531. PT120PRODUCTVERSION pRequestorVersion,
  532. PUSERDATAINFO pUserDataInfoEntries,
  533. UINT cUserDataEntries)
  534. {
  535. DebugEntry(COprahNCUI::OnIncomingJoinRequest);
  536. // shouldn't we be checking for an active conference before accepting a join
  537. // or will T120 not present this
  538. m_pIncomingCallManager->OnIncomingT120Call( this,
  539. FALSE,
  540. hConference,
  541. pcwszNodeName,
  542. pUserDataInfoEntries,
  543. cUserDataEntries,
  544. m_pConfObject->IsConfObjSecure());
  545. DebugExitHRESULT(COprahNCUI::OnIncomingJoinRequest, S_OK);
  546. return S_OK;
  547. }
  548. HRESULT COprahNCUI::OnConferenceStarted(CONF_HANDLE hConference, HRESULT hResult)
  549. {
  550. DebugEntry(COprahNCUI::OnConferenceStarted);
  551. if (m_pConfObject->GetConfHandle() == hConference)
  552. {
  553. m_pConfObject->OnConferenceStarted(hConference, hResult);
  554. m_pOutgoingCallManager->OnConferenceStarted(hConference, hResult);
  555. }
  556. DebugExitHRESULT(COprahNCUI::OnConferenceStarted, S_OK);
  557. return S_OK;
  558. }
  559. HRESULT COprahNCUI::OnQueryRemoteResult(PVOID pvCallerContext,
  560. HRESULT hResult,
  561. BOOL fMCU,
  562. PWSTR* ppwszConferenceNames,
  563. PT120PRODUCTVERSION pVersion,
  564. PWSTR* ppwszConfDescriptors)
  565. {
  566. DebugEntry(COprahNCUI::OnQueryRemoteResult);
  567. if (NO_ERROR == hResult)
  568. {
  569. TRACE_OUT(("COprahNCUI: OnQueryRemoteResult Success!"));
  570. }
  571. else
  572. {
  573. TRACE_OUT(("COprahNCUI: OnQueryRemoteResult Failure!"));
  574. }
  575. m_pOutgoingCallManager->OnQueryRemoteResult(pvCallerContext,
  576. hResult,
  577. fMCU,
  578. ppwszConferenceNames,
  579. pVersion,
  580. ppwszConfDescriptors);
  581. DebugExitHRESULT(COprahNCUI::OnQueryRemoteResult, S_OK);
  582. return S_OK;
  583. }
  584. HRESULT COprahNCUI::OnInviteResult( CONF_HANDLE hConference,
  585. REQUEST_HANDLE hRequest,
  586. UINT uNodeID,
  587. HRESULT hResult,
  588. PT120PRODUCTVERSION pVersion)
  589. {
  590. DebugEntry(COprahNCUI::OnInviteResult);
  591. if (hConference == m_pConfObject->GetConfHandle())
  592. {
  593. m_pOutgoingCallManager->OnInviteResult( hConference,
  594. hRequest,
  595. uNodeID,
  596. hResult,
  597. pVersion);
  598. }
  599. DebugExitHRESULT(COprahNCUI::OnInviteResult, S_OK);
  600. return S_OK;
  601. }
  602. HRESULT COprahNCUI::OnConferenceEnded(CONF_HANDLE hConference)
  603. {
  604. DebugEntry(COprahNCUI::OnConferenceEnded);
  605. if (m_pConfObject && (hConference == m_pConfObject->GetConfHandle()))
  606. {
  607. m_pConfObject->OnConferenceEnded();
  608. m_pOutgoingCallManager->OnConferenceEnded(hConference);
  609. m_pIncomingCallManager->OnT120ConferenceEnded(hConference);
  610. }
  611. DebugExitHRESULT(COprahNCUI::OnConferenceEnded, S_OK);
  612. return S_OK;
  613. }
  614. HRESULT COprahNCUI::OnRosterChanged(CONF_HANDLE hConf, PNC_ROSTER pRoster)
  615. {
  616. TRACE_OUT(("COprahNCUI::OnRosterChanged"));
  617. if (hConf == m_pConfObject->GetConfHandle())
  618. {
  619. m_pConfObject->OnRosterChanged(pRoster);
  620. }
  621. return S_OK;
  622. }
  623. ULONG STDMETHODCALLTYPE COprahNCUI::AddRef(void)
  624. {
  625. return RefCount::AddRef();
  626. }
  627. ULONG STDMETHODCALLTYPE COprahNCUI::Release(void)
  628. {
  629. return RefCount::Release();
  630. }
  631. HRESULT STDMETHODCALLTYPE COprahNCUI::QueryInterface(REFIID riid, PVOID *ppv)
  632. {
  633. HRESULT hr = S_OK;
  634. if ((riid == IID_INmManager2) || (riid == IID_INmManager) || (riid == IID_IUnknown))
  635. {
  636. *ppv = (INmManager2 *)this;
  637. ApiDebugMsg(("COprahNCUI::QueryInterface()"));
  638. }
  639. else if (riid == IID_IConnectionPointContainer)
  640. {
  641. *ppv = (IConnectionPointContainer *) this;
  642. ApiDebugMsg(("COprahNCUI::QueryInterface(): Returning IConnectionPointContainer."));
  643. }
  644. else
  645. {
  646. hr = E_NOINTERFACE;
  647. *ppv = NULL;
  648. ApiDebugMsg(("COprahNCUI::QueryInterface(): Called on unknown interface."));
  649. }
  650. if (S_OK == hr)
  651. {
  652. AddRef();
  653. }
  654. return hr;
  655. }
  656. /* I N I T I A L I Z E */
  657. /*-------------------------------------------------------------------------
  658. %%Function: Initialize
  659. REVIEW: What should the return value be if any of these parts fail
  660. to initialize or load?
  661. -------------------------------------------------------------------------*/
  662. HRESULT COprahNCUI::Initialize(ULONG *puOptions, ULONG *puchCaps)
  663. {
  664. HRESULT hr = S_OK;
  665. // puOptions is UNUSED
  666. ASSERT(puchCaps);
  667. m_pOutgoingCallManager = new COutgoingCallManager;
  668. if (!m_pOutgoingCallManager)
  669. {
  670. ERROR_OUT(("COprahNCUI::Initialize -- failed to create outgoing call mgr"));
  671. return(E_OUTOFMEMORY);
  672. }
  673. m_pIncomingCallManager = new CIncomingCallManager;
  674. if (!m_pIncomingCallManager)
  675. {
  676. ERROR_OUT(("COprahNCUI::Initialize -- failed to create incoming call mgr"));
  677. return(E_OUTOFMEMORY);
  678. }
  679. // The lifetime of this object is up to the reference counting crap
  680. m_pConfObject = new CConfObject;
  681. if (!m_pConfObject)
  682. {
  683. ERROR_OUT(("COprahNCUI::Initialize -- failed to create conf object"));
  684. return(E_OUTOFMEMORY);
  685. }
  686. m_pConfObject->Init(this);
  687. WNDCLASS wcHidden =
  688. {
  689. 0L,
  690. COprahNCUI::WndProc,
  691. 0,
  692. 0,
  693. GetInstanceHandle(),
  694. NULL,
  695. NULL,
  696. NULL,
  697. NULL,
  698. cszDllHiddenWndClassName
  699. };
  700. if (!RegisterClass(&wcHidden))
  701. {
  702. ERROR_OUT(("COprahNCUI::Initialize -- failed to register HiddenWnd class"));
  703. return(E_OUTOFMEMORY);
  704. }
  705. // Create a hidden window for event processing:
  706. m_hwnd = ::CreateWindow(cszDllHiddenWndClassName,
  707. _TEXT(""),
  708. WS_POPUP, // not visible!
  709. 0, 0, 0, 0,
  710. NULL,
  711. NULL,
  712. GetInstanceHandle(),
  713. NULL);
  714. if (NULL == m_hwnd)
  715. {
  716. return E_FAIL;
  717. }
  718. //
  719. // INIT QOS only if AV is in the picture (otherwise, there's nothing
  720. // to arbitrate).
  721. //
  722. if (CAPFLAGS_AV_STREAMS & *puchCaps)
  723. {
  724. m_pQoS = new CQoS();
  725. if (NULL != m_pQoS)
  726. {
  727. hr = m_pQoS->Initialize();
  728. if (FAILED(hr))
  729. {
  730. WARNING_OUT(("CQoS::Init() failed!"));
  731. // let NetMeeting hobble along without QoS.
  732. delete m_pQoS;
  733. m_pQoS = NULL;
  734. hr = S_FALSE; // we can live without QOS
  735. }
  736. }
  737. else
  738. {
  739. WARNING_OUT(("Could not allocate CQoS object"));
  740. }
  741. }
  742. //
  743. // IF DATA CONFERENCING IS ALLOWED
  744. //
  745. if (CAPFLAG_DATA & *puchCaps)
  746. {
  747. //
  748. // Create the node controller
  749. //
  750. hr = ::T120_CreateNodeController(&g_pNodeController, this);
  751. if (FAILED(hr))
  752. {
  753. ERROR_OUT(("T120_CreateNodeController() failed!"));
  754. return hr;
  755. }
  756. }
  757. // Initialize audio/video
  758. if (CAPFLAGS_AV_ALL & *puchCaps)
  759. {
  760. g_pH323UI = new CH323UI();
  761. if (NULL != g_pH323UI)
  762. {
  763. hr = g_pH323UI->Init(m_hwnd, ::GetInstanceHandle(), *puchCaps, this, this);
  764. if (FAILED(hr))
  765. {
  766. WARNING_OUT(("CH323UI::Init() failed!"));
  767. delete g_pH323UI;
  768. g_pH323UI = NULL;
  769. *puchCaps &= ~(CAPFLAGS_AV_ALL);
  770. hr = S_FALSE; // We can run without AV
  771. }
  772. else
  773. {
  774. if (CAPFLAGS_VIDEO & *puchCaps)
  775. {
  776. // if we can get a Preview channel, we can send video
  777. m_pPreviewChannel = CNmChannelVideo::CreatePreviewChannel();
  778. if (NULL == m_pPreviewChannel)
  779. {
  780. *puchCaps &= ~CAPFLAG_SEND_VIDEO;
  781. }
  782. }
  783. if (m_pConfObject && (CAPFLAGS_AV_STREAMS & *puchCaps))
  784. {
  785. IMediaChannelBuilder *pStreamProvider;
  786. pStreamProvider = g_pH323UI->GetStreamProvider();
  787. if (pStreamProvider)
  788. {
  789. pStreamProvider->SetStreamEventObj(m_pConfObject);
  790. pStreamProvider->Release();
  791. }
  792. }
  793. }
  794. }
  795. else
  796. {
  797. ERROR_OUT(("Could not allocate CH323UI object"));
  798. }
  799. }
  800. m_uCaps = *puchCaps;
  801. return CoCreateGuid(&g_guidLocalNodeId);
  802. }
  803. HRESULT COprahNCUI::GetSysInfo(INmSysInfo **ppSysInfo)
  804. {
  805. HRESULT hr = S_OK;
  806. if( ppSysInfo )
  807. {
  808. if(m_pSysInfo )
  809. {
  810. m_pSysInfo->AddRef();
  811. *ppSysInfo = m_pSysInfo;
  812. }
  813. else
  814. {
  815. hr = E_OUTOFMEMORY;
  816. }
  817. }
  818. else
  819. {
  820. hr = E_POINTER;
  821. }
  822. return hr;
  823. }
  824. HRESULT COprahNCUI::EnumConference(IEnumNmConference **ppEnum)
  825. {
  826. return E_NOTIMPL;
  827. }
  828. HRESULT COprahNCUI::CreateConference( INmConference **ppConference,
  829. BSTR bstrName,
  830. BSTR bstrPassword,
  831. ULONG uchCaps)
  832. {
  833. return(CreateConferenceEx(ppConference, bstrName, bstrPassword,
  834. uchCaps, NM_PERMIT_ALL, (UINT)-1));
  835. }
  836. HRESULT COprahNCUI::EnumCall(IEnumNmCall **ppEnum)
  837. {
  838. return E_NOTIMPL;
  839. }
  840. HRESULT COprahNCUI::CreateCall(
  841. INmCall **ppCall,
  842. NM_CALL_TYPE callType,
  843. NM_ADDR_TYPE addrType,
  844. BSTR bstrAddress,
  845. INmConference * pConference)
  846. {
  847. return E_NOTIMPL;
  848. }
  849. HRESULT COprahNCUI::CallConference(
  850. INmCall **ppCall,
  851. NM_CALL_TYPE callType,
  852. NM_ADDR_TYPE addrType,
  853. BSTR bstrAddress,
  854. BSTR bstrConfToJoin,
  855. BSTR bstrPassword)
  856. {
  857. return E_NOTIMPL;
  858. }
  859. STDMETHODIMP COprahNCUI::GetPreviewChannel(INmChannelVideo **ppChannelVideo)
  860. {
  861. HRESULT hr = E_POINTER;
  862. if (NULL != ppChannelVideo)
  863. {
  864. *ppChannelVideo = m_pPreviewChannel;
  865. if (NULL != m_pPreviewChannel)
  866. {
  867. m_pPreviewChannel->AddRef();
  868. hr = S_OK;
  869. }
  870. else
  871. {
  872. hr = E_FAIL;
  873. }
  874. }
  875. return hr;
  876. }
  877. STDMETHODIMP COprahNCUI::CreateASObject
  878. (
  879. IUnknown * pNotify,
  880. ULONG flags,
  881. IUnknown ** ppAS
  882. )
  883. {
  884. return(::CreateASObject((IAppSharingNotify *)pNotify, flags,
  885. (IAppSharing **)ppAS));
  886. }
  887. HRESULT COprahNCUI::CallEx(
  888. INmCall **ppCall,
  889. DWORD dwFlags,
  890. NM_ADDR_TYPE addrType,
  891. BSTR bstrName,
  892. BSTR bstrSetup,
  893. BSTR bstrDest,
  894. BSTR bstrAlias,
  895. BSTR bstrURL,
  896. BSTR bstrConference,
  897. BSTR bstrPassword,
  898. BSTR bstrUserData)
  899. {
  900. DebugEntry(COprahNCUI::CallEx);
  901. HRESULT hr = m_pOutgoingCallManager->Call( ppCall,
  902. this,
  903. dwFlags,
  904. addrType,
  905. bstrName,
  906. bstrSetup,
  907. bstrDest,
  908. bstrAlias,
  909. bstrURL,
  910. bstrConference,
  911. bstrPassword,
  912. bstrUserData);
  913. DebugExitHRESULT(COprahNCUI::CallEx, hr);
  914. return hr;
  915. }
  916. HRESULT COprahNCUI::CreateConferenceEx
  917. (
  918. INmConference **ppConference,
  919. BSTR bstrName,
  920. BSTR bstrPassword,
  921. DWORD uchCaps,
  922. DWORD attendeePermissions,
  923. DWORD maxParticipants
  924. )
  925. {
  926. if (NULL == ppConference)
  927. {
  928. ERROR_OUT(("CreateConferenceEx: null ppConference passed in"));
  929. return E_POINTER;
  930. }
  931. if (maxParticipants < 2)
  932. {
  933. ERROR_OUT(("CreateConferenceEx: bad maxParticipants %d", maxParticipants));
  934. return E_INVALIDARG;
  935. }
  936. if (m_pConfObject->IsConferenceActive())
  937. {
  938. WARNING_OUT(("CreateConference is failing because IsConferenceActive return TRUE"));
  939. return NM_CALLERR_IN_CONFERENCE;
  940. }
  941. m_pConfObject->SetConfName(bstrName);
  942. if (uchCaps & NMCH_SRVC)
  943. m_pConfObject->SetConfHashedPassword(bstrPassword);
  944. else
  945. m_pConfObject->SetConfPassword(bstrPassword);
  946. if (uchCaps & NMCH_SECURE)
  947. m_pConfObject->SetConfSecurity(TRUE);
  948. else
  949. m_pConfObject->SetConfSecurity(FALSE);
  950. m_pConfObject->SetConfAttendeePermissions(attendeePermissions);
  951. m_pConfObject->SetConfMaxParticipants(maxParticipants);
  952. if (!m_pConfObject->IsConferenceCreated())
  953. {
  954. m_pConfObject->OnConferenceCreated();
  955. }
  956. NotifySink((INmConference*) m_pConfObject, OnNotifyConferenceCreated);
  957. *ppConference = m_pConfObject;
  958. if(*ppConference)
  959. {
  960. (*ppConference)->AddRef();
  961. }
  962. return S_OK;
  963. }
  964. /* O N N O T I F Y C O N F E R E N C E C R E A T E D */
  965. /*-------------------------------------------------------------------------
  966. %%Function: OnNotifyConferenceCreated
  967. -------------------------------------------------------------------------*/
  968. HRESULT OnNotifyConferenceCreated(IUnknown *pManagerNotify, PVOID pv, REFIID riid)
  969. {
  970. ASSERT(NULL != pManagerNotify);
  971. ((INmManagerNotify*)pManagerNotify)->ConferenceCreated((INmConference *) pv);
  972. return S_OK;
  973. }
  974. /* O N N O T I F Y C A L L C R E A T E D */
  975. /*-------------------------------------------------------------------------
  976. %%Function: OnNotifyCallCreated
  977. -------------------------------------------------------------------------*/
  978. HRESULT OnNotifyCallCreated(IUnknown *pManagerNotify, PVOID pv, REFIID riid)
  979. {
  980. ASSERT(NULL != pManagerNotify);
  981. ((INmManagerNotify*)pManagerNotify)->CallCreated((INmCall *) pv);
  982. return S_OK;
  983. }
  984. /* O N N O T I F Y C A L L S T A T E C H A N G E D */
  985. /*-------------------------------------------------------------------------
  986. %%Function: OnNotifyCallStateChanged
  987. -------------------------------------------------------------------------*/
  988. HRESULT OnNotifyCallStateChanged(IUnknown *pCallNotify, PVOID pv, REFIID riid)
  989. {
  990. ASSERT(NULL != pCallNotify);
  991. ((INmCallNotify*)pCallNotify)->StateChanged((NM_CALL_STATE)(DWORD_PTR)pv);
  992. return S_OK;
  993. }
  994. VOID SetBandwidth(UINT uBandwidth)
  995. {
  996. COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
  997. if (NULL != pOprahNCUI)
  998. {
  999. pOprahNCUI->SetBandwidth(uBandwidth);
  1000. }
  1001. if (NULL != g_pH323UI)
  1002. {
  1003. //Inform the NAC of the connection speed
  1004. g_pH323UI->SetBandwidth(uBandwidth);
  1005. }
  1006. }
  1007. //
  1008. // BOGUS LAURABU!
  1009. // Do we need this HWND anymore? The hidden window is used now only to
  1010. // pass to H323, which passes it to the MediaStream interfaces in the NAC,
  1011. // which passes it to DirectX.
  1012. //
  1013. LRESULT CALLBACK COprahNCUI::WndProc(HWND hwnd, UINT uMsg,
  1014. WPARAM wParam, LPARAM lParam)
  1015. {
  1016. // if ms_msgChannelEvent is 0, that means that we are not initialized
  1017. // RegisterWindowMessage returns MSGIds in the range 0xC000 through 0xFFFF
  1018. if(CH323ChannelEvent::ms_msgChannelEvent && CH323ChannelEvent::ms_msgChannelEvent == uMsg)
  1019. {
  1020. COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
  1021. if (pOprahNCUI)
  1022. {
  1023. CH323ChannelEvent *pEvent = reinterpret_cast<CH323ChannelEvent*>(lParam);
  1024. if(pEvent)
  1025. {
  1026. // if we're shutting down m_hwnd will be NULL
  1027. if (pOprahNCUI->m_hwnd)
  1028. {
  1029. pOprahNCUI->_ChannelEvent(
  1030. pEvent->GetChannel(),
  1031. pEvent->GetEndpoint(),
  1032. pEvent->GetStatus());
  1033. }
  1034. delete pEvent;
  1035. }
  1036. else
  1037. {
  1038. WARNING_OUT(("Why are we getting a NULL pEvent?"));
  1039. }
  1040. }
  1041. return 1;
  1042. }
  1043. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1044. }
  1045. PIUnknown NewNmManager(OBJECTDESTROYEDPROC ObjectDestroyed)
  1046. {
  1047. COprahNCUI *pManager = new COprahNCUI(ObjectDestroyed);
  1048. if (NULL != pManager)
  1049. {
  1050. return (INmManager2 *) pManager;
  1051. }
  1052. return NULL;
  1053. }
  1054. VOID COprahNCUI::_ChannelEvent (ICommChannel *pIChannel,
  1055. IH323Endpoint * lpConnection, DWORD dwStatus )
  1056. {
  1057. ASSERT(pIChannel);
  1058. GUID guidMedia;
  1059. if (SUCCEEDED(pIChannel->GetMediaType(&guidMedia)))
  1060. {
  1061. if (MEDIA_TYPE_H323AUDIO == guidMedia)
  1062. {
  1063. OnAudioChannelStatus(pIChannel, lpConnection, dwStatus);
  1064. }
  1065. else if (MEDIA_TYPE_H323VIDEO == guidMedia)
  1066. {
  1067. OnVideoChannelStatus(pIChannel, lpConnection, dwStatus);
  1068. }
  1069. else if (MEDIA_TYPE_H323_T120 == guidMedia)
  1070. {
  1071. switch (dwStatus)
  1072. {
  1073. case CHANNEL_OPEN_ERROR:
  1074. case CHANNEL_OPEN:
  1075. case CHANNEL_CLOSED:
  1076. case CHANNEL_REJECTED:
  1077. case CHANNEL_NO_CAPABILITY:
  1078. OnT120ChannelOpen(pIChannel, lpConnection, dwStatus);
  1079. break;
  1080. default:
  1081. WARNING_OUT(("COprahNCUI::ChannelEvent - unrecognized T120 status"));
  1082. break;
  1083. }
  1084. }
  1085. else
  1086. {
  1087. WARNING_OUT(("COprahNCUI::ChannelEvent - unknown media type"));
  1088. }
  1089. }
  1090. else
  1091. {
  1092. WARNING_OUT(("COprahNCUI::ChannelEvent - pIChannel->GetMediaType() failed"));
  1093. }
  1094. }
  1095. STDMETHODIMP COprahNCUI::ChannelEvent (ICommChannel *pIChannel,
  1096. IH323Endpoint * lpConnection, DWORD dwStatus )
  1097. {
  1098. ASSERT(pIChannel);
  1099. GUID guidMedia;
  1100. if (SUCCEEDED(pIChannel->GetMediaType(&guidMedia)))
  1101. {
  1102. if (MEDIA_TYPE_H323_T120 == guidMedia)
  1103. {
  1104. if (NULL != m_hwnd)
  1105. {
  1106. CH323ChannelEvent* pEvent = new CH323ChannelEvent(
  1107. pIChannel,
  1108. lpConnection,
  1109. dwStatus);
  1110. if (pEvent)
  1111. {
  1112. PostMessage(m_hwnd,
  1113. CH323ChannelEvent::ms_msgChannelEvent,
  1114. 0,
  1115. reinterpret_cast<LPARAM>(pEvent));
  1116. return S_OK;
  1117. }
  1118. }
  1119. }
  1120. else
  1121. {
  1122. _ChannelEvent(pIChannel, lpConnection, dwStatus);
  1123. return S_OK;
  1124. }
  1125. }
  1126. return E_FAIL;
  1127. }
  1128. #ifdef DEBUG
  1129. VOID TraceStatus(DWORD dwStatus)
  1130. {
  1131. switch(dwStatus)
  1132. {
  1133. case CONNECTION_DISCONNECTED:
  1134. TRACE_OUT(("COprahNCUI::CallEvent: CONNECTION_DISCONNECTED"));
  1135. break;
  1136. case CONNECTION_CONNECTED:
  1137. TRACE_OUT(("COprahNCUI::CallEvent: CONNECTION_CONNECTED"));
  1138. break;
  1139. case CONNECTION_RECEIVED_DISCONNECT:
  1140. TRACE_OUT(( "COprahNCUI::CallEvent: RECEIVED_DISCONNECT"));
  1141. break;
  1142. case CONNECTION_PROCEEDING:
  1143. TRACE_OUT(("COprahNCUI::CallEvent: CONNECTION_PROCEEDING"));
  1144. break;
  1145. case CONNECTION_REJECTED:
  1146. TRACE_OUT(("COprahNCUI::CallEvent: CONNECTION_REJECTED"));
  1147. break;
  1148. default:
  1149. TRACE_OUT(("COprahNCUI::CallEvent: dwStatus = %d", dwStatus));
  1150. break;
  1151. }
  1152. }
  1153. #endif
  1154. STDMETHODIMP COprahNCUI::CallEvent(IH323Endpoint * lpConnection, DWORD dwStatus)
  1155. {
  1156. DebugEntry(COprahNCUI::CallEvent);
  1157. IH323CallControl * pH323CallControl = g_pH323UI->GetH323CallControl();
  1158. #ifdef DEBUG
  1159. TraceStatus(dwStatus);
  1160. #endif
  1161. switch (dwStatus)
  1162. {
  1163. case CONNECTION_DISCONNECTED:
  1164. OnH323Disconnected(lpConnection);
  1165. break;
  1166. case CONNECTION_CONNECTED:
  1167. // This is currently interpreted as CONNECTION_CAPABILITIES_READY.
  1168. // Lower layers are continuing to post CONNECTION_CONNECTED only after
  1169. // capabilities are exchanged. note that channels may be opened while
  1170. // inside OnH323Connected();
  1171. OnH323Connected(lpConnection);
  1172. break;
  1173. }
  1174. DebugExitVOID(COprahNCUI::CallEvent);
  1175. return S_OK;
  1176. }
  1177. STDMETHODIMP COprahNCUI::GetMediaChannel (GUID *pmediaID,
  1178. BOOL bSendDirection, IMediaChannel **ppI)
  1179. {
  1180. // delegate to the appropriate stream provider. For the time being
  1181. // there is only one provider that does both audio & video
  1182. return g_pH323UI->GetMediaChannel (pmediaID, bSendDirection, ppI);
  1183. }
  1184.