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.

2864 lines
71 KiB

  1. #include "precomp.h"
  2. //
  3. // CONTROL.CPP
  4. // Control by us, control of us
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. // CA_ReceivedPacket()
  11. //
  12. void ASShare::CA_ReceivedPacket
  13. (
  14. ASPerson * pasFrom,
  15. PS20DATAPACKET pPacket
  16. )
  17. {
  18. PCAPACKET pCAPacket;
  19. DebugEntry(ASShare::CA_ReceivedPacket);
  20. ValidatePerson(pasFrom);
  21. pCAPacket = (PCAPACKET)pPacket;
  22. switch (pCAPacket->msg)
  23. {
  24. case CA_MSG_NOTIFY_STATE:
  25. CAHandleNewState(pasFrom, (PCANOTPACKET)pPacket);
  26. break;
  27. default:
  28. // Ignore for now -- old 2.x messages
  29. break;
  30. }
  31. DebugExitVOID(ASShare::CA_ReceivedPacket);
  32. }
  33. //
  34. // CA30_ReceivedPacket()
  35. //
  36. void ASShare::CA30_ReceivedPacket
  37. (
  38. ASPerson * pasFrom,
  39. PS20DATAPACKET pPacket
  40. )
  41. {
  42. LPBYTE pCAPacket;
  43. DebugEntry(ASShare::CA30_ReceivedPacket);
  44. pCAPacket = (LPBYTE)pPacket + sizeof(CA30PACKETHEADER);
  45. switch (((PCA30PACKETHEADER)pPacket)->msg)
  46. {
  47. // From VIEWER (remote) to HOST (us)
  48. case CA_REQUEST_TAKECONTROL:
  49. {
  50. CAHandleRequestTakeControl(pasFrom, (PCA_RTC_PACKET)pCAPacket);
  51. break;
  52. }
  53. // From HOST (remote) to VIEWER (us)
  54. case CA_REPLY_REQUEST_TAKECONTROL:
  55. {
  56. CAHandleReplyRequestTakeControl(pasFrom, (PCA_REPLY_RTC_PACKET)pCAPacket);
  57. break;
  58. }
  59. // From HOST (remote) to VIEWER (us)
  60. case CA_REQUEST_GIVECONTROL:
  61. {
  62. CAHandleRequestGiveControl(pasFrom, (PCA_RGC_PACKET)pCAPacket);
  63. break;
  64. }
  65. // From VIEWER (remote) to HOST (us)
  66. case CA_REPLY_REQUEST_GIVECONTROL:
  67. {
  68. CAHandleReplyRequestGiveControl(pasFrom, (PCA_REPLY_RGC_PACKET)pCAPacket);
  69. break;
  70. }
  71. // From CONTROLLER (remote) to HOST (us)
  72. case CA_PREFER_PASSCONTROL:
  73. {
  74. CAHandlePreferPassControl(pasFrom, (PCA_PPC_PACKET)pCAPacket);
  75. break;
  76. }
  77. // From CONTROLLER (remote) to HOST (us)
  78. case CA_INFORM_RELEASEDCONTROL:
  79. {
  80. CAHandleInformReleasedControl(pasFrom, (PCA_INFORM_PACKET)pCAPacket);
  81. break;
  82. }
  83. // From HOST (remote) to CONTROLLER (us)
  84. case CA_INFORM_REVOKEDCONTROL:
  85. {
  86. CAHandleInformRevokedControl(pasFrom, (PCA_INFORM_PACKET)pCAPacket);
  87. break;
  88. }
  89. default:
  90. {
  91. WARNING_OUT(("CA30_ReceivedPacket: unrecognized message %d",
  92. ((PCA30PACKETHEADER)pPacket)->msg));
  93. break;
  94. }
  95. }
  96. DebugExitVOID(ASShare::CA30_ReceivedPacket);
  97. }
  98. //
  99. // CANewRequestID()
  100. //
  101. // Returns a new token. It uses the current value, fills in the new one, and
  102. // also returns the new one. We wrap around if necessary. ZERO is never
  103. // valid. Note that this is a unique identifier only to us.
  104. //
  105. // It is a stamp for the control operation. Since you can't be controlling
  106. // and controlled at the same time, we have one stamp for all ops.
  107. //
  108. UINT ASShare::CANewRequestID(void)
  109. {
  110. DebugEntry(ASShare::CANewRequestID);
  111. ++(m_pasLocal->m_caControlID);
  112. if (m_pasLocal->m_caControlID == 0)
  113. {
  114. ++(m_pasLocal->m_caControlID);
  115. }
  116. DebugExitDWORD(ASShare::CANewRequestID, m_pasLocal->m_caControlID);
  117. return(m_pasLocal->m_caControlID);
  118. }
  119. //
  120. // CA_ViewStarting()
  121. // Called when a REMOTE starts hosting
  122. //
  123. // We only do anything if it's a 2.x node since they could be cooperating
  124. // but not hosting.
  125. //
  126. BOOL ASShare::CA_ViewStarting(ASPerson * pasPerson)
  127. {
  128. DebugEntry(ASShare::CA_ViewStarting);
  129. DebugExitBOOL(ASShare::CA_ViewStarting, TRUE);
  130. return(TRUE);
  131. }
  132. //
  133. // CA_ViewEnded()
  134. // Called when a REMOTE stopped hosting
  135. //
  136. void ASShare::CA_ViewEnded(ASPerson * pasPerson)
  137. {
  138. PCAREQUEST pRequest;
  139. PCAREQUEST pNext;
  140. DebugEntry(ASShare::CA_ViewEnded);
  141. //
  142. // Clear any control stuff we are a part of where they are the host
  143. //
  144. CA_ClearLocalState(CACLEAR_VIEW, pasPerson, FALSE);
  145. //
  146. // Clear any control stuff involving remotes
  147. //
  148. if (pasPerson->m_caControlledBy)
  149. {
  150. ASSERT(pasPerson->m_caControlledBy != m_pasLocal);
  151. CAClearHostState(pasPerson, NULL);
  152. ASSERT(!pasPerson->m_caControlledBy);
  153. }
  154. pasPerson->m_caAllowControl = FALSE;
  155. //
  156. // Clean up outstanding control packets to this person
  157. //
  158. pRequest = (PCAREQUEST)COM_BasedListFirst(&m_caQueuedMsgs, FIELD_OFFSET(CAREQUEST, chain));
  159. while (pRequest)
  160. {
  161. pNext = (PCAREQUEST)COM_BasedListNext(&m_caQueuedMsgs, pRequest,
  162. FIELD_OFFSET(CAREQUEST, chain));
  163. if (pRequest->destID == pasPerson->mcsID)
  164. {
  165. //
  166. // Delete messages sent by us to this person who is hosting
  167. //
  168. switch (pRequest->msg)
  169. {
  170. case CA_REQUEST_TAKECONTROL:
  171. case CA_PREFER_PASSCONTROL:
  172. case CA_REPLY_REQUEST_GIVECONTROL:
  173. WARNING_OUT(("Deleting viewer control message %d, person [%d] stopped hosting",
  174. pRequest->msg, pasPerson->mcsID));
  175. COM_BasedListRemove(&pRequest->chain);
  176. delete pRequest;
  177. break;
  178. }
  179. }
  180. pRequest = pNext;
  181. }
  182. DebugExitVOID(ASView::CA_ViewEnded);
  183. }
  184. //
  185. // CA_PartyLeftShare()
  186. //
  187. void ASShare::CA_PartyLeftShare(ASPerson * pasPerson)
  188. {
  189. DebugEntry(ASShare::CA_PartyLeftShare);
  190. ValidatePerson(pasPerson);
  191. //
  192. // We must have cleaned up hosting info for this person already.
  193. // So it can't be controlled or controllable.
  194. //
  195. ASSERT(!pasPerson->m_caAllowControl);
  196. ASSERT(!pasPerson->m_caControlledBy);
  197. if (pasPerson != m_pasLocal)
  198. {
  199. PCAREQUEST pRequest;
  200. PCAREQUEST pNext;
  201. //
  202. // Clear any control stuff we are a part of where they are the
  203. // viewer.
  204. //
  205. CA_ClearLocalState(CACLEAR_HOST, pasPerson, FALSE);
  206. //
  207. // Clear any control stuff involving remotes
  208. //
  209. if (pasPerson->m_caInControlOf)
  210. {
  211. ASSERT(pasPerson->m_caInControlOf != m_pasLocal);
  212. CAClearHostState(pasPerson->m_caInControlOf, NULL);
  213. }
  214. //
  215. // Clean up outgoing packets meant for this person.
  216. //
  217. pRequest = (PCAREQUEST)COM_BasedListFirst(&m_caQueuedMsgs, FIELD_OFFSET(CAREQUEST, chain));
  218. while (pRequest)
  219. {
  220. pNext = (PCAREQUEST)COM_BasedListNext(&m_caQueuedMsgs, pRequest,
  221. FIELD_OFFSET(CAREQUEST, chain));
  222. //
  223. // This doesn't need to know if it's a 2.x or 3.0 request,
  224. // simply remove queued packets intended for somebody leaving.
  225. //
  226. // Only GRANTED_CONTROL requests will have non-zero destIDs of
  227. // the 2.x packets.
  228. //
  229. if (pRequest->destID == pasPerson->mcsID)
  230. {
  231. WARNING_OUT(("Freeing outgoing RESPONSE to node [%d]", pasPerson->mcsID));
  232. COM_BasedListRemove(&(pRequest->chain));
  233. delete pRequest;
  234. }
  235. pRequest = pNext;
  236. }
  237. ASSERT(m_caWaitingForReplyFrom != pasPerson);
  238. }
  239. else
  240. {
  241. //
  242. // When our waiting for/controlled dude stopped sharing, we should
  243. // have cleaned this goop up.
  244. //
  245. ASSERT(!pasPerson->m_caInControlOf);
  246. ASSERT(!pasPerson->m_caControlledBy);
  247. ASSERT(!m_caWaitingForReplyFrom);
  248. ASSERT(!m_caWaitingForReplyMsg);
  249. //
  250. // There should be NO outgoing control requests
  251. //
  252. ASSERT(COM_BasedListIsEmpty(&(m_caQueuedMsgs)));
  253. }
  254. DebugExitVOID(ASShare::CA_PartyLeftShare);
  255. }
  256. //
  257. // CA_Periodic() -> SHARE STUFF
  258. //
  259. void ASShare::CA_Periodic(void)
  260. {
  261. DebugEntry(ASShare::CA_Periodic);
  262. //
  263. // Flush as many queued outgoing messages as we can
  264. //
  265. CAFlushOutgoingPackets();
  266. DebugExitVOID(ASShare::CA_Periodic);
  267. }
  268. //
  269. // CA_SyncAlreadyHosting()
  270. //
  271. void ASHost::CA_SyncAlreadyHosting(void)
  272. {
  273. DebugEntry(ASHost::CA_SyncAlreadyHosting);
  274. m_caRetrySendState = TRUE;
  275. DebugExitVOID(ASHost::CA_SyncAlreadyHosting);
  276. }
  277. //
  278. // CA_Periodic() -> HOSTING STUFF
  279. //
  280. void ASHost::CA_Periodic(void)
  281. {
  282. DebugEntry(ASHost::CA_Periodic);
  283. if (m_caRetrySendState)
  284. {
  285. PCANOTPACKET pPacket;
  286. #ifdef _DEBUG
  287. UINT sentSize;
  288. #endif // _DEBUG
  289. pPacket = (PCANOTPACKET)m_pShare->SC_AllocPkt(PROT_STR_MISC, g_s20BroadcastID,
  290. sizeof(*pPacket));
  291. if (!pPacket)
  292. {
  293. WARNING_OUT(("CA_Periodic: couldn't broadcast new state"));
  294. }
  295. else
  296. {
  297. pPacket->header.data.dataType = DT_CA;
  298. pPacket->msg = CA_MSG_NOTIFY_STATE;
  299. pPacket->state = 0;
  300. if (m_pShare->m_pasLocal->m_caAllowControl)
  301. pPacket->state |= CASTATE_ALLOWCONTROL;
  302. if (m_pShare->m_pasLocal->m_caControlledBy)
  303. pPacket->controllerID = m_pShare->m_pasLocal->m_caControlledBy->mcsID;
  304. else
  305. pPacket->controllerID = 0;
  306. #ifdef _DEBUG
  307. sentSize =
  308. #endif // _DEBUG
  309. m_pShare->DCS_CompressAndSendPacket(PROT_STR_MISC, g_s20BroadcastID,
  310. &(pPacket->header), sizeof(*pPacket));
  311. m_caRetrySendState = FALSE;
  312. }
  313. }
  314. DebugExitVOID(ASHost::CA_Periodic);
  315. }
  316. //
  317. // CAFlushOutgoingPackets()
  318. //
  319. // This tries to send private packets (not broadcast notifications) that
  320. // we have accumulated. It returns TRUE if the outgoing queue is empty.
  321. //
  322. BOOL ASShare::CAFlushOutgoingPackets(void)
  323. {
  324. BOOL fEmpty = TRUE;
  325. PCAREQUEST pRequest;
  326. //
  327. // If we're hosting and haven't yet flushed the HET or CA state,
  328. // force queueing.
  329. //
  330. if (m_hetRetrySendState || (m_pHost && m_pHost->m_caRetrySendState))
  331. {
  332. TRACE_OUT(("CAFlushOutgoingPackets: force queuing, pending HET/CA state broadcast"));
  333. fEmpty = FALSE;
  334. DC_QUIT;
  335. }
  336. while (pRequest = (PCAREQUEST)COM_BasedListFirst(&m_caQueuedMsgs,
  337. FIELD_OFFSET(CAREQUEST, chain)))
  338. {
  339. //
  340. // Allocate/send packet
  341. //
  342. if (!CASendPacket(pRequest->destID, pRequest->msg,
  343. &pRequest->req30.packet))
  344. {
  345. WARNING_OUT(("CAFlushOutgoingPackets: couldn't send request"));
  346. fEmpty = FALSE;
  347. break;
  348. }
  349. //
  350. // Do we do state transitions here or when things are added to queue?
  351. // requestID, results are calculated when put on queue. Results can
  352. // change though based on a future action.
  353. //
  354. COM_BasedListRemove(&(pRequest->chain));
  355. delete pRequest;
  356. }
  357. DC_EXIT_POINT:
  358. DebugExitBOOL(CAFlushOutgoingPackets, fEmpty);
  359. return(fEmpty);
  360. }
  361. //
  362. // CASendPacket()
  363. // This sends a private message (request or response) to the destination.
  364. // If there are queued private messages in front of this one, or we can't
  365. // send it, we add it to the pending queue.
  366. //
  367. // This TRUE if sent.
  368. //
  369. // It's up to the caller to change state info appropriately.
  370. //
  371. BOOL ASShare::CASendPacket
  372. (
  373. UINT destID,
  374. UINT msg,
  375. PCA30P pData
  376. )
  377. {
  378. BOOL fSent = FALSE;
  379. PCA30PACKETHEADER pPacket;
  380. #ifdef _DEBUG
  381. UINT sentSize;
  382. #endif // _DEBUG
  383. DebugEntry(ASShare::CASendPacket);
  384. //
  385. // Note that CA30P does not include size of header.
  386. //
  387. pPacket = (PCA30PACKETHEADER)SC_AllocPkt(PROT_STR_INPUT, destID,
  388. sizeof(CA30PACKETHEADER) + sizeof(*pData));
  389. if (!pPacket)
  390. {
  391. WARNING_OUT(("CASendPacket: no memory to send %d packet to [%d]",
  392. msg, destID));
  393. DC_QUIT;
  394. }
  395. pPacket->header.data.dataType = DT_CA30;
  396. pPacket->msg = msg;
  397. memcpy(pPacket+1, pData, sizeof(*pData));
  398. #ifdef _DEBUG
  399. sentSize =
  400. #endif // _DEBUG
  401. DCS_CompressAndSendPacket(PROT_STR_INPUT, destID,
  402. &(pPacket->header), sizeof(*pPacket));
  403. TRACE_OUT(("CA30 request packet size: %08d, sent %08d", sizeof(*pPacket), sentSize));
  404. fSent = TRUE;
  405. DC_EXIT_POINT:
  406. DebugExitBOOL(ASShare::CASendPacket, fSent);
  407. return(fSent);
  408. }
  409. //
  410. // CAQueueSendPacket()
  411. // This flushes pending queued requests if there are any, then tries to
  412. // send this one. If it can't, we add it to the queue. If there's not any
  413. // memory even for that, we return an error about it.
  414. //
  415. BOOL ASShare::CAQueueSendPacket
  416. (
  417. UINT destID,
  418. UINT msg,
  419. PCA30P pPacketSend
  420. )
  421. {
  422. BOOL rc = TRUE;
  423. PCAREQUEST pCARequest;
  424. DebugEntry(ASShare::CAQueueSendPacket);
  425. //
  426. // These must go out in order. So if any queued messages are still
  427. // present, those must be sent first.
  428. //
  429. if (!CAFlushOutgoingPackets() ||
  430. !CASendPacket(destID, msg, pPacketSend))
  431. {
  432. //
  433. // We must queue this.
  434. //
  435. TRACE_OUT(("CAQueueSendPacket: queuing request for send later"));
  436. pCARequest = new CAREQUEST;
  437. if (!pCARequest)
  438. {
  439. ERROR_OUT(("CAQueueSendPacket: can't even allocate memory to queue request; must fail"));
  440. rc = FALSE;
  441. }
  442. else
  443. {
  444. SET_STAMP(pCARequest, CAREQUEST);
  445. pCARequest->destID = destID;
  446. pCARequest->msg = msg;
  447. pCARequest->req30.packet = *pPacketSend;
  448. //
  449. // Stick this at the end of the queue
  450. //
  451. COM_BasedListInsertBefore(&(m_caQueuedMsgs), &(pCARequest->chain));
  452. }
  453. }
  454. DebugExitBOOL(ASShare::CAQueueSendPacket, rc);
  455. return(rc);
  456. }
  457. //
  458. // CALangToggle()
  459. //
  460. // This temporarily turns off the keyboard language toggle key, so that a
  461. // remote controlling us doesn't inadvertently change it. When we stop being
  462. // controlled, we put it back.
  463. //
  464. void ASShare::CALangToggle(BOOL fBackOn)
  465. {
  466. //
  467. // Local Variables
  468. //
  469. LONG rc;
  470. HKEY hkeyToggle;
  471. BYTE regValue[2];
  472. DWORD cbRegValue;
  473. DWORD dwType;
  474. LPCSTR szValue;
  475. DebugEntry(ASShare::CALangToggle);
  476. szValue = (g_asWin95) ? NULL : LANGUAGE_TOGGLE_KEY_VAL;
  477. if (fBackOn)
  478. {
  479. //
  480. // We are gaining control of our local keyboard again - we restore the
  481. // language togging functionality.
  482. //
  483. // We must directly access the registry to accomplish this.
  484. //
  485. if (m_caToggle != LANGUAGE_TOGGLE_NOT_PRESENT)
  486. {
  487. rc = RegOpenKey(HKEY_CURRENT_USER, LANGUAGE_TOGGLE_KEY,
  488. &hkeyToggle);
  489. if (rc == ERROR_SUCCESS)
  490. {
  491. //
  492. // Clear the value for this key.
  493. //
  494. regValue[0] = m_caToggle;
  495. regValue[1] = '\0'; // ensure NUL termination
  496. //
  497. // Restore the value.
  498. //
  499. RegSetValueEx(hkeyToggle, szValue, 0, REG_SZ,
  500. regValue, sizeof(regValue));
  501. //
  502. // We need to inform the system about this change. We do not
  503. // tell any other apps about this (ie do not set any of the
  504. // notification flags as the last parm)
  505. //
  506. SystemParametersInfo(SPI_SETLANGTOGGLE, 0, 0, 0);
  507. }
  508. RegCloseKey(hkeyToggle);
  509. }
  510. }
  511. else
  512. {
  513. //
  514. // We are losing control of our keyboard - ensure that remote key
  515. // events will not change our local keyboard settings by disabling the
  516. // keyboard language toggle.
  517. //
  518. // We must directly access the registry to accomplish this.
  519. //
  520. rc = RegOpenKey(HKEY_CURRENT_USER, LANGUAGE_TOGGLE_KEY,
  521. &hkeyToggle);
  522. if (rc == ERROR_SUCCESS)
  523. {
  524. cbRegValue = sizeof(regValue);
  525. rc = RegQueryValueEx(hkeyToggle, szValue, NULL,
  526. &dwType, regValue, &cbRegValue);
  527. if (rc == ERROR_SUCCESS)
  528. {
  529. m_caToggle = regValue[0];
  530. //
  531. // Clear the value for this key.
  532. //
  533. regValue[0] = '3';
  534. regValue[1] = '\0'; // ensure NUL termination
  535. //
  536. // Clear the value.
  537. //
  538. RegSetValueEx(hkeyToggle, szValue, 0, REG_SZ,
  539. regValue, sizeof(regValue));
  540. //
  541. // We need to inform the system about this change. We do not
  542. // tell any other apps about this (ie do not set any of the
  543. // notification flags as the last parm)
  544. //
  545. SystemParametersInfo(SPI_SETLANGTOGGLE, 0, 0, 0);
  546. }
  547. else
  548. {
  549. m_caToggle = LANGUAGE_TOGGLE_NOT_PRESENT;
  550. }
  551. RegCloseKey(hkeyToggle);
  552. }
  553. }
  554. DebugExitVOID(ASShare::CALangToggle);
  555. }
  556. //
  557. // CAStartControlled()
  558. //
  559. void ASShare::CAStartControlled
  560. (
  561. ASPerson * pasInControl,
  562. UINT controlID
  563. )
  564. {
  565. DebugEntry(ASShare::CAStartControlled);
  566. ValidatePerson(pasInControl);
  567. //
  568. // Undo last known state of remote
  569. //
  570. CAClearRemoteState(pasInControl);
  571. //
  572. // Get any VIEW frame UI out of the way
  573. //
  574. VIEWStartControlled(TRUE);
  575. ASSERT(!m_pasLocal->m_caControlledBy);
  576. m_pasLocal->m_caControlledBy = pasInControl;
  577. ASSERT(!pasInControl->m_caInControlOf);
  578. pasInControl->m_caInControlOf = m_pasLocal;
  579. ASSERT(!pasInControl->m_caControlID);
  580. ASSERT(controlID);
  581. pasInControl->m_caControlID = controlID;
  582. //
  583. // Notify IM.
  584. //
  585. IM_Controlled(pasInControl);
  586. //
  587. // Disable language toggling.
  588. //
  589. CALangToggle(FALSE);
  590. ASSERT(m_pHost);
  591. m_pHost->CM_Controlled(pasInControl);
  592. //
  593. // Notify the UI. Pass GCCID of controller
  594. //
  595. DCS_NotifyUI(SH_EVT_STARTCONTROLLED, pasInControl->cpcCaps.share.gccID, 0);
  596. //
  597. // Broadcast new state
  598. //
  599. m_pHost->m_caRetrySendState = TRUE;
  600. m_pHost->CA_Periodic();
  601. DebugExitVOID(ASShare::CAStartControlled);
  602. }
  603. //
  604. // CAStopControlled()
  605. //
  606. void ASShare::CAStopControlled(void)
  607. {
  608. ASPerson * pasControlledBy;
  609. DebugEntry(ASShare::CAStopControlled);
  610. pasControlledBy = m_pasLocal->m_caControlledBy;
  611. ValidatePerson(pasControlledBy);
  612. m_pasLocal->m_caControlledBy = NULL;
  613. ASSERT(pasControlledBy->m_caInControlOf == m_pasLocal);
  614. pasControlledBy->m_caInControlOf = NULL;
  615. ASSERT(pasControlledBy->m_caControlID);
  616. pasControlledBy->m_caControlID = 0;
  617. //
  618. // Notify IM.
  619. //
  620. IM_Controlled(NULL);
  621. //
  622. // Restore language toggling functionality.
  623. //
  624. CALangToggle(TRUE);
  625. ASSERT(m_pHost);
  626. m_pHost->CM_Controlled(NULL);
  627. VIEWStartControlled(FALSE);
  628. //
  629. // Notify the UI
  630. //
  631. DCS_NotifyUI(SH_EVT_STOPCONTROLLED, pasControlledBy->cpcCaps.share.gccID, 0);
  632. //
  633. // Broadcast the new state
  634. //
  635. m_pHost->m_caRetrySendState = TRUE;
  636. m_pHost->CA_Periodic();
  637. DebugExitVOID(ASShare::CAStopControlled);
  638. }
  639. //
  640. // CAStartInControl()
  641. //
  642. void ASShare::CAStartInControl
  643. (
  644. ASPerson * pasControlled,
  645. UINT controlID
  646. )
  647. {
  648. DebugEntry(ASShare::CAStartInControl);
  649. ValidatePerson(pasControlled);
  650. //
  651. // Undo last known state of host
  652. //
  653. CAClearRemoteState(pasControlled);
  654. ASSERT(!m_pasLocal->m_caInControlOf);
  655. m_pasLocal->m_caInControlOf = pasControlled;
  656. ASSERT(!pasControlled->m_caControlledBy);
  657. pasControlled->m_caControlledBy = m_pasLocal;
  658. ASSERT(!pasControlled->m_caControlID);
  659. ASSERT(controlID);
  660. pasControlled->m_caControlID = controlID;
  661. ASSERT(!g_lpimSharedData->imControlled);
  662. IM_InControl(pasControlled);
  663. VIEW_InControl(pasControlled, TRUE);
  664. //
  665. // Pass GCC ID of node we're controlling
  666. //
  667. DCS_NotifyUI(SH_EVT_STARTINCONTROL, pasControlled->cpcCaps.share.gccID, 0);
  668. DebugExitVOID(ASShare::CAStartInControl);
  669. }
  670. //
  671. // CAStopInControl()
  672. //
  673. void ASShare::CAStopInControl(void)
  674. {
  675. ASPerson * pasInControlOf;
  676. DebugEntry(ASShare::CAStopInControl);
  677. pasInControlOf = m_pasLocal->m_caInControlOf;
  678. ValidatePerson(pasInControlOf);
  679. m_pasLocal->m_caInControlOf = NULL;
  680. ASSERT(pasInControlOf->m_caControlledBy == m_pasLocal);
  681. pasInControlOf->m_caControlledBy = NULL;
  682. ASSERT(pasInControlOf->m_caControlID);
  683. pasInControlOf->m_caControlID = 0;
  684. ASSERT(!g_lpimSharedData->imControlled);
  685. IM_InControl(NULL);
  686. VIEW_InControl(pasInControlOf, FALSE);
  687. DCS_NotifyUI(SH_EVT_STOPINCONTROL, pasInControlOf->cpcCaps.share.gccID, 0);
  688. DebugExitVOID(ASShare::CAStopInControl);
  689. }
  690. //
  691. // CA_AllowControl()
  692. // Allows/disallows remotes from controlling us.
  693. //
  694. void ASShare::CA_AllowControl(BOOL fAllow)
  695. {
  696. DebugEntry(ASShare::CA_AllowControl);
  697. if (!m_pHost)
  698. {
  699. WARNING_OUT(("CA_AllowControl: ignoring, we aren't hosting"));
  700. DC_QUIT;
  701. }
  702. if (fAllow != m_pasLocal->m_caAllowControl)
  703. {
  704. if (!fAllow)
  705. {
  706. // Undo pending control/control queries/being controlled stuff
  707. CA_ClearLocalState(CACLEAR_HOST, NULL, TRUE);
  708. }
  709. m_pasLocal->m_caAllowControl = fAllow;
  710. DCS_NotifyUI(SH_EVT_CONTROLLABLE, fAllow, 0);
  711. m_pHost->m_caRetrySendState = TRUE;
  712. }
  713. DC_EXIT_POINT:
  714. DebugExitVOID(ASShare::CA_AllowControl);
  715. }
  716. //
  717. // CA_HostEnded()
  718. //
  719. // When we stop hosting, we do not need to flush queued control
  720. // responses. But we need to delete them!
  721. //
  722. void ASHost::CA_HostEnded(void)
  723. {
  724. PCAREQUEST pCARequest;
  725. PCAREQUEST pCANext;
  726. DebugEntry(ASHost::CA_HostEnded);
  727. m_pShare->CA_ClearLocalState(CACLEAR_HOST, NULL, FALSE);
  728. //
  729. // Delete now obsolete messages originating from us as host.
  730. //
  731. pCARequest = (PCAREQUEST)COM_BasedListFirst(&m_pShare->m_caQueuedMsgs,
  732. FIELD_OFFSET(CAREQUEST, chain));
  733. while (pCARequest)
  734. {
  735. pCANext = (PCAREQUEST)COM_BasedListNext(&m_pShare->m_caQueuedMsgs, pCARequest,
  736. FIELD_OFFSET(CAREQUEST, chain));
  737. switch (pCARequest->msg)
  738. {
  739. //
  740. // Delete messages sent by us when we are hosting.
  741. //
  742. case CA_INFORM_PAUSEDCONTROL:
  743. case CA_INFORM_UNPAUSEDCONTROL:
  744. case CA_REPLY_REQUEST_TAKECONTROL:
  745. case CA_REQUEST_GIVECONTROL:
  746. WARNING_OUT(("Deleting host control message %d, we stopped hosting",
  747. pCARequest->msg));
  748. COM_BasedListRemove(&pCARequest->chain);
  749. delete pCARequest;
  750. break;
  751. }
  752. pCARequest = pCANext;
  753. }
  754. if (m_pShare->m_pasLocal->m_caAllowControl)
  755. {
  756. m_pShare->m_pasLocal->m_caAllowControl = FALSE;
  757. DCS_NotifyUI(SH_EVT_CONTROLLABLE, FALSE, 0);
  758. }
  759. DebugExitVOID(ASHost::CA_HostEnded);
  760. }
  761. //
  762. // CA_TakeControl()
  763. //
  764. // Called by viewer to ask to take control of host. Note parallels to
  765. // CA_GiveControl(), which is called by host to get same result.
  766. //
  767. void ASShare::CA_TakeControl(ASPerson * pasHost)
  768. {
  769. DebugEntry(ASShare::CA_TakeControl);
  770. ValidatePerson(pasHost);
  771. ASSERT(pasHost != m_pasLocal);
  772. //
  773. // If this person isn't hosting or controllable, fail.
  774. //
  775. if (!pasHost->m_pView)
  776. {
  777. WARNING_OUT(("CA_TakeControl: failing, person [%d] not hosting",
  778. pasHost->mcsID));
  779. DC_QUIT;
  780. }
  781. if (!pasHost->m_caAllowControl)
  782. {
  783. WARNING_OUT(("CA_TakeControl: failing, host [%d] not controllable",
  784. pasHost->mcsID));
  785. DC_QUIT;
  786. }
  787. //
  788. // Undo current state.
  789. //
  790. CA_ClearLocalState(CACLEAR_ALL, NULL, TRUE);
  791. //
  792. // Now take control.
  793. //
  794. {
  795. //
  796. // 3.0 host
  797. //
  798. CA30P packetSend;
  799. ZeroMemory(&packetSend, sizeof(packetSend));
  800. packetSend.rtc.viewerControlID = CANewRequestID();
  801. if (CAQueueSendPacket(pasHost->mcsID, CA_REQUEST_TAKECONTROL, &packetSend))
  802. {
  803. //
  804. // Now we're in waiting state.
  805. //
  806. CAStartWaiting(pasHost, CA_REPLY_REQUEST_TAKECONTROL);
  807. VIEW_UpdateStatus(pasHost, IDS_STATUS_WAITINGFORCONTROL);
  808. }
  809. else
  810. {
  811. WARNING_OUT(("CA_TakeControl of [%d]: failing, out of memory", pasHost->mcsID));
  812. }
  813. }
  814. DC_EXIT_POINT:
  815. DebugExitVOID(ASShare::CA_TakeControl);
  816. }
  817. //
  818. // CA_CancelTakeControl()
  819. //
  820. void ASShare::CA_CancelTakeControl
  821. (
  822. ASPerson * pasHost,
  823. BOOL fPacket
  824. )
  825. {
  826. DebugEntry(ASShare::CA_CancelTakeControl);
  827. ValidatePerson(pasHost);
  828. ASSERT(pasHost != m_pasLocal);
  829. if ((m_caWaitingForReplyFrom != pasHost) ||
  830. (m_caWaitingForReplyMsg != CA_REPLY_REQUEST_TAKECONTROL))
  831. {
  832. // We're not waiting for control of this host.
  833. WARNING_OUT(("CA_CancelTakeControl failing; not waiting to take control of [%d]",
  834. pasHost->mcsID));
  835. DC_QUIT;
  836. }
  837. ASSERT(pasHost->m_caControlID == 0);
  838. if (fPacket)
  839. {
  840. CA30P packetSend;
  841. ZeroMemory(&packetSend, sizeof(packetSend));
  842. packetSend.inform.viewerControlID = m_pasLocal->m_caControlID;
  843. packetSend.inform.hostControlID = pasHost->m_caControlID;
  844. if (!CAQueueSendPacket(pasHost->mcsID, CA_INFORM_RELEASEDCONTROL,
  845. &packetSend))
  846. {
  847. WARNING_OUT(("Couldn't tell node [%d] we're no longer waiting for control",
  848. pasHost->mcsID));
  849. }
  850. }
  851. m_caWaitingForReplyFrom = NULL;
  852. m_caWaitingForReplyMsg = 0;
  853. VIEW_UpdateStatus(pasHost, IDS_STATUS_NONE);
  854. DC_EXIT_POINT:
  855. DebugExitVOID(ASShare::CA_CancelTakeControl);
  856. }
  857. //
  858. // CA_ReleaseControl()
  859. //
  860. void ASShare::CA_ReleaseControl
  861. (
  862. ASPerson * pasHost,
  863. BOOL fPacket
  864. )
  865. {
  866. DebugEntry(ASShare::CA_ReleaseControl);
  867. ValidatePerson(pasHost);
  868. ASSERT(pasHost != m_pasLocal);
  869. if (pasHost->m_caControlledBy != m_pasLocal)
  870. {
  871. // We're not in control of this dude, nothing to do.
  872. WARNING_OUT(("CA_ReleaseControl failing; not in control of [%d]",
  873. pasHost->mcsID));
  874. DC_QUIT;
  875. }
  876. ASSERT(!m_caWaitingForReplyFrom);
  877. ASSERT(!m_caWaitingForReplyMsg);
  878. if (fPacket)
  879. {
  880. CA30P packetSend;
  881. ZeroMemory(&packetSend, sizeof(packetSend));
  882. packetSend.inform.viewerControlID = m_pasLocal->m_caControlID;
  883. packetSend.inform.hostControlID = pasHost->m_caControlID;
  884. if (!CAQueueSendPacket(pasHost->mcsID, CA_INFORM_RELEASEDCONTROL,
  885. &packetSend))
  886. {
  887. WARNING_OUT(("Couldn't tell node [%d] they're no longer controlled",
  888. pasHost->mcsID));
  889. }
  890. }
  891. CAStopInControl();
  892. DC_EXIT_POINT:
  893. DebugExitVOID(ASShare::CA_ReleaseControl);
  894. }
  895. //
  896. // CA_PassControl()
  897. //
  898. void ASShare::CA_PassControl(ASPerson * pasHost, ASPerson * pasViewer)
  899. {
  900. CA30P packetSend;
  901. DebugEntry(ASShare::CA_PassControl);
  902. ValidatePerson(pasHost);
  903. ValidatePerson(pasViewer);
  904. ASSERT(pasHost != pasViewer);
  905. ASSERT(pasHost != m_pasLocal);
  906. ASSERT(pasViewer != m_pasLocal);
  907. if (pasHost->m_caControlledBy != m_pasLocal)
  908. {
  909. WARNING_OUT(("CA_PassControl: failing, we're not in control of [%d]",
  910. pasHost->mcsID));
  911. DC_QUIT;
  912. }
  913. ASSERT(!m_caWaitingForReplyFrom);
  914. ASSERT(!m_caWaitingForReplyMsg);
  915. ZeroMemory(&packetSend, sizeof(packetSend));
  916. packetSend.ppc.viewerControlID = m_pasLocal->m_caControlID;
  917. packetSend.ppc.hostControlID = pasHost->m_caControlID;
  918. packetSend.ppc.mcsPassTo = pasViewer->mcsID;
  919. if (CAQueueSendPacket(pasHost->mcsID, CA_PREFER_PASSCONTROL, &packetSend))
  920. {
  921. CAStopInControl();
  922. }
  923. else
  924. {
  925. WARNING_OUT(("Couldn't tell node [%d] we want them to pass control to [%d]",
  926. pasHost->mcsID, pasViewer->mcsID));
  927. }
  928. DC_EXIT_POINT:
  929. DebugExitVOID(ASShare::CA_PassControl);
  930. }
  931. //
  932. // CA_GiveControl()
  933. //
  934. // Called by host to ask to grant control to viewer. Note parallels to
  935. // CA_TakeControl(), which is called by viewer to get same result.
  936. //
  937. void ASShare::CA_GiveControl(ASPerson * pasTo)
  938. {
  939. CA30P packetSend;
  940. DebugEntry(ASShare::CA_GiveControl);
  941. ValidatePerson(pasTo);
  942. ASSERT(pasTo != m_pasLocal);
  943. //
  944. // If we aren't hosting or controllable, fail.
  945. //
  946. if (!m_pHost)
  947. {
  948. WARNING_OUT(("CA_GiveControl: failing, we're not hosting"));
  949. DC_QUIT;
  950. }
  951. if (!m_pasLocal->m_caAllowControl)
  952. {
  953. WARNING_OUT(("CA_GiveControl: failing, we're not controllable"));
  954. DC_QUIT;
  955. }
  956. //
  957. // Undo our control state.
  958. //
  959. CA_ClearLocalState(CACLEAR_ALL, NULL, TRUE);
  960. //
  961. // Now invite control.
  962. //
  963. ZeroMemory(&packetSend, sizeof(packetSend));
  964. packetSend.rgc.hostControlID = CANewRequestID();
  965. packetSend.rgc.mcsPassFrom = 0;
  966. if (CAQueueSendPacket(pasTo->mcsID, CA_REQUEST_GIVECONTROL, &packetSend))
  967. {
  968. //
  969. // Now we're in waiting state.
  970. //
  971. CAStartWaiting(pasTo, CA_REPLY_REQUEST_GIVECONTROL);
  972. }
  973. else
  974. {
  975. WARNING_OUT(("CA_GiveControl of [%d]: failing, out of memory", pasTo->mcsID));
  976. }
  977. DC_EXIT_POINT:
  978. DebugExitVOID(ASShare::CA_GiveControl);
  979. }
  980. //
  981. // CA_CancelGiveControl()
  982. // Cancels an invite TAKE or PASS request.
  983. //
  984. void ASShare::CA_CancelGiveControl
  985. (
  986. ASPerson * pasTo,
  987. BOOL fPacket
  988. )
  989. {
  990. DebugEntry(ASShare::CA_CancelGiveControl);
  991. ValidatePerson(pasTo);
  992. ASSERT(pasTo != m_pasLocal);
  993. //
  994. // Have we invited this person, and are we now waiting for a response?
  995. //
  996. if ((m_caWaitingForReplyFrom != pasTo) ||
  997. (m_caWaitingForReplyMsg != CA_REPLY_REQUEST_GIVECONTROL))
  998. {
  999. // We're not waiting to be controlled by this viewer.
  1000. WARNING_OUT(("CA_CancelGiveControl failing; not waiting to give control to [%d]",
  1001. pasTo->mcsID));
  1002. DC_QUIT;
  1003. }
  1004. ASSERT(!pasTo->m_caControlID);
  1005. if (fPacket)
  1006. {
  1007. CA30P packetSend;
  1008. ZeroMemory(&packetSend, sizeof(packetSend));
  1009. packetSend.inform.viewerControlID = pasTo->m_caControlID;
  1010. packetSend.inform.hostControlID = m_pasLocal->m_caControlID;
  1011. if (!CAQueueSendPacket(pasTo->mcsID, CA_INFORM_REVOKEDCONTROL,
  1012. &packetSend))
  1013. {
  1014. WARNING_OUT(("Couldn't tell node [%d] they're no longer invited to control us",
  1015. pasTo->mcsID));
  1016. }
  1017. }
  1018. m_caWaitingForReplyFrom = NULL;
  1019. m_caWaitingForReplyMsg = 0;
  1020. DC_EXIT_POINT:
  1021. DebugExitVOID(ASShare::CA_CancelGiveControl);
  1022. }
  1023. //
  1024. // CA_RevokeControl()
  1025. // Takes control back. If we're cleaning up (we've stopped hosting or
  1026. //
  1027. //
  1028. void ASShare::CA_RevokeControl
  1029. (
  1030. ASPerson * pasInControl,
  1031. BOOL fPacket
  1032. )
  1033. {
  1034. CA30P packetSend;
  1035. PCAREQUEST pRequest;
  1036. DebugEntry(ASShare::CA_RevokeControl);
  1037. //
  1038. // If the response to pasController is still queued, simply delete it.
  1039. // There should NOT be any CARESULT_CONFIRMED responses left.
  1040. //
  1041. // Otherwise, if it wasn't found, we must send a packet.
  1042. //
  1043. ValidatePerson(pasInControl);
  1044. ASSERT(pasInControl != m_pasLocal);
  1045. if (pasInControl != m_pasLocal->m_caControlledBy)
  1046. {
  1047. WARNING_OUT(("CA_RevokeControl: node [%d] not in control of us",
  1048. pasInControl->mcsID));
  1049. DC_QUIT;
  1050. }
  1051. //
  1052. // Take control back if we're being controlled
  1053. //
  1054. if (fPacket)
  1055. {
  1056. //
  1057. // Regardless of whether we can queue or not, we get control back!
  1058. // Note that we use the controller's request ID, so he knows if
  1059. // this is still applicable.
  1060. //
  1061. ZeroMemory(&packetSend, sizeof(packetSend));
  1062. packetSend.inform.viewerControlID = pasInControl->m_caControlID;
  1063. packetSend.inform.hostControlID = m_pasLocal->m_caControlID;
  1064. if (!CAQueueSendPacket(pasInControl->mcsID, CA_INFORM_REVOKEDCONTROL,
  1065. &packetSend))
  1066. {
  1067. WARNING_OUT(("Couldn't tell node [%d] they're no longer in control",
  1068. pasInControl->mcsID));
  1069. }
  1070. }
  1071. CAStopControlled();
  1072. DC_EXIT_POINT:
  1073. DebugExitVOID(ASShare::CA_RevokeControl);
  1074. }
  1075. //
  1076. // CAHandleRequestTakeControl()
  1077. // WE are HOST, REMOTE is VIEWER
  1078. // Handles incoming take control request. If our state is good, we accept.
  1079. //
  1080. void ASShare::CAHandleRequestTakeControl
  1081. (
  1082. ASPerson * pasViewer,
  1083. PCA_RTC_PACKET pPacketRecv
  1084. )
  1085. {
  1086. UINT result = CARESULT_CONFIRMED;
  1087. DebugEntry(ASShare::CAHandleRequestTakeControl);
  1088. ValidatePerson(pasViewer);
  1089. //
  1090. // If we aren't hosting, or haven't turned allow control on, we're
  1091. // not controllable.
  1092. //
  1093. if (!m_pHost || !m_pasLocal->m_caAllowControl)
  1094. {
  1095. result = CARESULT_DENIED_WRONGSTATE;
  1096. goto RESPOND_PACKET;
  1097. }
  1098. //
  1099. // Are we doing something else right now? Waiting to hear back about
  1100. // something?
  1101. //
  1102. if (m_caWaitingForReplyFrom)
  1103. {
  1104. result = CARESULT_DENIED_BUSY;
  1105. goto RESPOND_PACKET;
  1106. }
  1107. if (m_caQueryDlg)
  1108. {
  1109. result = CARESULT_DENIED_BUSY;
  1110. goto RESPOND_PACKET;
  1111. }
  1112. //
  1113. // LAURABU TEMPORARY:
  1114. // In a bit, if we're controlled when a new control request comes in,
  1115. // pause control then allow host to handle it.
  1116. //
  1117. if (m_pasLocal->m_caControlledBy)
  1118. {
  1119. result = CARESULT_DENIED_BUSY;
  1120. goto RESPOND_PACKET;
  1121. }
  1122. //
  1123. // Try to put up query dialog
  1124. //
  1125. if (!CAStartQuery(pasViewer, CA_REQUEST_TAKECONTROL, (PCA30P)pPacketRecv))
  1126. {
  1127. result = CARESULT_DENIED;
  1128. }
  1129. RESPOND_PACKET:
  1130. if (result != CARESULT_CONFIRMED)
  1131. {
  1132. // Instant failure.
  1133. CACompleteRequestTakeControl(pasViewer, pPacketRecv, result);
  1134. }
  1135. else
  1136. {
  1137. //
  1138. // We're in a waiting state. CACompleteRequestTakeControl() will
  1139. // complete later or the request will just go away.
  1140. //
  1141. }
  1142. DebugExitVOID(ASShare::CAHandleRequestTakeControl);
  1143. }
  1144. //
  1145. // CACompleteRequestTakeControl()
  1146. // WE are HOST, REMOTE is VIEWER
  1147. // Completes the take control request.
  1148. //
  1149. void ASShare::CACompleteRequestTakeControl
  1150. (
  1151. ASPerson * pasFrom,
  1152. PCA_RTC_PACKET pPacketRecv,
  1153. UINT result
  1154. )
  1155. {
  1156. CA30P packetSend;
  1157. DebugEntry(ASShare::CACompleteRequestTakeControl);
  1158. ValidatePerson(pasFrom);
  1159. ZeroMemory(&packetSend, sizeof(packetSend));
  1160. packetSend.rrtc.viewerControlID = pPacketRecv->viewerControlID;
  1161. packetSend.rrtc.result = result;
  1162. if (result == CARESULT_CONFIRMED)
  1163. {
  1164. packetSend.rrtc.hostControlID = CANewRequestID();
  1165. }
  1166. if (CAQueueSendPacket(pasFrom->mcsID, CA_REPLY_REQUEST_TAKECONTROL, &packetSend))
  1167. {
  1168. if (result == CARESULT_CONFIRMED)
  1169. {
  1170. // Clear current state, whatever that is.
  1171. CA_ClearLocalState(CACLEAR_ALL, NULL, TRUE);
  1172. // We are now controlled by the sender.
  1173. CAStartControlled(pasFrom, pPacketRecv->viewerControlID);
  1174. }
  1175. else
  1176. {
  1177. WARNING_OUT(("Denying REQUEST TAKE CONTROL from [%d] with reason %d",
  1178. pasFrom->mcsID, result));
  1179. }
  1180. }
  1181. else
  1182. {
  1183. WARNING_OUT(("Reply to REQUEST TAKE CONTROL from [%d] failing, out of memory",
  1184. pasFrom->mcsID));
  1185. }
  1186. DebugExitVOID(ASShare::CACompleteRequestTakeControl);
  1187. }
  1188. //
  1189. // CAHandleReplyRequestTakeControl()
  1190. // WE are VIEWER, REMOTE is HOST
  1191. // Handles reply to previous take control request.
  1192. //
  1193. void ASShare::CAHandleReplyRequestTakeControl
  1194. (
  1195. ASPerson * pasHost,
  1196. PCA_REPLY_RTC_PACKET pPacketRecv
  1197. )
  1198. {
  1199. DebugEntry(ASShare::CAHandleReplyRequestTakeControl);
  1200. ValidatePerson(pasHost);
  1201. if (pPacketRecv->result == CARESULT_CONFIRMED)
  1202. {
  1203. // On success, should have valid op ID.
  1204. ASSERT(pPacketRecv->hostControlID);
  1205. }
  1206. else
  1207. {
  1208. // On failure, should have invalid op ID.
  1209. ASSERT(!pPacketRecv->hostControlID);
  1210. }
  1211. //
  1212. // Is this response for the current control op?
  1213. //
  1214. if ((m_caWaitingForReplyFrom != pasHost) ||
  1215. (m_caWaitingForReplyMsg != CA_REPLY_REQUEST_TAKECONTROL))
  1216. {
  1217. WARNING_OUT(("Ignoring TAKE CONTROL REPLY from [%d], not waiting for one",
  1218. pasHost->mcsID));
  1219. DC_QUIT;
  1220. }
  1221. if (pPacketRecv->viewerControlID != m_pasLocal->m_caControlID)
  1222. {
  1223. WARNING_OUT(("Ignoring TAKE CONTROL REPLY from [%d], request %d is out of date",
  1224. pasHost->mcsID, pPacketRecv->viewerControlID));
  1225. DC_QUIT;
  1226. }
  1227. ASSERT(!m_caQueryDlg);
  1228. //
  1229. // Cleanup waiting state (for both failure & success)
  1230. //
  1231. CA_CancelTakeControl(pasHost, FALSE);
  1232. ASSERT(!m_caWaitingForReplyFrom);
  1233. ASSERT(!m_caWaitingForReplyMsg);
  1234. if (pPacketRecv->result == CARESULT_CONFIRMED)
  1235. {
  1236. // Success! We're now in control of the host.
  1237. // Make sure our own state is OK
  1238. ASSERT(!m_pasLocal->m_caControlledBy);
  1239. ASSERT(!m_pasLocal->m_caInControlOf);
  1240. CAStartInControl(pasHost, pPacketRecv->hostControlID);
  1241. }
  1242. else
  1243. {
  1244. UINT ids;
  1245. WARNING_OUT(("TAKE CONTROL REPLY from host [%d] is failure %d", pasHost->mcsID,
  1246. pPacketRecv->result));
  1247. ids = IDS_ERR_TAKECONTROL_MIN + pPacketRecv->result;
  1248. if ((ids < IDS_ERR_TAKECONTROL_FIRST) || (ids > IDS_ERR_TAKECONTROL_LAST))
  1249. ids = IDS_ERR_TAKECONTROL_LAST;
  1250. VIEW_Message(pasHost, ids);
  1251. }
  1252. DC_EXIT_POINT:
  1253. DebugExitVOID(ASShare::CAHandleReplyRequestTakeControl);
  1254. }
  1255. //
  1256. // CAHandleRequestGiveControl()
  1257. // WE are VIEWER, REMOTE is HOST
  1258. // Handles incoming take control invite. If our state is good, we accept.
  1259. //
  1260. // NOTE how similar this routine is to CAHandleRequestTakeControl(). They
  1261. // are inverses of each other. With RequestTake/Reply sequence, viewer
  1262. // initiates, host finishes. With RequestGive/Reply sequence, host initiates,
  1263. // viewer finishes. Both end up with viewer in control of host when
  1264. // completed successfully.
  1265. //
  1266. void ASShare::CAHandleRequestGiveControl
  1267. (
  1268. ASPerson * pasHost,
  1269. PCA_RGC_PACKET pPacketRecv
  1270. )
  1271. {
  1272. UINT result = CARESULT_CONFIRMED;
  1273. DebugEntry(ASShare::CAHandleRequestGiveControl);
  1274. ValidatePerson(pasHost);
  1275. //
  1276. // Is this node hosting as far as we know. If not, or has not turned
  1277. // on allow control, we can't do it.
  1278. //
  1279. if (!pasHost->m_pView)
  1280. {
  1281. WARNING_OUT(("GIVE CONTROL went ahead of HOSTING, that's bad"));
  1282. result = CARESULT_DENIED_WRONGSTATE;
  1283. goto RESPOND_PACKET;
  1284. }
  1285. if (!pasHost->m_caAllowControl)
  1286. {
  1287. //
  1288. // We haven't got an AllowControl notification yet, this info is
  1289. // more up to-date. Make use of it.
  1290. //
  1291. WARNING_OUT(("GIVE CONTROL went ahead of ALLOW CONTROL, that's kind of bad"));
  1292. result = CARESULT_DENIED_WRONGSTATE;
  1293. goto RESPOND_PACKET;
  1294. }
  1295. //
  1296. // Are we doing something else right now? Waiting to hear back about
  1297. // something?
  1298. //
  1299. if (m_caWaitingForReplyFrom)
  1300. {
  1301. result = CARESULT_DENIED_BUSY;
  1302. goto RESPOND_PACKET;
  1303. }
  1304. if (m_caQueryDlg)
  1305. {
  1306. result = CARESULT_DENIED_BUSY;
  1307. goto RESPOND_PACKET;
  1308. }
  1309. //
  1310. // LAURABU TEMPORARY:
  1311. // In a bit, if we're controlled when a new control request comes in,
  1312. // pause control then allow host to handle it.
  1313. //
  1314. if (m_pasLocal->m_caControlledBy)
  1315. {
  1316. result = CARESULT_DENIED_BUSY;
  1317. goto RESPOND_PACKET;
  1318. }
  1319. //
  1320. // Try to put up query dialog
  1321. //
  1322. if (!CAStartQuery(pasHost, CA_REQUEST_GIVECONTROL, (PCA30P)pPacketRecv))
  1323. {
  1324. result = CARESULT_DENIED;
  1325. }
  1326. RESPOND_PACKET:
  1327. if (result != CARESULT_CONFIRMED)
  1328. {
  1329. // Instant failure.
  1330. CACompleteRequestGiveControl(pasHost, pPacketRecv, result);
  1331. }
  1332. else
  1333. {
  1334. //
  1335. // We're in a waiting state. CACompleteRequestGiveControl() will
  1336. // complete later or the request will just go away.
  1337. //
  1338. }
  1339. DebugExitVOID(ASShare::CAHandleRequestGiveControl);
  1340. }
  1341. //
  1342. // CACompleteRequestGiveControl()
  1343. // WE are VIEWER, REMOTE is HOST
  1344. // Completes the invite control request.
  1345. //
  1346. void ASShare::CACompleteRequestGiveControl
  1347. (
  1348. ASPerson * pasFrom,
  1349. PCA_RGC_PACKET pPacketRecv,
  1350. UINT result
  1351. )
  1352. {
  1353. CA30P packetSend;
  1354. DebugEntry(ASShare::CACompleteRequestGiveControl);
  1355. ValidatePerson(pasFrom);
  1356. ZeroMemory(&packetSend, sizeof(packetSend));
  1357. packetSend.rrgc.hostControlID = pPacketRecv->hostControlID;
  1358. packetSend.rrgc.result = result;
  1359. if (result == CARESULT_CONFIRMED)
  1360. {
  1361. packetSend.rrgc.viewerControlID = CANewRequestID();
  1362. }
  1363. if (CAQueueSendPacket(pasFrom->mcsID, CA_REPLY_REQUEST_GIVECONTROL, &packetSend))
  1364. {
  1365. //
  1366. // If this is successful, change our state. We're now in control.
  1367. //
  1368. if (result == CARESULT_CONFIRMED)
  1369. {
  1370. // Clear current state, whatever that is.
  1371. CA_ClearLocalState(CACLEAR_ALL, NULL, TRUE);
  1372. CAStartInControl(pasFrom, pPacketRecv->hostControlID);
  1373. }
  1374. else
  1375. {
  1376. WARNING_OUT(("Denying GIVE CONTROL from [%d] with reason %d",
  1377. pasFrom->mcsID, result));
  1378. }
  1379. }
  1380. else
  1381. {
  1382. WARNING_OUT(("Reply to GIVE CONTROL from [%d] failing, out of memory",
  1383. pasFrom->mcsID));
  1384. }
  1385. DebugExitVOID(ASShare::CACompleteRequestGiveControl);
  1386. }
  1387. //
  1388. // CAHandleReplyRequestGiveControl()
  1389. // WE are HOST, REMOTE is VIEWER
  1390. // Handles reply to previous take control invite.
  1391. //
  1392. void ASShare::CAHandleReplyRequestGiveControl
  1393. (
  1394. ASPerson * pasViewer,
  1395. PCA_REPLY_RGC_PACKET pPacketRecv
  1396. )
  1397. {
  1398. DebugEntry(ASShare::CAHandleReplyRequestGiveControl);
  1399. ValidatePerson(pasViewer);
  1400. if (pPacketRecv->result == CARESULT_CONFIRMED)
  1401. {
  1402. // On success, should have valid op ID.
  1403. ASSERT(pPacketRecv->viewerControlID);
  1404. }
  1405. else
  1406. {
  1407. // On failure, should have invalid op ID.
  1408. ASSERT(!pPacketRecv->viewerControlID);
  1409. }
  1410. //
  1411. // Is this response for the latest control op?
  1412. //
  1413. if ((m_caWaitingForReplyFrom != pasViewer) ||
  1414. (m_caWaitingForReplyMsg != CA_REPLY_REQUEST_GIVECONTROL))
  1415. {
  1416. WARNING_OUT(("Ignoring GIVE CONTROL REPLY from [%d], not waiting for one",
  1417. pasViewer->mcsID));
  1418. DC_QUIT;
  1419. }
  1420. if (pPacketRecv->hostControlID != m_pasLocal->m_caControlID)
  1421. {
  1422. WARNING_OUT(("Ignoring GIVE CONTROL REPLY from [%d], request %d is out of date",
  1423. pasViewer->mcsID, pPacketRecv->hostControlID));
  1424. DC_QUIT;
  1425. }
  1426. ASSERT(!m_caQueryDlg);
  1427. ASSERT(m_pHost);
  1428. ASSERT(m_pasLocal->m_caAllowControl);
  1429. //
  1430. // Cleanup waiting state (for both failure & success)
  1431. //
  1432. CA_CancelGiveControl(pasViewer, FALSE);
  1433. ASSERT(!m_caWaitingForReplyFrom);
  1434. ASSERT(!m_caWaitingForReplyMsg);
  1435. if (pPacketRecv->result == CARESULT_CONFIRMED)
  1436. {
  1437. // Success! We are now controlled by the viewer
  1438. // Make sure our own state is OK
  1439. ASSERT(!m_pasLocal->m_caControlledBy);
  1440. ASSERT(!m_pasLocal->m_caInControlOf);
  1441. CAStartControlled(pasViewer, pPacketRecv->viewerControlID);
  1442. }
  1443. else
  1444. {
  1445. WARNING_OUT(("GIVE CONTROL to viewer [%d] was denied", pasViewer->mcsID));
  1446. }
  1447. DC_EXIT_POINT:
  1448. DebugExitVOID(ASShare::CAHandleReplyRequestGiveControl);
  1449. }
  1450. //
  1451. // CAHandlePreferPassControl()
  1452. // WE are HOST, REMOTE is CONTROLLER
  1453. // Handles incoming pass control request. If we are controlled by the
  1454. // remote, and end user is cool with it, accept.
  1455. //
  1456. void ASShare::CAHandlePreferPassControl
  1457. (
  1458. ASPerson * pasController,
  1459. PCA_PPC_PACKET pPacketRecv
  1460. )
  1461. {
  1462. ASPerson * pasNewController;
  1463. DebugEntry(ASShare::CAHandlePreferPassControl);
  1464. ValidatePerson(pasController);
  1465. //
  1466. // If we're not controlled by the requester, ignore it.
  1467. //
  1468. if (m_pasLocal->m_caControlledBy != pasController)
  1469. {
  1470. WARNING_OUT(("Ignoring PASS CONTROL from [%d], not controlled by him",
  1471. pasController->mcsID));
  1472. DC_QUIT;
  1473. }
  1474. if ((pPacketRecv->viewerControlID != pasController->m_caControlID) ||
  1475. (pPacketRecv->hostControlID != m_pasLocal->m_caControlID))
  1476. {
  1477. WARNING_OUT(("Ignoring PASS CONTROL from [%d], request %d %d out of date",
  1478. pasController->mcsID, pPacketRecv->viewerControlID, pPacketRecv->hostControlID));
  1479. DC_QUIT;
  1480. }
  1481. ASSERT(!m_caQueryDlg);
  1482. ASSERT(!m_caWaitingForReplyFrom);
  1483. ASSERT(!m_caWaitingForReplyMsg);
  1484. //
  1485. // OK, the sender is not in control of us anymore.
  1486. //
  1487. CA_RevokeControl(pasController, FALSE);
  1488. // Is the pass to person specified valid?
  1489. pasNewController = SC_PersonFromNetID(pPacketRecv->mcsPassTo);
  1490. if (!pasNewController ||
  1491. (pasNewController == pasController) ||
  1492. (pasNewController == m_pasLocal))
  1493. {
  1494. WARNING_OUT(("PASS CONTROL to [%d] failing, not valid person to pass to",
  1495. pPacketRecv->mcsPassTo));
  1496. DC_QUIT;
  1497. }
  1498. //
  1499. // Try to put up query dialog
  1500. //
  1501. if (!CAStartQuery(pasController, CA_PREFER_PASSCONTROL, (PCA30P)pPacketRecv))
  1502. {
  1503. // Instant failure. In this case, no packet.
  1504. WARNING_OUT(("Denying PREFER PASS CONTROL from [%d], out of memory",
  1505. pasController->mcsID));
  1506. }
  1507. else
  1508. {
  1509. //
  1510. // We're in a waiting state. CACompletePreferPassControl() will
  1511. // complete later or the request will just go away.
  1512. //
  1513. }
  1514. DC_EXIT_POINT:
  1515. DebugExitVOID(ASShare::CAHandlePreferPassControl);
  1516. }
  1517. //
  1518. // CACompletePreferPassControl()
  1519. // WE are HOST, REMOTE is new potential CONTROLLER
  1520. // Completes the prefer pass control request.
  1521. //
  1522. void ASShare::CACompletePreferPassControl
  1523. (
  1524. ASPerson * pasTo,
  1525. UINT mcsOrg,
  1526. PCA_PPC_PACKET pPacketRecv,
  1527. UINT result
  1528. )
  1529. {
  1530. CA30P packetSend;
  1531. DebugEntry(ASShare::CACompletePreferPassControl);
  1532. ValidatePerson(pasTo);
  1533. if (result == CARESULT_CONFIRMED)
  1534. {
  1535. ZeroMemory(&packetSend, sizeof(packetSend));
  1536. packetSend.rgc.hostControlID = CANewRequestID();
  1537. packetSend.rgc.mcsPassFrom = mcsOrg;
  1538. if (CAQueueSendPacket(pasTo->mcsID, CA_REQUEST_GIVECONTROL,
  1539. &packetSend))
  1540. {
  1541. CA_ClearLocalState(CACLEAR_HOST, NULL, TRUE);
  1542. CAStartWaiting(pasTo, CA_REPLY_REQUEST_GIVECONTROL);
  1543. }
  1544. else
  1545. {
  1546. WARNING_OUT(("Reply to PREFER PASS CONTROL from [%d] to [%d] failing, out of memory",
  1547. mcsOrg, pasTo->mcsID));
  1548. }
  1549. }
  1550. else
  1551. {
  1552. WARNING_OUT(("Denying PREFER PASS CONTROL from [%d] to [%d] with reason %d",
  1553. mcsOrg, pasTo->mcsID, result));
  1554. }
  1555. DebugExitVOID(ASShare::CACompletePreferPassControl);
  1556. }
  1557. //
  1558. // CAHandleInformReleasedControl()
  1559. // WE are HOST, REMOTE is CONTROLLER
  1560. //
  1561. void ASShare::CAHandleInformReleasedControl
  1562. (
  1563. ASPerson * pasController,
  1564. PCA_INFORM_PACKET pPacketRecv
  1565. )
  1566. {
  1567. DebugEntry(ASShare::CAHandleInformReleasedControl);
  1568. ValidatePerson(pasController);
  1569. //
  1570. // Do we currently have a TakeControl dialog up for this request? If so,
  1571. // take it down but don't send a packet.
  1572. //
  1573. if (m_caQueryDlg &&
  1574. (m_caQuery.pasReplyTo == pasController) &&
  1575. (m_caQuery.msg == CA_REQUEST_TAKECONTROL) &&
  1576. (m_caQuery.request.rtc.viewerControlID == pPacketRecv->viewerControlID))
  1577. {
  1578. ASSERT(!pPacketRecv->hostControlID);
  1579. CACancelQuery(pasController, FALSE);
  1580. DC_QUIT;
  1581. }
  1582. //
  1583. // If this person isn't in control of us or the control op referred to
  1584. // isn't the current one, ignore. NULL hostControlID means the person
  1585. // cancelled a request before they heard back from us.
  1586. //
  1587. if (pasController->m_caInControlOf != m_pasLocal)
  1588. {
  1589. WARNING_OUT(("Ignoring RELEASE CONTROL from [%d], we're not controlled by them",
  1590. pasController->mcsID));
  1591. DC_QUIT;
  1592. }
  1593. if (pPacketRecv->viewerControlID != pasController->m_caControlID)
  1594. {
  1595. WARNING_OUT(("Ignoring RELEASE CONTROL from [%d], viewer ID out of date",
  1596. pasController->mcsID, pPacketRecv->viewerControlID));
  1597. DC_QUIT;
  1598. }
  1599. if (pPacketRecv->hostControlID && (pPacketRecv->hostControlID != m_pasLocal->m_caControlID))
  1600. {
  1601. WARNING_OUT(("Ignoring RELEASE CONTROL from [%d], host ID out of date",
  1602. pasController->mcsID, pPacketRecv->hostControlID));
  1603. DC_QUIT;
  1604. }
  1605. // Undo control, but no packet gets sent, we're just cleaning up.
  1606. CA_RevokeControl(pasController, FALSE);
  1607. DC_EXIT_POINT:
  1608. DebugExitVOID(ASShare::CAHandleInformReleasedControl);
  1609. }
  1610. //
  1611. // CAHandleInformRevokedControl()
  1612. // WE are CONTROLLER, REMOTE is HOST
  1613. //
  1614. void ASShare::CAHandleInformRevokedControl
  1615. (
  1616. ASPerson * pasHost,
  1617. PCA_INFORM_PACKET pPacketRecv
  1618. )
  1619. {
  1620. DebugEntry(ASShare::CAHandleInformRevokedControl);
  1621. ValidatePerson(pasHost);
  1622. //
  1623. // Do we currently have a GiveControl dialog up for this request? If so,
  1624. // take it down but don't send a packet.
  1625. //
  1626. if (m_caQueryDlg &&
  1627. (m_caQuery.pasReplyTo == pasHost) &&
  1628. (m_caQuery.msg == CA_REQUEST_GIVECONTROL) &&
  1629. (m_caQuery.request.rgc.hostControlID == pPacketRecv->hostControlID))
  1630. {
  1631. ASSERT(!pPacketRecv->viewerControlID);
  1632. CACancelQuery(pasHost, FALSE);
  1633. DC_QUIT;
  1634. }
  1635. //
  1636. // If this person isn't controlled by us or the control op referred to
  1637. // isn't the current one, ignore.
  1638. //
  1639. if (pasHost->m_caControlledBy != m_pasLocal)
  1640. {
  1641. WARNING_OUT(("Ignoring REVOKE CONTROL from [%d], not in control of them",
  1642. pasHost->mcsID));
  1643. DC_QUIT;
  1644. }
  1645. if (pPacketRecv->hostControlID != pasHost->m_caControlID)
  1646. {
  1647. WARNING_OUT(("Ignoring REVOKE CONTROL from [%d], host ID out of date",
  1648. pasHost->mcsID, pPacketRecv->hostControlID));
  1649. DC_QUIT;
  1650. }
  1651. if (pPacketRecv->viewerControlID && (pPacketRecv->viewerControlID != m_pasLocal->m_caControlID))
  1652. {
  1653. WARNING_OUT(("Ignoring REVOKE CONTROL from [%d], viewer ID out of date",
  1654. pasHost->mcsID, pPacketRecv->viewerControlID));
  1655. DC_QUIT;
  1656. }
  1657. // Undo control, but no packet gets sent, we're just cleaning up.
  1658. CA_ReleaseControl(pasHost, FALSE);
  1659. DC_EXIT_POINT:
  1660. DebugExitVOID(ASShare::CAHandleInformRevokedControl);
  1661. }
  1662. void ASShare::CAHandleNewState
  1663. (
  1664. ASPerson * pasHost,
  1665. PCANOTPACKET pPacket
  1666. )
  1667. {
  1668. BOOL caOldAllowControl;
  1669. BOOL caNewAllowControl;
  1670. ASPerson * pasController;
  1671. DebugEntry(ASShare::CAHandleNewState);
  1672. //
  1673. // If this node isn't hosting, ignore this.
  1674. //
  1675. ValidatePerson(pasHost);
  1676. ASSERT(pasHost->hetCount);
  1677. //
  1678. // Update controllable state FIRST, so view window changes will
  1679. // reflect it.
  1680. //
  1681. caOldAllowControl = pasHost->m_caAllowControl;
  1682. caNewAllowControl = ((pPacket->state & CASTATE_ALLOWCONTROL) != 0);
  1683. if (!caNewAllowControl && (pasHost->m_caControlledBy == m_pasLocal))
  1684. {
  1685. //
  1686. // Fix up bogus notification
  1687. //
  1688. ERROR_OUT(("CA_STATE notification error! We're in control of [%d] but he says he's not controllable.",
  1689. pasHost->mcsID));
  1690. CA_ReleaseControl(pasHost, FALSE);
  1691. }
  1692. pasHost->m_caAllowControl = caNewAllowControl;
  1693. // Update/clear controller
  1694. if (!pPacket->controllerID)
  1695. {
  1696. pasController = NULL;
  1697. }
  1698. else
  1699. {
  1700. pasController = SC_PersonFromNetID(pPacket->controllerID);
  1701. if (pasController == pasHost)
  1702. {
  1703. ERROR_OUT(("Bogus controller, same as host [%d]", pPacket->controllerID));
  1704. pasController = NULL;
  1705. }
  1706. }
  1707. if (!CAClearHostState(pasHost, pasController))
  1708. {
  1709. // This failed. Put back old controllable state.
  1710. pasHost->m_caAllowControl = caOldAllowControl;
  1711. }
  1712. // Force a state change if the allow state has altered
  1713. if (caOldAllowControl != pasHost->m_caAllowControl)
  1714. {
  1715. VIEW_HostStateChange(pasHost);
  1716. }
  1717. DebugExitVOID(ASShare::CAHandleNewState);
  1718. }
  1719. //
  1720. // CAStartWaiting()
  1721. // Sets up vars for waiting state.
  1722. //
  1723. void ASShare::CAStartWaiting
  1724. (
  1725. ASPerson * pasWaitForReplyFrom,
  1726. UINT msgWaitForReplyFrom
  1727. )
  1728. {
  1729. DebugEntry(ASShare::CAStartWaiting);
  1730. ValidatePerson(pasWaitForReplyFrom);
  1731. ASSERT(msgWaitForReplyFrom);
  1732. ASSERT(!m_caWaitingForReplyFrom);
  1733. ASSERT(!m_caWaitingForReplyMsg);
  1734. m_caWaitingForReplyFrom = pasWaitForReplyFrom;
  1735. m_caWaitingForReplyMsg = msgWaitForReplyFrom;
  1736. DebugExitVOID(ASShare::CAStartWaiting);
  1737. }
  1738. //
  1739. // CA_ClearLocalState()
  1740. //
  1741. // Called to reset control state for LOCAL dude.
  1742. //
  1743. void ASShare::CA_ClearLocalState
  1744. (
  1745. UINT flags,
  1746. ASPerson * pasRemote,
  1747. BOOL fPacket
  1748. )
  1749. {
  1750. DebugEntry(ASShare::CA_ClearLocalState);
  1751. //
  1752. // Clear HOST stuff
  1753. //
  1754. if (flags & CACLEAR_HOST)
  1755. {
  1756. if (m_caWaitingForReplyMsg == CA_REPLY_REQUEST_GIVECONTROL)
  1757. {
  1758. if (!pasRemote || (pasRemote == m_caWaitingForReplyFrom))
  1759. {
  1760. // Kill the outstanding invitation to the remote
  1761. CA_CancelGiveControl(m_caWaitingForReplyFrom, fPacket);
  1762. }
  1763. }
  1764. if (m_caQueryDlg &&
  1765. ((m_caQuery.msg == CA_REQUEST_TAKECONTROL) ||
  1766. (m_caQuery.msg == CA_PREFER_PASSCONTROL)))
  1767. {
  1768. if (!pasRemote || (pasRemote == m_caQuery.pasReplyTo))
  1769. {
  1770. // Kill the user query dialog that's up
  1771. CACancelQuery(m_caQuery.pasReplyTo, fPacket);
  1772. }
  1773. }
  1774. if (m_pasLocal->m_caControlledBy)
  1775. {
  1776. if (!pasRemote || (pasRemote == m_pasLocal->m_caControlledBy))
  1777. {
  1778. CA_RevokeControl(m_pasLocal->m_caControlledBy, fPacket);
  1779. ASSERT(!m_pasLocal->m_caControlledBy);
  1780. }
  1781. }
  1782. }
  1783. //
  1784. // Clear VIEW stuff
  1785. //
  1786. if (flags & CACLEAR_VIEW)
  1787. {
  1788. if (m_caWaitingForReplyMsg == CA_REPLY_REQUEST_TAKECONTROL)
  1789. {
  1790. if (!pasRemote || (pasRemote == m_caWaitingForReplyFrom))
  1791. {
  1792. CA_CancelTakeControl(m_caWaitingForReplyFrom, fPacket);
  1793. }
  1794. }
  1795. if (m_caQueryDlg && (m_caQuery.msg == CA_REQUEST_GIVECONTROL))
  1796. {
  1797. if (!pasRemote || (pasRemote == m_caQuery.pasReplyTo))
  1798. {
  1799. // Kill the user query dialog that's up
  1800. CACancelQuery(m_caQuery.pasReplyTo, fPacket);
  1801. }
  1802. }
  1803. if (m_pasLocal->m_caInControlOf)
  1804. {
  1805. if (!pasRemote || (pasRemote == m_pasLocal->m_caInControlOf))
  1806. {
  1807. CA_ReleaseControl(m_pasLocal->m_caInControlOf, fPacket);
  1808. ASSERT(!m_pasLocal->m_caInControlOf);
  1809. }
  1810. }
  1811. }
  1812. DebugExitVOID(ASShare::CA_ClearLocalState);
  1813. }
  1814. //
  1815. // CAClearRemoteState()
  1816. //
  1817. // Called to reset all control state for a REMOTE node
  1818. //
  1819. void ASShare::CAClearRemoteState(ASPerson * pasClear)
  1820. {
  1821. DebugEntry(ASShare::CAClearRemoteState);
  1822. if (pasClear->m_caInControlOf)
  1823. {
  1824. CAClearHostState(pasClear->m_caInControlOf, NULL);
  1825. ASSERT(!pasClear->m_caInControlOf);
  1826. ASSERT(!pasClear->m_caControlledBy);
  1827. }
  1828. else if (pasClear->m_caControlledBy)
  1829. {
  1830. CAClearHostState(pasClear, NULL);
  1831. ASSERT(!pasClear->m_caControlledBy);
  1832. ASSERT(!pasClear->m_caInControlOf);
  1833. }
  1834. DebugExitVOID(ASShare:CAClearRemoteState);
  1835. }
  1836. //
  1837. // CAClearHostState()
  1838. //
  1839. // Called to clean up the mutual pointers when undoing a node's host state.
  1840. // We need to undo the previous states:
  1841. // * Clear the previous controller of the host
  1842. // * Clear the previous controller of the controller
  1843. // * Clear the previous controllee of the controller
  1844. //
  1845. // This may be recursive.
  1846. //
  1847. // It returns TRUE if the change takes effect, FALSE if it's ignored because
  1848. // it involves us and we have more recent information.
  1849. //
  1850. BOOL ASShare::CAClearHostState
  1851. (
  1852. ASPerson * pasHost,
  1853. ASPerson * pasController
  1854. )
  1855. {
  1856. BOOL rc = FALSE;
  1857. UINT gccID;
  1858. DebugEntry(ASShare::CAClearHostState);
  1859. ValidatePerson(pasHost);
  1860. //
  1861. // If nothing is changing, do nothing
  1862. //
  1863. if (pasHost->m_caControlledBy == pasController)
  1864. {
  1865. TRACE_OUT(("Ignoring control change; nothing's changing"));
  1866. rc = TRUE;
  1867. DC_QUIT;
  1868. }
  1869. //
  1870. // If the host is us, ignore.
  1871. // Also, if the host isn't hosting yet we got an in control change,
  1872. // ignore it too.
  1873. //
  1874. if ((pasHost == m_pasLocal) ||
  1875. (pasController && !pasHost->hetCount))
  1876. {
  1877. WARNING_OUT(("Ignoring control change; host is us or not sharing"));
  1878. DC_QUIT;
  1879. }
  1880. //
  1881. // UNDO any old state of the controller
  1882. //
  1883. if (pasController)
  1884. {
  1885. if (pasController == m_pasLocal)
  1886. {
  1887. TRACE_OUT(("Ignoring control with us as controller"));
  1888. DC_QUIT;
  1889. }
  1890. else if (pasController->m_caInControlOf)
  1891. {
  1892. ASSERT(!pasController->m_caControlledBy);
  1893. ASSERT(pasController->m_caInControlOf->m_caControlledBy == pasController);
  1894. rc = CAClearHostState(pasController->m_caInControlOf, NULL);
  1895. if (!rc)
  1896. {
  1897. DC_QUIT;
  1898. }
  1899. ASSERT(!pasController->m_caInControlOf);
  1900. }
  1901. else if (pasController->m_caControlledBy)
  1902. {
  1903. ASSERT(!pasController->m_caInControlOf);
  1904. ASSERT(pasController->m_caControlledBy->m_caInControlOf == pasController);
  1905. rc = CAClearHostState(pasController, NULL);
  1906. if (!rc)
  1907. {
  1908. DC_QUIT;
  1909. }
  1910. ASSERT(!pasController->m_caControlledBy);
  1911. }
  1912. }
  1913. //
  1914. // UNDO any old IN CONTROL state of the host
  1915. //
  1916. if (pasHost->m_caInControlOf)
  1917. {
  1918. ASSERT(!pasHost->m_caControlledBy);
  1919. ASSERT(pasHost->m_caInControlOf->m_caControlledBy == pasHost);
  1920. rc = CAClearHostState(pasHost->m_caInControlOf, NULL);
  1921. if (!rc)
  1922. {
  1923. DC_QUIT;
  1924. }
  1925. ASSERT(!pasHost->m_caInControlOf);
  1926. }
  1927. //
  1928. // FINALLY! Update CONTROLLED BY state of the host
  1929. //
  1930. // Clear OLD ControlledBy
  1931. if (pasHost->m_caControlledBy)
  1932. {
  1933. ASSERT(pasHost->m_caControlledBy->m_caInControlOf == pasHost);
  1934. pasHost->m_caControlledBy->m_caInControlOf = NULL;
  1935. }
  1936. // Set NEW ControlledBy
  1937. pasHost->m_caControlledBy = pasController;
  1938. if (pasController)
  1939. {
  1940. pasController->m_caInControlOf = pasHost;
  1941. gccID = pasController->cpcCaps.share.gccID;
  1942. }
  1943. else
  1944. {
  1945. gccID = 0;
  1946. }
  1947. VIEW_HostStateChange(pasHost);
  1948. //
  1949. // The hosts' controller has changed. Repaint the shadow cursor with/wo
  1950. // the new initials.
  1951. //
  1952. CM_UpdateShadowCursor(pasHost, pasHost->cmShadowOff, pasHost->cmPos.x,
  1953. pasHost->cmPos.y, pasHost->cmHotSpot.x, pasHost->cmHotSpot.y);
  1954. rc = TRUE;
  1955. DC_EXIT_POINT:
  1956. DebugExitBOOL(ASShare::CAClearHostState, rc);
  1957. return(rc);
  1958. }
  1959. //
  1960. // CAStartQuery()
  1961. //
  1962. // This puts up the modeless dialog to query the user about a control
  1963. // request. It will timeout if not handled.
  1964. //
  1965. BOOL ASShare::CAStartQuery
  1966. (
  1967. ASPerson * pasFrom,
  1968. UINT msg,
  1969. PCA30P pReq
  1970. )
  1971. {
  1972. BOOL rc = FALSE;
  1973. DebugEntry(ASShare::CAStartQuery);
  1974. ValidatePerson(pasFrom);
  1975. //
  1976. // We have no stacked queries. If another comes in while the current
  1977. // one is up, it gets an immediate failure busy.
  1978. //
  1979. ASSERT(!m_caQueryDlg);
  1980. ASSERT(!m_caQuery.pasReplyTo);
  1981. ASSERT(!m_caQuery.msg);
  1982. //
  1983. // Setup for new query
  1984. //
  1985. if (msg == CA_PREFER_PASSCONTROL)
  1986. {
  1987. //
  1988. // With forwarding, the person we're going to send a packet to
  1989. // if accepted is not the person who sent us the request. It's the
  1990. // person we're forwarding to.
  1991. //
  1992. m_caQuery.pasReplyTo = SC_PersonFromNetID(pReq->ppc.mcsPassTo);
  1993. ValidatePerson(m_caQuery.pasReplyTo);
  1994. }
  1995. else
  1996. {
  1997. m_caQuery.pasReplyTo = pasFrom;
  1998. }
  1999. m_caQuery.mcsOrg = pasFrom->mcsID;
  2000. m_caQuery.msg = msg;
  2001. m_caQuery.request = *pReq;
  2002. //
  2003. // If we are unattended, or the requester is unattended, instantly
  2004. // confirm. That's why we show the window after creating the dialog.
  2005. //
  2006. if ((m_pasLocal->cpcCaps.general.typeFlags & AS_UNATTENDED) ||
  2007. (pasFrom->cpcCaps.general.typeFlags & AS_UNATTENDED))
  2008. {
  2009. CAFinishQuery(CARESULT_CONFIRMED);
  2010. rc = TRUE;
  2011. }
  2012. else
  2013. {
  2014. //
  2015. // If this is a request to us && we're hosting, check auto-accept/
  2016. // auto-reject settings.
  2017. //
  2018. if (m_pHost &&
  2019. ((msg == CA_REQUEST_TAKECONTROL) || (msg == CA_PREFER_PASSCONTROL)))
  2020. {
  2021. if (m_pHost->m_caTempRejectRequests)
  2022. {
  2023. CAFinishQuery(CARESULT_DENIED_BUSY);
  2024. rc = TRUE;
  2025. DC_QUIT;
  2026. }
  2027. else if (m_pHost->m_caAutoAcceptRequests)
  2028. {
  2029. CAFinishQuery(CARESULT_CONFIRMED);
  2030. rc = TRUE;
  2031. DC_QUIT;
  2032. }
  2033. }
  2034. m_caQueryDlg = CreateDialogParam(g_asInstance,
  2035. MAKEINTRESOURCE(IDD_QUERY), NULL, CAQueryDlgProc, 0);
  2036. if (!m_caQueryDlg)
  2037. {
  2038. ERROR_OUT(("Failed to create query message box from [%d]",
  2039. pasFrom->mcsID));
  2040. m_caQuery.pasReplyTo = NULL;
  2041. m_caQuery.mcsOrg = 0;
  2042. m_caQuery.msg = 0;
  2043. }
  2044. else
  2045. {
  2046. // Success
  2047. rc = TRUE;
  2048. }
  2049. }
  2050. DC_EXIT_POINT:
  2051. DebugExitBOOL(ASShare::CAStartQuery, rc);
  2052. return(rc);
  2053. }
  2054. //
  2055. // CAFinishQuery()
  2056. //
  2057. // Called to finish the query we started, either because of UI or because
  2058. // we or the remote are unattended.
  2059. //
  2060. void ASShare::CAFinishQuery(UINT result)
  2061. {
  2062. CA30PENDING request;
  2063. DebugEntry(ASShare::CAFinishQuery);
  2064. ValidatePerson(m_caQuery.pasReplyTo);
  2065. // Make a copy of our request
  2066. request = m_caQuery;
  2067. //
  2068. // If we have a dialog up, destroy it NOW. Completing the request
  2069. // may cause us to be controlled or whatever. So get the dialog
  2070. // out of the way immediately.
  2071. //
  2072. // Note that destroying ourself will clear the request vars, hence the
  2073. // copy above.
  2074. //
  2075. if (m_caQueryDlg)
  2076. {
  2077. DestroyWindow(m_caQueryDlg);
  2078. }
  2079. else
  2080. {
  2081. m_caQuery.pasReplyTo = NULL;
  2082. m_caQuery.mcsOrg = 0;
  2083. m_caQuery.msg = 0;
  2084. }
  2085. switch (request.msg)
  2086. {
  2087. case CA_REQUEST_TAKECONTROL:
  2088. {
  2089. CACompleteRequestTakeControl(request.pasReplyTo,
  2090. &request.request.rtc, result);
  2091. break;
  2092. }
  2093. case CA_REQUEST_GIVECONTROL:
  2094. {
  2095. CACompleteRequestGiveControl(request.pasReplyTo,
  2096. &request.request.rgc, result);
  2097. break;
  2098. }
  2099. case CA_PREFER_PASSCONTROL:
  2100. {
  2101. CACompletePreferPassControl(request.pasReplyTo,
  2102. request.mcsOrg, &request.request.ppc, result);
  2103. break;
  2104. }
  2105. default:
  2106. {
  2107. ERROR_OUT(("Unrecognized query msg %d", request.msg));
  2108. break;
  2109. }
  2110. }
  2111. DebugExitVOID(ASShare::CAFinishQuery);
  2112. }
  2113. //
  2114. // CA_QueryDlgProc()
  2115. //
  2116. // Handles querying user dialog
  2117. //
  2118. INT_PTR CALLBACK CAQueryDlgProc
  2119. (
  2120. HWND hwnd,
  2121. UINT message,
  2122. WPARAM wParam,
  2123. LPARAM lParam
  2124. )
  2125. {
  2126. return(g_asSession.pShare->CA_QueryDlgProc(hwnd, message, wParam, lParam));
  2127. }
  2128. BOOL ASShare::CA_QueryDlgProc
  2129. (
  2130. HWND hwnd,
  2131. UINT message,
  2132. WPARAM wParam,
  2133. LPARAM lParam
  2134. )
  2135. {
  2136. BOOL rc = TRUE;
  2137. DebugEntry(CA_QueryDlgProc);
  2138. switch (message)
  2139. {
  2140. case WM_INITDIALOG:
  2141. {
  2142. char szT[256];
  2143. char szRes[512];
  2144. char szShared[64];
  2145. UINT idsTitle;
  2146. ASPerson * pasT;
  2147. HDC hdc;
  2148. HFONT hfn;
  2149. RECT rc;
  2150. RECT rcOwner;
  2151. ValidatePerson(m_caQuery.pasReplyTo);
  2152. pasT = NULL;
  2153. // Set title.
  2154. ASSERT(m_caQuery.msg);
  2155. switch (m_caQuery.msg)
  2156. {
  2157. case CA_REQUEST_TAKECONTROL:
  2158. {
  2159. idsTitle = IDS_TITLE_QUERY_TAKECONTROL;
  2160. if (m_pasLocal->hetCount == HET_DESKTOPSHARED)
  2161. LoadString(g_asInstance, IDS_DESKTOP_LOWER, szShared, sizeof(szShared));
  2162. else
  2163. LoadString(g_asInstance, IDS_PROGRAMS_LOWER, szShared, sizeof(szShared));
  2164. LoadString(g_asInstance, IDS_MSG_QUERY_TAKECONTROL, szT, sizeof(szT));
  2165. wsprintf(szRes, szT, m_caQuery.pasReplyTo->scName, szShared);
  2166. break;
  2167. }
  2168. case CA_REQUEST_GIVECONTROL:
  2169. {
  2170. if (m_caQuery.pasReplyTo->hetCount == HET_DESKTOPSHARED)
  2171. LoadString(g_asInstance, IDS_DESKTOP_LOWER, szShared, sizeof(szShared));
  2172. else
  2173. LoadString(g_asInstance, IDS_PROGRAMS_LOWER, szShared, sizeof(szShared));
  2174. if (m_caQuery.request.rgc.mcsPassFrom)
  2175. {
  2176. pasT = SC_PersonFromNetID(m_caQuery.request.rgc.mcsPassFrom);
  2177. }
  2178. if (pasT)
  2179. {
  2180. idsTitle = IDS_TITLE_QUERY_YIELDCONTROL;
  2181. LoadString(g_asInstance, IDS_MSG_QUERY_YIELDCONTROL,
  2182. szT, sizeof(szT));
  2183. wsprintf(szRes, szT, pasT->scName, m_caQuery.pasReplyTo->scName, szShared);
  2184. }
  2185. else
  2186. {
  2187. idsTitle = IDS_TITLE_QUERY_GIVECONTROL;
  2188. LoadString(g_asInstance, IDS_MSG_QUERY_GIVECONTROL,
  2189. szT, sizeof(szT));
  2190. wsprintf(szRes, szT, m_caQuery.pasReplyTo->scName, szShared);
  2191. }
  2192. break;
  2193. }
  2194. case CA_PREFER_PASSCONTROL:
  2195. {
  2196. pasT = SC_PersonFromNetID(m_caQuery.mcsOrg);
  2197. ValidatePerson(pasT);
  2198. idsTitle = IDS_TITLE_QUERY_FORWARDCONTROL;
  2199. if (m_pasLocal->hetCount == HET_DESKTOPSHARED)
  2200. LoadString(g_asInstance, IDS_DESKTOP_LOWER, szShared, sizeof(szShared));
  2201. else
  2202. LoadString(g_asInstance, IDS_PROGRAMS_LOWER, szShared, sizeof(szShared));
  2203. LoadString(g_asInstance, IDS_MSG_QUERY_FORWARDCONTROL, szT, sizeof(szT));
  2204. wsprintf(szRes, szT, pasT->scName, szShared, m_caQuery.pasReplyTo->scName);
  2205. break;
  2206. }
  2207. default:
  2208. {
  2209. ERROR_OUT(("Bogus m_caQuery.msg %d", m_caQuery.msg));
  2210. break;
  2211. }
  2212. }
  2213. LoadString(g_asInstance, idsTitle, szT, sizeof(szT));
  2214. SetWindowText(hwnd, szT);
  2215. // Set message.
  2216. SetDlgItemText(hwnd, CTRL_QUERY, szRes);
  2217. // Center the message vertically
  2218. GetWindowRect(GetDlgItem(hwnd, CTRL_QUERY), &rcOwner);
  2219. MapWindowPoints(NULL, hwnd, (LPPOINT)&rcOwner, 2);
  2220. rc = rcOwner;
  2221. hdc = GetDC(hwnd);
  2222. hfn = (HFONT)SendDlgItemMessage(hwnd, CTRL_QUERY, WM_GETFONT, 0, 0);
  2223. hfn = SelectFont(hdc, hfn);
  2224. DrawText(hdc, szRes, -1, &rc, DT_NOCLIP | DT_EXPANDTABS |
  2225. DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
  2226. SelectFont(hdc, hfn);
  2227. ReleaseDC(hwnd, hdc);
  2228. ASSERT((rc.bottom - rc.top) <= (rcOwner.bottom - rcOwner.top));
  2229. SetWindowPos(GetDlgItem(hwnd, CTRL_QUERY), NULL,
  2230. rcOwner.left,
  2231. ((rcOwner.top + rcOwner.bottom) - (rc.bottom - rc.top)) / 2,
  2232. (rcOwner.right - rcOwner.left),
  2233. rc.bottom - rc.top,
  2234. SWP_NOACTIVATE | SWP_NOZORDER);
  2235. SetTimer(hwnd, IDT_CAQUERY, PERIOD_CAQUERY, 0);
  2236. //
  2237. // Show window, the user will handle
  2238. //
  2239. ShowWindow(hwnd, SW_SHOWNORMAL);
  2240. SetForegroundWindow(hwnd);
  2241. UpdateWindow(hwnd);
  2242. break;
  2243. }
  2244. case WM_COMMAND:
  2245. {
  2246. switch (GET_WM_COMMAND_ID(wParam, lParam))
  2247. {
  2248. case IDOK:
  2249. {
  2250. CAFinishQuery(CARESULT_CONFIRMED);
  2251. break;
  2252. }
  2253. case IDCANCEL:
  2254. {
  2255. CAFinishQuery(CARESULT_DENIED_USER);
  2256. break;
  2257. }
  2258. }
  2259. break;
  2260. }
  2261. case WM_TIMER:
  2262. {
  2263. if (wParam != IDT_CAQUERY)
  2264. {
  2265. rc = FALSE;
  2266. }
  2267. else
  2268. {
  2269. KillTimer(hwnd, IDT_CAQUERY);
  2270. // Timed out failure.
  2271. CAFinishQuery(CARESULT_DENIED_TIMEDOUT);
  2272. }
  2273. break;
  2274. }
  2275. case WM_DESTROY:
  2276. {
  2277. //
  2278. // Clear pending info
  2279. //
  2280. m_caQueryDlg = NULL;
  2281. m_caQuery.pasReplyTo = NULL;
  2282. m_caQuery.mcsOrg = 0;
  2283. m_caQuery.msg = 0;
  2284. break;
  2285. }
  2286. default:
  2287. {
  2288. rc = FALSE;
  2289. break;
  2290. }
  2291. }
  2292. DebugExitBOOL(CA_QueryDlgProc, rc);
  2293. return(rc);
  2294. }
  2295. //
  2296. // CACancelQuery()
  2297. //
  2298. // If a dialog is up for a take control request, it hasn't been handled yet,
  2299. // and we get a cancel notification from the viewer, we need to take the
  2300. // dialog down WITHOUT generating a response packet.
  2301. //
  2302. void ASShare::CACancelQuery
  2303. (
  2304. ASPerson * pasFrom,
  2305. BOOL fPacket
  2306. )
  2307. {
  2308. DebugEntry(ASShare::CACancelQuery);
  2309. ASSERT(m_caQueryDlg);
  2310. ASSERT(m_caQuery.pasReplyTo == pasFrom);
  2311. if (fPacket)
  2312. {
  2313. // This will send a packet then destroy the dialog
  2314. CAFinishQuery(CARESULT_DENIED);
  2315. }
  2316. else
  2317. {
  2318. // Destroy the dialog
  2319. DestroyWindow(m_caQueryDlg);
  2320. }
  2321. ASSERT(!m_caQueryDlg);
  2322. ASSERT(!m_caQuery.pasReplyTo);
  2323. ASSERT(!m_caQuery.msg);
  2324. DebugExitVOID(ASShare::CACancelQuery);
  2325. }
  2326.