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.

2003 lines
47 KiB

  1. // File: icall.cpp
  2. #include "precomp.h"
  3. #include "icall.h"
  4. #include "rostinfo.h"
  5. #include "imanager.h"
  6. #include "mperror.h"
  7. #include "nmremote.h"
  8. #include "util.h"
  9. typedef struct
  10. {
  11. BOOL fMCU;
  12. PWSTR * pwszConfNames;
  13. BSTR * pbstrConfToJoin;
  14. } REMOTE_CONFERENCE;
  15. typedef struct
  16. {
  17. BSTR bstrConference;
  18. BSTR *pbstrPassword;
  19. PBYTE pbRemoteCred;
  20. DWORD cbRemoteCred;
  21. BOOL fIsService;
  22. } REMOTE_PASSWORD;
  23. HRESULT OnNotifyCallError(IUnknown *pCallNotify, PVOID pv, REFIID riid);
  24. static HRESULT OnNotifyRemoteConference(IUnknown *pCallNotify, PVOID pv, REFIID riid);
  25. static HRESULT OnNotifyRemotePassword(IUnknown *pCallNotify, PVOID pv, REFIID riid);
  26. static const IID * g_apiidCP[] =
  27. {
  28. {&IID_INmCallNotify},
  29. {&IID_INmCallNotify2}
  30. };
  31. // String Functions
  32. inline VOID FreeBstr(BSTR *pbstr)
  33. {
  34. if (NULL != pbstr)
  35. {
  36. SysFreeString(*pbstr);
  37. *pbstr = NULL;
  38. }
  39. }
  40. /* P S Z A L L O C */
  41. /*-------------------------------------------------------------------------
  42. %%Function: PszAlloc
  43. -------------------------------------------------------------------------*/
  44. LPTSTR PszAlloc(LPCTSTR pszSrc)
  45. {
  46. if (NULL == pszSrc)
  47. return NULL;
  48. LPTSTR pszDest = new TCHAR[lstrlen(pszSrc) + 1];
  49. if (NULL != pszDest)
  50. {
  51. lstrcpy(pszDest, pszSrc);
  52. }
  53. return pszDest;
  54. }
  55. COutgoingCall::COutgoingCall(CConfObject* pco,
  56. DWORD dwFlags, NM_ADDR_TYPE addrType,
  57. BSTR bstrName, BSTR bstrDest, BSTR bstrAlias,
  58. BSTR bstrConference, BSTR bstrPassword, BSTR bstrUserString) :
  59. CConnectionPointContainer(g_apiidCP, ARRAY_ELEMENTS(g_apiidCP)),
  60. m_pConfObject (pco),
  61. m_addrType (addrType),
  62. m_dwFlags (dwFlags),
  63. m_bstrName (SysAllocString(bstrName)),
  64. m_bstrAlias (SysAllocString(bstrAlias)),
  65. m_bstrConfToJoin (SysAllocString(bstrConference)),
  66. m_bstrPassword (SysAllocString(bstrPassword)),
  67. m_bstrUserString (SysAllocString(bstrUserString)),
  68. m_hRequest (NULL),
  69. m_pH323Connection (NULL),
  70. m_fCanceled (FALSE),
  71. m_cnResult (CN_RC_NOERROR),
  72. m_cnState (CNS_IDLE),
  73. m_fService (FALSE)
  74. {
  75. m_pszAddr = PszAlloc(CUSTRING(bstrDest));
  76. DbgMsg(iZONE_OBJECTS, "Obj: %08X created COutgoingCall", this);
  77. }
  78. COutgoingCall::~COutgoingCall()
  79. {
  80. delete m_pszAddr;
  81. FreeBstr(&m_bstrName);
  82. FreeBstr(&m_bstrAlias);
  83. FreeBstr(&m_bstrConfToJoin);
  84. FreeBstr(&m_bstrPassword);
  85. FreeBstr(&m_bstrUserString);
  86. ASSERT(NULL == m_pH323Connection);
  87. DbgMsg(iZONE_OBJECTS, "Obj: %08X destroyed COutgoingCall", this);
  88. }
  89. BOOL COutgoingCall::MatchActiveCallee(LPCTSTR pszAddr, BSTR bstrAlias, BSTR bstrConference)
  90. {
  91. return ((0 == lstrcmp(pszAddr, m_pszAddr)) &&
  92. (0 == UnicodeCompare(bstrAlias, m_bstrAlias)));
  93. }
  94. /* P L A C E C A L L */
  95. /*-------------------------------------------------------------------------
  96. %%Function: PlaceCall
  97. -------------------------------------------------------------------------*/
  98. VOID COutgoingCall::PlaceCall(void)
  99. {
  100. DebugEntry(COutgoingCall::PlaceCall);
  101. COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
  102. ASSERT(NULL != pOprahNCUI);
  103. SetCallState(CNS_SEARCHING);
  104. if ((CRPCF_H323CC & m_dwFlags) && (NULL != g_pH323UI))
  105. {
  106. SetCallState(CNS_CONNECTING_H323);
  107. // Start placing the H.323 call:
  108. CNSTATUS cnResult = ConnectH323();
  109. if (CN_RC_NOERROR != cnResult)
  110. {
  111. m_cnResult = cnResult;
  112. SetCallState(CNS_COMPLETE);
  113. }
  114. }
  115. else if ((CRPCF_DATA & m_dwFlags) && (NULL != g_pNodeController))
  116. {
  117. // Start placing the T.120 call
  118. CNSTATUS cnResult = StartT120Call();
  119. if (CN_RC_NOERROR != cnResult)
  120. {
  121. m_cnResult = cnResult;
  122. SetCallState(CNS_COMPLETE);
  123. }
  124. }
  125. else
  126. {
  127. m_cnResult = CN_RC_TRANSPORT_FAILURE;
  128. SetCallState(CNS_COMPLETE);
  129. }
  130. DebugExitVOID(COutgoingCall::PlaceCall);
  131. }
  132. CNSTATUS COutgoingCall::ConnectH323()
  133. {
  134. DBGENTRY(COutgoingCall::ConnectH323);
  135. H323ALIASLIST AliasList;
  136. H323ALIASNAME AliasName;
  137. P_H323ALIASLIST pAliasList = &AliasList;
  138. SOCKADDR_IN sin;
  139. LPCWSTR pcwszPhone = NULL;
  140. CNSTATUS cnResult = CN_RC_NOERROR;
  141. if (NULL == g_pH323UI)
  142. return cnResult;
  143. AliasName.aType = AT_H323_ID;
  144. AliasName.lpwData = m_bstrAlias;
  145. AliasName.wDataLength = (WORD)SysStringLen(m_bstrAlias);// # of unicode chars, w/o NULL terminator
  146. AliasList.wCount = 1;
  147. AliasList.pItems = &AliasName;
  148. sin.sin_family = AF_INET;
  149. sin.sin_addr.s_addr = inet_addr(m_pszAddr);
  150. switch (m_addrType)
  151. {
  152. case NM_ADDR_PSTN:
  153. case NM_ADDR_H323_GATEWAY:
  154. case NM_ADDR_ALIAS_E164:
  155. // overide alias type and phone number
  156. AliasName.aType = AT_H323_E164;
  157. pcwszPhone = m_bstrAlias;
  158. break;
  159. case NM_ADDR_IP:
  160. case NM_ADDR_MACHINENAME:
  161. // overide alias list
  162. pAliasList = NULL;
  163. break;
  164. case NM_ADDR_ALIAS_ID:
  165. case NM_ADDR_ULS:
  166. default:
  167. break;
  168. }
  169. if (INADDR_NONE != sin.sin_addr.s_addr)
  170. {
  171. HRESULT hr;
  172. ASSERT(g_pH323UI);
  173. DWORD dwUserData = 0;
  174. APP_CALL_SETUP_DATA acsd;
  175. P_APP_CALL_SETUP_DATA pacsd = NULL;
  176. BYTE *pbUserData = NULL;
  177. COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
  178. ASSERT(NULL !=pOprahNCUI);
  179. if (CRPCF_DATA & m_dwFlags)
  180. {
  181. if (CRPCF_SECURE & m_dwFlags)
  182. {
  183. dwUserData |= H323UDF_SECURE;
  184. }
  185. if (m_pConfObject->IsConferenceActive())
  186. {
  187. dwUserData |= H323UDF_INVITE;
  188. }
  189. else if (m_bstrConfToJoin != NULL)
  190. {
  191. dwUserData |= H323UDF_JOIN;
  192. }
  193. else
  194. {
  195. dwUserData |= H323UDF_INVITE | H323UDF_JOIN;
  196. }
  197. }
  198. if (CRPCF_AUDIO & m_dwFlags)
  199. {
  200. dwUserData |= H323UDF_AUDIO;
  201. }
  202. if (CRPCF_VIDEO & m_dwFlags)
  203. {
  204. dwUserData |= H323UDF_VIDEO;
  205. }
  206. CRosterInfo ri;
  207. PVOID pvRosterData;
  208. UINT cbRosterData = 0;
  209. if (pOprahNCUI->GetULSName(&ri))
  210. {
  211. if (FAILED(ri.Save(&pvRosterData, &cbRosterData)))
  212. {
  213. cbRosterData = 0;
  214. }
  215. }
  216. UINT cbUserString = 0;
  217. if (m_bstrUserString)
  218. {
  219. cbUserString = SysStringByteLen(m_bstrUserString);
  220. }
  221. DWORD dwTotalSize = sizeof(DWORD);
  222. if (cbRosterData)
  223. {
  224. dwTotalSize += sizeof(GUID) + sizeof(DWORD) + cbRosterData;
  225. }
  226. if (cbUserString)
  227. {
  228. dwTotalSize += sizeof(GUID) + sizeof(DWORD) + cbUserString;
  229. }
  230. dwTotalSize += sizeof(GUID) + sizeof(DWORD) + sizeof(GUID);
  231. pbUserData = new BYTE [dwTotalSize];
  232. if (NULL != pbUserData)
  233. {
  234. BYTE *pb = pbUserData;
  235. // H323UDF_ first
  236. *((DWORD*)pb) = dwUserData;
  237. pb += sizeof(DWORD);
  238. if(cbRosterData)
  239. {
  240. // RosterInfo GUID next
  241. *((GUID*)pb) = g_csguidRostInfo,
  242. pb += sizeof(GUID);
  243. // then RosterInfo size (a DWORD)
  244. *((DWORD*)pb) = cbRosterData;
  245. pb += sizeof(DWORD);
  246. // then RosterInfo data
  247. CopyMemory(pb, pvRosterData, cbRosterData);
  248. pb += cbRosterData;
  249. }
  250. if(cbUserString)
  251. {
  252. // string GUID next
  253. *((GUID*)pb) = g_csguidUserString,
  254. pb += sizeof(GUID);
  255. // then string size (a DWORD)
  256. *((DWORD*)pb) = cbUserString;
  257. pb += sizeof(DWORD);
  258. // then string data
  259. CopyMemory(pb, m_bstrUserString, cbUserString);
  260. pb += cbUserString;
  261. }
  262. {
  263. // string GUID next
  264. *((GUID*)pb) = g_csguidNodeIdTag,
  265. pb += sizeof(GUID);
  266. // then string size (a DWORD)
  267. *((DWORD*)pb) = sizeof(GUID);
  268. pb += sizeof(DWORD);
  269. // then GUID data
  270. *(GUID*)pb = g_guidLocalNodeId;
  271. pb += sizeof(GUID);
  272. }
  273. acsd.dwDataSize = dwTotalSize;
  274. acsd.lpData = pbUserData;
  275. pacsd = &acsd;
  276. }
  277. sin.sin_port = htons(H323_PORT);
  278. hr = Connect(&sin, pAliasList, pcwszPhone, pacsd, PID_H323, &m_pH323Connection);
  279. delete [] pbUserData;
  280. if (SUCCEEDED(hr))
  281. {
  282. TRACE_OUT(("COutgoingCall - Connect() succeeded!"));
  283. cnResult = CN_RC_NOERROR;
  284. }
  285. else
  286. {
  287. WARNING_OUT(("COutgoingCall - Connect() failed!"));
  288. if (CONN_E_GK_NOT_REGISTERED == hr)
  289. {
  290. cnResult = CN_RC_GK_NOT_REGISTERED;
  291. }
  292. else
  293. {
  294. cnResult = CN_RC_AUDIO_CONNECT_FAILED;
  295. }
  296. }
  297. }
  298. else
  299. {
  300. WARNING_OUT(("COutgoingCall - inet_addr failed!"));
  301. cnResult = CN_RC_NAME_RESOLUTION_FAILED;
  302. }
  303. return cnResult;
  304. }
  305. HRESULT COutgoingCall::Connect( PSOCKADDR_IN psin,
  306. P_H323ALIASLIST pAliasList,
  307. LPCWSTR pcwszPSTNAddress,
  308. P_APP_CALL_SETUP_DATA lpvMNMData,
  309. GUID PIDofProtocolType,
  310. IH323Endpoint * *ppConnection)
  311. {
  312. DebugEntry(CH323UI::Connect);
  313. HRESULT hr = E_ACCESSDENIED;
  314. *ppConnection = NULL;
  315. COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
  316. ASSERT(NULL != pOprahNCUI);
  317. IH323CallControl * pH323CallControl = g_pH323UI->GetH323CallControl();
  318. // create the connection
  319. IH323Endpoint* pConn = NULL;
  320. ASSERT(pH323CallControl);
  321. hr = pH323CallControl->CreateConnection(&pConn, PIDofProtocolType);
  322. if (FAILED(hr) || (NULL == pConn))
  323. {
  324. ERROR_OUT(("Could not create a connection, hr=0x%lx", hr));
  325. }
  326. else
  327. {
  328. // if the following operations fail, we still can delete this conn obj
  329. *ppConnection = pConn;
  330. if (!pOprahNCUI->AcquireAV(pConn))
  331. {
  332. // we did not get AV, clear out the flags
  333. m_dwFlags &= ~(CRPCF_AUDIO | CRPCF_VIDEO);
  334. }
  335. hr = pConn->SetAdviseInterface (pOprahNCUI);
  336. ASSERT(SUCCEEDED(hr));
  337. // if we are using an alias, tell the Gatekeeper to resolve it
  338. BOOL fUseGKResolution = (NULL != pAliasList);
  339. // start the connection
  340. hr = pConn->PlaceCall (fUseGKResolution, psin, pAliasList, NULL, pcwszPSTNAddress, lpvMNMData);
  341. if (FAILED(hr))
  342. {
  343. // ERROR_OUT(("COutgoingCall::Connect: couldn't StartConnection, hr=0x%lx", hr));
  344. if(hr == CONN_E_GK_NOT_REGISTERED)
  345. {
  346. WARNING_OUT(("COutgoingCall::Connect: not registered. Do you want to re-register..., hr=0x%lx", hr));
  347. }
  348. *ppConnection = NULL;
  349. pConn->Release();
  350. pOprahNCUI->ReleaseAV(pConn);
  351. }
  352. }
  353. DebugExitULONG(CH323UI::Connect, hr);
  354. return hr;
  355. }
  356. BOOL COutgoingCall::OnConferenceEnded()
  357. {
  358. DebugEntry(COutgoingCall::OnConferenceEnded);
  359. BOOL bRet = FALSE;
  360. switch (m_cnState)
  361. {
  362. case CNS_INVITING_REMOTE:
  363. {
  364. TRACE_OUT(("COutgoingCall (calling) rec. UNEXPECTED ConfEnded event"));
  365. SetCallState(CNS_COMPLETE);
  366. bRet = TRUE;
  367. break;
  368. }
  369. case CNS_JOINING_REMOTE:
  370. {
  371. // JoinConference failed!
  372. TRACE_OUT(("COutgoingCall (joining) received ConferenceEnded event"));
  373. m_cnResult = CN_RC_CONFERENCE_JOIN_DENIED;
  374. SetCallState(CNS_COMPLETE);
  375. bRet = TRUE;
  376. break;
  377. }
  378. case CNS_TERMINATING_AFTER_INVITE:
  379. {
  380. TRACE_OUT(("COutgoingCall (terminating after invite) received ConferenceEnded event"));
  381. SetCallState(CNS_QUERYING_REMOTE_AFTER_INVITE);
  382. ASSERT(g_pNodeController);
  383. HRESULT hr = g_pNodeController->QueryRemote(this, m_pszAddr,
  384. m_pConfObject->IsConfObjSecure(),
  385. m_pConfObject->IsConferenceActive());
  386. if (S_OK != hr)
  387. {
  388. m_cnResult = CN_RC_QUERY_FAILED;
  389. SetCallState(CNS_COMPLETE);
  390. }
  391. bRet = TRUE;
  392. break;
  393. }
  394. default:
  395. {
  396. WARNING_OUT(("COutgoingCall received unexpected ConfEnded event"));
  397. }
  398. }
  399. DebugExitBOOL(COutgoingCall::OnConferenceEnded, bRet);
  400. return bRet;
  401. }
  402. BOOL COutgoingCall::OnInviteResult(HRESULT ncsResult, UINT uNodeID)
  403. {
  404. DebugEntry(COutgoingCall::OnInviteResult);
  405. BOOL bRet = TRUE;
  406. ASSERT(CNS_INVITING_REMOTE == m_cnState);
  407. TRACE_OUT(("COutgoingCall (calling) received InviteResult event"));
  408. // Clear the current request handle
  409. m_hRequest = NULL;
  410. if (0 == ncsResult)
  411. {
  412. SetCallState(CNS_COMPLETE);
  413. if (m_pH323Connection)
  414. {
  415. m_pConfObject->OnT120Connected(m_pH323Connection, uNodeID);
  416. }
  417. }
  418. else
  419. {
  420. if (UI_RC_USER_REJECTED == ncsResult)
  421. {
  422. SetCallState(CNS_TERMINATING_AFTER_INVITE);
  423. // Issue "soft" leave attempt (to allow auto-terminate)
  424. ASSERT(m_pConfObject);
  425. if (S_OK != m_pConfObject->LeaveConference(FALSE))
  426. {
  427. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  428. SetCallState(CNS_COMPLETE);
  429. }
  430. }
  431. else
  432. {
  433. // make sure that we are not recieving this notification due to
  434. // the conference going away
  435. ASSERT(m_pConfObject);
  436. if (CS_GOING_DOWN != m_pConfObject->GetT120State())
  437. {
  438. TRACE_OUT(("COutgoingCall - invite failed / couldn't connect -> leaving"));
  439. m_cnResult = CN_RC_INVITE_FAILED;
  440. SetCallState(CNS_COMPLETE);
  441. // Issue "soft" leave attempt (to allow auto-terminate)
  442. ASSERT(m_pConfObject);
  443. m_pConfObject->LeaveConference(FALSE);
  444. }
  445. }
  446. }
  447. DebugExitBOOL(COutgoingCall::OnInviteResult, bRet);
  448. return bRet;
  449. }
  450. BOOL COutgoingCall::OnQueryRemoteResult(HRESULT ncsResult,
  451. BOOL fMCU,
  452. PWSTR pwszConfNames[],
  453. PT120PRODUCTVERSION pVersion,
  454. PWSTR pwszConfDescriptors[])
  455. {
  456. DebugEntry(COutgoingCall::OnQueryRemoteResult);
  457. ASSERT ((CNS_QUERYING_REMOTE == m_cnState) ||
  458. (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState));
  459. ASSERT (NULL == m_bstrConfToJoin);
  460. if (SUCCEEDED(ncsResult))
  461. {
  462. BOOL fRemoteInConf = FALSE;
  463. if ((NULL != pwszConfNames) && (NULL != pwszConfNames[0]))
  464. {
  465. fRemoteInConf = TRUE;
  466. }
  467. m_fService = FALSE;
  468. if (fRemoteInConf && (NULL != pwszConfDescriptors) && (NULL != pwszConfDescriptors[0]))
  469. {
  470. if (0 == UnicodeCompare(pwszConfDescriptors[0],RDS_CONFERENCE_DESCRIPTOR))
  471. {
  472. m_fService = TRUE;
  473. }
  474. }
  475. if (m_pConfObject->IsConferenceActive())
  476. {
  477. if (fMCU)
  478. {
  479. TRACE_OUT(("COutgoingCall - QR ok, but is MCU -> complete"));
  480. m_cnResult = CN_RC_CANT_INVITE_MCU;
  481. }
  482. else if (fRemoteInConf)
  483. {
  484. TRACE_OUT(("COutgoingCall - QR ok, but callee is in a conference"));
  485. m_cnResult = CN_RC_INVITE_DENIED_REMOTE_IN_CONF;
  486. }
  487. else
  488. {
  489. if (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState)
  490. {
  491. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  492. SetCallState(CNS_COMPLETE);
  493. }
  494. else
  495. {
  496. SetCallState(CNS_INVITING_REMOTE);
  497. HRESULT hr = m_pConfObject->InviteConference(m_pszAddr, m_bstrUserString, &m_hRequest);
  498. if (S_OK != hr)
  499. {
  500. // Failure while inviting:
  501. m_cnResult = CN_RC_INVITE_FAILED;
  502. }
  503. }
  504. }
  505. if (CN_RC_NOERROR != m_cnResult)
  506. {
  507. SetCallState(CNS_COMPLETE);
  508. }
  509. }
  510. else if (fRemoteInConf || fMCU)
  511. {
  512. TRACE_OUT(("COutgoingCall - QR succeeded (>0 conf) -> joining"));
  513. TRACE_OUT(("\tfMCU is %d", fMCU));
  514. // There are remote conferences
  515. HRESULT hr = E_FAIL; // Assume a failure
  516. SetCallState(CNS_JOINING_REMOTE);
  517. if (!fMCU && (NULL == pwszConfNames[1]))
  518. {
  519. // we're not calling an MCU and we have just one conference, so join it
  520. m_bstrConfToJoin = SysAllocString(pwszConfNames[0]);
  521. hr = m_pConfObject->JoinConference( m_bstrConfToJoin,
  522. m_bstrPassword,
  523. m_pszAddr,
  524. m_bstrUserString);
  525. }
  526. else
  527. {
  528. ASSERT(NULL == m_bstrConfToJoin);
  529. REMOTE_CONFERENCE remoteConf;
  530. remoteConf.fMCU = fMCU;
  531. remoteConf.pwszConfNames = pwszConfNames;
  532. remoteConf.pbstrConfToJoin = &m_bstrConfToJoin;
  533. // Ask the app which conference to join
  534. NotifySink(&remoteConf, OnNotifyRemoteConference);
  535. if (NULL != m_bstrConfToJoin)
  536. {
  537. hr = m_pConfObject->JoinConference( m_bstrConfToJoin,
  538. m_bstrPassword,
  539. m_pszAddr,
  540. m_bstrUserString);
  541. }
  542. }
  543. if (S_OK != hr)
  544. {
  545. // JoinConference failed!
  546. m_cnResult = CN_RC_JOIN_FAILED;
  547. SetCallState(CNS_COMPLETE);
  548. }
  549. }
  550. else
  551. {
  552. if (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState)
  553. {
  554. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  555. SetCallState(CNS_COMPLETE);
  556. }
  557. else
  558. {
  559. // No conferences on remote machine, so create local:
  560. TRACE_OUT(("COutgoingCall - QR succeeded (no conf)-> creating local"));
  561. // Create local conf
  562. ASSERT(m_pConfObject);
  563. SetCallState(CNS_CREATING_LOCAL);
  564. HRESULT hr = m_pConfObject->CreateConference();
  565. if (S_OK != hr)
  566. {
  567. // CreateConference failed!
  568. m_cnResult = CN_RC_CONFERENCE_CREATE_FAILED;
  569. SetCallState(CNS_COMPLETE);
  570. }
  571. }
  572. }
  573. }
  574. else
  575. {
  576. // The QueryRemote failed
  577. switch( ncsResult )
  578. {
  579. case UI_RC_USER_REJECTED:
  580. // The initial QueryRemote failed because GCC symmetry determined
  581. // that the other node is calling someone, and it might be us
  582. // See Bug 1886
  583. TRACE_OUT(("COutgoingCall - QueryRemote rejected -> complete"));
  584. m_cnResult = CN_RC_REMOTE_PLACING_CALL;
  585. break;
  586. case UI_RC_T120_REMOTE_REQUIRE_SECURITY:
  587. m_cnResult = CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY;
  588. break;
  589. case UI_RC_T120_SECURITY_FAILED:
  590. m_cnResult = CN_RC_SECURITY_FAILED;
  591. break;
  592. case UI_RC_T120_REMOTE_NO_SECURITY:
  593. m_cnResult = CN_RC_CONNECT_REMOTE_NO_SECURITY;
  594. break;
  595. case UI_RC_T120_REMOTE_DOWNLEVEL_SECURITY:
  596. m_cnResult = CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY;
  597. break;
  598. case UI_RC_T120_AUTHENTICATION_FAILED:
  599. m_cnResult = CN_RC_CONNECT_AUTHENTICATION_FAILED;
  600. break;
  601. default:
  602. m_cnResult = CN_RC_CONNECT_FAILED;
  603. break;
  604. }
  605. SetCallState(CNS_COMPLETE);
  606. }
  607. DebugExitBOOL(COutgoingCall::OnQueryRemoteResult, TRUE);
  608. return TRUE;
  609. }
  610. BOOL COutgoingCall::OnConferenceStarted(CONF_HANDLE hNewConf, HRESULT ncsResult)
  611. {
  612. DebugEntry(COutgoingCall::OnConferenceStarted);
  613. switch (m_cnState)
  614. {
  615. case CNS_CREATING_LOCAL:
  616. {
  617. TRACE_OUT(("COutgoingCall (inviting) received ConferenceStarted event"));
  618. if (0 == ncsResult)
  619. {
  620. ASSERT(m_pConfObject);
  621. ASSERT(NULL == m_hRequest);
  622. SetCallState(CNS_INVITING_REMOTE);
  623. HRESULT hr = m_pConfObject->InviteConference(m_pszAddr, m_bstrUserString, &m_hRequest);
  624. if (S_OK != hr)
  625. {
  626. m_hRequest = NULL;
  627. m_cnResult = CN_RC_INVITE_FAILED;
  628. SetCallState(CNS_COMPLETE);
  629. // Issue "soft" leave attempt (to allow auto-terminate)
  630. ASSERT(m_pConfObject);
  631. hr = m_pConfObject->LeaveConference(FALSE);
  632. if (FAILED(hr))
  633. {
  634. WARNING_OUT(("Couldn't leave after failed invite"));
  635. }
  636. }
  637. }
  638. else
  639. {
  640. WARNING_OUT(("CreateConference (local) failed - need UI here!"));
  641. m_cnResult = CN_RC_CONFERENCE_CREATE_FAILED;
  642. SetCallState(CNS_COMPLETE);
  643. }
  644. break;
  645. }
  646. case CNS_JOINING_REMOTE:
  647. {
  648. TRACE_OUT(("COutgoingCall (joining) received ConferenceStarted event"));
  649. if (0 == ncsResult)
  650. {
  651. SetCallState(CNS_COMPLETE);
  652. if (m_pH323Connection)
  653. {
  654. UINT uNodeID = hNewConf->GetParentNodeID();
  655. m_pConfObject->OnT120Connected(m_pH323Connection, uNodeID);
  656. }
  657. }
  658. else if (UI_RC_INVALID_PASSWORD == ncsResult)
  659. {
  660. TRACE_OUT(("COutgoingCall - invalid password, prompt for password"));
  661. BSTR bstrPassword = NULL;
  662. REMOTE_PASSWORD remotePw;
  663. remotePw.bstrConference = m_bstrConfToJoin;
  664. remotePw.pbstrPassword = &bstrPassword;
  665. if (NO_ERROR != hNewConf->GetCred(&remotePw.pbRemoteCred, &remotePw.cbRemoteCred))
  666. {
  667. remotePw.pbRemoteCred = NULL;
  668. remotePw.cbRemoteCred = 0;
  669. }
  670. remotePw.fIsService = m_fService;
  671. NotifySink(&remotePw, OnNotifyRemotePassword);
  672. if (NULL != bstrPassword)
  673. {
  674. SysFreeString(m_bstrPassword);
  675. m_bstrPassword = bstrPassword;
  676. // reissue join with new password
  677. ASSERT(m_pConfObject);
  678. HRESULT ncs =
  679. m_pConfObject->JoinConference( m_bstrConfToJoin,
  680. m_bstrPassword,
  681. m_pszAddr,
  682. m_bstrUserString,
  683. TRUE); // retry
  684. if (0 != ncs)
  685. {
  686. // JoinConference failed!
  687. m_cnResult = CN_RC_JOIN_FAILED;
  688. SetCallState(CNS_COMPLETE);
  689. }
  690. }
  691. else
  692. {
  693. // cancel from pw dlg
  694. m_cnResult = CN_RC_INVALID_PASSWORD;
  695. SetCallState(CNS_COMPLETE);
  696. ASSERT(m_pConfObject);
  697. HRESULT hr = m_pConfObject->LeaveConference(TRUE);
  698. if (FAILED(hr))
  699. {
  700. ERROR_OUT(("Couldn't leave after cancelling pw join!"));
  701. }
  702. }
  703. }
  704. else if (UI_RC_UNKNOWN_CONFERENCE == ncsResult)
  705. {
  706. TRACE_OUT(("Join failed (conf does not exist) "
  707. "- notifying user"));
  708. // error while joining
  709. m_cnResult = CN_RC_CONFERENCE_DOES_NOT_EXIST;
  710. SetCallState(CNS_COMPLETE);
  711. }
  712. else
  713. {
  714. TRACE_OUT(("Join failed - notifying user"));
  715. // error while joining
  716. m_cnResult = CN_RC_CONFERENCE_JOIN_DENIED;
  717. SetCallState(CNS_COMPLETE);
  718. }
  719. break;
  720. }
  721. default:
  722. {
  723. if (m_pConfObject->GetConfHandle() == hNewConf)
  724. {
  725. WARNING_OUT(("COutgoingCall received unexpected ConferenceStarted event"));
  726. }
  727. else
  728. {
  729. TRACE_OUT(("COutgoingCall ignoring ConferenceStarted event - not our conf"));
  730. }
  731. }
  732. }
  733. DebugExitBOOL(COutgoingCall::OnConferenceStarted, TRUE);
  734. return TRUE;
  735. }
  736. BOOL COutgoingCall::OnH323Connected(IH323Endpoint * pConnection)
  737. {
  738. DebugEntry(COutgoingCall::OnH323Connected);
  739. BOOL bRet = TRUE;
  740. ASSERT(m_pH323Connection == pConnection);
  741. if (m_dwFlags & CRPCF_DATA)
  742. {
  743. PCC_VENDORINFO pLocalVendorInfo;
  744. PCC_VENDORINFO pRemoteVendorInfo;
  745. pConnection->GetVersionInfo(&pLocalVendorInfo, &pRemoteVendorInfo);
  746. H323VERSION version = GetH323Version(pRemoteVendorInfo);
  747. if (H323_NetMeeting20 == version)
  748. {
  749. if ((m_addrType != NM_ADDR_H323_GATEWAY) &&
  750. (m_addrType != NM_ADDR_PSTN) &&
  751. (m_addrType != NM_ADDR_ALIAS_ID) &&
  752. (m_addrType != NM_ADDR_ALIAS_E164))
  753. {
  754. CNSTATUS cnResult = StartT120Call();
  755. if (CN_RC_NOERROR != cnResult)
  756. {
  757. m_cnResult = cnResult;
  758. SetCallState(CNS_COMPLETE);
  759. }
  760. }
  761. else
  762. {
  763. SetCallState(CNS_COMPLETE);
  764. }
  765. }
  766. else
  767. {
  768. // wait for results of T.120 open logical channel
  769. TRACE_OUT(("COutgoingCall - H323Connected received -> waiting for T120 channel open"));
  770. SetCallState(CNS_WAITING_T120_OPEN);
  771. }
  772. }
  773. else
  774. {
  775. // no T120 for this call
  776. TRACE_OUT(("COutgoingCall - our H323 call started -> complete"));
  777. SetCallState(CNS_COMPLETE);
  778. }
  779. CConfObject *pco = ::GetConfObject();
  780. if (NULL != pco)
  781. {
  782. // add member if we are calling with A/V
  783. BOOL fAddMember = m_dwFlags & (CRPCF_AUDIO | CRPCF_VIDEO);
  784. pco->OnH323Connected(pConnection, m_dwFlags, fAddMember, GUID_NULL);
  785. }
  786. DebugExitBOOL(COutgoingCall::OnH323Connected, bRet);
  787. return bRet;
  788. }
  789. BOOL COutgoingCall::OnH323Disconnected(IH323Endpoint * pConnection)
  790. {
  791. DebugEntry(COutgoingCall::OnH323Disconnected);
  792. BOOL bRet = TRUE;
  793. ASSERT(m_pH323Connection == pConnection);
  794. HRESULT hSummary = m_pH323Connection->GetSummaryCode();
  795. // Check summary code for gatekeeper-caused disconnect
  796. // Note: this applies only to MY gatekeeper, not the callee's gatekeeper
  797. if(CUSTOM_FACILITY(hSummary) == FACILITY_GKIADMISSION)
  798. {
  799. DWORD dwRejectReason;
  800. dwRejectReason = CUSTOM_FACILITY_CODE(hSummary);
  801. // should the T.120 call be placed anyway?
  802. switch (dwRejectReason)
  803. {
  804. case ARJ_CALLEE_NOT_REGISTERED:
  805. m_cnResult = CN_RC_GK_CALLEE_NOT_REGISTERED;
  806. break;
  807. case ARJ_TIMEOUT:
  808. m_cnResult = CN_RC_GK_TIMEOUT;
  809. break;
  810. case ARJ_INVALID_PERMISSION:
  811. case ARJ_REQUEST_DENIED:
  812. case ARJ_UNDEFINED:
  813. case ARJ_CALLER_NOT_REGISTERED:
  814. case ARJ_ROUTE_TO_GK:
  815. case ARJ_INVALID_ENDPOINT_ID:
  816. case ARJ_RESOURCE_UNAVAILABLE:
  817. case ARJ_SECURTY_DENIAL:
  818. case ARJ_QOS_CONTROL_NOT_SUPPORTED:
  819. case ARJ_INCOMPLETE_ADDRESS:
  820. default:
  821. m_cnResult = CN_RC_GK_REJECTED;
  822. break;
  823. }
  824. SetCallState(CNS_COMPLETE);
  825. }
  826. else if (CNS_CONNECTING_H323 == m_cnState)
  827. {
  828. // attempted an H.323 call without success.
  829. TRACE_OUT(("COutgoingCall - our leading H323 call ended -> complete"));
  830. // check for cases of remote refusing the call
  831. switch (hSummary)
  832. {
  833. case CCR_REMOTE_DISCONNECT:
  834. case CCR_REMOTE_REJECTED:
  835. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  836. SetCallState(CNS_COMPLETE);
  837. break;
  838. case CCR_LOCAL_DISCONNECT:
  839. // cancelled by user, do not report error
  840. m_cnResult = CN_RC_LOCAL_CANCELED;
  841. m_fCanceled = TRUE;
  842. SetCallState(CNS_COMPLETE);
  843. break;
  844. case CCR_GK_NO_RESOURCES:
  845. // callee's gatekeeper would not let callee answer
  846. // do the same as CCR_REMOTE_REJECTED
  847. // as a temporary measure !!!!
  848. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  849. SetCallState(CNS_COMPLETE);
  850. break;
  851. case CCR_REMOTE_SECURITY_DENIED:
  852. if (m_pConfObject->IsConfObjSecure())
  853. {
  854. m_cnResult = CN_RC_CONNECT_REMOTE_NO_SECURITY;
  855. }
  856. else
  857. {
  858. m_cnResult = CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY;
  859. }
  860. SetCallState(CNS_COMPLETE);
  861. break;
  862. case CCR_REMOTE_BUSY:
  863. if (m_pConfObject->IsConferenceActive())
  864. {
  865. m_cnResult = CN_RC_INVITE_DENIED_REMOTE_IN_CONF;
  866. SetCallState(CNS_COMPLETE);
  867. break;
  868. }
  869. // else fall through
  870. default:
  871. if ((m_dwFlags & CRPCF_DATA) &&
  872. (m_addrType != NM_ADDR_H323_GATEWAY) &&
  873. (m_addrType != NM_ADDR_PSTN) &&
  874. (m_addrType != NM_ADDR_ALIAS_ID) &&
  875. (m_addrType != NM_ADDR_ALIAS_E164))
  876. {
  877. // The endpoint is not there, not listening for H.323 calls, or is busy,
  878. // and the address is a resolvable type (not an H.323 alias or E.164 number)
  879. // go back into the T.120 call state path
  880. CNSTATUS cnResult = StartT120Call();
  881. if (CN_RC_NOERROR != cnResult)
  882. {
  883. m_cnResult = cnResult;
  884. SetCallState(CNS_COMPLETE);
  885. bRet = FALSE;
  886. }
  887. }
  888. else
  889. {
  890. switch (hSummary)
  891. {
  892. case CCR_REMOTE_BUSY:
  893. m_cnResult = CN_RC_INVITE_DENIED_REMOTE_IN_CONF;
  894. break;
  895. case CCR_REMOTE_MEDIA_ERROR:
  896. m_cnResult = CN_RC_AUDIO_IN_USE_REMOTE;
  897. break;
  898. case CCR_LOCAL_MEDIA_ERROR:
  899. m_cnResult = CN_RC_AUDIO_IN_USE_LOCAL;
  900. break;
  901. case CCR_GK_NO_RESOURCES:
  902. m_cnResult = CN_RC_GK_REJECTED;
  903. break;
  904. default:
  905. m_cnResult = CN_RC_AUDIO_CONNECT_FAILED;
  906. break;
  907. }
  908. SetCallState(CNS_COMPLETE);
  909. }
  910. break;
  911. }
  912. }
  913. else if (CNS_WAITING_T120_OPEN == m_cnState)
  914. {
  915. TRACE_OUT(("COutgoingCall - OnH323Disconnected received -> call is canceled"));
  916. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  917. SetCallState(CNS_COMPLETE);
  918. }
  919. else
  920. {
  921. TRACE_OUT(("COutgoingCall - OnH323Disconnected received -> canceling call"));
  922. ASSERT(m_pConfObject);
  923. if (NULL != m_hRequest)
  924. {
  925. REQUEST_HANDLE hRequest = m_hRequest;
  926. m_hRequest = NULL;
  927. m_pConfObject->CancelInvite(hRequest);
  928. }
  929. if (m_pConfObject->IsConferenceActive())
  930. {
  931. // Issue "soft" leave attempt (to allow auto-terminate)
  932. m_pConfObject->LeaveConference(FALSE);
  933. }
  934. }
  935. // the connection may have been released due to the LeaveConference above
  936. // bug 3996
  937. if (m_pH323Connection)
  938. {
  939. m_pH323Connection->Release();
  940. m_pH323Connection = NULL;
  941. }
  942. DebugExitBOOL(COutgoingCall::OnH323Disconnected, bRet);
  943. return bRet;
  944. }
  945. BOOL COutgoingCall::OnT120ChannelOpen(ICommChannel *pIChannel, DWORD dwStatus)
  946. {
  947. DebugEntry(COutgoingCall::OnT120ChannelOpen);
  948. BOOL bRet = TRUE;
  949. // sometimes we get an extra T120 channel open
  950. // this is most likely due the master/slave anomolies that
  951. // venkatg discovered.
  952. if (CNS_WAITING_T120_OPEN == m_cnState)
  953. {
  954. switch(dwStatus)
  955. {
  956. case CHANNEL_OPEN:
  957. {
  958. // start the T.120 part of the call
  959. // get the negotiated address
  960. SOCKADDR_IN sin_T120;
  961. HRESULT hr = pIChannel->GetRemoteAddress(&sin_T120);
  962. delete m_pszAddr; // we won't be needing this anymore
  963. TCHAR szAddress[256]; // allow plenty of room for conversion from numberic to string
  964. wsprintf(szAddress, "%s:%d", inet_ntoa(sin_T120.sin_addr), ntohs(sin_T120.sin_port));
  965. m_pszAddr = PszAlloc(szAddress);
  966. CNSTATUS cnResult = StartT120Call();
  967. if (CN_RC_NOERROR != cnResult)
  968. {
  969. m_cnResult = cnResult;
  970. SetCallState(CNS_COMPLETE);
  971. }
  972. }
  973. break;
  974. case CHANNEL_CLOSED:
  975. // if the T.120 channel is being closed
  976. // the H.323 call is going down, so don't continue waiting for
  977. // T.120 to connect!
  978. m_cnResult = CN_RC_CONNECT_FAILED;
  979. SetCallState(CNS_COMPLETE);
  980. if (NULL != m_hRequest)
  981. {
  982. REQUEST_HANDLE hRequest = m_hRequest;
  983. m_hRequest = NULL;
  984. ASSERT(m_pConfObject);
  985. m_pConfObject->CancelInvite(hRequest);
  986. }
  987. break;
  988. case CHANNEL_NO_CAPABILITY:
  989. case CHANNEL_REJECTED:
  990. case CHANNEL_OPEN_ERROR:
  991. default:
  992. m_cnResult = CN_RC_CONNECT_FAILED;
  993. SetCallState(CNS_COMPLETE);
  994. break;
  995. }
  996. }
  997. DebugExitBOOL(COutgoingCall::OnT120ChannelOpen, bRet);
  998. return bRet;
  999. }
  1000. void COutgoingCall::CallComplete()
  1001. {
  1002. DebugEntry(COutgoingCall::CallComplete);
  1003. // If this fails, we are being destructed unexpectedly
  1004. ASSERT( (m_cnState == CNS_IDLE) ||
  1005. (m_cnState == CNS_COMPLETE));
  1006. // The request handle should have been reset
  1007. ASSERT(NULL == m_hRequest);
  1008. // make sure that the H323 connection is released
  1009. if (m_pH323Connection)
  1010. {
  1011. if (!IsDataOnly() &&
  1012. ((CN_RC_TRANSPORT_FAILURE == m_cnResult) ||
  1013. (CN_RC_QUERY_FAILED == m_cnResult) ||
  1014. (CN_RC_CONNECT_FAILED == m_cnResult)))
  1015. {
  1016. m_cnResult = CN_RC_NOERROR;
  1017. }
  1018. if (CN_RC_NOERROR != m_cnResult)
  1019. {
  1020. m_pH323Connection->Disconnect();
  1021. }
  1022. m_pH323Connection->Release();
  1023. m_pH323Connection = NULL;
  1024. }
  1025. if (!FCanceled() && (CN_RC_NOERROR != m_cnResult))
  1026. {
  1027. ReportError(m_cnResult);
  1028. }
  1029. NM_CALL_STATE state;
  1030. GetState(&state);
  1031. NotifySink((PVOID) state, OnNotifyCallStateChanged);
  1032. TRACE_OUT(("ConfNode destroying addr %s", m_pszAddr));
  1033. DebugExitVOID(COutgoingCall::CallComplete);
  1034. }
  1035. BOOL COutgoingCall::ReportError(CNSTATUS cns)
  1036. {
  1037. DebugEntry(COutgoingCall::ReportError);
  1038. TRACE_OUT(("CNSTATUS 0x%08x", cns));
  1039. NotifySink((PVOID)cns, OnNotifyCallError);
  1040. DebugExitBOOL(COutgoingCall::ReportError, TRUE);
  1041. return TRUE;
  1042. }
  1043. CNSTATUS COutgoingCall::StartT120Call()
  1044. {
  1045. DebugEntry(COutgoingCall::StartT120Call);
  1046. CNSTATUS cnResult = CN_RC_NOERROR;
  1047. if (NULL == m_bstrConfToJoin)
  1048. {
  1049. // conference name not specified
  1050. // need to start out with a QueryRemote
  1051. SetCallState(CNS_QUERYING_REMOTE);
  1052. ASSERT(g_pNodeController);
  1053. HRESULT hr = g_pNodeController->QueryRemote(this, m_pszAddr,
  1054. m_pConfObject->IsConfObjSecure(),
  1055. m_pConfObject->IsConferenceActive());
  1056. if (S_OK != hr)
  1057. {
  1058. cnResult = CN_RC_QUERY_FAILED;
  1059. }
  1060. }
  1061. else
  1062. {
  1063. ASSERT(m_pConfObject);
  1064. // conference name has been specified
  1065. // time to do a JoinConference
  1066. SetCallState(CNS_JOINING_REMOTE);
  1067. HRESULT hr = m_pConfObject->JoinConference( m_bstrConfToJoin,
  1068. m_bstrPassword,
  1069. m_pszAddr,
  1070. m_bstrUserString);
  1071. if (S_OK != hr)
  1072. {
  1073. cnResult = CN_RC_JOIN_FAILED;
  1074. }
  1075. }
  1076. DebugExitINT(COutgoingCall::StartT120Call, cnResult);
  1077. return cnResult;
  1078. }
  1079. VOID COutgoingCall::SetCallState(CNODESTATE cnState)
  1080. {
  1081. NM_CALL_STATE stateOld;
  1082. NM_CALL_STATE stateNew;
  1083. GetState(&stateOld);
  1084. m_cnState = cnState;
  1085. // completion state will be fired off later
  1086. if (CNS_COMPLETE != cnState)
  1087. {
  1088. GetState(&stateNew);
  1089. if (stateOld != stateNew)
  1090. {
  1091. NotifySink((PVOID) stateNew, OnNotifyCallStateChanged);
  1092. }
  1093. }
  1094. }
  1095. HRESULT COutgoingCall::_Cancel(BOOL fLeaving)
  1096. {
  1097. DebugEntry(COutgoingCall::Cancel);
  1098. BOOL fAbortT120 = (m_cnState != CNS_COMPLETE);
  1099. if (fAbortT120)
  1100. {
  1101. m_fCanceled = TRUE;
  1102. // Abort T.120 Call:
  1103. // Attempt to make this transition regardless of our
  1104. // current state:
  1105. SetCallState(CNS_COMPLETE);
  1106. ASSERT(m_pConfObject);
  1107. if (NULL != m_hRequest)
  1108. {
  1109. REQUEST_HANDLE hRequest = m_hRequest;
  1110. m_hRequest = NULL;
  1111. m_pConfObject->CancelInvite(hRequest);
  1112. }
  1113. if (!fLeaving && m_pConfObject->IsConferenceActive())
  1114. {
  1115. HRESULT hr = m_pConfObject->LeaveConference(FALSE);
  1116. if (FAILED(hr))
  1117. {
  1118. WARNING_OUT(("Couldn't leave after disconnecting"));
  1119. }
  1120. }
  1121. }
  1122. if (NULL != m_pH323Connection)
  1123. {
  1124. m_fCanceled = TRUE;
  1125. // Abort H.323 Call:
  1126. m_pH323Connection->Disconnect();
  1127. }
  1128. DebugExitULONG(COutgoingCall::Abort, m_cnResult);
  1129. return CN_RC_NOERROR ? S_OK : E_FAIL;
  1130. }
  1131. STDMETHODIMP_(ULONG) COutgoingCall::AddRef(void)
  1132. {
  1133. return RefCount::AddRef();
  1134. }
  1135. STDMETHODIMP_(ULONG) COutgoingCall::Release(void)
  1136. {
  1137. return RefCount::Release();
  1138. }
  1139. HRESULT STDMETHODCALLTYPE COutgoingCall::QueryInterface(REFIID riid, PVOID *ppv)
  1140. {
  1141. HRESULT hr = S_OK;
  1142. if ((riid == IID_INmCall) || (riid == IID_IUnknown))
  1143. {
  1144. *ppv = (INmCall *)this;
  1145. ApiDebugMsg(("COutgoingCall::QueryInterface()"));
  1146. }
  1147. else if (riid == IID_IConnectionPointContainer)
  1148. {
  1149. *ppv = (IConnectionPointContainer *) this;
  1150. ApiDebugMsg(("CNmCall::QueryInterface(): Returning IConnectionPointContainer."));
  1151. }
  1152. else
  1153. {
  1154. hr = E_NOINTERFACE;
  1155. *ppv = NULL;
  1156. ApiDebugMsg(("COutgoingCall::QueryInterface(): Called on unknown interface."));
  1157. }
  1158. if (S_OK == hr)
  1159. {
  1160. AddRef();
  1161. }
  1162. return hr;
  1163. }
  1164. HRESULT COutgoingCall::IsIncoming(void)
  1165. {
  1166. return S_FALSE;
  1167. }
  1168. HRESULT COutgoingCall::GetState(NM_CALL_STATE *pState)
  1169. {
  1170. HRESULT hr = E_POINTER;
  1171. if (NULL != pState)
  1172. {
  1173. if (FCanceled())
  1174. {
  1175. *pState = NM_CALL_CANCELED;
  1176. }
  1177. else
  1178. {
  1179. switch (m_cnState)
  1180. {
  1181. case CNS_IDLE:
  1182. *pState = NM_CALL_INIT;
  1183. break;
  1184. case CNS_SEARCHING:
  1185. *pState = NM_CALL_SEARCH;
  1186. break;
  1187. case CNS_CONNECTING_H323:
  1188. case CNS_WAITING_T120_OPEN:
  1189. case CNS_QUERYING_REMOTE:
  1190. case CNS_CREATING_LOCAL:
  1191. case CNS_INVITING_REMOTE:
  1192. case CNS_JOINING_REMOTE:
  1193. *pState = NM_CALL_WAIT;
  1194. break;
  1195. case CNS_COMPLETE:
  1196. switch (m_cnResult)
  1197. {
  1198. case CN_RC_NOERROR:
  1199. *pState = NM_CALL_ACCEPTED;
  1200. break;
  1201. case CN_RC_CONFERENCE_JOIN_DENIED:
  1202. case CN_RC_CONFERENCE_INVITE_DENIED:
  1203. case CN_RC_CONFERENCE_DOES_NOT_EXIST:
  1204. case CN_RC_AUDIO_CONNECT_FAILED:
  1205. case CN_RC_GK_CALLEE_NOT_REGISTERED:
  1206. case CN_RC_GK_TIMEOUT:
  1207. case CN_RC_GK_REJECTED:
  1208. case CN_RC_GK_NOT_REGISTERED:
  1209. case CN_RC_CONNECT_REMOTE_NO_SECURITY:
  1210. case CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY:
  1211. case CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY:
  1212. case CN_RC_TRANSPORT_FAILURE:
  1213. case CN_RC_QUERY_FAILED:
  1214. case CN_RC_CONNECT_FAILED:
  1215. *pState = NM_CALL_REJECTED;
  1216. break;
  1217. case CN_RC_ALREADY_IN_CONFERENCE:
  1218. case CN_RC_CANT_INVITE_MCU:
  1219. case CN_RC_CANT_JOIN_ALREADY_IN_CALL:
  1220. case CN_RC_INVITE_DENIED_REMOTE_IN_CONF:
  1221. case CN_RC_REMOTE_PLACING_CALL:
  1222. case CN_RC_ALREADY_IN_CONFERENCE_MCU:
  1223. case CN_RC_INVALID_PASSWORD:
  1224. default:
  1225. *pState = NM_CALL_CANCELED;
  1226. break;
  1227. }
  1228. break;
  1229. default:
  1230. *pState = NM_CALL_INVALID;
  1231. break;
  1232. }
  1233. }
  1234. hr = S_OK;
  1235. }
  1236. return hr;
  1237. }
  1238. HRESULT COutgoingCall::GetName(BSTR * pbstrName)
  1239. {
  1240. if (NULL == pbstrName)
  1241. return E_POINTER;
  1242. *pbstrName = SysAllocString(m_bstrName);
  1243. return (*pbstrName ? S_OK : E_FAIL);
  1244. }
  1245. HRESULT COutgoingCall::GetAddr(BSTR *pbstrAddr, NM_ADDR_TYPE *puType)
  1246. {
  1247. if ((NULL == pbstrAddr) || (NULL == puType))
  1248. return E_POINTER;
  1249. *pbstrAddr = SysAllocString(CUSTRING(m_pszAddr));
  1250. *puType = m_addrType;
  1251. return *pbstrAddr ? S_OK : E_FAIL;
  1252. }
  1253. HRESULT COutgoingCall::GetUserData(REFGUID rguid, BYTE **ppb, ULONG *pcb)
  1254. {
  1255. return E_NOTIMPL;
  1256. }
  1257. HRESULT COutgoingCall::GetConference(INmConference **ppConference)
  1258. {
  1259. HRESULT hr = E_POINTER;
  1260. if (NULL != ppConference)
  1261. {
  1262. *ppConference = m_pConfObject;
  1263. return S_OK;
  1264. }
  1265. return hr;
  1266. }
  1267. HRESULT COutgoingCall::Accept(void)
  1268. {
  1269. return E_UNEXPECTED;
  1270. }
  1271. HRESULT COutgoingCall::Reject(void)
  1272. {
  1273. return E_UNEXPECTED;
  1274. }
  1275. HRESULT COutgoingCall::Cancel(void)
  1276. {
  1277. DebugEntry(COutgoingCall::Cancel);
  1278. AddRef(); // protect against Release() while processing
  1279. // disconnect related indications & callbacks
  1280. HRESULT hr = _Cancel(FALSE);
  1281. if (FIsComplete())
  1282. {
  1283. COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
  1284. ASSERT(NULL !=pOprahNCUI);
  1285. pOprahNCUI->OnOutgoingCallCanceled(this);
  1286. }
  1287. DebugExitULONG(COutgoingCall::Abort, m_cnResult);
  1288. Release();
  1289. return hr;
  1290. }
  1291. /* O N N O T I F Y C A L L E R R O R */
  1292. /*-------------------------------------------------------------------------
  1293. %%Function: OnNotifyCallError
  1294. -------------------------------------------------------------------------*/
  1295. HRESULT OnNotifyCallError(IUnknown *pCallNotify, PVOID pv, REFIID riid)
  1296. {
  1297. ASSERT(NULL != pCallNotify);
  1298. CNSTATUS cnStatus = (CNSTATUS)((DWORD_PTR)pv);
  1299. switch (cnStatus)
  1300. {
  1301. case CN_RC_ALREADY_IN_CONFERENCE:
  1302. case CN_RC_CANT_INVITE_MCU:
  1303. case CN_RC_CANT_JOIN_ALREADY_IN_CALL:
  1304. case CN_RC_INVITE_DENIED_REMOTE_IN_CONF:
  1305. case CN_RC_REMOTE_PLACING_CALL:
  1306. case CN_RC_ALREADY_IN_CONFERENCE_MCU:
  1307. ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_IN_CONFERENCE);
  1308. break;
  1309. case CN_RC_CONFERENCE_JOIN_DENIED:
  1310. case CN_RC_CONFERENCE_INVITE_DENIED:
  1311. case CN_RC_CONFERENCE_DOES_NOT_EXIST:
  1312. case CN_RC_GK_CALLEE_NOT_REGISTERED:
  1313. case CN_RC_GK_TIMEOUT:
  1314. case CN_RC_GK_REJECTED:
  1315. case CN_RC_GK_NOT_REGISTERED:
  1316. case CN_RC_CONNECT_REMOTE_NO_SECURITY:
  1317. case CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY:
  1318. case CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY:
  1319. ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_IGNORED);
  1320. break;
  1321. case CN_RC_CONNECT_FAILED:
  1322. case CN_RC_AUDIO_CONNECT_FAILED:
  1323. ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_FAILED);
  1324. break;
  1325. default:
  1326. break;
  1327. }
  1328. if (IID_INmCallNotify2 == riid)
  1329. {
  1330. ((INmCallNotify2*)pCallNotify)->CallError(cnStatus);
  1331. }
  1332. return S_OK;
  1333. }
  1334. /* O N N O T I F Y R E M O T E C O N F E R E N C E */
  1335. /*-------------------------------------------------------------------------
  1336. %%Function: OnNotifyRemoteConference
  1337. -------------------------------------------------------------------------*/
  1338. HRESULT OnNotifyRemoteConference(IUnknown *pCallNotify, PVOID pv, REFIID riid)
  1339. {
  1340. REMOTE_CONFERENCE *prc = (REMOTE_CONFERENCE *)pv;
  1341. // WARNING: pwszConfName is an PWSTR array, not a BSTR
  1342. ASSERT(NULL != pCallNotify);
  1343. ((INmCallNotify2*)pCallNotify)->RemoteConference(prc->fMCU,
  1344. (BSTR *) prc->pwszConfNames, prc->pbstrConfToJoin);
  1345. return S_OK;
  1346. }
  1347. /* O N N O T I F Y R E M O T E P A S S W O R D */
  1348. /*-------------------------------------------------------------------------
  1349. %%Function: OnNotifyRemotePassword
  1350. -------------------------------------------------------------------------*/
  1351. HRESULT OnNotifyRemotePassword(IUnknown *pCallNotify, PVOID pv, REFIID riid)
  1352. {
  1353. REMOTE_PASSWORD *prp = (REMOTE_PASSWORD *)pv;
  1354. ASSERT(NULL != pCallNotify);
  1355. ((INmCallNotify2*)pCallNotify)->RemotePassword(prp->bstrConference, prp->pbstrPassword, prp->pbRemoteCred, prp->cbRemoteCred, prp->fIsService);
  1356. return S_OK;
  1357. }
  1358. COutgoingCallManager::COutgoingCallManager()
  1359. {
  1360. }
  1361. COutgoingCallManager::~COutgoingCallManager()
  1362. {
  1363. // Empty the call list:
  1364. while (!m_CallList.IsEmpty())
  1365. {
  1366. COutgoingCall* pCall = (COutgoingCall*) m_CallList.RemoveHead();
  1367. // Shouldn't have any NULL entries:
  1368. ASSERT(pCall);
  1369. pCall->Release();
  1370. }
  1371. }
  1372. UINT COutgoingCallManager::GetCallCount()
  1373. {
  1374. UINT nNodes = 0;
  1375. POSITION pos = m_CallList.GetHeadPosition();
  1376. while (pos)
  1377. {
  1378. nNodes++;
  1379. m_CallList.GetNext(pos);
  1380. }
  1381. return nNodes;
  1382. }
  1383. COutgoingCall* COutgoingCallManager::FindCall(IH323Endpoint * lpConnection)
  1384. {
  1385. POSITION pos = m_CallList.GetHeadPosition();
  1386. while (pos)
  1387. {
  1388. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  1389. if ((NULL != pCall) &&
  1390. (pCall->GetH323Connection() == lpConnection))
  1391. {
  1392. return pCall;
  1393. }
  1394. }
  1395. return NULL;
  1396. }
  1397. BOOL COutgoingCallManager::MatchActiveCallee(LPCTSTR pszDest, BSTR bstrAlias, BSTR bstrConference)
  1398. {
  1399. // Try to find a matching callee
  1400. POSITION pos = m_CallList.GetHeadPosition();
  1401. while (pos)
  1402. {
  1403. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  1404. if (NULL != pCall)
  1405. {
  1406. if (pCall->MatchActiveCallee(pszDest, bstrAlias, bstrConference))
  1407. {
  1408. return TRUE;
  1409. }
  1410. }
  1411. }
  1412. return FALSE;
  1413. }
  1414. HRESULT COutgoingCallManager::Call(
  1415. INmCall **ppCall,
  1416. COprahNCUI* pManager,
  1417. DWORD dwFlags,
  1418. NM_ADDR_TYPE addrType,
  1419. BSTR bstrName,
  1420. BSTR bstrSetup,
  1421. BSTR bstrDest,
  1422. BSTR bstrAlias,
  1423. BSTR bstrURL,
  1424. BSTR bstrConference,
  1425. BSTR bstrPassword,
  1426. BSTR bstrUserString)
  1427. {
  1428. DebugEntry(COutgoingCallManager::CallConference);
  1429. HRESULT hr = E_FAIL;
  1430. COutgoingCall* pCall = NULL;
  1431. CConfObject* pConfObject = pManager->GetConfObject();
  1432. if (NULL != ppCall)
  1433. {
  1434. *ppCall = NULL;
  1435. }
  1436. if (MatchActiveCallee(CUSTRING(bstrDest), bstrAlias, bstrConference))
  1437. {
  1438. hr = NM_CALLERR_ALREADY_CALLING;
  1439. }
  1440. else if (pConfObject->IsConferenceActive() && (NULL != bstrConference))
  1441. {
  1442. hr= NM_CALLERR_IN_CONFERENCE;
  1443. }
  1444. else
  1445. {
  1446. if (!pConfObject->IsConferenceActive())
  1447. {
  1448. pConfObject->SetConfSecurity(0 != (CRPCF_SECURE & dwFlags));
  1449. }
  1450. //
  1451. // Check outgoing call settings
  1452. //
  1453. if (pConfObject->GetNumMembers() >= pConfObject->GetConfMaxParticipants())
  1454. {
  1455. ASSERT(pConfObject->GetNumMembers() == pConfObject->GetConfMaxParticipants());
  1456. WARNING_OUT(("Outgoing call denied, reached limit of participants"));
  1457. goto END_CALL;
  1458. }
  1459. if ((pConfObject->IsHosting() != S_OK) &&
  1460. !(pConfObject->GetConfAttendeePermissions() & NM_PERMIT_OUTGOINGCALLS))
  1461. {
  1462. WARNING_OUT(("Outgoing call denied, not permitted by meeting settings"));
  1463. goto END_CALL;
  1464. }
  1465. pCall = new COutgoingCall( pConfObject,
  1466. dwFlags,
  1467. addrType,
  1468. bstrName,
  1469. bstrDest,
  1470. bstrAlias,
  1471. bstrConference,
  1472. bstrPassword,
  1473. bstrUserString);
  1474. if (NULL != pCall)
  1475. {
  1476. m_CallList.AddTail(pCall);
  1477. if (NULL != ppCall)
  1478. {
  1479. pCall->AddRef();
  1480. // This MUST be set before OnNotifyCallCreated
  1481. *ppCall = pCall;
  1482. }
  1483. pCall->AddRef();
  1484. pManager->OnOutgoingCallCreated(pCall);
  1485. pCall->PlaceCall();
  1486. if (pCall->FIsComplete())
  1487. {
  1488. RemoveFromList(pCall);
  1489. }
  1490. pCall->Release();
  1491. // let the caller know that we successfully created the call
  1492. // any error will be reported asynchronously
  1493. hr = S_OK;
  1494. }
  1495. }
  1496. END_CALL:
  1497. DebugExitHRESULT(COutgoingCallManager::CallConference, hr);
  1498. return hr;
  1499. }
  1500. BOOL COutgoingCallManager::RemoveFromList(COutgoingCall* pCall)
  1501. {
  1502. DebugEntry(COutgoingCallManager::RemoveFromList);
  1503. ASSERT(pCall);
  1504. BOOL bRet = FALSE;
  1505. POSITION pos = m_CallList.GetPosition(pCall);
  1506. if (NULL != pos)
  1507. {
  1508. m_CallList.RemoveAt(pos);
  1509. pCall->CallComplete();
  1510. pCall->Release();
  1511. bRet = TRUE;
  1512. }
  1513. else
  1514. {
  1515. WARNING_OUT(("COutgoingCallManager::RemoveFromList() could not match call"));
  1516. }
  1517. DebugExitBOOL(COutgoingCallManager::RemoveFromList, bRet);
  1518. return bRet;
  1519. }
  1520. BOOL COutgoingCallManager::OnH323Connected(IH323Endpoint* lpConnection)
  1521. {
  1522. DebugEntry(COutgoingCallManager::OnH323Connected);
  1523. BOOL fFound = FALSE;
  1524. COutgoingCall* pCall = FindCall(lpConnection);
  1525. if (pCall)
  1526. {
  1527. fFound = TRUE;
  1528. pCall->AddRef();
  1529. pCall->OnH323Connected(lpConnection);
  1530. if (pCall->FIsComplete())
  1531. {
  1532. RemoveFromList(pCall);
  1533. }
  1534. pCall->Release();
  1535. }
  1536. DebugExitBOOL(COutgoingCallManager::OnH323Connected, fFound);
  1537. return fFound;
  1538. }
  1539. BOOL COutgoingCallManager::OnH323Disconnected(IH323Endpoint * lpConnection)
  1540. {
  1541. DebugEntry(COutgoingCallManager::OnH323Disconnected);
  1542. BOOL fFound = FALSE;
  1543. COutgoingCall* pCall = FindCall(lpConnection);
  1544. if (pCall)
  1545. {
  1546. fFound = TRUE;
  1547. pCall->AddRef();
  1548. pCall->OnH323Disconnected(lpConnection);
  1549. if (pCall->FIsComplete())
  1550. {
  1551. RemoveFromList(pCall);
  1552. }
  1553. pCall->Release();
  1554. }
  1555. DebugExitBOOL(COutgoingCallManager::OnH323Disconnected, fFound);
  1556. return fFound;
  1557. }
  1558. VOID COutgoingCallManager::OnT120ChannelOpen(ICommChannel *pIChannel, IH323Endpoint * lpConnection, DWORD dwStatus)
  1559. {
  1560. DebugEntry(COutgoingCallManager::OnT120ChannelOpen);
  1561. COutgoingCall* pCall = FindCall(lpConnection);
  1562. if (pCall)
  1563. {
  1564. pCall->AddRef();
  1565. pCall->OnT120ChannelOpen(pIChannel, dwStatus);
  1566. if (pCall->FIsComplete())
  1567. {
  1568. RemoveFromList(pCall);
  1569. }
  1570. pCall->Release();
  1571. }
  1572. DebugExitVOID(COutgoingCallManager::OnT120ChannelOpen);
  1573. }
  1574. VOID COutgoingCallManager::OnConferenceStarted(CONF_HANDLE hConference, HRESULT hResult)
  1575. {
  1576. DebugEntry(COutgoingCallManager::OnConferenceStarted);
  1577. // Tell all ConfNode's that a conference has started
  1578. POSITION pos = m_CallList.GetHeadPosition();
  1579. while (pos)
  1580. {
  1581. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  1582. if (NULL != pCall)
  1583. {
  1584. pCall->AddRef();
  1585. pCall->OnConferenceStarted(hConference, hResult);
  1586. if (pCall->FIsComplete())
  1587. {
  1588. RemoveFromList(pCall);
  1589. }
  1590. pCall->Release();
  1591. }
  1592. }
  1593. DebugExitVOID(COutgoingCallManager::OnConferenceStarted);
  1594. }
  1595. VOID COutgoingCallManager::OnQueryRemoteResult(PVOID pvCallerContext,
  1596. HRESULT hResult,
  1597. BOOL fMCU,
  1598. PWSTR* ppwszConferenceNames,
  1599. PT120PRODUCTVERSION pVersion,
  1600. PWSTR* ppwszConfDescriptors)
  1601. {
  1602. DebugEntry(COutgoingCallManager::OnQueryRemoteResult);
  1603. POSITION pos = m_CallList.GetHeadPosition();
  1604. while (pos)
  1605. {
  1606. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  1607. // Notify the node that issued the query:
  1608. if ((COutgoingCall*) pvCallerContext == pCall)
  1609. {
  1610. pCall->AddRef();
  1611. pCall->OnQueryRemoteResult( hResult,
  1612. fMCU,
  1613. ppwszConferenceNames,
  1614. pVersion,
  1615. ppwszConfDescriptors);
  1616. if (pCall->FIsComplete())
  1617. {
  1618. RemoveFromList(pCall);
  1619. }
  1620. pCall->Release();
  1621. break;
  1622. }
  1623. }
  1624. DebugExitVOID(COutgoingCallManager::OnQueryRemoteResult);
  1625. }
  1626. VOID COutgoingCallManager::OnInviteResult( CONF_HANDLE hConference,
  1627. REQUEST_HANDLE hRequest,
  1628. UINT uNodeID,
  1629. HRESULT hResult,
  1630. PT120PRODUCTVERSION pVersion)
  1631. {
  1632. DebugEntry(COutgoingCallManager::OnInviteResult);
  1633. POSITION pos = m_CallList.GetHeadPosition();
  1634. while (pos)
  1635. {
  1636. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  1637. if ((NULL != pCall) &&
  1638. (pCall->GetCurrentRequestHandle() == hRequest))
  1639. {
  1640. pCall->AddRef();
  1641. pCall->OnInviteResult(hResult, uNodeID);
  1642. if (pCall->FIsComplete())
  1643. {
  1644. RemoveFromList(pCall);
  1645. }
  1646. pCall->Release();
  1647. break;
  1648. }
  1649. }
  1650. DebugExitVOID(COutgoingCallManager::OnInviteResult);
  1651. }
  1652. VOID COutgoingCallManager::OnConferenceEnded(CONF_HANDLE hConference)
  1653. {
  1654. DebugEntry(COutgoingCallManager::OnConferenceEnded);
  1655. // Tell all ConfNode's that a conference has started
  1656. POSITION pos = m_CallList.GetHeadPosition();
  1657. while (pos)
  1658. {
  1659. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  1660. if (NULL != pCall)
  1661. {
  1662. pCall->AddRef();
  1663. pCall->OnConferenceEnded();
  1664. if (pCall->FIsComplete())
  1665. {
  1666. RemoveFromList(pCall);
  1667. }
  1668. pCall->Release();
  1669. }
  1670. }
  1671. DebugExitVOID(COutgoingCallManager::OnConferenceEnded);
  1672. }
  1673. VOID COutgoingCallManager::CancelCalls()
  1674. {
  1675. DebugEntry(COutgoingCallManager::CancelCalls);
  1676. // Tell all ConfNode's that a conference has started
  1677. POSITION pos = m_CallList.GetHeadPosition();
  1678. while (pos)
  1679. {
  1680. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  1681. if (NULL != pCall)
  1682. {
  1683. pCall->AddRef();
  1684. pCall->_Cancel(TRUE);
  1685. if (pCall->FIsComplete())
  1686. {
  1687. RemoveFromList(pCall);
  1688. }
  1689. pCall->Release();
  1690. }
  1691. }
  1692. DebugExitVOID(COutgoingCallManager::CancelCalls);
  1693. }