Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1212 lines
26 KiB

  1. // File: icall.cpp
  2. #include "precomp.h"
  3. #include "icall.h"
  4. #include "imanager.h"
  5. #include <service.h>
  6. #include <confguid.h>
  7. typedef struct
  8. {
  9. BOOL fMCU;
  10. PWSTR * pwszConfNames;
  11. BSTR * pbstrConfToJoin;
  12. } REMOTE_CONFERENCE;
  13. typedef struct
  14. {
  15. BSTR bstrConference;
  16. BSTR *pbstrPassword;
  17. PBYTE pbRemoteCred;
  18. DWORD cbRemoteCred;
  19. BOOL fIsService;
  20. } REMOTE_PASSWORD;
  21. HRESULT OnNotifyCallError(IUnknown *pCallNotify, PVOID pv, REFIID riid);
  22. static HRESULT OnNotifyRemoteConference(IUnknown *pCallNotify, PVOID pv, REFIID riid);
  23. static HRESULT OnNotifyRemotePassword(IUnknown *pCallNotify, PVOID pv, REFIID riid);
  24. static const IID * g_apiidCP[] =
  25. {
  26. {&IID_INmCallNotify}
  27. };
  28. // String Functions
  29. inline VOID FreeBstr(BSTR *pbstr)
  30. {
  31. if (NULL != pbstr)
  32. {
  33. SysFreeString(*pbstr);
  34. *pbstr = NULL;
  35. }
  36. }
  37. /* P S Z A L L O C */
  38. /*-------------------------------------------------------------------------
  39. %%Function: PszAlloc
  40. -------------------------------------------------------------------------*/
  41. LPTSTR PszAlloc(LPCTSTR pszSrc)
  42. {
  43. if (NULL == pszSrc)
  44. return NULL;
  45. LPTSTR pszDest = new TCHAR[lstrlen(pszSrc) + 1];
  46. if (NULL != pszDest)
  47. {
  48. lstrcpy(pszDest, pszSrc);
  49. }
  50. return pszDest;
  51. }
  52. COutgoingCall::COutgoingCall
  53. (
  54. CConfObject* pco,
  55. DWORD dwFlags,
  56. NM_ADDR_TYPE addrType,
  57. BSTR bstrAddr,
  58. BSTR bstrConference,
  59. BSTR bstrPassword
  60. ) :
  61. CConnectionPointContainer(g_apiidCP, ARRAY_ELEMENTS(g_apiidCP)),
  62. m_pConfObject (pco),
  63. m_addrType (addrType),
  64. m_dwFlags (dwFlags),
  65. m_bstrAddr (SysAllocString(bstrAddr)),
  66. m_bstrConfToJoin (SysAllocString(bstrConference)),
  67. m_bstrPassword (SysAllocString(bstrPassword)),
  68. m_hRequest (NULL),
  69. m_fCanceled (FALSE),
  70. m_cnResult (CN_RC_NOERROR),
  71. m_cnState (CNS_IDLE),
  72. m_fService (FALSE)
  73. {
  74. m_pszAddr = PszAlloc(CUSTRING(bstrAddr));
  75. TRACE_OUT(("Obj: %08X created COutgoingCall", this));
  76. }
  77. COutgoingCall::~COutgoingCall()
  78. {
  79. if (m_pszAddr)
  80. {
  81. delete m_pszAddr;
  82. m_pszAddr = NULL;
  83. }
  84. if (m_bstrAddr)
  85. {
  86. SysFreeString(m_bstrAddr);
  87. m_bstrAddr = NULL;
  88. }
  89. TRACE_OUT(("Obj: %08X destroyed COutgoingCall", this));
  90. }
  91. /* P L A C E C A L L */
  92. /*-------------------------------------------------------------------------
  93. %%Function: PlaceCall
  94. -------------------------------------------------------------------------*/
  95. VOID COutgoingCall::PlaceCall(void)
  96. {
  97. DebugEntry(COutgoingCall::PlaceCall);
  98. COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
  99. ASSERT(NULL != pOprahNCUI);
  100. SetCallState(CNS_SEARCHING);
  101. if (NULL != g_pNodeController)
  102. {
  103. // Start placing the T.120 call
  104. CNSTATUS cnResult = CN_RC_NOERROR;
  105. if (NULL == m_bstrConfToJoin)
  106. {
  107. // conference name not specified
  108. // need to start out with a QueryRemote
  109. SetCallState(CNS_QUERYING_REMOTE);
  110. HRESULT hr = g_pNodeController->QueryRemote(this, m_pszAddr,
  111. m_pConfObject->IsConfObjSecure(),
  112. m_pConfObject->IsConferenceActive());
  113. if (S_OK != hr)
  114. {
  115. cnResult = CN_RC_QUERY_FAILED;
  116. }
  117. }
  118. else
  119. {
  120. ASSERT(m_pConfObject);
  121. // conference name has been specified
  122. // time to do a JoinConference
  123. SetCallState(CNS_JOINING_REMOTE);
  124. HRESULT hr = m_pConfObject->JoinConference(m_bstrConfToJoin,
  125. m_bstrPassword,
  126. m_pszAddr);
  127. if (S_OK != hr)
  128. {
  129. cnResult = CN_RC_JOIN_FAILED;
  130. }
  131. }
  132. if (CN_RC_NOERROR != cnResult)
  133. {
  134. m_cnResult = cnResult;
  135. SetCallState(CNS_COMPLETE);
  136. }
  137. }
  138. else
  139. {
  140. m_cnResult = CN_RC_TRANSPORT_FAILURE;
  141. SetCallState(CNS_COMPLETE);
  142. }
  143. DebugExitVOID(COutgoingCall::PlaceCall);
  144. }
  145. BOOL COutgoingCall::OnConferenceEnded()
  146. {
  147. DebugEntry(COutgoingCall::OnConferenceEnded);
  148. BOOL bRet = FALSE;
  149. switch (m_cnState)
  150. {
  151. case CNS_INVITING_REMOTE:
  152. {
  153. TRACE_OUT(("COutgoingCall (calling) rec. UNEXPECTED ConfEnded event"));
  154. SetCallState(CNS_COMPLETE);
  155. bRet = TRUE;
  156. break;
  157. }
  158. case CNS_JOINING_REMOTE:
  159. {
  160. // JoinConference failed!
  161. TRACE_OUT(("COutgoingCall (joining) received ConferenceEnded event"));
  162. m_cnResult = CN_RC_CONFERENCE_JOIN_DENIED;
  163. SetCallState(CNS_COMPLETE);
  164. bRet = TRUE;
  165. break;
  166. }
  167. case CNS_TERMINATING_AFTER_INVITE:
  168. {
  169. TRACE_OUT(("COutgoingCall (terminating after invite) received ConferenceEnded event"));
  170. SetCallState(CNS_QUERYING_REMOTE_AFTER_INVITE);
  171. ASSERT(g_pNodeController);
  172. HRESULT hr = g_pNodeController->QueryRemote(this, m_pszAddr,
  173. m_pConfObject->IsConfObjSecure(),
  174. m_pConfObject->IsConferenceActive());
  175. if (S_OK != hr)
  176. {
  177. m_cnResult = CN_RC_QUERY_FAILED;
  178. SetCallState(CNS_COMPLETE);
  179. }
  180. bRet = TRUE;
  181. break;
  182. }
  183. default:
  184. {
  185. WARNING_OUT(("COutgoingCall received unexpected ConfEnded event"));
  186. }
  187. }
  188. DebugExitBOOL(COutgoingCall::OnConferenceEnded, bRet);
  189. return bRet;
  190. }
  191. BOOL COutgoingCall::OnInviteResult(HRESULT ncsResult, UINT uNodeID)
  192. {
  193. DebugEntry(COutgoingCall::OnInviteResult);
  194. BOOL bRet = TRUE;
  195. ASSERT(CNS_INVITING_REMOTE == m_cnState);
  196. TRACE_OUT(("COutgoingCall (calling) received InviteResult event"));
  197. // Clear the current request handle
  198. m_hRequest = NULL;
  199. if (0 == ncsResult)
  200. {
  201. SetCallState(CNS_COMPLETE);
  202. }
  203. else
  204. {
  205. if (UI_RC_USER_REJECTED == ncsResult)
  206. {
  207. SetCallState(CNS_TERMINATING_AFTER_INVITE);
  208. // Issue "soft" leave attempt (to allow auto-terminate)
  209. ASSERT(m_pConfObject);
  210. if (S_OK != m_pConfObject->LeaveConference(FALSE))
  211. {
  212. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  213. SetCallState(CNS_COMPLETE);
  214. }
  215. }
  216. else
  217. {
  218. // make sure that we are not recieving this notification due to
  219. // the conference going away
  220. ASSERT(m_pConfObject);
  221. if (CS_GOING_DOWN != m_pConfObject->GetT120State())
  222. {
  223. TRACE_OUT(("COutgoingCall - invite failed / couldn't connect -> leaving"));
  224. m_cnResult = CN_RC_INVITE_FAILED;
  225. SetCallState(CNS_COMPLETE);
  226. // Issue "soft" leave attempt (to allow auto-terminate)
  227. ASSERT(m_pConfObject);
  228. m_pConfObject->LeaveConference(FALSE);
  229. }
  230. }
  231. }
  232. DebugExitBOOL(COutgoingCall::OnInviteResult, bRet);
  233. return bRet;
  234. }
  235. BOOL COutgoingCall::OnQueryRemoteResult(HRESULT ncsResult,
  236. BOOL fMCU,
  237. PWSTR pwszConfNames[],
  238. PWSTR pwszConfDescriptors[])
  239. {
  240. DebugEntry(COutgoingCall::OnQueryRemoteResult);
  241. ASSERT ((CNS_QUERYING_REMOTE == m_cnState) ||
  242. (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState));
  243. ASSERT (NULL == m_bstrConfToJoin);
  244. if (SUCCEEDED(ncsResult))
  245. {
  246. BOOL fRemoteInConf = FALSE;
  247. if ((NULL != pwszConfNames) && (NULL != pwszConfNames[0]))
  248. {
  249. fRemoteInConf = TRUE;
  250. }
  251. m_fService = FALSE;
  252. if (fRemoteInConf && (NULL != pwszConfDescriptors) && (NULL != pwszConfDescriptors[0]))
  253. {
  254. if (0 == UnicodeCompare(pwszConfDescriptors[0],RDS_CONFERENCE_DESCRIPTOR))
  255. {
  256. m_fService = TRUE;
  257. }
  258. }
  259. if (m_pConfObject->IsConferenceActive())
  260. {
  261. if (fMCU)
  262. {
  263. TRACE_OUT(("COutgoingCall - QR ok, but is MCU -> complete"));
  264. m_cnResult = CN_RC_CANT_INVITE_MCU;
  265. }
  266. else if (fRemoteInConf)
  267. {
  268. TRACE_OUT(("COutgoingCall - QR ok, but callee is in a conference"));
  269. m_cnResult = CN_RC_INVITE_DENIED_REMOTE_IN_CONF;
  270. }
  271. else
  272. {
  273. if (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState)
  274. {
  275. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  276. SetCallState(CNS_COMPLETE);
  277. }
  278. else
  279. {
  280. SetCallState(CNS_INVITING_REMOTE);
  281. HRESULT hr = m_pConfObject->InviteConference(m_pszAddr, &m_hRequest);
  282. if (S_OK != hr)
  283. {
  284. // Failure while inviting:
  285. m_cnResult = CN_RC_INVITE_FAILED;
  286. }
  287. }
  288. }
  289. if (CN_RC_NOERROR != m_cnResult)
  290. {
  291. SetCallState(CNS_COMPLETE);
  292. }
  293. }
  294. else if (fRemoteInConf || fMCU)
  295. {
  296. TRACE_OUT(("COutgoingCall - QR succeeded (>0 conf) -> joining"));
  297. TRACE_OUT(("\tfMCU is %d", fMCU));
  298. // There are remote conferences
  299. HRESULT hr = E_FAIL; // Assume a failure
  300. SetCallState(CNS_JOINING_REMOTE);
  301. if (!fMCU && (NULL == pwszConfNames[1]))
  302. {
  303. // we're not calling an MCU and we have just one conference, so join it
  304. m_bstrConfToJoin = SysAllocString(pwszConfNames[0]);
  305. hr = m_pConfObject->JoinConference( m_bstrConfToJoin,
  306. m_bstrPassword,
  307. m_pszAddr);
  308. }
  309. else
  310. {
  311. ASSERT(NULL == m_bstrConfToJoin);
  312. REMOTE_CONFERENCE remoteConf;
  313. remoteConf.fMCU = fMCU;
  314. remoteConf.pwszConfNames = pwszConfNames;
  315. remoteConf.pbstrConfToJoin = &m_bstrConfToJoin;
  316. // Ask the app which conference to join
  317. NotifySink(&remoteConf, OnNotifyRemoteConference);
  318. if (NULL != m_bstrConfToJoin)
  319. {
  320. hr = m_pConfObject->JoinConference( m_bstrConfToJoin,
  321. m_bstrPassword,
  322. m_pszAddr);
  323. }
  324. }
  325. if (S_OK != hr)
  326. {
  327. // JoinConference failed!
  328. m_cnResult = CN_RC_JOIN_FAILED;
  329. SetCallState(CNS_COMPLETE);
  330. }
  331. }
  332. else
  333. {
  334. if (CNS_QUERYING_REMOTE_AFTER_INVITE == m_cnState)
  335. {
  336. m_cnResult = CN_RC_CONFERENCE_INVITE_DENIED;
  337. SetCallState(CNS_COMPLETE);
  338. }
  339. else
  340. {
  341. // No conferences on remote machine, so create local:
  342. TRACE_OUT(("COutgoingCall - QR succeeded (no conf)-> creating local"));
  343. // Create local conf
  344. ASSERT(m_pConfObject);
  345. SetCallState(CNS_CREATING_LOCAL);
  346. HRESULT hr = m_pConfObject->CreateConference();
  347. if (S_OK != hr)
  348. {
  349. // CreateConference failed!
  350. m_cnResult = CN_RC_CONFERENCE_CREATE_FAILED;
  351. SetCallState(CNS_COMPLETE);
  352. }
  353. }
  354. }
  355. }
  356. else
  357. {
  358. // The QueryRemote failed
  359. switch( ncsResult )
  360. {
  361. case UI_RC_USER_REJECTED:
  362. // The initial QueryRemote failed because GCC symmetry determined
  363. // that the other node is calling someone, and it might be us
  364. // See Bug 1886
  365. TRACE_OUT(("COutgoingCall - QueryRemote rejected -> complete"));
  366. m_cnResult = CN_RC_REMOTE_PLACING_CALL;
  367. break;
  368. case UI_RC_T120_REMOTE_REQUIRE_SECURITY:
  369. m_cnResult = CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY;
  370. break;
  371. case UI_RC_T120_SECURITY_FAILED:
  372. m_cnResult = CN_RC_SECURITY_FAILED;
  373. break;
  374. case UI_RC_T120_REMOTE_NO_SECURITY:
  375. m_cnResult = CN_RC_CONNECT_REMOTE_NO_SECURITY;
  376. break;
  377. case UI_RC_T120_REMOTE_DOWNLEVEL_SECURITY:
  378. m_cnResult = CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY;
  379. break;
  380. case UI_RC_T120_AUTHENTICATION_FAILED:
  381. m_cnResult = CN_RC_CONNECT_AUTHENTICATION_FAILED;
  382. break;
  383. default:
  384. m_cnResult = CN_RC_CONNECT_FAILED;
  385. break;
  386. }
  387. SetCallState(CNS_COMPLETE);
  388. }
  389. DebugExitBOOL(COutgoingCall::OnQueryRemoteResult, TRUE);
  390. return TRUE;
  391. }
  392. BOOL COutgoingCall::OnConferenceStarted(CONF_HANDLE hNewConf, HRESULT ncsResult)
  393. {
  394. DebugEntry(COutgoingCall::OnConferenceStarted);
  395. switch (m_cnState)
  396. {
  397. case CNS_CREATING_LOCAL:
  398. {
  399. TRACE_OUT(("COutgoingCall (inviting) received ConferenceStarted event"));
  400. if (0 == ncsResult)
  401. {
  402. ASSERT(m_pConfObject);
  403. ASSERT(NULL == m_hRequest);
  404. SetCallState(CNS_INVITING_REMOTE);
  405. HRESULT hr = m_pConfObject->InviteConference(m_pszAddr, &m_hRequest);
  406. if (S_OK != hr)
  407. {
  408. m_hRequest = NULL;
  409. m_cnResult = CN_RC_INVITE_FAILED;
  410. SetCallState(CNS_COMPLETE);
  411. // Issue "soft" leave attempt (to allow auto-terminate)
  412. ASSERT(m_pConfObject);
  413. HRESULT hr = m_pConfObject->LeaveConference(FALSE);
  414. if (FAILED(hr))
  415. {
  416. WARNING_OUT(("Couldn't leave after failed invite"));
  417. }
  418. }
  419. }
  420. else
  421. {
  422. WARNING_OUT(("CreateConference (local) failed - need UI here!"));
  423. m_cnResult = CN_RC_CONFERENCE_CREATE_FAILED;
  424. SetCallState(CNS_COMPLETE);
  425. }
  426. break;
  427. }
  428. case CNS_JOINING_REMOTE:
  429. {
  430. TRACE_OUT(("COutgoingCall (joining) received ConferenceStarted event"));
  431. if (0 == ncsResult)
  432. {
  433. SetCallState(CNS_COMPLETE);
  434. }
  435. else if (UI_RC_INVALID_PASSWORD == ncsResult)
  436. {
  437. TRACE_OUT(("COutgoingCall - invalid password, prompt for password"));
  438. BSTR bstrPassword = NULL;
  439. REMOTE_PASSWORD remotePw;
  440. remotePw.bstrConference = m_bstrConfToJoin;
  441. remotePw.pbstrPassword = &bstrPassword;
  442. if (NO_ERROR != hNewConf->GetCred(&remotePw.pbRemoteCred, &remotePw.cbRemoteCred))
  443. {
  444. remotePw.pbRemoteCred = NULL;
  445. remotePw.cbRemoteCred = 0;
  446. }
  447. remotePw.fIsService = m_fService;
  448. NotifySink(&remotePw, OnNotifyRemotePassword);
  449. if (NULL != bstrPassword)
  450. {
  451. SysFreeString(m_bstrPassword);
  452. m_bstrPassword = bstrPassword;
  453. // reissue join with new password
  454. ASSERT(m_pConfObject);
  455. HRESULT ncs =
  456. m_pConfObject->JoinConference( m_bstrConfToJoin,
  457. m_bstrPassword,
  458. m_pszAddr,
  459. TRUE); // retry
  460. if (0 != ncs)
  461. {
  462. // JoinConference failed!
  463. m_cnResult = CN_RC_JOIN_FAILED;
  464. SetCallState(CNS_COMPLETE);
  465. }
  466. }
  467. else
  468. {
  469. // cancel from pw dlg
  470. m_cnResult = CN_RC_INVALID_PASSWORD;
  471. SetCallState(CNS_COMPLETE);
  472. ASSERT(m_pConfObject);
  473. HRESULT hr = m_pConfObject->LeaveConference(TRUE);
  474. if (FAILED(hr))
  475. {
  476. ERROR_OUT(("Couldn't leave after cancelling pw join!"));
  477. }
  478. }
  479. }
  480. else if (UI_RC_UNKNOWN_CONFERENCE == ncsResult)
  481. {
  482. TRACE_OUT(("Join failed (conf does not exist) "
  483. "- notifying user"));
  484. // error while joining
  485. m_cnResult = CN_RC_CONFERENCE_DOES_NOT_EXIST;
  486. SetCallState(CNS_COMPLETE);
  487. }
  488. else
  489. {
  490. TRACE_OUT(("Join failed - notifying user"));
  491. // error while joining
  492. m_cnResult = CN_RC_CONFERENCE_JOIN_DENIED;
  493. SetCallState(CNS_COMPLETE);
  494. }
  495. break;
  496. }
  497. default:
  498. {
  499. if (m_pConfObject->GetConfHandle() == hNewConf)
  500. {
  501. WARNING_OUT(("COutgoingCall received unexpected ConferenceStarted event"));
  502. }
  503. else
  504. {
  505. TRACE_OUT(("COutgoingCall ignoring ConferenceStarted event - not our conf"));
  506. }
  507. }
  508. }
  509. DebugExitBOOL(COutgoingCall::OnConferenceStarted, TRUE);
  510. return TRUE;
  511. }
  512. void COutgoingCall::CallComplete()
  513. {
  514. DebugEntry(COutgoingCall::CallComplete);
  515. // If this fails, we are being destructed unexpectedly
  516. ASSERT( (m_cnState == CNS_IDLE) ||
  517. (m_cnState == CNS_COMPLETE));
  518. // The request handle should have been reset
  519. ASSERT(NULL == m_hRequest);
  520. if (!FCanceled() && (CN_RC_NOERROR != m_cnResult))
  521. {
  522. ReportError(m_cnResult);
  523. }
  524. NM_CALL_STATE state;
  525. GetState(&state);
  526. NotifySink((PVOID) state, OnNotifyCallStateChanged);
  527. TRACE_OUT(("ConfNode destroying addr %s", m_pszAddr));
  528. DebugExitVOID(COutgoingCall::CallComplete);
  529. }
  530. BOOL COutgoingCall::ReportError(CNSTATUS cns)
  531. {
  532. DebugEntry(COutgoingCall::ReportError);
  533. TRACE_OUT(("CNSTATUS 0x%08x", cns));
  534. NotifySink((PVOID)cns, OnNotifyCallError);
  535. DebugExitBOOL(COutgoingCall::ReportError, TRUE);
  536. return TRUE;
  537. }
  538. VOID COutgoingCall::SetCallState(CNODESTATE cnState)
  539. {
  540. NM_CALL_STATE stateOld;
  541. NM_CALL_STATE stateNew;
  542. GetState(&stateOld);
  543. m_cnState = cnState;
  544. // completion state will be fired off later
  545. if (CNS_COMPLETE != cnState)
  546. {
  547. GetState(&stateNew);
  548. if (stateOld != stateNew)
  549. {
  550. NotifySink((PVOID) stateNew, OnNotifyCallStateChanged);
  551. }
  552. }
  553. }
  554. HRESULT COutgoingCall::_Cancel(BOOL fLeaving)
  555. {
  556. DebugEntry(COutgoingCall::Cancel);
  557. BOOL fAbortT120 = (m_cnState != CNS_COMPLETE);
  558. if (fAbortT120)
  559. {
  560. m_fCanceled = TRUE;
  561. // Abort T.120 Call:
  562. // Attempt to make this transition regardless of our
  563. // current state:
  564. SetCallState(CNS_COMPLETE);
  565. ASSERT(m_pConfObject);
  566. if (NULL != m_hRequest)
  567. {
  568. REQUEST_HANDLE hRequest = m_hRequest;
  569. m_hRequest = NULL;
  570. m_pConfObject->CancelInvite(hRequest);
  571. }
  572. if (!fLeaving && m_pConfObject->IsConferenceActive())
  573. {
  574. HRESULT hr = m_pConfObject->LeaveConference(FALSE);
  575. if (FAILED(hr))
  576. {
  577. WARNING_OUT(("Couldn't leave after disconnecting"));
  578. }
  579. }
  580. }
  581. DebugExitULONG(COutgoingCall::Abort, m_cnResult);
  582. return CN_RC_NOERROR ? S_OK : E_FAIL;
  583. }
  584. STDMETHODIMP_(ULONG) COutgoingCall::AddRef(void)
  585. {
  586. return RefCount::AddRef();
  587. }
  588. STDMETHODIMP_(ULONG) COutgoingCall::Release(void)
  589. {
  590. return RefCount::Release();
  591. }
  592. HRESULT STDMETHODCALLTYPE COutgoingCall::QueryInterface(REFIID riid, PVOID *ppv)
  593. {
  594. HRESULT hr = S_OK;
  595. if ((riid == IID_INmCall) || (riid == IID_IUnknown))
  596. {
  597. *ppv = (INmCall *)this;
  598. TRACE_OUT(("COutgoingCall::QueryInterface()"));
  599. }
  600. else if (riid == IID_IConnectionPointContainer)
  601. {
  602. *ppv = (IConnectionPointContainer *) this;
  603. TRACE_OUT(("CNmCall::QueryInterface(): Returning IConnectionPointContainer."));
  604. }
  605. else
  606. {
  607. hr = E_NOINTERFACE;
  608. *ppv = NULL;
  609. TRACE_OUT(("COutgoingCall::QueryInterface(): Called on unknown interface."));
  610. }
  611. if (S_OK == hr)
  612. {
  613. AddRef();
  614. }
  615. return hr;
  616. }
  617. HRESULT COutgoingCall::IsIncoming(void)
  618. {
  619. return S_FALSE;
  620. }
  621. HRESULT COutgoingCall::GetState(NM_CALL_STATE *pState)
  622. {
  623. HRESULT hr = E_POINTER;
  624. if (NULL != pState)
  625. {
  626. if (FCanceled())
  627. {
  628. *pState = NM_CALL_CANCELED;
  629. }
  630. else
  631. {
  632. switch (m_cnState)
  633. {
  634. case CNS_IDLE:
  635. *pState = NM_CALL_INIT;
  636. break;
  637. case CNS_SEARCHING:
  638. *pState = NM_CALL_SEARCH;
  639. break;
  640. case CNS_WAITING_T120_OPEN:
  641. case CNS_QUERYING_REMOTE:
  642. case CNS_CREATING_LOCAL:
  643. case CNS_INVITING_REMOTE:
  644. case CNS_JOINING_REMOTE:
  645. *pState = NM_CALL_WAIT;
  646. break;
  647. case CNS_COMPLETE:
  648. switch (m_cnResult)
  649. {
  650. case CN_RC_NOERROR:
  651. *pState = NM_CALL_ACCEPTED;
  652. break;
  653. case CN_RC_CONFERENCE_JOIN_DENIED:
  654. case CN_RC_CONFERENCE_INVITE_DENIED:
  655. case CN_RC_CONFERENCE_DOES_NOT_EXIST:
  656. case CN_RC_CONNECT_REMOTE_NO_SECURITY:
  657. case CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY:
  658. case CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY:
  659. case CN_RC_TRANSPORT_FAILURE:
  660. case CN_RC_QUERY_FAILED:
  661. case CN_RC_CONNECT_FAILED:
  662. *pState = NM_CALL_REJECTED;
  663. break;
  664. case CN_RC_ALREADY_IN_CONFERENCE:
  665. case CN_RC_CANT_INVITE_MCU:
  666. case CN_RC_CANT_JOIN_ALREADY_IN_CALL:
  667. case CN_RC_INVITE_DENIED_REMOTE_IN_CONF:
  668. case CN_RC_REMOTE_PLACING_CALL:
  669. case CN_RC_ALREADY_IN_CONFERENCE_MCU:
  670. case CN_RC_INVALID_PASSWORD:
  671. default:
  672. *pState = NM_CALL_CANCELED;
  673. break;
  674. }
  675. break;
  676. default:
  677. *pState = NM_CALL_INVALID;
  678. break;
  679. }
  680. }
  681. hr = S_OK;
  682. }
  683. return hr;
  684. }
  685. HRESULT COutgoingCall::GetAddress(BSTR * pbstrAddr)
  686. {
  687. if (NULL == pbstrAddr)
  688. return E_POINTER;
  689. *pbstrAddr = SysAllocString(m_bstrAddr);
  690. return (*pbstrAddr ? S_OK : E_FAIL);
  691. }
  692. HRESULT COutgoingCall::GetConference(INmConference **ppConference)
  693. {
  694. HRESULT hr = E_POINTER;
  695. if (NULL != ppConference)
  696. {
  697. *ppConference = m_pConfObject;
  698. return S_OK;
  699. }
  700. return hr;
  701. }
  702. HRESULT COutgoingCall::Accept(void)
  703. {
  704. return E_UNEXPECTED;
  705. }
  706. HRESULT COutgoingCall::Reject(void)
  707. {
  708. return E_UNEXPECTED;
  709. }
  710. HRESULT COutgoingCall::Cancel(void)
  711. {
  712. DebugEntry(COutgoingCall::Cancel);
  713. AddRef(); // protect against Release() while processing
  714. // disconnect related indications & callbacks
  715. HRESULT hr = _Cancel(FALSE);
  716. if (FIsComplete())
  717. {
  718. COprahNCUI *pOprahNCUI = COprahNCUI::GetInstance();
  719. ASSERT(NULL !=pOprahNCUI);
  720. pOprahNCUI->OnOutgoingCallCanceled(this);
  721. }
  722. DebugExitULONG(COutgoingCall::Abort, m_cnResult);
  723. Release();
  724. return hr;
  725. }
  726. /* O N N O T I F Y C A L L E R R O R */
  727. /*-------------------------------------------------------------------------
  728. %%Function: OnNotifyCallError
  729. -------------------------------------------------------------------------*/
  730. HRESULT OnNotifyCallError(IUnknown *pCallNotify, PVOID pv, REFIID riid)
  731. {
  732. ASSERT(NULL != pCallNotify);
  733. CNSTATUS cnStatus = (CNSTATUS)((DWORD_PTR)pv);
  734. switch (cnStatus)
  735. {
  736. case CN_RC_ALREADY_IN_CONFERENCE:
  737. case CN_RC_CANT_INVITE_MCU:
  738. case CN_RC_CANT_JOIN_ALREADY_IN_CALL:
  739. case CN_RC_INVITE_DENIED_REMOTE_IN_CONF:
  740. case CN_RC_REMOTE_PLACING_CALL:
  741. case CN_RC_ALREADY_IN_CONFERENCE_MCU:
  742. ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_IN_CONFERENCE);
  743. break;
  744. case CN_RC_CONFERENCE_JOIN_DENIED:
  745. case CN_RC_CONFERENCE_INVITE_DENIED:
  746. case CN_RC_CONFERENCE_DOES_NOT_EXIST:
  747. case CN_RC_CONNECT_REMOTE_NO_SECURITY:
  748. case CN_RC_CONNECT_REMOTE_DOWNLEVEL_SECURITY:
  749. case CN_RC_CONNECT_REMOTE_REQUIRE_SECURITY:
  750. ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_IGNORED);
  751. break;
  752. case CN_RC_CONNECT_FAILED:
  753. ((INmCallNotify*)pCallNotify)->NmUI(CONFN_CALL_FAILED);
  754. break;
  755. default:
  756. break;
  757. }
  758. if (IID_INmCallNotify == riid)
  759. {
  760. ((INmCallNotify*)pCallNotify)->CallError(cnStatus);
  761. }
  762. return S_OK;
  763. }
  764. /* O N N O T I F Y R E M O T E C O N F E R E N C E */
  765. /*-------------------------------------------------------------------------
  766. %%Function: OnNotifyRemoteConference
  767. -------------------------------------------------------------------------*/
  768. HRESULT OnNotifyRemoteConference(IUnknown *pCallNotify, PVOID pv, REFIID riid)
  769. {
  770. REMOTE_CONFERENCE *prc = (REMOTE_CONFERENCE *)pv;
  771. // WARNING: pwszConfName is an PWSTR array, not a BSTR
  772. ASSERT(NULL != pCallNotify);
  773. ((INmCallNotify*)pCallNotify)->RemoteConference(prc->fMCU,
  774. (BSTR *) prc->pwszConfNames, prc->pbstrConfToJoin);
  775. return S_OK;
  776. }
  777. /* O N N O T I F Y R E M O T E P A S S W O R D */
  778. /*-------------------------------------------------------------------------
  779. %%Function: OnNotifyRemotePassword
  780. -------------------------------------------------------------------------*/
  781. HRESULT OnNotifyRemotePassword(IUnknown *pCallNotify, PVOID pv, REFIID riid)
  782. {
  783. REMOTE_PASSWORD *prp = (REMOTE_PASSWORD *)pv;
  784. ASSERT(NULL != pCallNotify);
  785. ((INmCallNotify*)pCallNotify)->RemotePassword(prp->bstrConference, prp->pbstrPassword, prp->pbRemoteCred, prp->cbRemoteCred);
  786. return S_OK;
  787. }
  788. COutgoingCallManager::COutgoingCallManager()
  789. {
  790. }
  791. COutgoingCallManager::~COutgoingCallManager()
  792. {
  793. // Empty the call list:
  794. while (!m_CallList.IsEmpty())
  795. {
  796. COutgoingCall* pCall = (COutgoingCall*) m_CallList.RemoveHead();
  797. // Shouldn't have any NULL entries:
  798. ASSERT(pCall);
  799. pCall->Release();
  800. }
  801. }
  802. UINT COutgoingCallManager::GetCallCount()
  803. {
  804. UINT nNodes = 0;
  805. POSITION pos = m_CallList.GetHeadPosition();
  806. while (pos)
  807. {
  808. nNodes++;
  809. m_CallList.GetNext(pos);
  810. }
  811. return nNodes;
  812. }
  813. HRESULT COutgoingCallManager::Call(
  814. INmCall **ppCall,
  815. COprahNCUI* pManager,
  816. DWORD dwFlags,
  817. NM_ADDR_TYPE addrType,
  818. BSTR bstrAddr,
  819. BSTR bstrConference,
  820. BSTR bstrPassword)
  821. {
  822. DebugEntry(COutgoingCallManager::CallConference);
  823. HRESULT hr = E_FAIL;
  824. COutgoingCall* pCall = NULL;
  825. CConfObject* pConfObject = pManager->GetConfObject();
  826. if (NULL != ppCall)
  827. {
  828. *ppCall = NULL;
  829. }
  830. if (pConfObject->IsConferenceActive() && (NULL != bstrConference))
  831. {
  832. hr= NM_CALLERR_IN_CONFERENCE;
  833. }
  834. else
  835. {
  836. if (!pConfObject->IsConferenceActive())
  837. {
  838. pConfObject->SetConfSecurity(0 != (CRPCF_SECURE & dwFlags));
  839. }
  840. pCall = new COutgoingCall( pConfObject,
  841. dwFlags,
  842. addrType,
  843. bstrAddr,
  844. bstrConference,
  845. bstrPassword);
  846. if (NULL != pCall)
  847. {
  848. m_CallList.AddTail(pCall);
  849. if (NULL != ppCall)
  850. {
  851. pCall->AddRef();
  852. // This MUST be set before OnNotifyCallCreated
  853. *ppCall = pCall;
  854. }
  855. pCall->AddRef();
  856. pManager->OnOutgoingCallCreated(pCall);
  857. pCall->PlaceCall();
  858. if (pCall->FIsComplete())
  859. {
  860. RemoveFromList(pCall);
  861. }
  862. pCall->Release();
  863. // let the caller know that we successfully created the call
  864. // any error will be reported asynchronously
  865. hr = S_OK;
  866. }
  867. }
  868. DebugExitHRESULT(COutgoingCallManager::CallConference, hr);
  869. return hr;
  870. }
  871. BOOL COutgoingCallManager::RemoveFromList(COutgoingCall* pCall)
  872. {
  873. DebugEntry(COutgoingCallManager::RemoveFromList);
  874. ASSERT(pCall);
  875. BOOL bRet = FALSE;
  876. POSITION pos = m_CallList.GetPosition(pCall);
  877. if (NULL != pos)
  878. {
  879. m_CallList.RemoveAt(pos);
  880. pCall->CallComplete();
  881. pCall->Release();
  882. bRet = TRUE;
  883. }
  884. else
  885. {
  886. WARNING_OUT(("COutgoingCallManager::RemoveFromList() could not match call"));
  887. }
  888. DebugExitBOOL(COutgoingCallManager::RemoveFromList, bRet);
  889. return bRet;
  890. }
  891. VOID COutgoingCallManager::OnConferenceStarted(CONF_HANDLE hConference, HRESULT hResult)
  892. {
  893. DebugEntry(COutgoingCallManager::OnConferenceStarted);
  894. // Tell all ConfNode's that a conference has started
  895. POSITION pos = m_CallList.GetHeadPosition();
  896. while (pos)
  897. {
  898. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  899. if (NULL != pCall)
  900. {
  901. pCall->AddRef();
  902. pCall->OnConferenceStarted(hConference, hResult);
  903. if (pCall->FIsComplete())
  904. {
  905. RemoveFromList(pCall);
  906. }
  907. pCall->Release();
  908. }
  909. }
  910. DebugExitVOID(COutgoingCallManager::OnConferenceStarted);
  911. }
  912. VOID COutgoingCallManager::OnQueryRemoteResult(PVOID pvCallerContext,
  913. HRESULT hResult,
  914. BOOL fMCU,
  915. PWSTR* ppwszConferenceNames,
  916. PWSTR* ppwszConfDescriptors)
  917. {
  918. DebugEntry(COutgoingCallManager::OnQueryRemoteResult);
  919. POSITION pos = m_CallList.GetHeadPosition();
  920. while (pos)
  921. {
  922. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  923. // Notify the node that issued the query:
  924. if ((COutgoingCall*) pvCallerContext == pCall)
  925. {
  926. pCall->AddRef();
  927. pCall->OnQueryRemoteResult( hResult,
  928. fMCU,
  929. ppwszConferenceNames,
  930. ppwszConfDescriptors);
  931. if (pCall->FIsComplete())
  932. {
  933. RemoveFromList(pCall);
  934. }
  935. pCall->Release();
  936. break;
  937. }
  938. }
  939. DebugExitVOID(COutgoingCallManager::OnQueryRemoteResult);
  940. }
  941. VOID COutgoingCallManager::OnInviteResult( CONF_HANDLE hConference,
  942. REQUEST_HANDLE hRequest,
  943. UINT uNodeID,
  944. HRESULT hResult)
  945. {
  946. DebugEntry(COutgoingCallManager::OnInviteResult);
  947. POSITION pos = m_CallList.GetHeadPosition();
  948. while (pos)
  949. {
  950. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  951. if ((NULL != pCall) &&
  952. (pCall->GetCurrentRequestHandle() == hRequest))
  953. {
  954. pCall->AddRef();
  955. pCall->OnInviteResult(hResult, uNodeID);
  956. if (pCall->FIsComplete())
  957. {
  958. RemoveFromList(pCall);
  959. }
  960. pCall->Release();
  961. break;
  962. }
  963. }
  964. DebugExitVOID(COutgoingCallManager::OnInviteResult);
  965. }
  966. VOID COutgoingCallManager::OnConferenceEnded(CONF_HANDLE hConference)
  967. {
  968. DebugEntry(COutgoingCallManager::OnConferenceEnded);
  969. // Tell all ConfNode's that a conference has started
  970. POSITION pos = m_CallList.GetHeadPosition();
  971. while (pos)
  972. {
  973. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  974. if (NULL != pCall)
  975. {
  976. pCall->AddRef();
  977. pCall->OnConferenceEnded();
  978. if (pCall->FIsComplete())
  979. {
  980. RemoveFromList(pCall);
  981. }
  982. pCall->Release();
  983. }
  984. }
  985. DebugExitVOID(COutgoingCallManager::OnConferenceEnded);
  986. }
  987. VOID COutgoingCallManager::CancelCalls()
  988. {
  989. DebugEntry(COutgoingCallManager::CancelCalls);
  990. // Tell all ConfNode's that a conference has started
  991. POSITION pos = m_CallList.GetHeadPosition();
  992. while (pos)
  993. {
  994. COutgoingCall* pCall = (COutgoingCall*) m_CallList.GetNext(pos);
  995. if (NULL != pCall)
  996. {
  997. pCall->AddRef();
  998. pCall->_Cancel(TRUE);
  999. if (pCall->FIsComplete())
  1000. {
  1001. RemoveFromList(pCall);
  1002. }
  1003. pCall->Release();
  1004. }
  1005. }
  1006. DebugExitVOID(COutgoingCallManager::CancelCalls);
  1007. }