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.

681 lines
14 KiB

  1. // Folder.cpp: implementation of the CFolder class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #define __FILE_ID__ 21
  6. #ifdef _DEBUG
  7. #undef THIS_FILE
  8. static char THIS_FILE[]=__FILE__;
  9. #define new DEBUG_NEW
  10. #endif
  11. IMPLEMENT_DYNAMIC(CFolder, CTreeNode)
  12. //////////////////////////////////////////////////////////////////////
  13. // Construction/Destruction
  14. //////////////////////////////////////////////////////////////////////
  15. void
  16. CFolder::PreDestruct ()
  17. {
  18. DBG_ENTER(TEXT("CFolder::PreDestruct"), TEXT("Type=%d"), m_Type);
  19. //
  20. // Stop the build thread - and wait for its death
  21. //
  22. DWORD dwRes = StopBuildThread ();
  23. if (ERROR_SUCCESS != dwRes)
  24. {
  25. CALL_FAIL (GENERAL_ERR, TEXT("CFolder::StopBuildThread"), dwRes);
  26. }
  27. //
  28. // Clear the map of items
  29. //
  30. dwRes = InvalidateContents(FALSE);
  31. if (ERROR_SUCCESS != dwRes)
  32. {
  33. CALL_FAIL (GENERAL_ERR, TEXT("CFolder::InvalidateContents"), dwRes);
  34. }
  35. } // CFolder::PreDestruct
  36. CFolder::~CFolder()
  37. {
  38. DBG_ENTER(TEXT("CFolder::~CFolder"), TEXT("Type=%d"), m_Type);
  39. //
  40. // Destroy data critical section
  41. //
  42. if (m_bCsDataInitialized)
  43. {
  44. DeleteCriticalSection (&m_CsData);
  45. }
  46. } // CFolder::~CFolder
  47. CFaxMsg*
  48. CFolder::FindMessage (
  49. DWORDLONG dwlMsgId
  50. )
  51. {
  52. DBG_ENTER(TEXT("CFolder::FindMessage"));
  53. MSGS_MAP::iterator it = m_Msgs.find (dwlMsgId);
  54. if (m_Msgs.end() == it)
  55. {
  56. //
  57. // Not found
  58. //
  59. return NULL;
  60. }
  61. else
  62. {
  63. return (*it).second;
  64. }
  65. } // CFolder::FindMessage
  66. void CFolder::AssertValid() const
  67. {
  68. CTreeNode::AssertValid();
  69. }
  70. void
  71. CFolder::SetServer (
  72. CServerNode *pServer
  73. )
  74. {
  75. DBG_ENTER(TEXT("CFolder::SetServer"));
  76. ASSERTION (NULL != pServer);
  77. m_pServer = pServer;
  78. VERBOSE (DBG_MSG,
  79. TEXT ("Folder on server %s, Type=%d"),
  80. m_pServer->Machine(),
  81. m_Type);
  82. }
  83. DWORD
  84. CFolder::Init ()
  85. /*++
  86. Routine name : CFolder::Init
  87. Routine description:
  88. Init a folder
  89. Author:
  90. Eran Yariv (EranY), Jan, 2000
  91. Arguments:
  92. Return Value:
  93. Standard Win32 error code
  94. --*/
  95. {
  96. DWORD dwRes = ERROR_SUCCESS;
  97. DBG_ENTER(TEXT("CFolder::Init"), dwRes);
  98. //
  99. // Init the build thread critical section
  100. //
  101. try
  102. {
  103. InitializeCriticalSection (&m_CsData);
  104. }
  105. catch (...)
  106. {
  107. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  108. CALL_FAIL (MEM_ERR, TEXT ("InitializeCriticalSection"), dwRes);
  109. return dwRes;
  110. }
  111. m_bCsDataInitialized = TRUE;
  112. return dwRes;
  113. } // CFolder::Init
  114. void
  115. CFolder::AttachView()
  116. {
  117. DBG_ENTER(TEXT("CFolder::AttachView"));
  118. m_pAssignedView = NULL;
  119. CMainFrame *pFrm = GetFrm();
  120. if (!pFrm)
  121. {
  122. //
  123. // Shutdown in progress
  124. //
  125. return;
  126. }
  127. //
  128. // Attach the right view to the folder
  129. //
  130. switch (m_Type)
  131. {
  132. case FOLDER_TYPE_INBOX:
  133. m_pAssignedView = pFrm->GetInboxView ();
  134. break;
  135. case FOLDER_TYPE_INCOMING:
  136. m_pAssignedView = pFrm->GetIncomingView ();
  137. break;
  138. case FOLDER_TYPE_OUTBOX:
  139. m_pAssignedView = pFrm->GetOutboxView ();
  140. break;
  141. case FOLDER_TYPE_SENT_ITEMS:
  142. m_pAssignedView = pFrm->GetSentItemsView ();
  143. break;
  144. default:
  145. ASSERTION_FAILURE;
  146. }
  147. ASSERTION(m_pAssignedView);
  148. } //CFolder::AttachView
  149. void
  150. CFolder::SetVisible()
  151. /*++
  152. Routine name : CFolder::SetVisible
  153. Routine description:
  154. Sets the visiblity of a folder
  155. Author:
  156. Eran Yariv (EranY), Jan, 2000
  157. Return Value:
  158. None.
  159. --*/
  160. {
  161. DBG_ENTER(TEXT("CFolder::SetVisible"),
  162. TEXT("Server = %s, Type=%d"),
  163. m_pServer ? m_pServer->Machine() : TEXT("None"),
  164. m_Type);
  165. //
  166. // This folder's tree node was just selected
  167. //
  168. m_bVisible = TRUE;
  169. if (!m_bValidList && !m_bRefreshing)
  170. {
  171. //
  172. // The items list is invalid and there's not thread currently creating it.
  173. //
  174. // This is the 1st time this node is being selected for display
  175. // (since its creation) - build the list of jobs / messages now
  176. //
  177. // NOTICE: RebuildContents() calls StopBuildThread() which waits for
  178. // the previous thread to die WHILE DEQUEUEING WINDOWS MESSAGES.
  179. // This may causes a seconds call to this function BEFORE
  180. // RebuildContents() returned.
  181. //
  182. DWORD dwRes = RebuildContents ();
  183. if (ERROR_SUCCESS != dwRes)
  184. {
  185. CALL_FAIL (GENERAL_ERR, TEXT ("CFolder::RebuildContents"), dwRes);
  186. }
  187. }
  188. } // CFolder::SetVisible
  189. DWORD
  190. CFolder::InvalidateContents (
  191. BOOL bClearView
  192. )
  193. /*++
  194. Routine name : CFolder::InvalidateContents
  195. Routine description:
  196. Clears the contents of a folder (and the view if attached)
  197. Author:
  198. Eran Yariv (EranY), Jan, 2000
  199. Arguments:
  200. bClearView [in] - Should we clear attached view ?
  201. Return Value:
  202. Standard Win32 error code
  203. --*/
  204. {
  205. DWORD dwRes = ERROR_SUCCESS;
  206. DBG_ENTER(TEXT("CFolder::InvalidateContents"), dwRes, TEXT("Type=%d"), m_Type);
  207. CFaxMsg* pMsg;
  208. EnterData ();
  209. for (MSGS_MAP::iterator it = m_Msgs.begin(); it != m_Msgs.end(); ++it)
  210. {
  211. pMsg = (*it).second;
  212. if(bClearView && m_pAssignedView)
  213. {
  214. m_pAssignedView->OnUpdate (NULL, UPDATE_HINT_REMOVE_ITEM, pMsg);
  215. }
  216. SAFE_DELETE (pMsg);
  217. }
  218. m_Msgs.clear();
  219. LeaveData ();
  220. //
  221. // Mark list as invalid
  222. //
  223. m_bValidList = FALSE;
  224. return dwRes;
  225. } // CFolder::InvalidateContents
  226. DWORD
  227. CFolder::RebuildContents ()
  228. /*++
  229. Routine name : CFolder::RebuildContents
  230. Routine description:
  231. Rebuilds the contents of a folder (by creating a worker thread)
  232. Author:
  233. Eran Yariv (EranY), Jan, 2000
  234. Arguments:
  235. Return Value:
  236. Standard Win32 error code
  237. --*/
  238. {
  239. DWORD dwRes = ERROR_SUCCESS;
  240. DBG_ENTER(TEXT("CFolder::RebuildContents"), dwRes, TEXT("Type=%d"), m_Type);
  241. ASSERTION(!m_bRefreshing);
  242. m_bRefreshing = TRUE;
  243. //
  244. // Stop the current (if any) build thread and make sure it's dead
  245. //
  246. m_bRefreshFailed = FALSE;
  247. DWORD dwThreadId;
  248. dwRes = StopBuildThread ();
  249. EnterCriticalSection (&m_CsData);
  250. if (ERROR_SUCCESS != dwRes)
  251. {
  252. CALL_FAIL (RESOURCE_ERR, TEXT("CFolder::StopBuildThread"), dwRes);
  253. m_bRefreshing = FALSE;
  254. goto exit;
  255. }
  256. //
  257. // Lock the folder, so that notifications will not add jobs / messages
  258. // to the map and list view.
  259. //
  260. m_bLocked = TRUE;
  261. //
  262. // Clear our list and our view (list control)
  263. //
  264. dwRes = InvalidateContents(FALSE);
  265. if (ERROR_SUCCESS != dwRes)
  266. {
  267. CALL_FAIL (RPC_ERR, TEXT("CFolder::InvalidateContents"), dwRes);
  268. m_bLocked = FALSE;
  269. m_bRefreshing = FALSE;
  270. goto exit;
  271. }
  272. //
  273. // Start the thread that will fill the data (in the background)
  274. //
  275. m_bStopRefresh = FALSE;
  276. m_hBuildThread = CreateThread (
  277. NULL, // No security
  278. 0, // Default stack size
  279. BuildThreadProc,// Thread procedure
  280. (LPVOID)this, // Parameter
  281. 0, // Normal creation
  282. &dwThreadId // We must have a thread id for win9x
  283. );
  284. if (NULL == m_hBuildThread)
  285. {
  286. dwRes = GetLastError ();
  287. CALL_FAIL (RESOURCE_ERR, TEXT("CreateThread"), dwRes);
  288. PopupError (dwRes);
  289. m_bLocked = FALSE;
  290. m_bRefreshing = FALSE;
  291. }
  292. exit:
  293. LeaveCriticalSection (&m_CsData);
  294. return dwRes;
  295. } // CFolder::RebuildContents
  296. DWORD
  297. CFolder::StopBuildThread (BOOL bWaitForDeath)
  298. /*++
  299. Routine name : CFolder::StopBuildThread
  300. Routine description:
  301. Stops the contents-building worker thread.
  302. Author:
  303. Eran Yariv (EranY), Jan, 2000
  304. Arguments:
  305. bWaitForDeath [in] - Should we wait until the therad actually dies?
  306. Return Value:
  307. Standard Win32 error code
  308. --*/
  309. {
  310. DWORD dwRes = ERROR_SUCCESS;
  311. DBG_ENTER(TEXT("CFolder::StopBuildThread"), dwRes, TEXT("Type=%d"), m_Type);
  312. m_bStopRefresh = TRUE;
  313. if (!bWaitForDeath)
  314. {
  315. return dwRes;
  316. }
  317. if (NULL == m_hBuildThread)
  318. {
  319. //
  320. // Background build thread is already dead
  321. //
  322. return dwRes;
  323. }
  324. dwRes = WaitForThreadDeathOrShutdown (m_hBuildThread);
  325. if (ERROR_SUCCESS != dwRes)
  326. {
  327. CALL_FAIL (GENERAL_ERR, TEXT("WaitForThreadDeathOrShutdown"), dwRes);
  328. }
  329. CloseHandle (m_hBuildThread);
  330. m_hBuildThread = NULL;
  331. return dwRes;
  332. } // CFolder::StopBuildThread
  333. DWORD
  334. WINAPI
  335. CFolder::BuildThreadProc (
  336. LPVOID lpParameter
  337. )
  338. /*++
  339. Routine name : CFolder::BuildThreadProc
  340. Routine description:
  341. Static thread entry point.
  342. Author:
  343. Eran Yariv (EranY), Jan, 2000
  344. Arguments:
  345. lpParameter [in] - Pointer to the CFolder instance that created the thread.
  346. Return Value:
  347. Standard Win32 error code
  348. --*/
  349. {
  350. DWORD dwRes = ERROR_SUCCESS;
  351. DBG_ENTER(TEXT("CFolder::BuildThreadProc"), dwRes);
  352. CFolder *pFolder = (CFolder *)lpParameter;
  353. ASSERT (pFolder);
  354. const CServerNode* pServer = pFolder->GetServer();
  355. if(NULL != pServer)
  356. {
  357. VERBOSE (DBG_MSG,
  358. TEXT ("Folder on server %s"),
  359. pServer->Machine());
  360. }
  361. //
  362. // Call the refresh function for the right folder
  363. //
  364. dwRes = pFolder->Refresh ();
  365. if (ERROR_SUCCESS != dwRes)
  366. {
  367. CALL_FAIL (GENERAL_ERR, TEXT("CFolder::Refresh"), dwRes);
  368. //
  369. // Check if the view still alive
  370. //
  371. pFolder->AttachView();
  372. if(pFolder->m_pAssignedView)
  373. {
  374. //
  375. // Invalidate contents
  376. //
  377. pFolder->m_pAssignedView->SendMessage (
  378. WM_FOLDER_INVALIDATE,
  379. WPARAM (0),
  380. LPARAM (pFolder));
  381. }
  382. pFolder->m_bRefreshFailed = TRUE;
  383. }
  384. else
  385. {
  386. //
  387. // Refresh thread succeeded, there's a point in updating the view
  388. //
  389. pFolder->m_bValidList = TRUE;
  390. //
  391. // Check if the view still alive
  392. //
  393. pFolder->AttachView();
  394. if (pFolder->m_pAssignedView)
  395. {
  396. //
  397. // Folder has a view attached
  398. //
  399. pFolder->m_pAssignedView->SendMessage (
  400. WM_FOLDER_REFRESH_ENDED,
  401. WPARAM (dwRes),
  402. LPARAM (pFolder));
  403. }
  404. }
  405. pFolder->EnterData ();
  406. //
  407. // Unlock the folder - notifications can now be processed
  408. //
  409. pFolder->m_bLocked = FALSE;
  410. pFolder->LeaveData ();
  411. pFolder->m_bRefreshing = FALSE;
  412. CMainFrame *pFrm = GetFrm();
  413. if (!pFrm)
  414. {
  415. //
  416. // Shutdown in progress
  417. //
  418. }
  419. else
  420. {
  421. pFrm->RefreshStatusBar ();
  422. }
  423. //
  424. // That's it, return the result
  425. //
  426. return dwRes;
  427. } // CFolder::BuildThreadProc
  428. int
  429. CFolder::GetActivityStringResource() const
  430. /*++
  431. Routine name : CFolder::GetActivityStringResource
  432. Routine description:
  433. Returns the resource id of a string identifying the activity of the folder
  434. Author:
  435. Eran Yariv (EranY), Jan, 2000
  436. Arguments:
  437. Return Value:
  438. Activity string resource id
  439. --*/
  440. {
  441. if (m_bRefreshFailed)
  442. {
  443. //
  444. // Last refresh failed
  445. //
  446. return IDS_FOLDER_REFRESH_FAILED;
  447. }
  448. if (m_pAssignedView && m_pAssignedView->Sorting())
  449. {
  450. //
  451. // Folder has a view and the view is currently sorting
  452. //
  453. return IDS_FOLDER_SORTING;
  454. }
  455. if (IsRefreshing())
  456. {
  457. //
  458. // Folder is busy building up its data
  459. //
  460. return IDS_FOLDER_REFRESHING;
  461. }
  462. //
  463. // Folder is doing nothing
  464. //
  465. return IDS_FOLDER_IDLE;
  466. } // CFolder::GetActivityStringResource
  467. DWORD
  468. CFolder::OnJobRemoved (
  469. DWORDLONG dwlMsgId,
  470. CFaxMsg* pMsg /* = NULL */
  471. )
  472. /*++
  473. Routine name : CFolder::OnJobRemoved
  474. Routine description:
  475. Handles notification of a message removed from the archive
  476. Author:
  477. Eran Yariv (EranY), Feb, 2000
  478. Arguments:
  479. dwlMsgId [in] - Message unique id
  480. pMsg [in] - Optional pointer to message to remove (for optimization)
  481. Return Value:
  482. Standard Win32 error code
  483. --*/
  484. {
  485. DWORD dwRes = ERROR_SUCCESS;
  486. DBG_ENTER(TEXT("CFolder::OnJobRemoved"),
  487. dwRes,
  488. TEXT("MsgId=0x%016I64x, Type=%d"),
  489. dwlMsgId,
  490. Type());
  491. EnterData ();
  492. if (!pMsg)
  493. {
  494. //
  495. // No message pointer was supplied - search for it
  496. //
  497. pMsg = FindMessage (dwlMsgId);
  498. }
  499. if (!pMsg)
  500. {
  501. //
  502. // This message is already not in the archive
  503. //
  504. VERBOSE (DBG_MSG, TEXT("Message is already gone"));
  505. goto exit;
  506. }
  507. if (m_pAssignedView)
  508. {
  509. //
  510. // If this folder is alive - tell our view to remove the message
  511. //
  512. m_pAssignedView->OnUpdate (NULL, UPDATE_HINT_REMOVE_ITEM, pMsg);
  513. }
  514. //
  515. // Remove the message from the map
  516. //
  517. try
  518. {
  519. m_Msgs.erase (dwlMsgId);
  520. }
  521. catch (...)
  522. {
  523. dwRes = ERROR_NOT_ENOUGH_MEMORY;
  524. CALL_FAIL (MEM_ERR, TEXT("map::erase"), dwRes);
  525. delete pMsg;
  526. goto exit;
  527. }
  528. //
  529. // Delete message
  530. //
  531. delete pMsg;
  532. ASSERTION (ERROR_SUCCESS == dwRes);
  533. exit:
  534. LeaveData ();
  535. return dwRes;
  536. } // CFolder::OnJobRemoved