Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2059 lines
52 KiB

  1. // ServerNode.cpp: implementation of the CServerNode class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #define __FILE_ID__ 23
  6. #ifdef _DEBUG
  7. #undef THIS_FILE
  8. static char THIS_FILE[]=__FILE__;
  9. #define new DEBUG_NEW
  10. #endif
  11. IMPLEMENT_DYNAMIC(CServerNode, CTreeNode)
  12. //////////////////////////////////////////////////////////////////////
  13. // Construction/Destruction
  14. //////////////////////////////////////////////////////////////////////
  15. CServerNode::CServerNode() :
  16. CTreeNode(FOLDER_TYPE_SERVER),
  17. m_bValid(TRUE),
  18. m_dwRights (0),
  19. m_dwQueueState (0),
  20. m_bSelfDestruct (FALSE),
  21. m_hConnection (NULL),
  22. m_hNotification (NULL),
  23. m_bCsBuildupValid (FALSE),
  24. m_bCsBuildupThreadValid(FALSE),
  25. m_hBuildupThread (NULL),
  26. m_bInBuildup (FALSE),
  27. m_dwLastRPCError (0),
  28. m_Inbox (FOLDER_TYPE_INBOX, FAX_MESSAGE_FOLDER_INBOX),
  29. m_SentItems (FOLDER_TYPE_SENT_ITEMS, FAX_MESSAGE_FOLDER_SENTITEMS),
  30. m_Outbox (FOLDER_TYPE_OUTBOX, JT_SEND),
  31. m_Incoming (FOLDER_TYPE_INCOMING, JT_RECEIVE | JT_ROUTING)
  32. {}
  33. CServerNode::~CServerNode()
  34. {
  35. DBG_ENTER(TEXT("CServerNode::~CServerNode"), TEXT("%s"), m_cstrMachine);
  36. DWORD dwRes = StopBuildThread ();
  37. if (ERROR_SUCCESS != dwRes)
  38. {
  39. CALL_FAIL (GENERAL_ERR, TEXT("CServerNode::StopBuildThread"), dwRes);
  40. }
  41. dwRes = Disconnect (TRUE); // Shutdown aware
  42. if (ERROR_SUCCESS != dwRes)
  43. {
  44. CALL_FAIL (GENERAL_ERR, TEXT("CServerNode::Disconnect"), dwRes);
  45. }
  46. if (m_bCsBuildupValid)
  47. {
  48. DeleteCriticalSection (&m_csBuildup);
  49. }
  50. if(m_bCsBuildupThreadValid)
  51. {
  52. DeleteCriticalSection (&m_csBuildupThread);
  53. }
  54. }
  55. void CServerNode::AssertValid() const
  56. {
  57. CObject::AssertValid();
  58. }
  59. void CServerNode::Dump( CDumpContext &dc ) const
  60. {
  61. CObject::Dump( dc );
  62. dc << TEXT(" Server = ") << m_cstrMachine;
  63. }
  64. //
  65. // Static class members:
  66. //
  67. CServerNode::MESSAGES_MAP CServerNode::m_sMsgs;
  68. DWORD CServerNode::m_sdwMinFreeMsg = WM_SERVER_NOTIFY_BASE;
  69. CRITICAL_SECTION CServerNode::m_sMsgsCs;
  70. BOOL CServerNode::m_sbMsgsCsInitialized = FALSE;
  71. DWORD
  72. CServerNode::InitMsgsMap ()
  73. /*++
  74. Routine name : CServerNode::InitMsgsMap
  75. Routine description:
  76. Initializes the notification messages map
  77. Author:
  78. Eran Yariv (EranY), Jan, 2000
  79. Arguments:
  80. Return Value:
  81. Standard Win32 error code
  82. --*/
  83. {
  84. DWORD dwRes = ERROR_SUCCESS;
  85. DBG_ENTER(TEXT("CServerNode::InitMsgsMap"), dwRes);
  86. ASSERTION (!m_sbMsgsCsInitialized);
  87. try
  88. {
  89. InitializeCriticalSection (&m_sMsgsCs);
  90. }
  91. catch (...)
  92. {
  93. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  94. CALL_FAIL (MEM_ERR, TEXT ("InitializeCriticalSection"), dwRes);
  95. return dwRes;
  96. }
  97. m_sbMsgsCsInitialized = TRUE;
  98. return dwRes;
  99. } // CServerNode::InitMsgsMap
  100. DWORD
  101. CServerNode::ShutdownMsgsMap ()
  102. /*++
  103. Routine name : CServerNode::ShutdownMsgsMap
  104. Routine description:
  105. Shuts down the notification messages map
  106. Author:
  107. Eran Yariv (EranY), Jan, 2000
  108. Arguments:
  109. Return Value:
  110. Standard Win32 error code
  111. --*/
  112. {
  113. DWORD dwRes = ERROR_SUCCESS;
  114. DBG_ENTER(TEXT("CServerNode::ShutdownMsgsMap"), dwRes);
  115. if (!m_sbMsgsCsInitialized)
  116. {
  117. return dwRes;
  118. }
  119. EnterCriticalSection (&m_sMsgsCs);
  120. m_sMsgs.clear ();
  121. LeaveCriticalSection (&m_sMsgsCs);
  122. m_sbMsgsCsInitialized = FALSE;
  123. DeleteCriticalSection (&m_sMsgsCs);
  124. return dwRes;
  125. } // CServerNode::ShutdownMsgsMap
  126. CServerNode *
  127. CServerNode::LookupServerFromMessageId (
  128. DWORD dwMsgId
  129. )
  130. /*++
  131. Routine name : CServerNode::LookupServerFromMessageId
  132. Routine description:
  133. Given a mesage id, looks up the server this message was sent to
  134. Author:
  135. Eran Yariv (EranY), Jan, 2000
  136. Arguments:
  137. dwMsgId [in] - Message id
  138. Return Value:
  139. Server node that should process the message or NULL if message id is not mapped
  140. --*/
  141. {
  142. DBG_ENTER(TEXT("CServerNode::LookupServerFromMessageId"), TEXT("%ld"), dwMsgId);
  143. CServerNode *pRes = NULL;
  144. if (!m_sbMsgsCsInitialized)
  145. {
  146. return pRes;
  147. }
  148. EnterCriticalSection (&m_sMsgsCs);
  149. MESSAGES_MAP::iterator it = m_sMsgs.find (dwMsgId);
  150. if (m_sMsgs.end() == it)
  151. {
  152. //
  153. // Item not found there
  154. //
  155. VERBOSE (DBG_MSG,
  156. TEXT("Notification message %ld has no associated server"),
  157. dwMsgId);
  158. }
  159. else
  160. {
  161. pRes = (*it).second;
  162. }
  163. LeaveCriticalSection (&m_sMsgsCs);
  164. return pRes;
  165. } // CServerNode::LookupServerFromMessageId
  166. DWORD
  167. CServerNode::AllocateNewMessageId (
  168. CServerNode *pServer,
  169. DWORD &dwMsgId
  170. )
  171. /*++
  172. Routine name : CServerNode::AllocateNewMessageId
  173. Routine description:
  174. Allocates a new message id for server's notification
  175. Author:
  176. Eran Yariv (EranY), Jan, 2000
  177. Arguments:
  178. pServer [in] - Pointer to server
  179. dwMsgId [out] - New message id
  180. Return Value:
  181. Standard Win32 error code
  182. --*/
  183. {
  184. DWORD dwRes = ERROR_SUCCESS;
  185. DBG_ENTER(TEXT("CServerNode::AllocateNewMessageId"), dwRes, TEXT("%s"), pServer->Machine());
  186. if (!m_sbMsgsCsInitialized)
  187. {
  188. //
  189. // Map no longer exists
  190. //
  191. dwRes = ERROR_SHUTDOWN_IN_PROGRESS;
  192. return dwRes;
  193. }
  194. EnterCriticalSection (&m_sMsgsCs);
  195. for (DWORD dw = m_sdwMinFreeMsg; ; dw++)
  196. {
  197. CServerNode *pSrv = LookupServerFromMessageId (dw);
  198. if (!pSrv)
  199. {
  200. //
  201. // Free spot found
  202. //
  203. dwMsgId = dw;
  204. try
  205. {
  206. m_sMsgs[dwMsgId] = pServer;
  207. }
  208. catch (...)
  209. {
  210. //
  211. // Not enough memory
  212. //
  213. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  214. CALL_FAIL (MEM_ERR, TEXT("map::operator []"), dwRes);
  215. goto exit;
  216. }
  217. //
  218. // Success
  219. //
  220. VERBOSE (DBG_MSG,
  221. TEXT("Server %s registered for notification on message 0x%08x"),
  222. pServer->Machine(),
  223. dwMsgId);
  224. goto exit;
  225. }
  226. }
  227. exit:
  228. LeaveCriticalSection (&m_sMsgsCs);
  229. return dwRes;
  230. } // CServerNode::AllocateNewMessageId
  231. DWORD
  232. CServerNode::FreeMessageId (
  233. DWORD dwMsgId
  234. )
  235. /*++
  236. Routine name : CServerNode::FreeMessageId
  237. Routine description:
  238. Frees a message id back to the map
  239. Author:
  240. Eran Yariv (EranY), Jan, 2000
  241. Arguments:
  242. dwMsgId [in] - Message id to free
  243. Return Value:
  244. Standard Win32 error code
  245. --*/
  246. {
  247. DWORD dwRes = ERROR_SUCCESS;
  248. DBG_ENTER(TEXT("CServerNode::FreeMessageId"), dwRes);
  249. if (!m_sbMsgsCsInitialized)
  250. {
  251. //
  252. // Map no longer exists
  253. //
  254. dwRes = ERROR_SHUTDOWN_IN_PROGRESS;
  255. return dwRes;
  256. }
  257. EnterCriticalSection (&m_sMsgsCs);
  258. try
  259. {
  260. m_sMsgs.erase (dwMsgId);
  261. }
  262. catch (...)
  263. {
  264. //
  265. // Not enough memory
  266. //
  267. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  268. CALL_FAIL (MEM_ERR, TEXT("map::erase"), dwRes);
  269. goto exit;
  270. }
  271. //
  272. // Success
  273. //
  274. VERBOSE (DBG_MSG,
  275. TEXT("Server unregistered for notification on message 0x%08x"),
  276. dwMsgId);
  277. if (dwMsgId < m_sdwMinFreeMsg)
  278. {
  279. //
  280. // Free spot was created lower than before.
  281. //
  282. m_sdwMinFreeMsg = dwMsgId;
  283. }
  284. exit:
  285. LeaveCriticalSection (&m_sMsgsCs);
  286. return dwRes;
  287. } // CServerNode::FreeMessageId
  288. DWORD
  289. CServerNode::Connect()
  290. /*++
  291. Routine name : CServerNode::Connect
  292. Routine description:
  293. Connects to the fax server
  294. Author:
  295. Eran Yariv (EranY), Jan, 2000
  296. Arguments:
  297. Return Value:
  298. Standard Win32 error code
  299. --*/
  300. {
  301. DWORD dwRes = ERROR_SUCCESS;
  302. DBG_ENTER(TEXT("CServerNode::Connect"), dwRes, TEXT("%s"), m_cstrMachine);
  303. ASSERTION (!m_hConnection);
  304. START_RPC_TIME(TEXT("FaxConnectFaxServer"));
  305. if (!FaxConnectFaxServer ((LPCTSTR)m_cstrMachine, &m_hConnection))
  306. {
  307. dwRes = GetLastError ();
  308. SetLastRPCError (dwRes, FALSE); // Don't disconnect on error
  309. CALL_FAIL (RPC_ERR, TEXT("FaxConnectFaxServer"), dwRes);
  310. m_hConnection = NULL;
  311. }
  312. END_RPC_TIME(TEXT("FaxConnectFaxServer"));
  313. return dwRes;
  314. } // CServerNode::Connect
  315. DWORD
  316. CServerNode::Disconnect(
  317. BOOL bShutdownAware,
  318. BOOL bWaitForBuildThread
  319. )
  320. /*++
  321. Routine name : CServerNode::Disconnect
  322. Routine description:
  323. Disconnects from the server and closes the notification handle.
  324. Author:
  325. Eran Yariv (EranY), Jan, 2000
  326. Arguments:
  327. bShutdownAware [in] - If TRUE, disables disconnection
  328. while application is shutting down
  329. bWaitForBuildThread [in] - If TRUE, wait for build threads stop
  330. Return Value:
  331. Standard Win32 error code
  332. --*/
  333. {
  334. DWORD dwRes = ERROR_SUCCESS;
  335. DBG_ENTER(TEXT("CServerNode::Disconnect"), dwRes, TEXT("%s"), m_cstrMachine);
  336. if(bWaitForBuildThread)
  337. {
  338. //
  339. // just turn on m_bStopBuildup flag
  340. //
  341. StopBuildThread (FALSE);
  342. m_Inbox.StopBuildThread(FALSE);
  343. m_SentItems.StopBuildThread(FALSE);
  344. m_Outbox.StopBuildThread(FALSE);
  345. m_Incoming.StopBuildThread(FALSE);
  346. //
  347. // wait for the all threads finish
  348. //
  349. dwRes = StopBuildThread();
  350. if (ERROR_SUCCESS != dwRes)
  351. {
  352. CALL_FAIL (GENERAL_ERR, TEXT("CServerNode::StopBuildThread"), dwRes);
  353. }
  354. dwRes = m_Inbox.StopBuildThread();
  355. if (ERROR_SUCCESS != dwRes)
  356. {
  357. CALL_FAIL (GENERAL_ERR, TEXT("m_Inbox.StopBuildThread"), dwRes);
  358. }
  359. dwRes = m_SentItems.StopBuildThread();
  360. if (ERROR_SUCCESS != dwRes)
  361. {
  362. CALL_FAIL (GENERAL_ERR, TEXT("m_SentItems.StopBuildThread"), dwRes);
  363. }
  364. dwRes = m_Outbox.StopBuildThread();
  365. if (ERROR_SUCCESS != dwRes)
  366. {
  367. CALL_FAIL (GENERAL_ERR, TEXT("m_Outbox.StopBuildThread"), dwRes);
  368. }
  369. dwRes = m_Incoming.StopBuildThread();
  370. if (ERROR_SUCCESS != dwRes)
  371. {
  372. CALL_FAIL (GENERAL_ERR, TEXT("m_Incoming.StopBuildThread"), dwRes);
  373. }
  374. }
  375. if (!m_hConnection)
  376. {
  377. //
  378. // Already disconnected
  379. //
  380. return dwRes;
  381. }
  382. if (bShutdownAware && CClientConsoleDoc::ShuttingDown())
  383. {
  384. VERBOSE (DBG_MSG,
  385. TEXT("Left open connection (and notification) to %s because we're shutting down."),
  386. m_cstrMachine);
  387. return dwRes;
  388. }
  389. if (m_hNotification)
  390. {
  391. //
  392. // Unregister server notifications
  393. //
  394. START_RPC_TIME(TEXT("FaxUnregisterForServerEvents"));
  395. if (!FaxUnregisterForServerEvents (m_hNotification))
  396. {
  397. dwRes = GetLastError ();
  398. END_RPC_TIME(TEXT("FaxUnregisterForServerEvents"));
  399. SetLastRPCError (dwRes, FALSE); // Don't disconnect on error
  400. CALL_FAIL (RPC_ERR, TEXT("FaxUnregisterForServerEvents"), dwRes);
  401. //
  402. // Carry on with disconnection
  403. //
  404. }
  405. END_RPC_TIME(TEXT("FaxUnregisterForServerEvents"));
  406. //
  407. // Free the message id back to the map
  408. //
  409. dwRes = FreeMessageId (m_dwMsgId);
  410. if (ERROR_SUCCESS != dwRes)
  411. {
  412. CALL_FAIL (GENERAL_ERR, TEXT("FreeMessageId"), dwRes);
  413. //
  414. // Carry on with disconnection
  415. //
  416. }
  417. }
  418. //
  419. // Close connection
  420. //
  421. START_RPC_TIME(TEXT("FaxClose"));
  422. if (!FaxClose (m_hConnection))
  423. {
  424. dwRes = GetLastError ();
  425. END_RPC_TIME(TEXT("FaxClose"));
  426. SetLastRPCError (dwRes, FALSE); // Don't disconnect on error
  427. CALL_FAIL (RPC_ERR, TEXT("FaxClose"), dwRes);
  428. m_hConnection = NULL;
  429. return dwRes;
  430. }
  431. END_RPC_TIME(TEXT("FaxClose"));
  432. m_hConnection = NULL;
  433. m_hNotification = NULL;
  434. return dwRes;
  435. } // CServerNode::Disconnect
  436. DWORD
  437. CServerNode::GetConnectionHandle (
  438. HANDLE &hFax
  439. )
  440. /*++
  441. Routine name : CServerNode::GetConnectionHandle
  442. Routine description:
  443. Retrieves connection handle (re-connects if neeed)
  444. Author:
  445. Eran Yariv (EranY), Jan, 2000
  446. Arguments:
  447. hFax [out] - Connection handle
  448. Return Value:
  449. Standard Win32 error code
  450. --*/
  451. {
  452. DWORD dwRes = ERROR_SUCCESS;
  453. DBG_ENTER(TEXT("CServerNode::GetConnectionHandle"), dwRes);
  454. //
  455. // Protect the m_hBuildupThread from CloseHandle() more then once
  456. //
  457. EnterCriticalSection (&m_csBuildupThread);
  458. if (m_hConnection)
  459. {
  460. //
  461. // We already have a live connection
  462. //
  463. hFax = m_hConnection;
  464. goto exit;
  465. }
  466. //
  467. // Refresh server state with first connection.
  468. // RefreshState() creates a background thread that will call Connect()
  469. //
  470. dwRes = RefreshState();
  471. if (ERROR_SUCCESS != dwRes)
  472. {
  473. CALL_FAIL (GENERAL_ERR, TEXT ("RefreshState"), dwRes);
  474. goto exit;
  475. }
  476. if(NULL != m_hBuildupThread)
  477. {
  478. //
  479. // Wait for that background thread to end
  480. //
  481. dwRes = WaitForThreadDeathOrShutdown (m_hBuildupThread);
  482. if (ERROR_SUCCESS != dwRes)
  483. {
  484. CALL_FAIL (GENERAL_ERR, TEXT("WaitForThreadDeathOrShutdown"), dwRes);
  485. }
  486. CloseHandle (m_hBuildupThread);
  487. m_hBuildupThread = NULL;
  488. }
  489. hFax = m_hConnection;
  490. if(!hFax)
  491. {
  492. dwRes = ERROR_INVALID_HANDLE;
  493. }
  494. exit:
  495. LeaveCriticalSection (&m_csBuildupThread);
  496. return dwRes;
  497. } // CServerNode::GetConnectionHandle
  498. DWORD
  499. CServerNode::Init (
  500. LPCTSTR tstrMachine
  501. )
  502. /*++
  503. Routine name : CServerNode::Init
  504. Routine description:
  505. Inits server node information
  506. Author:
  507. Eran Yariv (EranY), Jan, 2000
  508. Arguments:
  509. tstrMachine [in] - Server machine name
  510. Return Value:
  511. Standard Win32 error code
  512. --*/
  513. {
  514. DWORD dwRes = ERROR_SUCCESS;
  515. DBG_ENTER(TEXT("CServerNode::Init"), dwRes);
  516. ASSERTION (!m_bCsBuildupValid);
  517. ASSERTION (!m_hConnection);
  518. //
  519. // Create buildup thread critical section
  520. //
  521. try
  522. {
  523. InitializeCriticalSection (&m_csBuildup);
  524. }
  525. catch (...)
  526. {
  527. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  528. CALL_FAIL (MEM_ERR, TEXT ("InitializeCriticalSection(&m_csBuildup)"), dwRes);
  529. return dwRes;
  530. }
  531. m_bCsBuildupValid = TRUE;
  532. try
  533. {
  534. InitializeCriticalSection (&m_csBuildupThread);
  535. }
  536. catch (...)
  537. {
  538. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  539. CALL_FAIL (MEM_ERR, TEXT ("InitializeCriticalSection(&m_csBuildupThread)"), dwRes);
  540. return dwRes;
  541. }
  542. m_bCsBuildupThreadValid = TRUE;
  543. //
  544. // Save our connection + server names
  545. //
  546. try
  547. {
  548. m_cstrMachine = tstrMachine;
  549. //
  550. // Remove leading backslashes from machine's name
  551. //
  552. m_cstrMachine.Remove (TEXT('\\'));
  553. }
  554. catch (CException *pException)
  555. {
  556. TCHAR wszCause[1024];
  557. pException->GetErrorMessage (wszCause, 1024);
  558. pException->Delete ();
  559. VERBOSE (EXCEPTION_ERR,
  560. TEXT("CString::operator = caused exception : %s"),
  561. wszCause);
  562. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  563. return dwRes;
  564. }
  565. dwRes = CreateFolders ();
  566. if (ERROR_SUCCESS != dwRes)
  567. {
  568. CALL_FAIL (GENERAL_ERR, TEXT("CreateFolders"), dwRes);
  569. }
  570. return dwRes;
  571. } // CServerNode::Init
  572. DWORD
  573. CServerNode::SetNewQueueState (
  574. DWORD dwNewState
  575. )
  576. /*++
  577. Routine name : CServerNode::SetNewQueueState
  578. Routine description:
  579. Sets the news state of the queue
  580. Author:
  581. Eran Yariv (EranY), Jan, 2000
  582. Arguments:
  583. dwNewState [in] - New queue state
  584. Return Value:
  585. Standard Win32 error code
  586. --*/
  587. {
  588. HANDLE hFax;
  589. DWORD dwRes;
  590. DBG_ENTER(TEXT("CServerNode::SetNewQueueState"), dwRes);
  591. dwRes = GetConnectionHandle(hFax);
  592. if (ERROR_SUCCESS != dwRes)
  593. {
  594. return dwRes;
  595. }
  596. START_RPC_TIME(TEXT("FaxSetQueue"));
  597. if (!FaxSetQueue (hFax, dwNewState))
  598. {
  599. dwRes = GetLastError ();
  600. END_RPC_TIME(TEXT("FaxSetQueue"));
  601. SetLastRPCError (dwRes);
  602. CALL_FAIL (RPC_ERR, TEXT("FaxSetQueue"), dwRes);
  603. return dwRes;
  604. }
  605. END_RPC_TIME(TEXT("FaxSetQueue"));
  606. return dwRes;
  607. } // CServerNode::SetNewQueueState
  608. DWORD
  609. CServerNode::BlockIncoming (
  610. BOOL bBlock
  611. )
  612. /*++
  613. Routine name : CServerNode::BlockIncoming
  614. Routine description:
  615. Blocks / unblocks the incoming queue
  616. Author:
  617. Eran Yariv (EranY), Jan, 2000
  618. Arguments:
  619. bBlock [in] - TRUE if block
  620. Return Value:
  621. Standard Win32 error code
  622. --*/
  623. {
  624. DWORD dwRes;
  625. DBG_ENTER(TEXT("CServerNode::BlockIncoming"), dwRes);
  626. DWORD dwNewState = bBlock ? (m_dwQueueState | FAX_INCOMING_BLOCKED) :
  627. (m_dwQueueState & ~FAX_INCOMING_BLOCKED);
  628. dwRes = SetNewQueueState (dwNewState);
  629. if (ERROR_SUCCESS == dwRes)
  630. {
  631. m_dwQueueState = dwNewState;
  632. }
  633. return dwRes;
  634. } // CServerNode::BlockIncoming
  635. DWORD
  636. CServerNode::BlockOutbox (
  637. BOOL bBlock
  638. )
  639. /*++
  640. Routine name : CServerNode::BlockOutbox
  641. Routine description:
  642. Blocks / unblocks the outgoing queue
  643. Author:
  644. Eran Yariv (EranY), Jan, 2000
  645. Arguments:
  646. bBlock [in] - TRUE if block
  647. Return Value:
  648. Standard Win32 error code
  649. --*/
  650. {
  651. DWORD dwRes;
  652. DBG_ENTER(TEXT("CServerNode::BlockOutbox"), dwRes);
  653. DWORD dwNewState = bBlock ? (m_dwQueueState | FAX_OUTBOX_BLOCKED) :
  654. (m_dwQueueState & ~FAX_OUTBOX_BLOCKED);
  655. dwRes = SetNewQueueState (dwNewState);
  656. if (ERROR_SUCCESS == dwRes)
  657. {
  658. m_dwQueueState = dwNewState;
  659. }
  660. return dwRes;
  661. } // CServerNode::BlockOutbox
  662. DWORD
  663. CServerNode::PauseOutbox (
  664. BOOL bPause
  665. )
  666. /*++
  667. Routine name : CServerNode::PauseOutbox
  668. Routine description:
  669. Pauses / resumes the outgoing queue
  670. Author:
  671. Eran Yariv (EranY), Jan, 2000
  672. Arguments:
  673. bPause [in] - TRUE if pause
  674. Return Value:
  675. Standard Win32 error code
  676. --*/
  677. {
  678. DWORD dwRes;
  679. DBG_ENTER(TEXT("CServerNode::PauseOutbox"), dwRes);
  680. DWORD dwNewState = bPause ? (m_dwQueueState | FAX_OUTBOX_PAUSED) :
  681. (m_dwQueueState & ~FAX_OUTBOX_PAUSED);
  682. dwRes = SetNewQueueState (dwNewState);
  683. if (ERROR_SUCCESS == dwRes)
  684. {
  685. m_dwQueueState = dwNewState;
  686. }
  687. return dwRes;
  688. } // CServerNode::PauseOutbox
  689. DWORD
  690. CServerNode::CreateFolders ()
  691. /*++
  692. Routine name : CServerNode::CreateFolders
  693. Routine description:
  694. Creates the 4 folders of the server
  695. Author:
  696. Eran Yariv (EranY), Jan, 2000
  697. Arguments:
  698. Return Value:
  699. Standard Win32 error code
  700. --*/
  701. {
  702. DWORD dwRes = ERROR_SUCCESS;
  703. DBG_ENTER(TEXT("CServerNode::CreateFolders"), dwRes);
  704. //
  705. // Create inbox folder
  706. //
  707. m_Inbox.SetServer(this);
  708. dwRes = m_Inbox.Init ();
  709. if (ERROR_SUCCESS != dwRes)
  710. {
  711. CALL_FAIL (WINDOW_ERR, TEXT("CMessageFolder::Init"), dwRes);
  712. goto error;
  713. }
  714. //
  715. // Create outbox folder
  716. //
  717. m_Outbox.SetServer(this);
  718. dwRes = m_Outbox.Init ();
  719. if (ERROR_SUCCESS != dwRes)
  720. {
  721. CALL_FAIL (WINDOW_ERR, TEXT("CQueueFolder::Init"), dwRes);
  722. goto error;
  723. }
  724. //
  725. // Create sentitems folder
  726. //
  727. m_SentItems.SetServer(this);
  728. dwRes = m_SentItems.Init ();
  729. if (ERROR_SUCCESS != dwRes)
  730. {
  731. CALL_FAIL (WINDOW_ERR, TEXT("CMessageFolder::Init"), dwRes);
  732. goto error;
  733. }
  734. //
  735. // Create incoming folder
  736. //
  737. m_Incoming.SetServer(this);
  738. dwRes = m_Incoming.Init ();
  739. if (ERROR_SUCCESS != dwRes)
  740. {
  741. CALL_FAIL (WINDOW_ERR, TEXT("CQueueFolder::Init"), dwRes);
  742. goto error;
  743. }
  744. ASSERTION (ERROR_SUCCESS == dwRes);
  745. error:
  746. return dwRes;
  747. } // CServerNode::CreateFolders
  748. DWORD
  749. CServerNode::InvalidateSubFolders (
  750. BOOL bClearView
  751. )
  752. /*++
  753. Routine name : CServerNode::InvalidateSubFolders
  754. Routine description:
  755. Invalidates the contents of all 4 sub folders
  756. Author:
  757. Eran Yariv (EranY), Jan, 2000
  758. Arguments:
  759. bClearView [in] Should we clear attached view ?
  760. Return Value:
  761. Standard Win32 error code
  762. --*/
  763. {
  764. DWORD dwRes = ERROR_SUCCESS;
  765. DBG_ENTER(TEXT("CServerNode::InvalidateSubFolders"), dwRes);
  766. dwRes = m_Inbox.InvalidateContents (bClearView);
  767. if (ERROR_SUCCESS != dwRes)
  768. {
  769. CALL_FAIL (GENERAL_ERR, TEXT("m_Inbox.InvalidateContents"), dwRes);
  770. return dwRes;
  771. }
  772. dwRes = m_Outbox.InvalidateContents (bClearView);
  773. if (ERROR_SUCCESS != dwRes)
  774. {
  775. CALL_FAIL (GENERAL_ERR, TEXT("m_Outbox.InvalidateContents"), dwRes);
  776. return dwRes;
  777. }
  778. dwRes = m_SentItems.InvalidateContents (bClearView);
  779. if (ERROR_SUCCESS != dwRes)
  780. {
  781. CALL_FAIL (GENERAL_ERR, TEXT("m_SentItems.InvalidateContents"), dwRes);
  782. return dwRes;
  783. }
  784. dwRes = m_Incoming.InvalidateContents (bClearView);
  785. if (ERROR_SUCCESS != dwRes)
  786. {
  787. CALL_FAIL (GENERAL_ERR, TEXT("m_Incoming.InvalidateContents"), dwRes);
  788. return dwRes;
  789. }
  790. return dwRes;
  791. } // CServerNode::InvalidateSubFolders
  792. //
  793. // Buildup thread functions:
  794. //
  795. DWORD
  796. CServerNode::ClearContents ()
  797. /*++
  798. Routine name : CServerNode::ClearContents
  799. Routine description:
  800. Clears the server's contents
  801. Author:
  802. Eran Yariv (EranY), Jan, 2000
  803. Arguments:
  804. Return Value:
  805. Standard Win32 error code
  806. --*/
  807. {
  808. DWORD dwRes;
  809. DBG_ENTER(TEXT("CServerNode::ClearContents"), dwRes);
  810. dwRes = Disconnect ();
  811. if (ERROR_SUCCESS != dwRes)
  812. {
  813. CALL_FAIL (RPC_ERR, TEXT("Disconnect"), dwRes);
  814. return dwRes;
  815. }
  816. dwRes = InvalidateSubFolders(FALSE);
  817. if (ERROR_SUCCESS != dwRes)
  818. {
  819. CALL_FAIL (RPC_ERR, TEXT("InvalidateSubFolders"), dwRes);
  820. return dwRes;
  821. }
  822. return dwRes;
  823. } // CServerNode::ClearContents
  824. DWORD
  825. CServerNode::RefreshState()
  826. /*++
  827. Routine name : CServerNode::RefreshState
  828. Routine description:
  829. Refreshes the server's state
  830. Author:
  831. Eran Yariv (EranY), Jan, 2000
  832. Arguments:
  833. Return Value:
  834. Standard Win32 error code
  835. --*/
  836. {
  837. DWORD dwRes;
  838. DBG_ENTER(TEXT("CServerNode::RefreshState"), dwRes, TEXT("%s"), m_cstrMachine);
  839. DWORD dwThreadId;
  840. //
  841. // Stop the current (if any) buildup thread and make sure it's dead
  842. //
  843. dwRes = StopBuildThread ();
  844. EnterCriticalSection (&m_csBuildup);
  845. if (ERROR_SUCCESS != dwRes)
  846. {
  847. CALL_FAIL (RESOURCE_ERR, TEXT("CServerNode::StopBuildThread"), dwRes);
  848. goto exit;
  849. }
  850. //
  851. // Tell our view to refresh our image
  852. //
  853. m_bInBuildup = TRUE;
  854. //
  855. // Start the thread that will fill the data (in the background)
  856. //
  857. m_bStopBuildup = FALSE;
  858. m_hBuildupThread = CreateThread (
  859. NULL, // No security
  860. 0, // Default stack size
  861. BuildupThreadProc, // Thread procedure
  862. (LPVOID)this, // Parameter
  863. 0, // Normal creation
  864. &dwThreadId // We must have a thread id for win9x
  865. );
  866. if (NULL == m_hBuildupThread)
  867. {
  868. dwRes = GetLastError ();
  869. CALL_FAIL (RESOURCE_ERR, TEXT("CreateThread"), dwRes);
  870. goto exit;
  871. }
  872. ASSERTION (ERROR_SUCCESS == dwRes);
  873. exit:
  874. LeaveCriticalSection (&m_csBuildup);
  875. if (ERROR_SUCCESS != dwRes)
  876. {
  877. //
  878. // Build up failed
  879. //
  880. m_bInBuildup = FALSE;
  881. }
  882. return dwRes;
  883. } // CServerNode::RefreshState
  884. DWORD
  885. CServerNode::Buildup ()
  886. /*++
  887. Routine name : CServerNode::Buildup
  888. Routine description:
  889. Server refresh worker thread function.
  890. Works in a background thread and performs the following:
  891. 1. FaxConnectFaxServer (if not already connected)
  892. 2. FaxGetQueueStates
  893. 3. FaxAccessCheckEx (MAXIMUM_ALLOWED)
  894. 4. FaxRegisterForServerEvents
  895. Author:
  896. Eran Yariv (EranY), Jan, 2000
  897. Arguments:
  898. Return Value:
  899. Standard Win32 error code
  900. --*/
  901. {
  902. DWORD dwRes = ERROR_SUCCESS;
  903. DBG_ENTER(TEXT("CServerNode::Buildup"), dwRes, TEXT("%s"), m_cstrMachine);
  904. HANDLE hFax;
  905. HWND hwnd;
  906. CMainFrame *pMainFrm = NULL;
  907. DWORD dwEventTypes = FAX_EVENT_TYPE_OUT_QUEUE | // Outbox events
  908. FAX_EVENT_TYPE_QUEUE_STATE | // Paused / blocked queue events
  909. FAX_EVENT_TYPE_OUT_ARCHIVE | // SentItems events
  910. FAX_EVENT_TYPE_FXSSVC_ENDED; // Server shutdown events
  911. //
  912. // get connection
  913. //
  914. if (m_hConnection)
  915. {
  916. hFax = m_hConnection;
  917. }
  918. else
  919. {
  920. dwRes = Connect ();
  921. if (ERROR_SUCCESS != dwRes)
  922. {
  923. goto exit;
  924. }
  925. ASSERTION (m_hConnection);
  926. hFax = m_hConnection;
  927. }
  928. if (m_bStopBuildup)
  929. {
  930. //
  931. // Thread should stop abruptly
  932. //
  933. dwRes = ERROR_CANCELLED;
  934. goto exit;
  935. }
  936. {
  937. START_RPC_TIME(TEXT("FaxGetQueueStates"));
  938. if (!FaxGetQueueStates (hFax, &m_dwQueueState))
  939. {
  940. dwRes = GetLastError ();
  941. END_RPC_TIME(TEXT("FaxGetQueueStates"));
  942. SetLastRPCError (dwRes);
  943. CALL_FAIL (RPC_ERR, TEXT("FaxGetQueueStates"), dwRes);
  944. goto exit;
  945. }
  946. END_RPC_TIME(TEXT("FaxGetQueueStates"));
  947. }
  948. if (m_bStopBuildup)
  949. {
  950. //
  951. // Thread should stop abruptly
  952. //
  953. dwRes = ERROR_CANCELLED;
  954. goto exit;
  955. }
  956. {
  957. //
  958. // retrieve the access rights of the caller
  959. //
  960. START_RPC_TIME(TEXT("FaxAccessCheckEx"));
  961. if (!FaxAccessCheckEx (hFax, MAXIMUM_ALLOWED, &m_dwRights))
  962. {
  963. dwRes = GetLastError ();
  964. END_RPC_TIME(TEXT("FaxAccessCheckEx"));
  965. SetLastRPCError (dwRes);
  966. CALL_FAIL (RPC_ERR, TEXT("FaxAccessCheckEx"), dwRes);
  967. goto exit;
  968. }
  969. END_RPC_TIME(TEXT("FaxAccessCheckEx"));
  970. }
  971. if (m_bStopBuildup)
  972. {
  973. //
  974. // Thread should stop abruptly
  975. //
  976. dwRes = ERROR_CANCELLED;
  977. goto exit;
  978. }
  979. //
  980. // Register for notifications - start by allocating a message id
  981. //
  982. if(m_hNotification)
  983. {
  984. //
  985. // already registered
  986. //
  987. goto exit;
  988. }
  989. dwRes = AllocateNewMessageId (this, m_dwMsgId);
  990. if (ERROR_SUCCESS != dwRes)
  991. {
  992. CALL_FAIL (GENERAL_ERR, TEXT("AllocateNewMessageId"), dwRes);
  993. goto exit;
  994. }
  995. //
  996. // Ask the server for a notification handle
  997. //
  998. pMainFrm = GetFrm();
  999. if (NULL == pMainFrm)
  1000. {
  1001. //
  1002. // No main frame - probably we're shutting down
  1003. //
  1004. goto exit;
  1005. }
  1006. hwnd = pMainFrm->m_hWnd;
  1007. if (CanSeeAllJobs())
  1008. {
  1009. dwEventTypes |= FAX_EVENT_TYPE_IN_QUEUE; // Incoming folder events
  1010. }
  1011. if (CanSeeInbox())
  1012. {
  1013. dwEventTypes |= FAX_EVENT_TYPE_IN_ARCHIVE; // Inbox folder events
  1014. }
  1015. {
  1016. START_RPC_TIME(TEXT("FaxRegisterForServerEvents"));
  1017. if (!FaxRegisterForServerEvents (
  1018. hFax,
  1019. dwEventTypes, // Types of events to receive
  1020. NULL, // Not using completion ports
  1021. 0, // Not using completion ports
  1022. hwnd, // Handle of window to receive notification messages
  1023. m_dwMsgId, // Message id
  1024. &m_hNotification// Notification handle
  1025. ))
  1026. {
  1027. dwRes = GetLastError ();
  1028. SetLastRPCError (dwRes, FALSE); // Do not auto-disconnect
  1029. CALL_FAIL (RPC_ERR, TEXT("FaxRegisterForServerEvents"), dwRes);
  1030. m_hNotification = NULL;
  1031. goto exit;
  1032. }
  1033. END_RPC_TIME(TEXT("FaxRegisterForServerEvents"));
  1034. }
  1035. ASSERTION (ERROR_SUCCESS == dwRes);
  1036. exit:
  1037. m_bInBuildup = FALSE;
  1038. if (!m_bStopBuildup)
  1039. {
  1040. if (ERROR_SUCCESS != dwRes)
  1041. {
  1042. //
  1043. // Some error occured during refresh
  1044. //
  1045. Disconnect (FALSE, FALSE);
  1046. }
  1047. }
  1048. //
  1049. // Check if the frame still alive
  1050. //
  1051. pMainFrm = GetFrm();
  1052. if (pMainFrm)
  1053. {
  1054. pMainFrm->RefreshStatusBar ();
  1055. }
  1056. return dwRes;
  1057. } // CServerNode::Buildup
  1058. DWORD
  1059. WINAPI
  1060. CServerNode::BuildupThreadProc (
  1061. LPVOID lpParameter
  1062. )
  1063. /*++
  1064. Routine name : CServerNode::BuildupThreadProc
  1065. Routine description:
  1066. Server refresh thread entry point.
  1067. This is a static function which accepts a pointer to the actual CServerNode instance
  1068. and calls the Buildup function on the real instance.
  1069. Author:
  1070. Eran Yariv (EranY), Jan, 2000
  1071. Arguments:
  1072. lpParameter [in] - Pointer to server node that created the thread
  1073. Return Value:
  1074. Standard Win32 error code
  1075. --*/
  1076. {
  1077. DWORD dwRes = ERROR_SUCCESS;
  1078. DBG_ENTER(TEXT("CServerNode::BuildupThreadProc"), dwRes);
  1079. CServerNode *pServer = (CServerNode *)lpParameter;
  1080. ASSERTION (pServer);
  1081. ASSERT_KINDOF (CServerNode, pServer);
  1082. dwRes = pServer->Buildup ();
  1083. if (pServer->m_bSelfDestruct)
  1084. {
  1085. //
  1086. // Object was waiting for thread to stop before it could destruct itself
  1087. //
  1088. delete pServer;
  1089. }
  1090. return dwRes;
  1091. } // CServerNode::BuildupThreadProc
  1092. DWORD
  1093. CServerNode::StopBuildThread (
  1094. BOOL bWaitForDeath
  1095. )
  1096. /*++
  1097. Routine name : CServerNode::StopBuildThread
  1098. Routine description:
  1099. Stops the server's buildup thread
  1100. Author:
  1101. Eran Yariv (EranY), Jan, 2000
  1102. Arguments:
  1103. bWaitForDeath [in] - If TRUE, waits until the thread is dead
  1104. Return Value:
  1105. Standard Win32 error code
  1106. --*/
  1107. {
  1108. DWORD dwRes = ERROR_SUCCESS;
  1109. DBG_ENTER(TEXT("CServerNode::StopBuildThread"), dwRes);
  1110. m_bStopBuildup = TRUE;
  1111. if (!bWaitForDeath)
  1112. {
  1113. return dwRes;
  1114. }
  1115. //
  1116. // Protect the m_hBuildupThread from CloseHandle() more then once
  1117. //
  1118. if(!m_bCsBuildupThreadValid)
  1119. {
  1120. return dwRes;
  1121. }
  1122. EnterCriticalSection (&m_csBuildupThread);
  1123. if(NULL == m_hBuildupThread)
  1124. {
  1125. goto exit;
  1126. }
  1127. //
  1128. // Wait for build thread to die
  1129. //
  1130. dwRes = WaitForThreadDeathOrShutdown (m_hBuildupThread);
  1131. if (ERROR_SUCCESS != dwRes)
  1132. {
  1133. CALL_FAIL (GENERAL_ERR, TEXT("WaitForThreadDeathOrShutdown"), dwRes);
  1134. }
  1135. CloseHandle (m_hBuildupThread);
  1136. m_hBuildupThread = NULL;
  1137. exit:
  1138. LeaveCriticalSection (&m_csBuildupThread);
  1139. return dwRes;
  1140. } // CServerNode::StopBuildThread
  1141. BOOL
  1142. CServerNode::FatalRPCError (
  1143. DWORD dwErr
  1144. )
  1145. /*++
  1146. Routine name : CServerNode::FatalRPCError
  1147. Routine description:
  1148. Checks if an error code means a fatal RPC connection state
  1149. Author:
  1150. Eran Yariv (EranY), Feb, 2000
  1151. Arguments:
  1152. dwErr [in] - Error code to check
  1153. Return Value:
  1154. TRUE if error code means a fatal RPC connection state, FALSE otherwise.
  1155. --*/
  1156. {
  1157. BOOL bRes = FALSE;
  1158. DBG_ENTER(TEXT("CServerNode::FatalRPCError"), bRes);
  1159. switch (bRes)
  1160. {
  1161. case RPC_S_INVALID_BINDING:
  1162. case EPT_S_CANT_PERFORM_OP:
  1163. case RPC_S_ADDRESS_ERROR:
  1164. case RPC_S_COMM_FAILURE:
  1165. case RPC_S_NO_BINDINGS:
  1166. case RPC_S_SERVER_UNAVAILABLE:
  1167. //
  1168. // Something really bad happened to our RPC connection
  1169. //
  1170. bRes = TRUE;
  1171. break;
  1172. }
  1173. return bRes;
  1174. } // CServerNode::FatalRPCError
  1175. void
  1176. CServerNode::SetLastRPCError (
  1177. DWORD dwErr,
  1178. BOOL DisconnectOnFailure
  1179. )
  1180. /*++
  1181. Routine name : CServerNode::SetLastRPCError
  1182. Routine description:
  1183. Sets the last RPC error encountered on this server
  1184. Author:
  1185. Eran Yariv (EranY), Jan, 2000
  1186. Arguments:
  1187. dwErr [in] - Error code
  1188. DisconnectOnFailure [in] - If TRUE, disconnects from the server upon error
  1189. Return Value:
  1190. None.
  1191. --*/
  1192. {
  1193. DBG_ENTER(TEXT("CServerNode::SetLastRPCError"), TEXT("%ld"), dwErr);
  1194. m_dwLastRPCError = dwErr;
  1195. if (DisconnectOnFailure && FatalRPCError(dwErr))
  1196. {
  1197. //
  1198. // We have a real failure here - disconnect now.
  1199. //
  1200. DWORD dwRes = Disconnect ();
  1201. if (ERROR_SUCCESS != dwRes)
  1202. {
  1203. CALL_FAIL (RPC_ERR, TEXT("CServerNode::Disconnect"), dwRes);
  1204. }
  1205. }
  1206. } // CServerNode::SetLastRPCError
  1207. void
  1208. CServerNode::Destroy ()
  1209. /*++
  1210. Routine name : CServerNode::Destroy
  1211. Routine description:
  1212. Destroys the server's node.
  1213. Since the dtor is private, this is the only way to destroy the server node.
  1214. If the server is not busy refreshing itself, it deletes itself.
  1215. Otherwise, it signals a suicide request and the thread destorys the node.
  1216. Author:
  1217. Eran Yariv (EranY), Jan, 2000
  1218. Arguments:
  1219. Return Value:
  1220. None.
  1221. --*/
  1222. {
  1223. if (m_bSelfDestruct)
  1224. {
  1225. //
  1226. // Already being destroyed
  1227. //
  1228. return;
  1229. }
  1230. EnterCriticalSection (&m_csBuildup);
  1231. m_bSelfDestruct = TRUE;
  1232. if (m_hBuildupThread)
  1233. {
  1234. //
  1235. // Thread is running, just mark request for self-destruction
  1236. //
  1237. LeaveCriticalSection (&m_csBuildup);
  1238. }
  1239. else
  1240. {
  1241. //
  1242. // Suicide
  1243. //
  1244. LeaveCriticalSection (&m_csBuildup);
  1245. try
  1246. {
  1247. delete this;
  1248. }
  1249. catch (...)
  1250. {
  1251. DBG_ENTER(TEXT("CServerNode::Destroy"));
  1252. CALL_FAIL (GENERAL_ERR, TEXT("CServerNode::Destructor exception"), 0);
  1253. ASSERTION_FAILURE;
  1254. }
  1255. }
  1256. } // CServerNode::Destroy
  1257. DWORD
  1258. CServerNode::GetActivity(
  1259. CString& cstrText,
  1260. TreeIconType& iconIndex
  1261. ) const
  1262. /*++
  1263. Routine name : CServerNode::GetActivityStringResource
  1264. Routine description:
  1265. Returns the resource id of a string identifying the activity of the server
  1266. Author:
  1267. Eran Yariv (EranY), Jan, 2000
  1268. Arguments:
  1269. cstrText [out] - activity string
  1270. iconIndex [out] - icon index
  1271. Return Value:
  1272. Activity string resource id
  1273. --*/
  1274. {
  1275. DWORD dwRes = ERROR_SUCCESS;
  1276. DBG_ENTER(TEXT("CServerNode::GetActivity"), dwRes);
  1277. DWORD dwStrRes = 0;
  1278. if (IsRefreshing())
  1279. {
  1280. iconIndex = TREE_IMAGE_SERVER_REFRESHING;
  1281. dwStrRes = IDS_SERVER_REFRESHING;
  1282. }
  1283. else if (IsOnline ())
  1284. {
  1285. if (IsOutboxBlocked())
  1286. {
  1287. //
  1288. // Server's Outgoing queue is blocked
  1289. //
  1290. iconIndex = TREE_IMAGE_OUTBOX_BLOCKED;
  1291. dwStrRes = IDS_SERVER_OUTBOX_BLOCKED;
  1292. }
  1293. else if (IsOutboxPaused())
  1294. {
  1295. //
  1296. // Server's Outgoing queue is paused
  1297. //
  1298. iconIndex = TREE_IMAGE_OUTBOX_PAUSED;
  1299. dwStrRes = IDS_SERVER_OUTBOX_PAUSED;
  1300. }
  1301. else
  1302. {
  1303. //
  1304. // Server's Outgoing queue is fully functional
  1305. //
  1306. iconIndex = TREE_IMAGE_SERVER_ONLINE;
  1307. dwStrRes = IDS_SERVER_ONLINE;
  1308. }
  1309. }
  1310. else
  1311. {
  1312. iconIndex = TREE_IMAGE_SERVER_OFFLINE;
  1313. //
  1314. // Server is offline
  1315. //
  1316. if (RPC_S_SERVER_UNAVAILABLE == m_dwLastRPCError)
  1317. {
  1318. //
  1319. // The RPC server is unavailable.
  1320. //
  1321. dwStrRes = IDS_SERVER_OFFLINE;
  1322. }
  1323. else
  1324. {
  1325. //
  1326. // General network / RPC error
  1327. //
  1328. dwStrRes = IDS_SERVER_NET_ERROR;
  1329. }
  1330. }
  1331. dwRes = LoadResourceString(cstrText, dwStrRes);
  1332. if(ERROR_SUCCESS != dwRes)
  1333. {
  1334. CALL_FAIL (GENERAL_ERR, TEXT("LoadResourceString"), dwRes);
  1335. return dwRes;
  1336. }
  1337. return dwRes;
  1338. } // CServerNode::GetActivityStringResource
  1339. DWORD
  1340. CServerNode::OnNotificationMessage (
  1341. PFAX_EVENT_EX pEvent
  1342. )
  1343. {
  1344. DWORD dwRes = ERROR_SUCCESS;
  1345. DBG_ENTER(TEXT("CServerNode::OnNotificationMessage"), dwRes);
  1346. ASSERTION (pEvent);
  1347. switch (pEvent->EventType)
  1348. {
  1349. case FAX_EVENT_TYPE_IN_QUEUE:
  1350. //
  1351. // Something happened in the incoming folder
  1352. //
  1353. if (m_Incoming.Locked() || !m_Incoming.IsValid())
  1354. {
  1355. //
  1356. // Folder is locked or invalid - do not process notifications
  1357. //
  1358. dwRes = ERROR_LOCK_VIOLATION;
  1359. VERBOSE (DBG_MSG,
  1360. TEXT("Incoming folder is locked or invalid - notification is NOT processed"));
  1361. return dwRes;
  1362. }
  1363. switch (pEvent->EventInfo.JobInfo.Type)
  1364. {
  1365. case FAX_JOB_EVENT_TYPE_ADDED:
  1366. //
  1367. // A job was added
  1368. //
  1369. VERBOSE (DBG_MSG,
  1370. TEXT("Got server notification from %s - ")
  1371. TEXT("FAX_EVENT_TYPE_IN_QUEUE / FAX_JOB_EVENT_TYPE_ADDED")
  1372. TEXT(" / 0x%016I64x"),
  1373. m_cstrMachine,
  1374. pEvent->EventInfo.JobInfo.dwlMessageId);
  1375. dwRes = m_Incoming.OnJobAdded (pEvent->EventInfo.JobInfo.dwlMessageId);
  1376. break;
  1377. case FAX_JOB_EVENT_TYPE_REMOVED:
  1378. //
  1379. // A job was removed
  1380. //
  1381. VERBOSE (DBG_MSG,
  1382. TEXT("Got server notification from %s - ")
  1383. TEXT("FAX_EVENT_TYPE_IN_QUEUE / FAX_JOB_EVENT_TYPE_REMOVED")
  1384. TEXT(" / 0x%016I64x"),
  1385. m_cstrMachine,
  1386. pEvent->EventInfo.JobInfo.dwlMessageId);
  1387. dwRes = m_Incoming.OnJobRemoved (pEvent->EventInfo.JobInfo.dwlMessageId);
  1388. break;
  1389. case FAX_JOB_EVENT_TYPE_STATUS:
  1390. //
  1391. // A job has changed its status
  1392. //
  1393. VERBOSE (DBG_MSG,
  1394. TEXT("Got server notification from %s - ")
  1395. TEXT("FAX_EVENT_TYPE_IN_QUEUE / FAX_JOB_EVENT_TYPE_STATUS")
  1396. TEXT(" / 0x%016I64x (status = 0x%08x)"),
  1397. m_cstrMachine,
  1398. pEvent->EventInfo.JobInfo.dwlMessageId,
  1399. pEvent->EventInfo.JobInfo.pJobData->dwQueueStatus);
  1400. if((pEvent->EventInfo.JobInfo.pJobData->dwQueueStatus & JS_COMPLETED) ||
  1401. (pEvent->EventInfo.JobInfo.pJobData->dwQueueStatus & JS_CANCELED))
  1402. {
  1403. //
  1404. // don't display completed or canceled jobs
  1405. //
  1406. dwRes = m_Incoming.OnJobRemoved (pEvent->EventInfo.JobInfo.dwlMessageId);
  1407. }
  1408. else
  1409. {
  1410. dwRes = m_Incoming.OnJobUpdated (pEvent->EventInfo.JobInfo.dwlMessageId,
  1411. pEvent->EventInfo.JobInfo.pJobData);
  1412. }
  1413. break;
  1414. default:
  1415. dwRes = ERROR_GEN_FAILURE;
  1416. VERBOSE (DBG_MSG,
  1417. TEXT("Got unknown server notification from %s - ")
  1418. TEXT("FAX_EVENT_TYPE_IN_QUEUE / %d / 0x%016I64x"),
  1419. m_cstrMachine,
  1420. pEvent->EventInfo.JobInfo.Type,
  1421. pEvent->EventInfo.JobInfo.dwlMessageId);
  1422. break;
  1423. }
  1424. break;
  1425. case FAX_EVENT_TYPE_OUT_QUEUE:
  1426. //
  1427. // Something happened in the outbox folder
  1428. //
  1429. if (m_Outbox.Locked() || !m_Outbox.IsValid())
  1430. {
  1431. //
  1432. // Folder is locked or invalid - do not process notifications
  1433. //
  1434. dwRes = ERROR_LOCK_VIOLATION;
  1435. VERBOSE (DBG_MSG,
  1436. TEXT("Outbox folder is locked or invalid - notification is NOT processed"));
  1437. return dwRes;
  1438. }
  1439. switch (pEvent->EventInfo.JobInfo.Type)
  1440. {
  1441. case FAX_JOB_EVENT_TYPE_ADDED:
  1442. //
  1443. // A job was added
  1444. //
  1445. VERBOSE (DBG_MSG,
  1446. TEXT("Got server notification from %s - ")
  1447. TEXT("FAX_EVENT_TYPE_OUT_QUEUE / FAX_JOB_EVENT_TYPE_ADDED")
  1448. TEXT(" / 0x%016I64x"),
  1449. m_cstrMachine,
  1450. pEvent->EventInfo.JobInfo.dwlMessageId);
  1451. dwRes = m_Outbox.OnJobAdded (pEvent->EventInfo.JobInfo.dwlMessageId);
  1452. break;
  1453. case FAX_JOB_EVENT_TYPE_REMOVED:
  1454. //
  1455. // A job was removed
  1456. //
  1457. VERBOSE (DBG_MSG,
  1458. TEXT("Got server notification from %s - ")
  1459. TEXT("FAX_EVENT_TYPE_OUT_QUEUE / FAX_JOB_EVENT_TYPE_REMOVED")
  1460. TEXT(" / 0x%016I64x"),
  1461. m_cstrMachine,
  1462. pEvent->EventInfo.JobInfo.dwlMessageId);
  1463. dwRes = m_Outbox.OnJobRemoved (pEvent->EventInfo.JobInfo.dwlMessageId);
  1464. break;
  1465. case FAX_JOB_EVENT_TYPE_STATUS:
  1466. //
  1467. // A job has changed its status
  1468. //
  1469. VERBOSE (DBG_MSG,
  1470. TEXT("Got server notification from %s - ")
  1471. TEXT("FAX_EVENT_TYPE_OUT_QUEUE / FAX_JOB_EVENT_TYPE_STATUS")
  1472. TEXT(" / 0x%016I64x (status = 0x%08x)"),
  1473. m_cstrMachine,
  1474. pEvent->EventInfo.JobInfo.dwlMessageId,
  1475. pEvent->EventInfo.JobInfo.pJobData->dwQueueStatus);
  1476. if((pEvent->EventInfo.JobInfo.pJobData->dwQueueStatus & JS_COMPLETED) ||
  1477. (pEvent->EventInfo.JobInfo.pJobData->dwQueueStatus & JS_CANCELED))
  1478. {
  1479. //
  1480. // don't display completed or canceled jobs
  1481. //
  1482. dwRes = m_Outbox.OnJobRemoved (pEvent->EventInfo.JobInfo.dwlMessageId);
  1483. }
  1484. else
  1485. {
  1486. dwRes = m_Outbox.OnJobUpdated (pEvent->EventInfo.JobInfo.dwlMessageId,
  1487. pEvent->EventInfo.JobInfo.pJobData);
  1488. }
  1489. break;
  1490. default:
  1491. dwRes = ERROR_GEN_FAILURE;
  1492. VERBOSE (DBG_MSG,
  1493. TEXT("Got unknown server notification from %s - ")
  1494. TEXT("FAX_EVENT_TYPE_OUT_QUEUE / %d / 0x%016I64x"),
  1495. m_cstrMachine,
  1496. pEvent->EventInfo.JobInfo.Type,
  1497. pEvent->EventInfo.JobInfo.dwlMessageId);
  1498. break;
  1499. }
  1500. break;
  1501. case FAX_EVENT_TYPE_QUEUE_STATE:
  1502. //
  1503. // Queue states have changed.
  1504. // Update internal data with new queue states.
  1505. //
  1506. VERBOSE (DBG_MSG,
  1507. TEXT("Got server notification from %s - FAX_EVENT_TYPE_QUEUE_STATE / %d"),
  1508. m_cstrMachine,
  1509. pEvent->EventInfo.dwQueueStates);
  1510. //
  1511. // Assert valid values only
  1512. //
  1513. ASSERTION (0 == (pEvent->EventInfo.dwQueueStates & ~(FAX_INCOMING_BLOCKED |
  1514. FAX_OUTBOX_BLOCKED |
  1515. FAX_OUTBOX_PAUSED)));
  1516. m_dwQueueState = pEvent->EventInfo.dwQueueStates;
  1517. break;
  1518. case FAX_EVENT_TYPE_IN_ARCHIVE:
  1519. //
  1520. // Something happened in the Inbox folder
  1521. //
  1522. if (m_Inbox.Locked() || !m_Inbox.IsValid())
  1523. {
  1524. //
  1525. // Folder is locked or invalid - do not process notifications
  1526. //
  1527. dwRes = ERROR_LOCK_VIOLATION;
  1528. VERBOSE (DBG_MSG,
  1529. TEXT("Inbox folder is locked or invalid - notification is NOT processed"));
  1530. return dwRes;
  1531. }
  1532. switch (pEvent->EventInfo.JobInfo.Type)
  1533. {
  1534. case FAX_JOB_EVENT_TYPE_ADDED:
  1535. //
  1536. // A message was added
  1537. //
  1538. VERBOSE (DBG_MSG,
  1539. TEXT("Got server notification from %s - ")
  1540. TEXT("FAX_EVENT_TYPE_IN_ARCHIVE / FAX_JOB_EVENT_TYPE_ADDED")
  1541. TEXT(" / 0x%016I64x"),
  1542. m_cstrMachine,
  1543. pEvent->EventInfo.JobInfo.dwlMessageId);
  1544. dwRes = m_Inbox.OnJobAdded (pEvent->EventInfo.JobInfo.dwlMessageId);
  1545. break;
  1546. case FAX_JOB_EVENT_TYPE_REMOVED:
  1547. //
  1548. // A message was removed
  1549. //
  1550. VERBOSE (DBG_MSG,
  1551. TEXT("Got server notification from %s - ")
  1552. TEXT("FAX_EVENT_TYPE_IN_ARCHIVE / FAX_JOB_EVENT_TYPE_REMOVED")
  1553. TEXT(" / 0x%016I64x"),
  1554. m_cstrMachine,
  1555. pEvent->EventInfo.JobInfo.dwlMessageId);
  1556. dwRes = m_Inbox.OnJobRemoved (pEvent->EventInfo.JobInfo.dwlMessageId);
  1557. break;
  1558. default:
  1559. dwRes = ERROR_GEN_FAILURE;
  1560. VERBOSE (DBG_MSG,
  1561. TEXT("Got unknown server notification from %s - ")
  1562. TEXT("FAX_EVENT_TYPE_IN_ARCHIVE / %d / 0x%016I64x"),
  1563. m_cstrMachine,
  1564. pEvent->EventInfo.JobInfo.Type,
  1565. pEvent->EventInfo.JobInfo.dwlMessageId);
  1566. break;
  1567. }
  1568. break;
  1569. case FAX_EVENT_TYPE_OUT_ARCHIVE:
  1570. //
  1571. // Something happened in the SentItems folder
  1572. //
  1573. if (m_SentItems.Locked() || !m_SentItems.IsValid())
  1574. {
  1575. //
  1576. // Folder is locked or invalid - do not process notifications
  1577. //
  1578. dwRes = ERROR_LOCK_VIOLATION;
  1579. VERBOSE (DBG_MSG,
  1580. TEXT("SentItems folder is locked or invalid - notification is NOT processed"));
  1581. return dwRes;
  1582. }
  1583. switch (pEvent->EventInfo.JobInfo.Type)
  1584. {
  1585. case FAX_JOB_EVENT_TYPE_ADDED:
  1586. //
  1587. // A message was added
  1588. //
  1589. VERBOSE (DBG_MSG,
  1590. TEXT("Got server notification from %s - ")
  1591. TEXT("FAX_EVENT_TYPE_OUT_ARCHIVE / FAX_JOB_EVENT_TYPE_ADDED")
  1592. TEXT(" / 0x%016I64x"),
  1593. m_cstrMachine,
  1594. pEvent->EventInfo.JobInfo.dwlMessageId);
  1595. dwRes = m_SentItems.OnJobAdded (pEvent->EventInfo.JobInfo.dwlMessageId);
  1596. break;
  1597. case FAX_JOB_EVENT_TYPE_REMOVED:
  1598. //
  1599. // A message was removed
  1600. //
  1601. VERBOSE (DBG_MSG,
  1602. TEXT("Got server notification from %s - ")
  1603. TEXT("FAX_EVENT_TYPE_OUT_ARCHIVE / FAX_JOB_EVENT_TYPE_REMOVED")
  1604. TEXT(" / 0x%016I64x"),
  1605. m_cstrMachine,
  1606. pEvent->EventInfo.JobInfo.dwlMessageId);
  1607. dwRes = m_SentItems.OnJobRemoved (pEvent->EventInfo.JobInfo.dwlMessageId);
  1608. break;
  1609. default:
  1610. dwRes = ERROR_GEN_FAILURE;
  1611. VERBOSE (DBG_MSG,
  1612. TEXT("Got unknown server notification from %s - ")
  1613. TEXT("FAX_EVENT_TYPE_OUT_ARCHIVE / %d / 0x%016I64x"),
  1614. m_cstrMachine,
  1615. pEvent->EventInfo.JobInfo.Type,
  1616. pEvent->EventInfo.JobInfo.dwlMessageId);
  1617. break;
  1618. }
  1619. break;
  1620. case FAX_EVENT_TYPE_FXSSVC_ENDED:
  1621. //
  1622. // Fax service is shutting down
  1623. //
  1624. VERBOSE (DBG_MSG,
  1625. TEXT("Got server notification from %s - FAX_EVENT_TYPE_FXSSVC_ENDED"),
  1626. m_cstrMachine);
  1627. dwRes = Disconnect ();
  1628. if (ERROR_SUCCESS != dwRes)
  1629. {
  1630. CALL_FAIL (GENERAL_ERR, TEXT("Disconnect"), dwRes);
  1631. }
  1632. dwRes = InvalidateSubFolders (TRUE);
  1633. if (ERROR_SUCCESS != dwRes)
  1634. {
  1635. CALL_FAIL (GENERAL_ERR, TEXT("InvalidateSubFolders"), dwRes);
  1636. }
  1637. break;
  1638. default:
  1639. dwRes = ERROR_GEN_FAILURE;
  1640. VERBOSE (DBG_MSG,
  1641. TEXT("Got unknown server notification from %s - %d"),
  1642. m_cstrMachine,
  1643. pEvent->EventType);
  1644. break;
  1645. }
  1646. return dwRes;
  1647. } // CServerNode::OnNotificationMessage
  1648. CFolder*
  1649. CServerNode::GetFolder(FolderType type)
  1650. {
  1651. CFolder* pFolder=NULL;
  1652. switch(type)
  1653. {
  1654. case FOLDER_TYPE_INBOX:
  1655. pFolder = &m_Inbox;
  1656. break;
  1657. case FOLDER_TYPE_OUTBOX:
  1658. pFolder = &m_Outbox;
  1659. break;
  1660. case FOLDER_TYPE_SENT_ITEMS:
  1661. pFolder = &m_SentItems;
  1662. break;
  1663. case FOLDER_TYPE_INCOMING:
  1664. pFolder = &m_Incoming;
  1665. break;
  1666. default:
  1667. {
  1668. DBG_ENTER(TEXT("CServerNode::GetFolder"));
  1669. ASSERTION_FAILURE
  1670. }
  1671. break;
  1672. }
  1673. return pFolder;
  1674. }