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.

1528 lines
42 KiB

  1. //--------------------------------------------------------------------------
  2. // FindFold.cpp
  3. //--------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "finder.h"
  6. #include "findfold.h"
  7. #include "storutil.h"
  8. #include "msgfldr.h"
  9. #include "shlwapip.h"
  10. #include "storecb.h"
  11. //--------------------------------------------------------------------------
  12. // ENUMFINDFOLDERS
  13. //--------------------------------------------------------------------------
  14. typedef struct tagENUMFINDFOLDERS {
  15. LPFOLDERENTRY prgFolder;
  16. DWORD cFolders;
  17. DWORD cAllocated;
  18. DWORD cMax;
  19. } ENUMFINDFOLDERS, *LPENUMFINDFOLDERS;
  20. //--------------------------------------------------------------------------
  21. // CLEAR_MESSAGE_FIELDS(_pMessage)
  22. //--------------------------------------------------------------------------
  23. #define CLEAR_MESSAGE_FIELDS(_Message) \
  24. _Message.pszUidl = NULL; \
  25. _Message.pszServer = NULL; \
  26. _Message.faStream = 0; \
  27. _Message.Offsets.cbSize = 0; \
  28. _Message.Offsets.pBlobData = NULL
  29. //--------------------------------------------------------------------------
  30. // EnumerateFindFolders
  31. //--------------------------------------------------------------------------
  32. HRESULT EnumerateFindFolders(LPFOLDERINFO pFolder, BOOL fSubFolders,
  33. DWORD cIndent, DWORD_PTR dwCookie)
  34. {
  35. // Locals
  36. HRESULT hr=S_OK;
  37. FOLDERID idDeleted;
  38. FOLDERID idServer;
  39. LPENUMFINDFOLDERS pEnum=(LPENUMFINDFOLDERS)dwCookie;
  40. LPFOLDERENTRY pEntry;
  41. IMessageFolder *pFolderObject=NULL;
  42. // Trace
  43. TraceCall("EnumerateFindFolders");
  44. // If not a server
  45. if (ISFLAGSET(pFolder->dwFlags, FOLDER_SERVER) || FOLDERID_ROOT == pFolder->idFolder)
  46. goto exit;
  47. // Room For One More
  48. if (pEnum->cFolders + 1 > pEnum->cAllocated)
  49. {
  50. // Realloc
  51. IF_FAILEXIT(hr = HrRealloc((LPVOID *)&pEnum->prgFolder, sizeof(FOLDERENTRY) * (pEnum->cAllocated + 5)));
  52. // Set cAllocated
  53. pEnum->cAllocated += 5;
  54. }
  55. // Readability
  56. pEntry = &pEnum->prgFolder[pEnum->cFolders];
  57. // Open the Folder
  58. if (SUCCEEDED(g_pStore->OpenFolder(pFolder->idFolder, NULL, OPEN_FOLDER_NOCREATE, &pFolderObject)))
  59. {
  60. // Get the Database
  61. if (SUCCEEDED(pFolderObject->GetDatabase(&pEntry->pDB)))
  62. {
  63. // No Folder
  64. pEntry->pFolder = NULL;
  65. // fInDeleted
  66. if (S_OK == IsParentDeletedItems(pFolder->idFolder, &idDeleted, &idServer))
  67. {
  68. // We are in the deleted items folder
  69. pEntry->fInDeleted = TRUE;
  70. }
  71. // Otherwise, not in deleted items
  72. else
  73. {
  74. // Nope
  75. pEntry->fInDeleted = FALSE;
  76. }
  77. // Count Record
  78. IF_FAILEXIT(hr = pEntry->pDB->GetRecordCount(IINDEX_PRIMARY, &pEntry->cRecords));
  79. // Save the Folder id
  80. pEntry->idFolder = pFolder->idFolder;
  81. // Save the Folder Type
  82. pEntry->tyFolder = pFolder->tyFolder;
  83. // Increment Max
  84. pEnum->cMax += pEntry->cRecords;
  85. // Copy folder Name
  86. IF_NULLEXIT(pEntry->pszName = PszDupA(pFolder->pszName));
  87. // Increment Folder Count
  88. pEnum->cFolders++;
  89. }
  90. }
  91. exit:
  92. // Cleanup
  93. SafeRelease(pFolderObject);
  94. // Done
  95. return(hr);
  96. }
  97. //--------------------------------------------------------------------------
  98. // CFindFolder::CFindFolder
  99. //--------------------------------------------------------------------------
  100. CFindFolder::CFindFolder(void)
  101. {
  102. m_cRef = 1;
  103. m_pCriteria = NULL;
  104. m_pSearch = NULL;
  105. m_pStore = NULL;
  106. m_cFolders = 0;
  107. m_cAllocated = 0;
  108. m_cMax = 0;
  109. m_cCur = 0;
  110. m_fCancel = FALSE;
  111. m_prgFolder = NULL;
  112. m_pCallback = NULL;
  113. m_idRoot = FOLDERID_INVALID;
  114. m_idFolder = FOLDERID_INVALID;
  115. m_pMessage = NULL;
  116. }
  117. //--------------------------------------------------------------------------
  118. // CFindFolder::~CFindFolder
  119. //--------------------------------------------------------------------------
  120. CFindFolder::~CFindFolder(void)
  121. {
  122. // Locals
  123. LPACTIVEFINDFOLDER pCurrent;
  124. LPACTIVEFINDFOLDER pPrevious=NULL;
  125. // Thread Safety
  126. EnterCriticalSection(&g_csFindFolder);
  127. // Walk Through the global list of Active Search Folders
  128. for (pCurrent=g_pHeadFindFolder; pCurrent!=NULL; pCurrent=pCurrent->pNext)
  129. {
  130. // Is this it
  131. if (m_idFolder == pCurrent->idFolder)
  132. {
  133. // If there was a Previous
  134. if (pPrevious)
  135. pPrevious->pNext = pCurrent->pNext;
  136. // Otherwise, reset the header
  137. else
  138. g_pHeadFindFolder = pCurrent->pNext;
  139. // Free pCurrent
  140. g_pMalloc->Free(pCurrent);
  141. // Done
  142. break;
  143. }
  144. // Save Previous
  145. pPrevious = pCurrent;
  146. }
  147. // Thread Safety
  148. LeaveCriticalSection(&g_csFindFolder);
  149. // Release Database
  150. SafeRelease(m_pSearch);
  151. // Delete this folder
  152. if (FOLDERID_INVALID != m_idFolder && m_pStore)
  153. {
  154. // Delete this folder
  155. m_pStore->DeleteFolder(m_idFolder, DELETE_FOLDER_NOTRASHCAN, (IStoreCallback *)this);
  156. }
  157. // Release the Store
  158. SafeRelease(m_pStore);
  159. // Release the Callback
  160. SafeRelease(m_pCallback);
  161. // Free the Folder Array
  162. for (ULONG i=0; i<m_cFolders; i++)
  163. {
  164. // Free the Folder Name
  165. SafeMemFree(m_prgFolder[i].pszName);
  166. // Remove Notify
  167. m_prgFolder[i].pDB->UnregisterNotify((IDatabaseNotify *)this);
  168. // Release the Folder Object
  169. SafeRelease(m_prgFolder[i].pDB);
  170. // Release the Folder Object
  171. SafeRelease(m_prgFolder[i].pFolder);
  172. }
  173. // Release my mime message
  174. SafeRelease(m_pMessage);
  175. // Free the Array
  176. SafeMemFree(m_prgFolder);
  177. // Free Find Info
  178. if (m_pCriteria)
  179. {
  180. FreeFindInfo(m_pCriteria);
  181. SafeMemFree(m_pCriteria);
  182. }
  183. }
  184. //--------------------------------------------------------------------------
  185. // CFindFolder::AddRef
  186. //--------------------------------------------------------------------------
  187. STDMETHODIMP_(ULONG) CFindFolder::AddRef(void)
  188. {
  189. TraceCall("CFindFolder::AddRef");
  190. return InterlockedIncrement(&m_cRef);
  191. }
  192. //--------------------------------------------------------------------------
  193. // CFindFolder::Release
  194. //--------------------------------------------------------------------------
  195. STDMETHODIMP_(ULONG) CFindFolder::Release(void)
  196. {
  197. TraceCall("CFindFolder::Release");
  198. LONG cRef = InterlockedDecrement(&m_cRef);
  199. if (0 == cRef)
  200. delete this;
  201. return (ULONG)cRef;
  202. }
  203. //--------------------------------------------------------------------------
  204. // CFindFolder::QueryInterface
  205. //--------------------------------------------------------------------------
  206. STDMETHODIMP CFindFolder::QueryInterface(REFIID riid, LPVOID *ppv)
  207. {
  208. // Locals
  209. HRESULT hr=S_OK;
  210. // Stack
  211. TraceCall("CFindFolder::QueryInterface");
  212. // Invalid Arg
  213. Assert(ppv);
  214. // Find IID
  215. if (IID_IUnknown == riid)
  216. *ppv = (IUnknown *)(IMessageFolder *)this;
  217. else if (IID_IMessageFolder == riid)
  218. *ppv = (IMessageFolder *)this;
  219. else if (IID_IDatabase == riid)
  220. *ppv = (IDatabase *)this;
  221. else if (IID_IDatabaseNotify == riid)
  222. *ppv = (IDatabaseNotify *)this;
  223. else if (IID_IServiceProvider == riid)
  224. *ppv = (IServiceProvider *)this;
  225. else
  226. {
  227. *ppv = NULL;
  228. hr = E_NOINTERFACE;
  229. goto exit;
  230. }
  231. // AddRef It
  232. ((IUnknown *)*ppv)->AddRef();
  233. exit:
  234. // Done
  235. return(hr);
  236. }
  237. //--------------------------------------------------------------------------
  238. // CFindFolder::QueryService
  239. //--------------------------------------------------------------------------
  240. STDMETHODIMP CFindFolder::QueryService(REFGUID guidService, REFIID riid,
  241. LPVOID *ppvObject)
  242. {
  243. // Trace
  244. TraceCall("CFindFolder::QueryService");
  245. // Just a Query Interface
  246. return(QueryInterface(riid, ppvObject));
  247. }
  248. //--------------------------------------------------------------------------
  249. // CFindFolder::Initialize
  250. //--------------------------------------------------------------------------
  251. HRESULT CFindFolder::Initialize(IMessageStore *pStore, IMessageServer *pServer,
  252. OPENFOLDERFLAGS dwFlags, FOLDERID idFolder)
  253. {
  254. // Locals
  255. HRESULT hr=S_OK;
  256. FOLDERINFO Folder={0};
  257. FOLDERUSERDATA UserData={0};
  258. TABLEINDEX Index;
  259. LPACTIVEFINDFOLDER pActiveFind;
  260. // Trace
  261. TraceCall("CFindFolder::Initialize");
  262. // I don't need a server
  263. Assert(NULL == pServer);
  264. // Invalid Arg
  265. if (NULL == pStore)
  266. return TraceResult(E_INVALIDARG);
  267. // Should be NULL
  268. Assert(NULL == m_pCriteria);
  269. // Save the Folder Id
  270. m_idRoot = idFolder;
  271. // Save the Store
  272. m_pStore = pStore;
  273. m_pStore->AddRef();
  274. // Fill Up My folder Info
  275. Folder.pszName = "Search Folder";
  276. Folder.tyFolder = FOLDER_LOCAL;
  277. Folder.tySpecial = FOLDER_NOTSPECIAL;
  278. Folder.dwFlags = FOLDER_HIDDEN | FOLDER_FINDRESULTS;
  279. Folder.idParent = FOLDERID_LOCAL_STORE;
  280. // Create a Folder
  281. IF_FAILEXIT(hr = m_pStore->CreateFolder(CREATE_FOLDER_UNIQUIFYNAME, &Folder, (IStoreCallback *)this));
  282. // Save the Id
  283. m_idFolder = Folder.idFolder;
  284. // Create a CMessageFolder Object
  285. IF_NULLEXIT(m_pSearch = new CMessageFolder);
  286. // Initialize
  287. IF_FAILEXIT(hr = m_pSearch->Initialize((IMessageStore *)pStore, NULL, NOFLAGS, m_idFolder));
  288. // Fill the IINDEX_FINDER Information
  289. ZeroMemory(&Index, sizeof(TABLEINDEX));
  290. Index.cKeys = 2;
  291. Index.rgKey[0].iColumn = MSGCOL_FINDFOLDER;
  292. Index.rgKey[1].iColumn = MSGCOL_FINDSOURCE;
  293. // Set Index
  294. IF_FAILEXIT(hr = m_pSearch->ModifyIndex(IINDEX_FINDER, NULL, &Index));
  295. // Allocate ACTIVEFINDFOLDER
  296. IF_NULLEXIT(pActiveFind = (LPACTIVEFINDFOLDER)ZeroAllocate(sizeof(ACTIVEFINDFOLDER)));
  297. // Set idFolder
  298. pActiveFind->idFolder = m_idFolder;
  299. // Set this
  300. pActiveFind->pFolder = this;
  301. // Thread Safety
  302. EnterCriticalSection(&g_csFindFolder);
  303. // Set Next
  304. pActiveFind->pNext = g_pHeadFindFolder;
  305. // Set Head
  306. g_pHeadFindFolder = pActiveFind;
  307. // Thread Safety
  308. LeaveCriticalSection(&g_csFindFolder);
  309. exit:
  310. // Done
  311. return(hr);
  312. }
  313. //--------------------------------------------------------------------------
  314. // CFindFolder::GetMessageFolderId
  315. //--------------------------------------------------------------------------
  316. HRESULT CFindFolder::GetMessageFolderId(MESSAGEID idMessage, LPFOLDERID pidFolder)
  317. {
  318. // Locals
  319. HRESULT hr=S_OK;
  320. MESSAGEINFO Message={0};
  321. // Trace
  322. TraceCall("CFindFolder::GetMessageFolderId");
  323. // Invalid Args
  324. if (NULL == m_pSearch || NULL == pidFolder)
  325. return TraceResult(E_INVALIDARG);
  326. // Initialize Message
  327. IF_FAILEXIT(hr = GetMessageInfo(m_pSearch, idMessage, &Message));
  328. // Get the Folder Entry
  329. *pidFolder = m_prgFolder[Message.iFindFolder].idFolder;
  330. exit:
  331. // Done
  332. m_pSearch->FreeRecord(&Message);
  333. // Done
  334. return(hr);
  335. }
  336. //--------------------------------------------------------------------------
  337. // CFindFolder::GetMessageFolderType
  338. //--------------------------------------------------------------------------
  339. HRESULT CFindFolder::GetMessageFolderType(MESSAGEID idMessage,
  340. FOLDERTYPE *ptyFolder)
  341. {
  342. // Locals
  343. HRESULT hr=S_OK;
  344. MESSAGEINFO Message={0};
  345. // Trace
  346. TraceCall("CFindFolder::GetMessageFolderType");
  347. // Invalid Args
  348. if (NULL == m_pSearch || NULL == ptyFolder)
  349. return TraceResult(E_INVALIDARG);
  350. // Initialize Message
  351. IF_FAILEXIT(hr = GetMessageInfo(m_pSearch, idMessage, &Message));
  352. // Get the Folder Entry
  353. *ptyFolder = m_prgFolder[Message.iFindFolder].tyFolder;
  354. exit:
  355. // Done
  356. m_pSearch->FreeRecord(&Message);
  357. // Done
  358. return(hr);
  359. }
  360. //--------------------------------------------------------------------------
  361. // CFindFolder::StartFind
  362. //--------------------------------------------------------------------------
  363. HRESULT CFindFolder::StartFind(LPFINDINFO pCriteria, IStoreCallback *pCallback)
  364. {
  365. // Locals
  366. HRESULT hr=S_OK;
  367. RECURSEFLAGS dwFlags=RECURSE_ONLYSUBSCRIBED;
  368. ENUMFINDFOLDERS EnumFolders={0};
  369. // Trace
  370. TraceCall("CFindFolder::StartFind");
  371. // Invalid Arg
  372. if (NULL == pCriteria || NULL == pCallback)
  373. return TraceResult(E_INVALIDARG);
  374. // Should be NULL
  375. Assert(NULL == m_pCriteria && m_pStore);
  376. // Allocate m_pCriteria
  377. IF_NULLEXIT(m_pCriteria = (FINDINFO *)g_pMalloc->Alloc(sizeof(FINDINFO)));
  378. // Copy the Find Info
  379. IF_FAILEXIT(hr = CopyFindInfo(pCriteria, m_pCriteria));
  380. // Hold Onto the Callback
  381. m_pCallback = pCallback;
  382. m_pCallback->AddRef();
  383. // Setup Flags
  384. if (FOLDERID_ROOT != m_idRoot)
  385. FLAGSET(dwFlags, RECURSE_INCLUDECURRENT);
  386. // SubFolder
  387. if (m_pCriteria->fSubFolders)
  388. FLAGSET(dwFlags, RECURSE_SUBFOLDERS);
  389. // Build my Folder Table
  390. IF_FAILEXIT(hr = RecurseFolderHierarchy(m_idRoot, dwFlags, 0, (DWORD_PTR)&EnumFolders, (PFNRECURSECALLBACK)EnumerateFindFolders));
  391. // Take Stuff Back
  392. m_prgFolder = EnumFolders.prgFolder;
  393. m_cFolders = EnumFolders.cFolders;
  394. m_cAllocated = EnumFolders.cAllocated;
  395. m_cMax = EnumFolders.cMax;
  396. // Start the find...
  397. IF_FAILEXIT(hr = _StartFind());
  398. exit:
  399. // Done
  400. return(hr);
  401. }
  402. //--------------------------------------------------------------------------
  403. // CFindFolder::_StartFind
  404. //--------------------------------------------------------------------------
  405. HRESULT CFindFolder::_StartFind(void)
  406. {
  407. // Locals
  408. HRESULT hr=S_OK;
  409. DWORD i;
  410. // Trace
  411. TraceCall("CFindFolder::_StartFind");
  412. // Callback
  413. if (m_pCallback)
  414. m_pCallback->OnBegin(SOT_SEARCHING, NULL, (IOperationCancel *)this);
  415. // Loop through the Folders
  416. for (i=0; i<m_cFolders; i++)
  417. {
  418. // Query the Folder
  419. IF_FAILEXIT(hr = _SearchFolder(i));
  420. }
  421. exit:
  422. // Callback
  423. if (m_pCallback)
  424. m_pCallback->OnComplete(SOT_SEARCHING, hr, NULL, NULL);
  425. // Done
  426. return(hr);
  427. }
  428. //--------------------------------------------------------------------------
  429. // CFindFolder::_SearchFolder
  430. //--------------------------------------------------------------------------
  431. HRESULT CFindFolder::_SearchFolder(DWORD iFolder)
  432. {
  433. // Locals
  434. HRESULT hr=S_OK;
  435. DWORD iRow=0;
  436. DWORD cRows=0;
  437. HROWSET hRowset=NULL;
  438. LPSTR pszName;
  439. HLOCK hNotify=NULL;
  440. MESSAGEINFO rgMessage[100];
  441. BOOL fFree=FALSE;
  442. LPFOLDERENTRY pEntry;
  443. BOOL fMatch;
  444. IDatabase *pDB;
  445. DWORD cMatch=0;
  446. // Trace
  447. TraceCall("CFindFolder::_SearchFolder");
  448. // Get pEntry
  449. pEntry = &m_prgFolder[iFolder];
  450. // Get the Folder Name
  451. pszName = pEntry->pszName;
  452. // Get the Folder Object
  453. pDB = pEntry->pDB;
  454. // Create a Rowset for this Folder
  455. IF_FAILEXIT(hr = pDB->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
  456. // Progress
  457. if (m_fCancel || (m_pCallback && S_FALSE == m_pCallback->OnProgress(SOT_SEARCHING, m_cCur, m_cMax, pszName)))
  458. goto exit;
  459. // Queue Notifications
  460. IF_FAILEXIT(hr = m_pSearch->LockNotify(NOFLAGS, &hNotify));
  461. // Walk the Rowset
  462. while (S_OK == pDB->QueryRowset(hRowset, 100, (LPVOID *)rgMessage, &cRows))
  463. {
  464. // Need to Free
  465. fFree = TRUE;
  466. // Walk through the Rows
  467. for (iRow=0; iRow<cRows; iRow++)
  468. {
  469. // Does Row Match Criteria
  470. IF_FAILEXIT(hr = _OnInsert(iFolder, &rgMessage[iRow], &fMatch));
  471. // Count Matched
  472. if (fMatch)
  473. cMatch++;
  474. // Incrment m_cCur
  475. m_cCur++;
  476. // Adjust the max
  477. if (m_cCur > m_cMax)
  478. m_cMax = m_cCur;
  479. // Do Progress Stuff
  480. if ((m_cCur % 50) == 0 && m_cCur > 0)
  481. {
  482. // Progress
  483. if (m_fCancel || (m_pCallback && S_FALSE == m_pCallback->OnProgress(SOT_SEARCHING, m_cCur, m_cMax, NULL)))
  484. {
  485. // Register for a notifications on the stuff that we've searched
  486. pDB->RegisterNotify(IINDEX_PRIMARY, REGISTER_NOTIFY_NOADDREF, iFolder, (IDatabaseNotify *)this);
  487. // Done..
  488. goto exit;
  489. }
  490. }
  491. // Do Progress Stuff
  492. if ((cMatch % 50) == 0 && cMatch > 0)
  493. {
  494. // Unlock the Notificaton Queue
  495. m_pSearch->UnlockNotify(&hNotify);
  496. // Lock It Again
  497. m_pSearch->LockNotify(NOFLAGS, &hNotify);
  498. }
  499. // Free It
  500. pDB->FreeRecord(&rgMessage[iRow]);
  501. }
  502. // No Need to Free
  503. fFree = FALSE;
  504. }
  505. // Register for a notificatoin on this folder
  506. pDB->RegisterNotify(IINDEX_PRIMARY, REGISTER_NOTIFY_NOADDREF, iFolder, (IDatabaseNotify *)this);
  507. exit:
  508. // Unlock the Notificaton Queue
  509. m_pSearch->UnlockNotify(&hNotify);
  510. // Free ?
  511. if (fFree)
  512. {
  513. // Loop through remaining unfreed rows
  514. for (; iRow<cRows; iRow++)
  515. {
  516. // Free the Row
  517. pDB->FreeRecord(&rgMessage[iRow]);
  518. }
  519. }
  520. // Cleanup
  521. pDB->CloseRowset(&hRowset);
  522. // Done
  523. return(hr);
  524. }
  525. //--------------------------------------------------------------------------
  526. // CFindFolder::_OnInsert
  527. //--------------------------------------------------------------------------
  528. HRESULT CFindFolder::_OnInsert(DWORD iFolder, LPMESSAGEINFO pInfo,
  529. BOOL *pfMatch, LPMESSAGEID pidNew /* =NULL */)
  530. {
  531. // Locals
  532. HRESULT hr=S_OK;
  533. MESSAGEINFO Message;
  534. // Trace
  535. TraceCall("CFindFolder::_OnInsert");
  536. // Invalid Argts
  537. Assert(iFolder < m_cFolders && pInfo);
  538. // Init
  539. if (pfMatch)
  540. *pfMatch = FALSE;
  541. // Doesn't match my criteria ?
  542. if (S_FALSE == _IsMatch(iFolder, pInfo))
  543. goto exit;
  544. // Init
  545. if (pfMatch)
  546. *pfMatch = TRUE;
  547. // Copy the Message Info
  548. CopyMemory(&Message, pInfo, sizeof(MESSAGEINFO));
  549. // Store the Folder Name
  550. Message.pszFolder = m_prgFolder[iFolder].pszName;
  551. // Set the Source Id
  552. Message.idFindSource = Message.idMessage;
  553. // Set the Tag
  554. Message.iFindFolder = iFolder;
  555. // Generate a New Message Id
  556. IF_FAILEXIT(hr = m_pSearch->GenerateId((LPDWORD)&Message.idMessage));
  557. // Remove some stuff to make it smaller
  558. CLEAR_MESSAGE_FIELDS(Message);
  559. // Insert the Record
  560. IF_FAILEXIT(hr = m_pSearch->InsertRecord(&Message));
  561. // Return the Id
  562. if (pidNew)
  563. *pidNew = Message.idMessage;
  564. exit:
  565. // Done
  566. return(hr);
  567. }
  568. //--------------------------------------------------------------------------
  569. // CFindFolder::_OnDelete
  570. //--------------------------------------------------------------------------
  571. HRESULT CFindFolder::_OnDelete(DWORD iFolder, LPMESSAGEINFO pInfo)
  572. {
  573. // Locals
  574. HRESULT hr=S_OK;
  575. MESSAGEINFO Message={0};
  576. // Trace
  577. TraceCall("CFindFolder::_OnDelete");
  578. // Invalid Argts
  579. Assert(iFolder < m_cFolders && pInfo);
  580. // Setup the Search key
  581. Message.iFindFolder = iFolder;
  582. Message.idFindSource = pInfo->idMessage;
  583. // Find It
  584. IF_FAILEXIT(hr = m_pSearch->FindRecord(IINDEX_FINDER, COLUMNS_ALL, &Message, NULL));
  585. // Not Found
  586. if (DB_S_NOTFOUND == hr)
  587. {
  588. hr = TraceResult(DB_E_NOTFOUND);
  589. goto exit;
  590. }
  591. // Delete this Record
  592. IF_FAILEXIT(hr = m_pSearch->DeleteRecord(&Message));
  593. exit:
  594. // Cleanup
  595. m_pSearch->FreeRecord(&Message);
  596. // Done
  597. return(hr);
  598. }
  599. //--------------------------------------------------------------------------
  600. // CFindFolder::_OnUpdate
  601. //--------------------------------------------------------------------------
  602. HRESULT CFindFolder::_OnUpdate(DWORD iFolder, LPMESSAGEINFO pInfo1,
  603. LPMESSAGEINFO pInfo2)
  604. {
  605. // Locals
  606. HRESULT hr=S_OK;
  607. MESSAGEINFO Message;
  608. MESSAGEINFO Current={0};
  609. // Trace
  610. TraceCall("CFindFolder::_OnUpdate");
  611. // Invalid Argts
  612. Assert(iFolder < m_cFolders && pInfo1 && pInfo2);
  613. // Doesn't match my criteria ?
  614. if (S_FALSE == _IsMatch(iFolder, pInfo1))
  615. {
  616. // If the Original Record was not in the find folder, then see if record 2 should be added
  617. _OnInsert(iFolder, pInfo2, NULL);
  618. }
  619. // If pInfo2 should not be displayed, then delete pInfo1
  620. else if (S_FALSE == _IsMatch(iFolder, pInfo2))
  621. {
  622. // Delete pInfo1
  623. _OnDelete(iFolder, pInfo1);
  624. }
  625. // Otherwise, update pInfo1
  626. else
  627. {
  628. // Setup the Search key
  629. Current.iFindFolder = iFolder;
  630. Current.idFindSource = pInfo1->idMessage;
  631. // Find It
  632. IF_FAILEXIT(hr = m_pSearch->FindRecord(IINDEX_FINDER, COLUMNS_ALL, &Current, NULL));
  633. // Not Found
  634. if (DB_S_NOTFOUND == hr)
  635. {
  636. hr = TraceResult(DB_E_NOTFOUND);
  637. goto exit;
  638. }
  639. // Copy the Message Info
  640. CopyMemory(&Message, pInfo2, sizeof(MESSAGEINFO));
  641. // Fixup the Version
  642. Message.bVersion = Current.bVersion;
  643. // Store the Folder Name
  644. Message.pszFolder = m_prgFolder[iFolder].pszName;
  645. // Set the Source Id
  646. Message.idFindSource = Current.idFindSource;
  647. // Set the Tag
  648. Message.iFindFolder = iFolder;
  649. // Set the id
  650. Message.idMessage = Current.idMessage;
  651. // Remove some stuff to make it smaller
  652. Message.pszUidl = NULL;
  653. Message.pszServer = NULL;
  654. Message.faStream = 0;
  655. // Insert the Record
  656. IF_FAILEXIT(hr = m_pSearch->UpdateRecord(&Message));
  657. }
  658. exit:
  659. // Cleanup
  660. m_pSearch->FreeRecord(&Current);
  661. // Done
  662. return(hr);
  663. }
  664. //--------------------------------------------------------------------------
  665. // CFindFolder::_IsMatch
  666. //--------------------------------------------------------------------------
  667. HRESULT CFindFolder::_IsMatch(DWORD iFolder, LPMESSAGEINFO pInfo)
  668. {
  669. // Trace
  670. TraceCall("CFindFolder::_ProcessMessageInfo");
  671. // Has Attachment
  672. if (ISFLAGSET(m_pCriteria->mask, FIM_ATTACHMENT))
  673. {
  674. // No Attachment
  675. if (FALSE == ISFLAGSET(pInfo->dwFlags, ARF_HASATTACH))
  676. return(S_FALSE);
  677. }
  678. // Is Flagged
  679. if (ISFLAGSET(m_pCriteria->mask, FIM_FLAGGED))
  680. {
  681. // No Attachment
  682. if (FALSE == ISFLAGSET(pInfo->dwFlags, ARF_FLAGGED))
  683. return(S_FALSE);
  684. }
  685. // Was Forwarded
  686. if (ISFLAGSET(m_pCriteria->mask, FIM_FORWARDED))
  687. {
  688. // No Attachment
  689. if (FALSE == ISFLAGSET(pInfo->dwFlags, ARF_FORWARDED))
  690. return(S_FALSE);
  691. }
  692. // Was Replied to
  693. if (ISFLAGSET(m_pCriteria->mask, FIM_REPLIED))
  694. {
  695. // No Attachment
  696. if (FALSE == ISFLAGSET(pInfo->dwFlags, ARF_REPLIED))
  697. return(S_FALSE);
  698. }
  699. // From
  700. if (ISFLAGSET(m_pCriteria->mask, FIM_FROM))
  701. {
  702. // No pszFrom
  703. if (NULL == m_pCriteria->pszFrom)
  704. return(S_FALSE);
  705. // Check pszEmail From
  706. if (NULL == pInfo->pszDisplayFrom || NULL == StrStrIA(pInfo->pszDisplayFrom, m_pCriteria->pszFrom))
  707. {
  708. // Try Email
  709. if (NULL == pInfo->pszEmailFrom || NULL == StrStrIA(pInfo->pszEmailFrom, m_pCriteria->pszFrom))
  710. return(S_FALSE);
  711. }
  712. }
  713. // Subject
  714. if (ISFLAGSET(m_pCriteria->mask, FIM_SUBJECT))
  715. {
  716. // Check Subject
  717. if (NULL == m_pCriteria->pszSubject || NULL == pInfo->pszSubject || NULL == StrStrIA(pInfo->pszSubject, m_pCriteria->pszSubject))
  718. return(S_FALSE);
  719. }
  720. // Recipient
  721. if (ISFLAGSET(m_pCriteria->mask, FIM_TO))
  722. {
  723. // No pszFrom
  724. if (NULL == m_pCriteria->pszTo)
  725. return(S_FALSE);
  726. // Check pszEmail From
  727. if (NULL == pInfo->pszDisplayTo || NULL == StrStrIA(pInfo->pszDisplayTo, m_pCriteria->pszTo))
  728. {
  729. // Try Email
  730. if (NULL == pInfo->pszEmailTo || NULL == StrStrIA(pInfo->pszEmailTo, m_pCriteria->pszTo))
  731. return(S_FALSE);
  732. }
  733. }
  734. // DateFrom <= pInfo <= DateTo
  735. if (ISFLAGSET(m_pCriteria->mask, FIM_DATEFROM))
  736. {
  737. // Locals
  738. FILETIME ftLocal;
  739. // Convert to local file time
  740. FileTimeToLocalFileTime(&pInfo->ftReceived, &ftLocal);
  741. // Compare Received
  742. if (CompareFileTime(&ftLocal, &m_pCriteria->ftDateFrom) < 0)
  743. return(S_FALSE);
  744. }
  745. // DateFrom <= pInfo <= DateTo
  746. if (ISFLAGSET(m_pCriteria->mask, FIM_DATETO))
  747. {
  748. // Locals
  749. FILETIME ftLocal;
  750. // Convert to local file time
  751. FileTimeToLocalFileTime(&pInfo->ftReceived, &ftLocal);
  752. // Compare Received
  753. if (CompareFileTime(&ftLocal, &m_pCriteria->ftDateTo) > 0)
  754. return(S_FALSE);
  755. }
  756. // Body Text
  757. if (ISFLAGSET(m_pCriteria->mask, FIM_BODYTEXT))
  758. {
  759. // Locals
  760. BOOL fMatch=FALSE;
  761. IStream *pStream;
  762. // No Body TExt
  763. if (NULL == m_pCriteria->pszBody)
  764. return(S_FALSE);
  765. // Open the mime message
  766. if (SUCCEEDED(LighweightOpenMessage(m_prgFolder[iFolder].pDB, pInfo, &m_pMessage)))
  767. {
  768. // Try to Get the Plain Text Stream
  769. if (FAILED(m_pMessage->GetTextBody(TXT_PLAIN, IET_DECODED, &pStream, NULL)))
  770. {
  771. // Try to get the HTML stream
  772. if (FAILED(m_pMessage->GetTextBody(TXT_HTML, IET_DECODED, &pStream, NULL)))
  773. pStream = NULL;
  774. }
  775. // Do we have a strema
  776. if (pStream)
  777. {
  778. // Search the Stream
  779. fMatch = StreamSubStringMatch(pStream, m_pCriteria->pszBody);
  780. // Release the Stream
  781. pStream->Release();
  782. }
  783. }
  784. // No Match
  785. if (FALSE == fMatch)
  786. return(S_FALSE);
  787. }
  788. // Its a match
  789. return(S_OK);
  790. }
  791. //--------------------------------------------------------------------------
  792. // CFindFolder::SaveMessage
  793. //--------------------------------------------------------------------------
  794. STDMETHODIMP CFindFolder::SaveMessage(LPMESSAGEID pidMessage,
  795. SAVEMESSAGEFLAGS dwOptions, MESSAGEFLAGS dwFlags,
  796. IStream *pStream, IMimeMessage *pMessage, IStoreCallback *pCallback)
  797. {
  798. // Locals
  799. HRESULT hr=S_OK;
  800. HLOCK hLock=NULL;
  801. MESSAGEID idSaved;
  802. MESSAGEINFO Saved={0};
  803. MESSAGEINFO Message={0};
  804. LPFOLDERENTRY pEntry=NULL;
  805. BOOL fRegNotify=FALSE;
  806. IMessageFolder *pFolder=NULL;
  807. // Trace
  808. TraceCall("CFindFolder::SaveMessage");
  809. // Invalid Args
  810. if (NULL == pidMessage || NULL == pMessage || !ISFLAGSET(dwOptions, SAVE_MESSAGE_GENID))
  811. {
  812. Assert(FALSE);
  813. return TraceResult(E_INVALIDARG);
  814. }
  815. // Set the messageId
  816. Message.idMessage = *pidMessage;
  817. // Find It
  818. IF_FAILEXIT(hr = m_pSearch->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL));
  819. // Not Found
  820. if (DB_S_NOTFOUND == hr)
  821. {
  822. AssertSz(FALSE, "This can't happen because you can't save new messages into a search folder.");
  823. hr = TraceResult(DB_E_NOTFOUND);
  824. goto exit;
  825. }
  826. // Get the Folder Entry
  827. pEntry = &m_prgFolder[Message.iFindFolder];
  828. // Open the folder
  829. IF_FAILEXIT(hr = g_pStore->OpenFolder(pEntry->idFolder, NULL, NOFLAGS, &pFolder));
  830. // Lock
  831. IF_FAILEXIT(hr = pEntry->pDB->Lock(&hLock));
  832. // Remove my notification
  833. pEntry->pDB->UnregisterNotify((IDatabaseNotify *)this);
  834. // Re-Register for notifications
  835. fRegNotify = TRUE;
  836. // Set idFindSource
  837. idSaved = Message.idFindSource;
  838. // Open the Message
  839. IF_FAILEXIT(hr = pFolder->SaveMessage(&idSaved, dwOptions, dwFlags, pStream, pMessage, pCallback));
  840. // Get the new message info
  841. IF_FAILEXIT(hr = GetMessageInfo(pFolder, idSaved, &Saved));
  842. // Insert This Dude
  843. IF_FAILEXIT(hr = _OnInsert(Message.iFindFolder, &Saved, NULL, pidMessage));
  844. exit:
  845. // Cleanup
  846. if (pEntry)
  847. {
  848. // fRegNotify
  849. if (fRegNotify)
  850. {
  851. // Re-register for notifications
  852. pEntry->pDB->RegisterNotify(IINDEX_PRIMARY, REGISTER_NOTIFY_NOADDREF, Message.iFindFolder, (IDatabaseNotify *)this);
  853. }
  854. // Unlock the Folder
  855. pEntry->pDB->Unlock(&hLock);
  856. }
  857. // Free Message
  858. m_pSearch->FreeRecord(&Message);
  859. // Free
  860. if (pFolder)
  861. pFolder->FreeRecord(&Saved);
  862. // Release the Folder
  863. SafeRelease(pFolder);
  864. // Done
  865. return(hr);
  866. }
  867. //--------------------------------------------------------------------------
  868. // CFindFolder::OpenMessage
  869. //--------------------------------------------------------------------------
  870. STDMETHODIMP CFindFolder::OpenMessage(MESSAGEID idMessage,
  871. OPENMESSAGEFLAGS dwFlags, IMimeMessage **ppMessage,
  872. IStoreCallback *pCallback)
  873. {
  874. // Locals
  875. HRESULT hr=S_OK;
  876. MESSAGEINFO Message={0};
  877. LPFOLDERENTRY pEntry;
  878. // Trace
  879. TraceCall("CFindFolder::OpenMessage");
  880. // Set the messageId
  881. Message.idMessage = idMessage;
  882. // Find It
  883. IF_FAILEXIT(hr = m_pSearch->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL));
  884. // Not Found
  885. if (DB_S_NOTFOUND == hr)
  886. {
  887. hr = TraceResult(DB_E_NOTFOUND);
  888. goto exit;
  889. }
  890. // Get entry
  891. pEntry = &m_prgFolder[Message.iFindFolder];
  892. // Do we have a folder open yet ?
  893. if (NULL == pEntry->pFolder)
  894. {
  895. // Get the Real Folder
  896. IF_FAILEXIT(hr = g_pStore->OpenFolder(pEntry->idFolder, NULL, NOFLAGS, &pEntry->pFolder));
  897. }
  898. // Open the Message
  899. IF_FAILEXIT(hr = pEntry->pFolder->OpenMessage(Message.idFindSource, dwFlags, ppMessage, pCallback));
  900. exit:
  901. // Cleanup
  902. m_pSearch->FreeRecord(&Message);
  903. // Done
  904. return(hr);
  905. }
  906. //--------------------------------------------------------------------------
  907. // CFindFolder::SetMessageFlags
  908. //--------------------------------------------------------------------------
  909. STDMETHODIMP CFindFolder::SetMessageFlags(LPMESSAGEIDLIST pList,
  910. LPADJUSTFLAGS pFlags, LPRESULTLIST pResults,
  911. IStoreCallback *pCallback)
  912. {
  913. // Locals
  914. HRESULT hr=S_OK;
  915. HWND hwndParent;
  916. DWORD i;
  917. LPMESSAGEIDLIST prgList=NULL;
  918. IMessageFolder *pFolder=NULL;
  919. // Trace
  920. TraceCall("CFindFolder::SetMessageFlags");
  921. // Invalid Args
  922. Assert(NULL == pList || pList->cMsgs > 0);
  923. Assert(pCallback);
  924. // Invalid Args
  925. if (NULL == pCallback)
  926. return TraceResult(E_INVALIDARG);
  927. // Get the Parent Window
  928. IF_FAILEXIT(hr = pCallback->GetParentWindow(0, &hwndParent));
  929. // Collate into folders
  930. IF_FAILEXIT(hr = _CollateIdList(pList, &prgList, NULL));
  931. // Walk through the folders...
  932. for (i=0; i<m_cFolders; i++)
  933. {
  934. // Call Into the Folder unless cMsgs == 0
  935. if (prgList[i].cMsgs > 0)
  936. {
  937. // Get the Real Folder
  938. IF_FAILEXIT(hr = g_pStore->OpenFolder(m_prgFolder[i].idFolder, NULL, NOFLAGS, &pFolder));
  939. // Blocking...
  940. IF_FAILEXIT(hr = SetMessageFlagsProgress(hwndParent, pFolder, pFlags, &prgList[i]));
  941. // Cleanup
  942. SafeRelease(pFolder);
  943. }
  944. }
  945. exit:
  946. // Cleanup
  947. SafeRelease(pFolder);
  948. _FreeIdListArray(&prgList);
  949. // Done
  950. return(hr);
  951. }
  952. //--------------------------------------------------------------------------
  953. // CFindFolder::CopyMessages
  954. //--------------------------------------------------------------------------
  955. STDMETHODIMP CFindFolder::CopyMessages(IMessageFolder *pDest,
  956. COPYMESSAGEFLAGS dwFlags, LPMESSAGEIDLIST pList, LPADJUSTFLAGS pFlags,
  957. LPRESULTLIST pResults, IStoreCallback *pCallback)
  958. {
  959. // Locals
  960. HRESULT hr=S_OK;
  961. HWND hwndParent;
  962. DWORD i;
  963. LPMESSAGEIDLIST prgList=NULL;
  964. IMessageFolder *pFolder=NULL;
  965. // Trace
  966. TraceCall("CFindFolder::CopyMessages");
  967. // Better have a callback
  968. Assert(pCallback);
  969. // Invalid Args
  970. if (NULL == pCallback)
  971. return TraceResult(E_INVALIDARG);
  972. // Get the Parent Window
  973. IF_FAILEXIT(hr = pCallback->GetParentWindow(0, &hwndParent));
  974. // Collate into folders
  975. IF_FAILEXIT(hr = _CollateIdList(pList, &prgList, NULL));
  976. // Walk through the folders...
  977. for (i=0; i<m_cFolders; i++)
  978. {
  979. // Anything to do?
  980. if (prgList[i].cMsgs > 0)
  981. {
  982. // Get the Real Folder
  983. IF_FAILEXIT(hr = g_pStore->OpenFolder(m_prgFolder[i].idFolder, NULL, NOFLAGS, &pFolder));
  984. // Call Justins
  985. IF_FAILEXIT(hr = CopyMessagesProgress(hwndParent, pFolder, pDest, dwFlags, &prgList[i], pFlags));
  986. // Cleanup
  987. SafeRelease(pFolder);
  988. }
  989. }
  990. exit:
  991. // Cleanup
  992. SafeRelease(pFolder);
  993. _FreeIdListArray(&prgList);
  994. // Done
  995. return(hr);
  996. }
  997. //--------------------------------------------------------------------------
  998. // CFindFolder::DeleteMessages
  999. //--------------------------------------------------------------------------
  1000. STDMETHODIMP CFindFolder::DeleteMessages(DELETEMESSAGEFLAGS dwFlags,
  1001. LPMESSAGEIDLIST pList, LPRESULTLIST pResults,
  1002. IStoreCallback *pCallback)
  1003. {
  1004. // Locals
  1005. HRESULT hr=S_OK;
  1006. DWORD i;
  1007. BOOL fSomeInDeleted;
  1008. HWND hwndParent;
  1009. LPMESSAGEIDLIST prgList=NULL;
  1010. IMessageFolder *pFolder=NULL;
  1011. // Trace
  1012. TraceCall("CFindFolder::DeleteMessages");
  1013. // Invalid Args
  1014. Assert(NULL == pList || pList->cMsgs > 0);
  1015. Assert(pCallback);
  1016. // Invalid Args
  1017. if (NULL == pCallback)
  1018. return TraceResult(E_INVALIDARG);
  1019. // Collate into folders
  1020. IF_FAILEXIT(hr = _CollateIdList(pList, &prgList, &fSomeInDeleted));
  1021. // Prompt...
  1022. if (fSomeInDeleted && FALSE == ISFLAGSET(dwFlags, DELETE_MESSAGE_NOPROMPT))
  1023. {
  1024. // Get a Parent Hwnd
  1025. Assert(pCallback);
  1026. // Get Parent Window
  1027. if (FAILED(pCallback->GetParentWindow(0, &hwndParent)))
  1028. hwndParent = NULL;
  1029. // Prompt...
  1030. if (IDNO == AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsWarnSomePermDelete), NULL, MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION ))
  1031. goto exit;
  1032. }
  1033. // Get the Parent Window
  1034. IF_FAILEXIT(hr = pCallback->GetParentWindow(0, &hwndParent));
  1035. // Walk through the folders...
  1036. for (i=0; i<m_cFolders; i++)
  1037. {
  1038. // Call Into the Folder unless cMsgs == 0
  1039. if (prgList[i].cMsgs > 0)
  1040. {
  1041. // Get the Real Folder
  1042. IF_FAILEXIT(hr = g_pStore->OpenFolder(m_prgFolder[i].idFolder, NULL, NOFLAGS, &pFolder));
  1043. // Call Into the Folder
  1044. IF_FAILEXIT(hr = DeleteMessagesProgress(hwndParent, pFolder, dwFlags | DELETE_MESSAGE_NOPROMPT, &prgList[i]));
  1045. // Cleanup
  1046. SafeRelease(pFolder);
  1047. }
  1048. }
  1049. exit:
  1050. // Cleanup
  1051. SafeRelease(pFolder);
  1052. _FreeIdListArray(&prgList);
  1053. // Done
  1054. return(hr);
  1055. }
  1056. //--------------------------------------------------------------------------
  1057. // CFindFolder::_CollateIdList
  1058. //--------------------------------------------------------------------------
  1059. HRESULT CFindFolder::_CollateIdList(LPMESSAGEIDLIST pList,
  1060. LPMESSAGEIDLIST *pprgCollated, BOOL *pfSomeInDeleted)
  1061. {
  1062. // Locals
  1063. HRESULT hr=S_OK;
  1064. HROWSET hRowset=NULL;
  1065. LPMESSAGEIDLIST pListDst;
  1066. DWORD i;
  1067. MESSAGEINFO Message={0};
  1068. // Trace
  1069. TraceCall("CFindFolder::_CollateIdList");
  1070. // Initialize
  1071. if (pfSomeInDeleted)
  1072. *pfSomeInDeleted = FALSE;
  1073. // Allocate pprgCollated
  1074. IF_NULLEXIT(*pprgCollated = (LPMESSAGEIDLIST)ZeroAllocate(sizeof(MESSAGEIDLIST) * m_cFolders));
  1075. // Need a Rowset
  1076. if (NULL == pList)
  1077. {
  1078. // Create a Rowset
  1079. IF_FAILEXIT(hr = m_pSearch->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
  1080. }
  1081. // Loop through the messageIds
  1082. for (i=0;;i++)
  1083. {
  1084. // Done
  1085. if (pList)
  1086. {
  1087. // Done
  1088. if (i >= pList->cMsgs)
  1089. break;
  1090. // Set the MessageId
  1091. Message.idMessage = pList->prgidMsg[i];
  1092. // Look for this record
  1093. IF_FAILEXIT(hr = m_pSearch->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL));
  1094. }
  1095. // Otherwise, enumerate next
  1096. else
  1097. {
  1098. // Get the next
  1099. IF_FAILEXIT(hr = m_pSearch->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL));
  1100. // Done
  1101. if (S_FALSE == hr)
  1102. {
  1103. hr = S_OK;
  1104. break;
  1105. }
  1106. // Found
  1107. hr = DB_S_FOUND;
  1108. }
  1109. // Was It Found
  1110. if (DB_S_FOUND == hr)
  1111. {
  1112. // Validate
  1113. Assert(Message.iFindFolder < m_cFolders);
  1114. // Return pfSomeInDeleted
  1115. if (pfSomeInDeleted && m_prgFolder[Message.iFindFolder].fInDeleted)
  1116. *pfSomeInDeleted = TRUE;
  1117. // Locate the Correct
  1118. pListDst = &((*pprgCollated)[Message.iFindFolder]);
  1119. // Need to Grow this puppy
  1120. if (pListDst->cMsgs + 1 >= pListDst->cAllocated)
  1121. {
  1122. // Realloc the Array
  1123. IF_FAILEXIT(hr = HrRealloc((LPVOID *)&pListDst->prgidMsg, sizeof(MESSAGEID) * (pListDst->cAllocated + 256)));
  1124. // Increment
  1125. pListDst->cAllocated += 256;
  1126. }
  1127. // Store the Id
  1128. pListDst->prgidMsg[pListDst->cMsgs++] = Message.idFindSource;
  1129. // Free
  1130. m_pSearch->FreeRecord(&Message);
  1131. }
  1132. }
  1133. exit:
  1134. // Cleanup
  1135. m_pSearch->FreeRecord(&Message);
  1136. m_pSearch->CloseRowset(&hRowset);
  1137. // Failure
  1138. if (FAILED(hr))
  1139. _FreeIdListArray(pprgCollated);
  1140. // Done
  1141. return(hr);
  1142. }
  1143. //--------------------------------------------------------------------------
  1144. // CFindFolder::_FreeIdListArray
  1145. //--------------------------------------------------------------------------
  1146. HRESULT CFindFolder::_FreeIdListArray(LPMESSAGEIDLIST *pprgList)
  1147. {
  1148. // Locals
  1149. DWORD i;
  1150. // Trace
  1151. TraceCall("CFindFolder::_FreeIdListArray");
  1152. // Nothing to Free
  1153. if (NULL == *pprgList)
  1154. return(S_OK);
  1155. // Loop
  1156. for (i=0; i<m_cFolders; i++)
  1157. {
  1158. // Free prgidMsg
  1159. SafeMemFree((*pprgList)[i].prgidMsg);
  1160. }
  1161. // Free the Array
  1162. SafeMemFree((*pprgList));
  1163. // Done
  1164. return(S_OK);
  1165. }
  1166. //--------------------------------------------------------------------------
  1167. // CFindFolder::OnTransaction
  1168. //--------------------------------------------------------------------------
  1169. STDMETHODIMP CFindFolder::OnTransaction(HTRANSACTION hTransaction, DWORD_PTR dwCookie,
  1170. IDatabase *pDB)
  1171. {
  1172. // Locals
  1173. HRESULT hr;
  1174. HLOCK hNotify=NULL;
  1175. MESSAGEINFO Message1={0};
  1176. MESSAGEINFO Message2={0};
  1177. ORDINALLIST Ordinals;
  1178. INDEXORDINAL iIndex;
  1179. TRANSACTIONTYPE tyTransaction;
  1180. // Trace
  1181. TraceCall("CFindFolder::OnRecordNotify");
  1182. // Lock Notifications
  1183. m_pSearch->LockNotify(NOFLAGS, &hNotify);
  1184. // While we have a Transaction...
  1185. while (hTransaction)
  1186. {
  1187. // Get Transaction
  1188. IF_FAILEXIT(hr = pDB->GetTransaction(&hTransaction, &tyTransaction, &Message1, &Message2, &iIndex, &Ordinals));
  1189. // Insert
  1190. if (TRANSACTION_INSERT == tyTransaction)
  1191. {
  1192. // Ccall OnInsert
  1193. _OnInsert((DWORD) dwCookie, &Message1, NULL);
  1194. }
  1195. // Delete
  1196. else if (TRANSACTION_DELETE == tyTransaction)
  1197. {
  1198. // Ccall OnDelete
  1199. _OnDelete((DWORD) dwCookie, &Message1);
  1200. }
  1201. // Update
  1202. else if (TRANSACTION_UPDATE == tyTransaction)
  1203. {
  1204. // Ccall OnInsert
  1205. _OnUpdate((DWORD) dwCookie, &Message1, &Message2);
  1206. }
  1207. }
  1208. exit:
  1209. // Cleanup
  1210. pDB->FreeRecord(&Message1);
  1211. pDB->FreeRecord(&Message2);
  1212. // Lock Notifications
  1213. m_pSearch->UnlockNotify(&hNotify);
  1214. // Done
  1215. return(S_OK);
  1216. }
  1217. HRESULT CFindFolder::ConnectionAddRef()
  1218. {
  1219. if (m_pSearch)
  1220. m_pSearch->ConnectionAddRef();
  1221. return S_OK;
  1222. }
  1223. HRESULT CFindFolder::ConnectionRelease()
  1224. {
  1225. if (m_pSearch)
  1226. m_pSearch->ConnectionAddRef();
  1227. return S_OK;
  1228. }