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.

3649 lines
110 KiB

  1. // --------------------------------------------------------------------------------
  2. // Pop3task.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "pop3task.h"
  8. #include "resource.h"
  9. #include "xputil.h"
  10. #include "goptions.h"
  11. #include "strconst.h"
  12. #include "mimeutil.h"
  13. #include "shlwapi.h"
  14. #include "shlwapip.h"
  15. #include "options.h"
  16. #include "xpcomm.h"
  17. #include "ourguid.h"
  18. #include "msgfldr.h"
  19. #include "storecb.h"
  20. #include "mailutil.h"
  21. #include "ruleutil.h"
  22. #include "demand.h"
  23. // --------------------------------------------------------------------------------
  24. // Debug Modifiers
  25. // --------------------------------------------------------------------------------
  26. #ifdef DEBUG
  27. BOOL g_fUidlByTop = FALSE;
  28. BOOL g_fFailTopCommand = FALSE;
  29. LONG g_ulFailNumber=-1;
  30. #endif
  31. // --------------------------------------------------------------------------------
  32. // ISLASTPOPID
  33. // --------------------------------------------------------------------------------
  34. #define ISLASTPOPID(_dwPopId) \
  35. (_dwPopId == m_rTable.cItems)
  36. // --------------------------------------------------------------------------------
  37. // ISVALIDPOPID
  38. // --------------------------------------------------------------------------------
  39. #define ISVALIDPOPID(_dwPopId) \
  40. (_dwPopId - 1 < m_rTable.cItems)
  41. // --------------------------------------------------------------------------------
  42. // ITEMFROMPOPID
  43. // --------------------------------------------------------------------------------
  44. #define ITEMFROMPOPID(_dwPopId) \
  45. (&m_rTable.prgItem[_dwPopId - 1])
  46. // --------------------------------------------------------------------------------
  47. // CPop3Task::CPop3Task
  48. // --------------------------------------------------------------------------------
  49. CPop3Task::CPop3Task(void)
  50. {
  51. m_cRef = 1;
  52. m_dwFlags = 0;
  53. m_dwState = 0;
  54. m_dwExpireDays = 0;
  55. m_pSpoolCtx = NULL;
  56. m_pAccount = NULL;
  57. m_pTransport = NULL;
  58. m_pUI = NULL;
  59. m_pIExecRules = NULL;
  60. m_pIRuleSender = NULL;
  61. m_pIRuleJunk = NULL;
  62. m_pInbox = NULL;
  63. m_pOutbox = NULL;
  64. m_eidEvent = 0;
  65. m_pUidlCache = NULL;
  66. m_uidlsupport = UIDL_SUPPORT_NONE;
  67. m_dwProgressMax = 0;
  68. m_dwProgressCur = 0;
  69. m_wProgress = 0;
  70. m_eidEvent = 0;
  71. m_hrResult = S_OK;
  72. m_pStream = NULL;
  73. m_state = POP3STATE_NONE;
  74. m_hwndTimeout = NULL;
  75. m_pLogFile = NULL;
  76. m_pSmartLog = NULL;
  77. *m_szAccountId = '\0';
  78. ZeroMemory(&m_rMetrics, sizeof(POP3METRICS));
  79. ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO));
  80. ZeroMemory(&m_rTable, sizeof(POP3ITEMTABLE));
  81. ZeroMemory(&m_rServer, sizeof(INETSERVER));
  82. InitializeCriticalSection(&m_cs);
  83. }
  84. // --------------------------------------------------------------------------------
  85. // CPop3Task::~CPop3Task
  86. // --------------------------------------------------------------------------------
  87. CPop3Task::~CPop3Task(void)
  88. {
  89. ZeroMemory(&m_rServer, sizeof(m_rServer)); // Done for security.
  90. // Reset the Object
  91. _ResetObject(TRUE);
  92. // Kill the critical section
  93. DeleteCriticalSection(&m_cs);
  94. }
  95. // --------------------------------------------------------------------------------
  96. // CPop3Task::_ResetObject
  97. // --------------------------------------------------------------------------------
  98. void CPop3Task::_ResetObject(BOOL fDeconstruct)
  99. {
  100. // Release Folder Objects
  101. _ReleaseFolderObjects();
  102. // Make sure the transport is disconnect
  103. if (m_pTransport)
  104. {
  105. m_pTransport->Release();
  106. m_pTransport = NULL;
  107. }
  108. // Release the Outbox
  109. SafeRelease(m_pAccount);
  110. SafeRelease(m_pInbox);
  111. SafeRelease(m_pOutbox);
  112. SafeRelease(m_pIExecRules);
  113. SafeRelease(m_pIRuleSender);
  114. SafeRelease(m_pIRuleJunk);
  115. SafeRelease(m_pSpoolCtx);
  116. SafeRelease(m_pUI);
  117. SafeRelease(m_pUidlCache);
  118. SafeRelease(m_pStream);
  119. SafeRelease(m_pLogFile);
  120. // Kill the log file
  121. _FreeSmartLog();
  122. // Free the event table elements
  123. _FreeItemTableElements();
  124. // Deconstructing
  125. if (fDeconstruct)
  126. {
  127. // Free Event Table
  128. SafeMemFree(m_rTable.prgItem);
  129. }
  130. // Otherwise, reset some vars
  131. else
  132. {
  133. // Reset total byte count
  134. m_dwFlags = 0;
  135. m_dwState = 0;
  136. m_dwExpireDays = 0;
  137. m_eidEvent = 0;
  138. m_wProgress = 0;
  139. m_uidlsupport = UIDL_SUPPORT_NONE;
  140. m_state = POP3STATE_NONE;
  141. ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO));
  142. ZeroMemory(&m_rMetrics, sizeof(POP3METRICS));
  143. ZeroMemory(&m_rServer, sizeof(INETSERVER));
  144. }
  145. }
  146. // --------------------------------------------------------------------------------
  147. // CPop3Task::_ReleaseFolderObjects
  148. // --------------------------------------------------------------------------------
  149. void CPop3Task::_ReleaseFolderObjects(void)
  150. {
  151. // m_rFolder should have been release
  152. _CloseFolder();
  153. // Force Inbox Rules to release folder objects
  154. if (m_pIExecRules)
  155. {
  156. m_pIExecRules->ReleaseObjects();
  157. }
  158. // Download only locks the inbox
  159. SafeRelease(m_pInbox);
  160. }
  161. // --------------------------------------------------------------------------------
  162. // CPop3Task::_FreeItemTableElements
  163. // --------------------------------------------------------------------------------
  164. void CPop3Task::_FreeItemTableElements(void)
  165. {
  166. // Loop the table of events
  167. for (ULONG i=0; i<m_rTable.cItems; i++)
  168. {
  169. // Free pszForwardTo
  170. SafeMemFree(m_rTable.prgItem[i].pszUidl);
  171. RuleUtil_HrFreeActionsItem(m_rTable.prgItem[i].pActList, m_rTable.prgItem[i].cActList);
  172. SafeMemFree(m_rTable.prgItem[i].pActList);
  173. }
  174. // No Events
  175. m_rTable.cItems = 0;
  176. }
  177. // --------------------------------------------------------------------------------
  178. // CPop3Task::QueryInterface
  179. // --------------------------------------------------------------------------------
  180. STDMETHODIMP CPop3Task::QueryInterface(REFIID riid, LPVOID *ppv)
  181. {
  182. // Locals
  183. HRESULT hr=S_OK;
  184. // check params
  185. if (ppv == NULL)
  186. return TrapError(E_INVALIDARG);
  187. // Thread Safety
  188. EnterCriticalSection(&m_cs);
  189. // Find IID
  190. if (IID_IUnknown == riid)
  191. *ppv = (IUnknown *)(ISpoolerTask *)this;
  192. else if (IID_ISpoolerTask == riid)
  193. *ppv = (ISpoolerTask *)this;
  194. else if (IID_ITimeoutCallback == riid)
  195. *ppv = (ITimeoutCallback *) this;
  196. else if (IID_ITransportCallbackService == riid)
  197. *ppv = (ITransportCallbackService *) this;
  198. else
  199. {
  200. *ppv = NULL;
  201. hr = TrapError(E_NOINTERFACE);
  202. goto exit;
  203. }
  204. // AddRef It
  205. ((IUnknown *)*ppv)->AddRef();
  206. exit:
  207. // Thread Safety
  208. LeaveCriticalSection(&m_cs);
  209. // Done
  210. return hr;
  211. }
  212. // --------------------------------------------------------------------------------
  213. // CPop3Task::CPop3Task
  214. // --------------------------------------------------------------------------------
  215. STDMETHODIMP_(ULONG) CPop3Task::AddRef(void)
  216. {
  217. EnterCriticalSection(&m_cs);
  218. ULONG cRef = ++m_cRef;
  219. LeaveCriticalSection(&m_cs);
  220. return cRef;
  221. }
  222. // --------------------------------------------------------------------------------
  223. // CPop3Task::CPop3Task
  224. // --------------------------------------------------------------------------------
  225. STDMETHODIMP_(ULONG) CPop3Task::Release(void)
  226. {
  227. EnterCriticalSection(&m_cs);
  228. ULONG cRef = --m_cRef;
  229. LeaveCriticalSection(&m_cs);
  230. if (0 != cRef)
  231. return cRef;
  232. delete this;
  233. return 0;
  234. }
  235. // --------------------------------------------------------------------------------
  236. // CPop3Task::Init
  237. // --------------------------------------------------------------------------------
  238. STDMETHODIMP CPop3Task::Init(DWORD dwFlags, ISpoolerBindContext *pBindCtx)
  239. {
  240. // Invalid Arg
  241. if (NULL == pBindCtx)
  242. return TrapError(E_INVALIDARG);
  243. // Thread Safety
  244. EnterCriticalSection(&m_cs);
  245. // Reset this object
  246. _ResetObject(FALSE);
  247. // Save the Activity Flags - DELIVER_xxx
  248. m_dwFlags = dwFlags;
  249. // Hold onto the bind context
  250. Assert(NULL == m_pSpoolCtx);
  251. m_pSpoolCtx = pBindCtx;
  252. m_pSpoolCtx->AddRef();
  253. // Thread Safety
  254. LeaveCriticalSection(&m_cs);
  255. // Done
  256. return S_OK;
  257. }
  258. // --------------------------------------------------------------------------------
  259. // CPop3Task::BuildEvents
  260. // --------------------------------------------------------------------------------
  261. STDMETHODIMP CPop3Task::BuildEvents(ISpoolerUI *pSpoolerUI, IImnAccount *pAccount, FOLDERID idFolder)
  262. {
  263. // Locals
  264. HRESULT hr=S_OK;
  265. DWORD dw;
  266. CHAR szAccountName[CCHMAX_ACCOUNT_NAME];
  267. CHAR szRes[CCHMAX_RES];
  268. CHAR szMessage[CCHMAX_RES + CCHMAX_ACCOUNT_NAME];
  269. LPSTR pszLogFile=NULL;
  270. DWORD dwState;
  271. PROPVARIANT propvar = {0};
  272. // Invalid Arg
  273. if (NULL == pSpoolerUI || NULL == pAccount)
  274. return TrapError(E_INVALIDARG);
  275. // Thread Safety
  276. EnterCriticalSection(&m_cs);
  277. // Validate State
  278. Assert(NULL == m_pTransport && NULL == m_pAccount && NULL == m_pInbox && 0 == m_rTable.cItems);
  279. // Save the UI Object
  280. m_pUI = pSpoolerUI;
  281. m_pUI->AddRef();
  282. // Release current Account
  283. m_pAccount = pAccount;
  284. m_pAccount->AddRef();
  285. // Leave mail on server
  286. if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_LEAVE_ON_SERVER, &dw)) && TRUE == dw)
  287. FLAGSET(m_dwState, POP3STATE_LEAVEONSERVER);
  288. // Delete Expire
  289. if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_REMOVE_EXPIRED, &dw)) && TRUE == dw)
  290. FLAGSET(m_dwState, POP3STATE_DELETEEXPIRED);
  291. // Days to Expire
  292. if (FAILED(m_pAccount->GetPropDw(AP_POP3_EXPIRE_DAYS, &m_dwExpireDays)))
  293. m_dwExpireDays = 5;
  294. // Delete From Server when deleted from Deleted Items Folder...
  295. if (SUCCEEDED(m_pAccount->GetPropDw(AP_POP3_REMOVE_DELETED, &dw)) && TRUE == dw)
  296. FLAGSET(m_dwState, POP3STATE_SYNCDELETED);
  297. // Get the inbox rules object
  298. Assert(g_pRulesMan);
  299. CHECKHR(hr = g_pRulesMan->ExecRules(EXECF_ALL, RULE_TYPE_MAIL, &m_pIExecRules));
  300. // Get the block sender rule
  301. Assert(NULL == m_pIRuleSender);
  302. (VOID) g_pRulesMan->GetRule(RULEID_SENDERS, RULE_TYPE_MAIL, 0, &m_pIRuleSender);
  303. // Only use it if it there and enabled
  304. if (NULL != m_pIRuleSender)
  305. {
  306. if (FAILED(m_pIRuleSender->GetProp(RULE_PROP_DISABLED, 0, &propvar)))
  307. {
  308. m_pIRuleSender->Release();
  309. m_pIRuleSender = NULL;
  310. }
  311. else
  312. {
  313. Assert(VT_BOOL == propvar.vt);
  314. if (FALSE != propvar.boolVal)
  315. {
  316. m_pIRuleSender->Release();
  317. m_pIRuleSender = NULL;
  318. }
  319. PropVariantClear(&propvar);
  320. }
  321. }
  322. Assert(NULL == m_pIRuleJunk);
  323. (VOID) g_pRulesMan->GetRule(RULEID_JUNK, RULE_TYPE_MAIL, 0, &m_pIRuleJunk);
  324. // Only use it if it enabled
  325. if (NULL != m_pIRuleJunk)
  326. {
  327. if (FAILED(m_pIRuleJunk->GetProp(RULE_PROP_DISABLED, 0, &propvar)))
  328. {
  329. m_pIRuleJunk->Release();
  330. m_pIRuleJunk = NULL;
  331. }
  332. else
  333. {
  334. Assert(VT_BOOL == propvar.vt);
  335. if (FALSE != propvar.boolVal)
  336. {
  337. m_pIRuleJunk->Release();
  338. m_pIRuleJunk = NULL;
  339. }
  340. PropVariantClear(&propvar);
  341. }
  342. }
  343. // Predownload rules
  344. CHECKHR(hr = m_pIExecRules->GetState(&dwState));
  345. // Do we have server actions to do?
  346. if (0 != (dwState & ACT_STATE_SERVER))
  347. FLAGSET(m_dwState, POP3STATE_PDR);
  348. // No Post Download Rules
  349. if ((0 == (dwState & (ACT_STATE_LOCAL|CRIT_STATE_ALL))) &&
  350. (NULL == m_pIRuleSender) &&
  351. (NULL == m_pIRuleJunk))
  352. FLAGSET(m_dwState, POP3STATE_NOPOSTRULES);
  353. // No Body Rules
  354. if ((ISFLAGSET(dwState, CRIT_STATE_ALL)) || (NULL != m_pIRuleJunk))
  355. FLAGSET(m_dwState, POP3STATE_BODYRULES);
  356. // Get the outbox
  357. CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreOutbox, (LPVOID *)&m_pOutbox));
  358. // Get a pop3 log file
  359. m_pSpoolCtx->BindToObject(IID_CPop3LogFile, (LPVOID *)&m_pLogFile);
  360. // Get Account Id
  361. CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccountName, ARRAYSIZE(szAccountName)));
  362. // Register Event - Get new messages from '%s'.
  363. LOADSTRING(IDS_SPS_POP3EVENT, szRes);
  364. // Format the String
  365. wnsprintf(szMessage, ARRAYSIZE(szMessage), szRes, szAccountName);
  366. // Register for the event...
  367. CHECKHR(hr = m_pSpoolCtx->RegisterEvent(szMessage, (ISpoolerTask *)this, POP3EVENT_DOWNLOADMAIL, m_pAccount, &m_eidEvent));
  368. exit:
  369. // Failure
  370. if (FAILED(hr))
  371. {
  372. _CatchResult(hr);
  373. _ResetObject(FALSE);
  374. }
  375. // Thread Safety
  376. LeaveCriticalSection(&m_cs);
  377. // Done
  378. return hr;
  379. }
  380. // --------------------------------------------------------------------------------
  381. // CPop3Task::_DoSmartLog
  382. // --------------------------------------------------------------------------------
  383. void CPop3Task::_DoSmartLog(IMimeMessage *pMessage)
  384. {
  385. // Don't make the function call if this is null...
  386. Assert(m_pSmartLog && m_pSmartLog->pStmFile && m_pSmartLog->pszProperty && m_pSmartLog->pszValue && pMessage);
  387. // Do a query property...
  388. if (lstrcmpi("all", m_pSmartLog->pszProperty) == 0 || S_OK == pMessage->QueryProp(m_pSmartLog->pszProperty, m_pSmartLog->pszValue, TRUE, FALSE))
  389. {
  390. // Locals
  391. LPSTR psz=NULL;
  392. PROPVARIANT rVariant;
  393. IStream *pStream=NULL;
  394. // Get IAT_FROM
  395. if (FAILED(pMessage->GetAddressFormat(IAT_FROM, AFT_DISPLAY_BOTH, &psz)))
  396. {
  397. // Try IAT_SENDER
  398. pMessage->GetAddressFormat(IAT_SENDER, AFT_DISPLAY_BOTH, &psz);
  399. }
  400. // Write the Sender
  401. if (psz)
  402. {
  403. // Write It
  404. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(psz, lstrlen(psz), NULL)));
  405. // Free psz
  406. SafeMemFree(psz);
  407. }
  408. // Otherwise, write Unknown
  409. else
  410. {
  411. CHAR sz[255];
  412. LoadString(g_hLocRes, idsUnknown, sz, ARRAYSIZE(sz));
  413. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(sz, lstrlen(sz), NULL)));
  414. }
  415. // Write a tab
  416. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
  417. // Get IAT_CC
  418. if (SUCCEEDED(pMessage->GetAddressFormat(IAT_CC, AFT_DISPLAY_BOTH, &psz)))
  419. {
  420. // Write It
  421. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(psz, lstrlen(psz), NULL)));
  422. // Free psz
  423. SafeMemFree(psz);
  424. }
  425. // Write a tab
  426. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
  427. // Lets write the X-Mailer just to be a nice guy
  428. rVariant.vt = VT_LPSTR;
  429. if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_XMAILER), 0, &rVariant)))
  430. {
  431. // Write It
  432. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL)));
  433. // Free psz
  434. SafeMemFree(rVariant.pszVal);
  435. }
  436. // Write a tab
  437. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
  438. // Lets write the X-MimeOLE just to be a nice guy
  439. rVariant.vt = VT_LPSTR;
  440. if (SUCCEEDED(pMessage->GetProp("X-MimeOLE", 0, &rVariant)))
  441. {
  442. // Write It
  443. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL)));
  444. // Free psz
  445. SafeMemFree(rVariant.pszVal);
  446. }
  447. // Write a tab
  448. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
  449. // Lets write the Subject just to be a nice guy
  450. rVariant.vt = VT_LPSTR;
  451. if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_DATE), 0, &rVariant)))
  452. {
  453. // Write It
  454. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL)));
  455. // Free psz
  456. SafeMemFree(rVariant.pszVal);
  457. }
  458. // Write a tab
  459. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
  460. // Lets write the Subject just to be a nice guy
  461. rVariant.vt = VT_LPSTR;
  462. if (SUCCEEDED(pMessage->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rVariant)))
  463. {
  464. // Write It
  465. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(rVariant.pszVal, lstrlen(rVariant.pszVal), NULL)));
  466. // Free psz
  467. SafeMemFree(rVariant.pszVal);
  468. }
  469. // Write a tab
  470. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write("\t", 1, NULL)));
  471. // Write the first line of the message body
  472. if (FAILED(pMessage->GetTextBody(TXT_PLAIN, IET_DECODED, &pStream, NULL)))
  473. {
  474. // Try to get the HTML body
  475. if (FAILED(pMessage->GetTextBody(TXT_HTML, IET_DECODED, &pStream, NULL)))
  476. pStream = NULL;
  477. }
  478. // Did we find a stream
  479. if (pStream)
  480. {
  481. // Locals
  482. BYTE rgBuffer[1048];
  483. ULONG cbRead;
  484. ULONG i;
  485. ULONG cGood=0;
  486. // Read a buffer
  487. if (SUCCEEDED(pStream->Read(rgBuffer, sizeof(rgBuffer), &cbRead)))
  488. {
  489. // Write until we hit a \r or \n
  490. for (i=0; i<cbRead; i++)
  491. {
  492. // End of line
  493. if ('\r' == rgBuffer[i] || '\n' == rgBuffer[i])
  494. {
  495. // If we found 3 or more non-space chars, we found the first line
  496. if (cGood > 3)
  497. break;
  498. // Otherwise, continue...
  499. else
  500. {
  501. rgBuffer[i] = ' ';
  502. cGood = 0;
  503. continue;
  504. }
  505. }
  506. // Replace Tabs with spaces so that it doesn't mess up tab delimited file
  507. if ('\t' == rgBuffer[i])
  508. rgBuffer[i] = ' ';
  509. // If not a space
  510. if (FALSE == FIsSpaceA((LPSTR)(rgBuffer + i)))
  511. cGood++;
  512. }
  513. // Write the character
  514. m_pSmartLog->pStmFile->Write(rgBuffer, ((i > 0) ? i - 1 : i), NULL);
  515. }
  516. // Free psz
  517. SafeRelease(pStream);
  518. }
  519. // Write a tab
  520. SideAssert(SUCCEEDED(m_pSmartLog->pStmFile->Write(g_szCRLF, lstrlen(g_szCRLF), NULL)));
  521. }
  522. }
  523. // --------------------------------------------------------------------------------
  524. // CPop3Task::_FreeSmartLog
  525. // --------------------------------------------------------------------------------
  526. void CPop3Task::_FreeSmartLog(void)
  527. {
  528. if (m_pSmartLog)
  529. {
  530. SafeMemFree(m_pSmartLog->pszAccount);
  531. SafeMemFree(m_pSmartLog->pszProperty);
  532. SafeMemFree(m_pSmartLog->pszValue);
  533. SafeMemFree(m_pSmartLog->pszLogFile);
  534. SafeRelease(m_pSmartLog->pStmFile);
  535. g_pMalloc->Free(m_pSmartLog);
  536. m_pSmartLog = NULL;
  537. }
  538. }
  539. // --------------------------------------------------------------------------------
  540. // CPop3Task::_ReadSmartLogEntry
  541. // --------------------------------------------------------------------------------
  542. HRESULT CPop3Task::_ReadSmartLogEntry(HKEY hKey, LPCSTR pszKey, LPSTR *ppszValue)
  543. {
  544. // Locals
  545. HRESULT hr=S_OK;
  546. ULONG cb;
  547. // Read the pszKey
  548. if (RegQueryValueEx(hKey, pszKey, NULL, NULL, NULL, &cb) != ERROR_SUCCESS)
  549. {
  550. hr = E_FAIL;
  551. goto exit;
  552. }
  553. // Allocate
  554. cb++;
  555. CHECKALLOC(*ppszValue = PszAllocA(cb));
  556. // Read the pszKey
  557. if (RegQueryValueEx(hKey, pszKey, NULL, NULL, (LPBYTE)*ppszValue, &cb) != ERROR_SUCCESS)
  558. {
  559. hr = E_FAIL;
  560. goto exit;
  561. }
  562. exit:
  563. // Done
  564. return hr;
  565. }
  566. // --------------------------------------------------------------------------------
  567. // CPop3Task::_InitializeSmartLog
  568. // --------------------------------------------------------------------------------
  569. HRESULT CPop3Task::_InitializeSmartLog(void)
  570. {
  571. // Locals
  572. HRESULT hr=S_OK;
  573. HKEY hKey=NULL;
  574. ULARGE_INTEGER uliPos = {0,0};
  575. LARGE_INTEGER liOrigin = {0,0};
  576. // Get Advanced Logging Information
  577. if (AthUserOpenKey(c_szRegPathSmartLog, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
  578. {
  579. hr = E_FAIL;
  580. goto exit;
  581. }
  582. // Allocate smart log
  583. CHECKALLOC(m_pSmartLog = (LPSMARTLOGINFO)g_pMalloc->Alloc(sizeof(SMARTLOGINFO)));
  584. // Zero Init
  585. ZeroMemory(m_pSmartLog, sizeof(SMARTLOGINFO));
  586. // Read the Account
  587. CHECKHR(hr = _ReadSmartLogEntry(hKey, "Account", &m_pSmartLog->pszAccount));
  588. // Read the Property
  589. CHECKHR(hr = _ReadSmartLogEntry(hKey, "Property", &m_pSmartLog->pszProperty));
  590. // Read the ContainsValue
  591. CHECKHR(hr = _ReadSmartLogEntry(hKey, "ContainsValue", &m_pSmartLog->pszValue));
  592. // Read the LogFile
  593. CHECKHR(hr = _ReadSmartLogEntry(hKey, "LogFile", &m_pSmartLog->pszLogFile));
  594. // Open the logfile
  595. CHECKHR(hr = OpenFileStream(m_pSmartLog->pszLogFile, OPEN_ALWAYS, GENERIC_WRITE | GENERIC_READ, &m_pSmartLog->pStmFile));
  596. // Seek to the end
  597. CHECKHR(hr = m_pSmartLog->pStmFile->Seek(liOrigin, STREAM_SEEK_END, &uliPos));
  598. exit:
  599. // Failure
  600. if (FAILED(hr))
  601. _FreeSmartLog();
  602. // Cleanup
  603. if (hKey)
  604. RegCloseKey(hKey);
  605. // Done
  606. return hr;
  607. }
  608. // --------------------------------------------------------------------------------
  609. // CPop3Task::Execute
  610. // --------------------------------------------------------------------------------
  611. STDMETHODIMP CPop3Task::Execute(EVENTID eid, DWORD_PTR dwTwinkie)
  612. {
  613. // Locals
  614. HRESULT hr=S_OK;
  615. CHAR szRes[CCHMAX_RES];
  616. CHAR szBuf[CCHMAX_RES + CCHMAX_SERVER_NAME];
  617. DWORD cb;
  618. // Thread Safety
  619. EnterCriticalSection(&m_cs);
  620. // Check State
  621. Assert(eid == m_eidEvent && m_pAccount && m_pUI);
  622. // Create the Transport Object
  623. CHECKHR(hr = CreatePOP3Transport(&m_pTransport));
  624. // Init the Transport
  625. CHECKHR(hr = m_pTransport->InitNew(NULL, (IPOP3Callback *)this));
  626. // Fill an INETSERVER structure from the account object
  627. CHECKHR(hr = m_pTransport->InetServerFromAccount(m_pAccount, &m_rServer));
  628. // Get Account Id
  629. CHECKHR(hr = m_pAccount->GetPropSz(AP_ACCOUNT_ID, m_szAccountId, ARRAYSIZE(m_szAccountId)));
  630. // Always connect using the most recently supplied password from the user
  631. hr = GetPassword(m_rServer.dwPort, m_rServer.szServerName, m_rServer.szUserName,
  632. m_rServer.szPassword, sizeof(m_rServer.szPassword));
  633. // If this account is set to always prompt for password and password isn't
  634. // already cached, show UI so we can prompt user for password
  635. if (m_pUI && ISFLAGSET(m_rServer.dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) && FAILED(hr))
  636. {
  637. m_pUI->ShowWindow(SW_SHOW);
  638. }
  639. // Get Smart Logging INformation
  640. _InitializeSmartLog();
  641. // Set the animation
  642. m_pUI->SetAnimation(idanInbox, TRUE);
  643. // Setup Progress Meter
  644. m_pUI->SetProgressRange(100);
  645. // Connecting to ...
  646. LoadString(g_hLocRes, idsInetMailConnectingHost, szRes, ARRAYSIZE(szRes));
  647. wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_rServer.szAccount);
  648. m_pUI->SetGeneralProgress(szBuf);
  649. // Notify
  650. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_CONNECTING, 0);
  651. // Connect
  652. CHECKHR(hr = m_pTransport->Connect(&m_rServer, TRUE, TRUE));
  653. exit:
  654. // Failure
  655. if (FAILED(hr))
  656. {
  657. FLAGSET(m_dwState, POP3STATE_EXECUTEFAILED);
  658. _CatchResult(hr);
  659. // Tell the transport to release my callback: otherwise I leak
  660. SideAssert(m_pTransport->HandsOffCallback() == S_OK);
  661. }
  662. // Thread Safety
  663. LeaveCriticalSection(&m_cs);
  664. // Done
  665. return hr;
  666. }
  667. STDMETHODIMP CPop3Task::CancelEvent(EVENTID eid, DWORD_PTR dwTwinkie)
  668. {
  669. return(S_OK);
  670. }
  671. // --------------------------------------------------------------------------------
  672. // CPop3Task::OnTimeout
  673. // --------------------------------------------------------------------------------
  674. STDMETHODIMP CPop3Task::OnTimeout(DWORD *pdwTimeout, IInternetTransport *pTransport)
  675. {
  676. // Locals
  677. HRESULT hr=S_OK;
  678. // Thread Safety
  679. EnterCriticalSection(&m_cs);
  680. // Is there currently a timeout dialog
  681. if (m_hwndTimeout)
  682. {
  683. // Set foreground
  684. SetForegroundWindow(m_hwndTimeout);
  685. }
  686. else
  687. {
  688. // Not suppose to be showing UI ?
  689. if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
  690. {
  691. hr = S_FALSE;
  692. goto exit;
  693. }
  694. // Do Timeout Dialog
  695. m_hwndTimeout = TaskUtil_HwndOnTimeout(m_rServer.szServerName, m_rServer.szAccount, "POP3", m_rServer.dwTimeout, (ITimeoutCallback *) this);
  696. // Couldn't create the dialog
  697. if (NULL == m_hwndTimeout)
  698. {
  699. hr = S_FALSE;
  700. goto exit;
  701. }
  702. }
  703. exit:
  704. // Thread Safety
  705. LeaveCriticalSection(&m_cs);
  706. // Always tell the transport to keep on trucking
  707. return hr;
  708. }
  709. // --------------------------------------------------------------------------------
  710. // CPop3Task::OnLogonPrompt
  711. // --------------------------------------------------------------------------------
  712. STDMETHODIMP CPop3Task::OnLogonPrompt(LPINETSERVER pInetServer, IInternetTransport *pTransport)
  713. {
  714. // Locals
  715. HRESULT hr=S_FALSE;
  716. char szPassword[CCHMAX_PASSWORD];
  717. // Check if we have a cached password that's different from current password
  718. hr = GetPassword(pInetServer->dwPort, pInetServer->szServerName, pInetServer->szUserName,
  719. szPassword, sizeof(szPassword));
  720. if (SUCCEEDED(hr) && 0 != lstrcmp(szPassword, pInetServer->szPassword))
  721. {
  722. StrCpyN(pInetServer->szPassword, szPassword, ARRAYSIZE(pInetServer->szPassword));
  723. ZeroMemory(szPassword, sizeof(szPassword)); // Done for security.
  724. return S_OK;
  725. }
  726. hr = S_FALSE; // Re-initialize
  727. // Thread Safety
  728. EnterCriticalSection(&m_cs);
  729. // NOERRORS...
  730. if (ISFLAGSET(m_dwFlags, DELIVER_NOUI))
  731. goto exit;
  732. // TaskUtil_OnLogonPrompt
  733. hr = TaskUtil_OnLogonPrompt(m_pAccount, m_pUI, NULL, pInetServer, AP_POP3_USERNAME,
  734. AP_POP3_PASSWORD, AP_POP3_PROMPT_PASSWORD, TRUE);
  735. // Cache the password for this session
  736. if (S_OK == hr)
  737. SavePassword(pInetServer->dwPort, pInetServer->szServerName,
  738. pInetServer->szUserName, pInetServer->szPassword);
  739. exit:
  740. // Thread Safety
  741. LeaveCriticalSection(&m_cs);
  742. ZeroMemory(szPassword, sizeof(szPassword)); // Done for security.
  743. // Done
  744. return hr;
  745. }
  746. // --------------------------------------------------------------------------------
  747. // CPop3Task::OnPrompt
  748. // --------------------------------------------------------------------------------
  749. STDMETHODIMP_(INT) CPop3Task::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType, IInternetTransport *pTransport)
  750. {
  751. // Locals
  752. HWND hwnd;
  753. INT nAnswer;
  754. // Thread Safety
  755. EnterCriticalSection(&m_cs);
  756. // Invalid State
  757. Assert(m_pUI);
  758. // Get Window
  759. if (FAILED(m_pUI->GetWindow(&hwnd)))
  760. hwnd = NULL;
  761. // I assume this is a critical prompt, so I will not check for no UI mode
  762. nAnswer = MessageBox(hwnd, pszText, pszCaption, uType);
  763. // Thread Safety
  764. LeaveCriticalSection(&m_cs);
  765. // Done
  766. return nAnswer;
  767. }
  768. // --------------------------------------------------------------------------------
  769. // CPop3Task::OnError
  770. // --------------------------------------------------------------------------------
  771. STDMETHODIMP CPop3Task::OnError(IXPSTATUS ixpstatus, LPIXPRESULT pResult, IInternetTransport *pTransport)
  772. {
  773. // Thread Safety
  774. EnterCriticalSection(&m_cs);
  775. // Invalid State
  776. Assert(m_pUI);
  777. // Insert Error Into UI
  778. _CatchResult(POP3_NONE, pResult);
  779. // Thread Safety
  780. LeaveCriticalSection(&m_cs);
  781. // Done
  782. return S_OK;
  783. }
  784. // --------------------------------------------------------------------------------
  785. // CPop3Task::OnCommand
  786. // --------------------------------------------------------------------------------
  787. STDMETHODIMP CPop3Task::OnCommand(CMDTYPE cmdtype, LPSTR pszLine, HRESULT hrResponse, IInternetTransport *pTransport)
  788. {
  789. // Logging
  790. if (m_pLogFile && pszLine)
  791. {
  792. // Response
  793. if (CMD_RESP == cmdtype)
  794. m_pLogFile->WriteLog(LOGFILE_RX, pszLine);
  795. // Send
  796. else if (CMD_SEND == cmdtype)
  797. m_pLogFile->WriteLog(LOGFILE_TX, pszLine);
  798. }
  799. // Done
  800. return S_OK;
  801. }
  802. // --------------------------------------------------------------------------------
  803. // CPop3Task::_CatchResult
  804. // --------------------------------------------------------------------------------
  805. TASKRESULTTYPE CPop3Task::_CatchResult(HRESULT hr)
  806. {
  807. // Locals
  808. IXPRESULT rResult;
  809. // Build an IXPRESULT
  810. ZeroMemory(&rResult, sizeof(IXPRESULT));
  811. rResult.hrResult = hr;
  812. // Get the SMTP Result Type
  813. return _CatchResult(POP3_NONE, &rResult);
  814. }
  815. // --------------------------------------------------------------------------------
  816. // CPop3Task::_CatchResult
  817. // --------------------------------------------------------------------------------
  818. TASKRESULTTYPE CPop3Task::_CatchResult(POP3COMMAND command, LPIXPRESULT pResult)
  819. {
  820. // Locals
  821. HWND hwndParent;
  822. TASKRESULTTYPE tyTaskResult=TASKRESULT_FAILURE;
  823. // If Succeeded
  824. if (SUCCEEDED(pResult->hrResult))
  825. return TASKRESULT_SUCCESS;
  826. // Get Window
  827. if (FAILED(m_pUI->GetWindow(&hwndParent)))
  828. hwndParent = NULL;
  829. // Process generic protocol errro
  830. tyTaskResult = TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, pResult, &m_rServer, NULL, m_pUI,
  831. !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
  832. // Save Result
  833. m_hrResult = pResult->hrResult;
  834. // If Task Failure, drop the connection
  835. if (NULL != m_pTransport)
  836. m_pTransport->DropConnection();
  837. // Return Result
  838. return tyTaskResult;
  839. }
  840. // --------------------------------------------------------------------------------
  841. // CPop3Task::OnStatus
  842. // --------------------------------------------------------------------------------
  843. STDMETHODIMP CPop3Task::OnStatus(IXPSTATUS ixpstatus, IInternetTransport *pTransport)
  844. {
  845. // Locals
  846. EVENTCOMPLETEDSTATUS tyEventStatus=EVENT_SUCCEEDED;
  847. // Invalid State
  848. Assert(m_pUI && m_pSpoolCtx);
  849. if (!m_pUI || !m_pSpoolCtx)
  850. {
  851. return E_FAIL;
  852. }
  853. // Thread Safety
  854. EnterCriticalSection(&m_cs);
  855. // Feed the the IXP status to the UI object
  856. m_pUI->SetSpecificProgress(MAKEINTRESOURCE(XPUtil_StatusToString(ixpstatus)));
  857. // Disconnected
  858. if (ixpstatus == IXP_DISCONNECTED)
  859. {
  860. // Locals
  861. BOOL fWarning=FALSE;
  862. // Note that OnDisconnect was called
  863. FLAGSET(m_dwState, POP3STATE_ONDISCONNECT);
  864. // If a UIDL Sync is in progress, then return now...
  865. if (POP3STATE_UIDLSYNC == m_state)
  866. goto exit;
  867. // Kill the timeout dialog
  868. if (m_hwndTimeout)
  869. {
  870. DestroyWindow(m_hwndTimeout);
  871. m_hwndTimeout = NULL;
  872. }
  873. // Cache Cleanup
  874. _CleanupUidlCache();
  875. // Reset the progress
  876. // m_pUI->SetProgressRange(100);
  877. // State
  878. m_state = POP3STATE_NONE;
  879. // Set the animation
  880. m_pUI->SetAnimation(idanInbox, FALSE);
  881. // Infinite Loop
  882. if (m_rMetrics.cInfiniteLoopAutoGens)
  883. {
  884. // Load the Warning
  885. CHAR szRes[CCHMAX_RES];
  886. LOADSTRING(idsReplyForwardLoop, szRes);
  887. // Format the Error
  888. CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_SERVER_NAME + CCHMAX_RES];
  889. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.cInfiniteLoopAutoGens, m_rServer.szAccount, m_rServer.szServerName);
  890. // Insert the warning
  891. m_pUI->InsertError(m_eidEvent, szMsg);
  892. // Warning
  893. fWarning = TRUE;
  894. }
  895. // Nothing to download
  896. if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING))
  897. tyEventStatus = EVENT_CANCELED;
  898. else if (FAILED(m_hrResult) || (m_rMetrics.cDownloaded == 0 && m_rMetrics.cDownload > 0))
  899. tyEventStatus = EVENT_FAILED;
  900. else if (!ISFLAGSET(m_dwState, POP3STATE_LOGONSUCCESS))
  901. tyEventStatus = EVENT_WARNINGS;
  902. else if (m_rMetrics.cDownloaded && m_rMetrics.cDownload && m_rMetrics.cDownloaded < m_rMetrics.cDownload)
  903. tyEventStatus = EVENT_WARNINGS;
  904. else if (fWarning)
  905. tyEventStatus = EVENT_WARNINGS;
  906. // Result
  907. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RESULT, tyEventStatus);
  908. // Success and messages were downloaded
  909. if (EVENT_FAILED != tyEventStatus && m_rMetrics.cDownloaded && m_rMetrics.cPartials)
  910. {
  911. // Sitch Partials
  912. _HrStitchPartials();
  913. }
  914. // Notify
  915. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_COMPLETE, m_rMetrics.cDownloaded);
  916. // Tell the transport to release my callback
  917. SideAssert(m_pTransport->HandsOffCallback() == S_OK);
  918. // This task is complete
  919. if (!ISFLAGSET(m_dwState, POP3STATE_EXECUTEFAILED))
  920. m_pSpoolCtx->EventDone(m_eidEvent, tyEventStatus);
  921. }
  922. // Authorizing
  923. else if (ixpstatus == IXP_AUTHORIZING)
  924. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_AUTHORIZING, 0);
  925. exit:
  926. // Thread Safety
  927. LeaveCriticalSection(&m_cs);
  928. // Done
  929. return S_OK;
  930. }
  931. // --------------------------------------------------------------------------------
  932. // CPop3Task::_CleanupUidlCache
  933. // --------------------------------------------------------------------------------
  934. void CPop3Task::_CleanupUidlCache(void)
  935. {
  936. // Locals
  937. ULONG i;
  938. UIDLRECORD UidlInfo={0};
  939. LPPOP3ITEM pItem;
  940. // No Cache Objects
  941. if (NULL == m_pUidlCache)
  942. return;
  943. // Count the number of messages we will have to get a top for
  944. for (i=0; i<m_rTable.cItems; i++)
  945. {
  946. // Readability
  947. pItem = &m_rTable.prgItem[i];
  948. // Delete the Cached Uidl
  949. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETED) && ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL))
  950. {
  951. // No UIDL
  952. if (pItem->pszUidl)
  953. {
  954. // Set Search Info
  955. UidlInfo.pszUidl = pItem->pszUidl;
  956. UidlInfo.pszServer = m_rServer.szServerName;
  957. UidlInfo.pszAccountId = m_szAccountId;
  958. // Set Props on the cached uidl message
  959. m_pUidlCache->DeleteRecord(&UidlInfo);
  960. }
  961. }
  962. }
  963. // Remove all traces of if the account from the uid cache
  964. if (ISFLAGSET(m_dwState, POP3STATE_CLEANUPCACHE))
  965. {
  966. // Locaks
  967. HROWSET hRowset=NULL;
  968. // Create a rowset
  969. if (SUCCEEDED(m_pUidlCache->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset)))
  970. {
  971. // Delete Enumeration
  972. while (S_OK == m_pUidlCache->QueryRowset(hRowset, 1, (LPVOID *)&UidlInfo, NULL))
  973. {
  974. // Delete this puppy ?
  975. if (lstrcmpi(UidlInfo.pszServer, m_rServer.szServerName) == 0 &&
  976. UidlInfo.pszAccountId != NULL &&
  977. lstrcmpi(UidlInfo.pszAccountId, m_szAccountId) == 0)
  978. {
  979. // Delete this record
  980. m_pUidlCache->DeleteRecord(&UidlInfo);
  981. }
  982. // Free
  983. m_pUidlCache->FreeRecord(&UidlInfo);
  984. }
  985. // Purge everthing that matches this
  986. m_pUidlCache->CloseRowset(&hRowset);
  987. }
  988. }
  989. }
  990. // --------------------------------------------------------------------------------
  991. // CPop3Task::OnResponse
  992. // --------------------------------------------------------------------------------
  993. STDMETHODIMP CPop3Task::OnResponse(LPPOP3RESPONSE pResponse)
  994. {
  995. // Thread Safety
  996. EnterCriticalSection(&m_cs);
  997. // Testing UIDL Command
  998. if (m_uidlsupport == UIDL_SUPPORT_TESTING_UIDL_COMMAND && POP3_UIDL == pResponse->command)
  999. {
  1000. #ifdef DEBUG
  1001. pResponse->rIxpResult.hrResult = g_fUidlByTop ? E_FAIL : pResponse->rIxpResult.hrResult;
  1002. #endif
  1003. // Failure ?
  1004. if (FAILED(pResponse->rIxpResult.hrResult))
  1005. {
  1006. // Set Specific Progress
  1007. //CHAR szRes[CCHMAX_RES];
  1008. //LOADSTRING(IDS_SPS_POP3UIDL_UIDL, szRes);
  1009. //m_pUI->SetSpecificProgress(szRes);
  1010. // Try to top command
  1011. _CatchResult(m_pTransport->CommandTOP(POP3CMD_GET_POPID, 1, 0));
  1012. // Testing by top command
  1013. m_uidlsupport = UIDL_SUPPORT_TESTING_TOP_COMMAND;
  1014. }
  1015. // Otherwise
  1016. else
  1017. {
  1018. // State
  1019. m_state = POP3STATE_GETTINGUIDLS;
  1020. // Using the UIDL command
  1021. m_uidlsupport = UIDL_SUPPORT_USE_UIDL_COMMAND;
  1022. // Set Specific Progress
  1023. //CHAR szRes[CCHMAX_RES];
  1024. //LOADSTRING(IDS_SPS_POP3UIDL_UIDL, szRes);
  1025. //m_pUI->SetSpecificProgress(szRes);
  1026. // Issue full UIDL command
  1027. _CatchResult(m_pTransport->CommandUIDL(POP3CMD_GET_ALL, 0));
  1028. }
  1029. // Done
  1030. goto exit;
  1031. }
  1032. // Testing Top Command
  1033. else if (m_uidlsupport == UIDL_SUPPORT_TESTING_TOP_COMMAND && POP3_TOP == pResponse->command)
  1034. {
  1035. #ifdef DEBUG
  1036. pResponse->rIxpResult.hrResult = g_fFailTopCommand ? E_FAIL : pResponse->rIxpResult.hrResult;
  1037. #endif
  1038. // Failure ?
  1039. if (FAILED(pResponse->rIxpResult.hrResult))
  1040. {
  1041. // Disable the leave on server option in the account
  1042. m_pAccount->SetPropDw(AP_POP3_LEAVE_ON_SERVER, FALSE);
  1043. // Save the Changed
  1044. m_pAccount->SaveChanges();
  1045. // Failure
  1046. _CatchResult(SP_E_CANTLEAVEONSERVER);
  1047. // Done
  1048. goto exit;
  1049. }
  1050. // Using the UIDL command
  1051. else
  1052. {
  1053. // State
  1054. m_state = POP3STATE_GETTINGUIDLS;
  1055. // Set this and fall through to the switch...
  1056. m_uidlsupport = UIDL_SUPPORT_USE_TOP_COMMAND;
  1057. }
  1058. }
  1059. #ifdef DEBUG
  1060. if (POP3_RETR == pResponse->command && TRUE == pResponse->fDone && (ULONG)g_ulFailNumber == pResponse->rRetrInfo.dwPopId)
  1061. pResponse->rIxpResult.hrResult = E_FAIL;
  1062. #endif
  1063. // If Succeeded
  1064. if (FAILED(pResponse->rIxpResult.hrResult))
  1065. {
  1066. // Get Window
  1067. HWND hwndParent;
  1068. if (FAILED(m_pUI->GetWindow(&hwndParent)))
  1069. hwndParent = NULL;
  1070. // Dont drop if working on POP3_PASS or POP3_USER
  1071. if (POP3_PASS == pResponse->command || POP3_USER == pResponse->command)
  1072. {
  1073. // Log an Error ? If the user's password is not empty or they have fSavePassword enabled
  1074. TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, &pResponse->rIxpResult, &m_rServer, NULL, m_pUI, !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
  1075. // Done
  1076. goto exit;
  1077. }
  1078. // Command base Failure
  1079. else if (POP3_RETR == pResponse->command)
  1080. {
  1081. // Message Number %d could not be retrieved."
  1082. CHAR szRes[CCHMAX_RES];
  1083. LoadString(g_hLocRes, IDS_SP_E_RETRFAILED, szRes, ARRAYSIZE(szRes));
  1084. // Format the Error
  1085. CHAR szMsg[CCHMAX_RES + CCHMAX_RES];
  1086. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, pResponse->rRetrInfo.dwPopId);
  1087. // Fill the IXPRESULT
  1088. IXPRESULT rResult;
  1089. CopyMemory(&rResult, &pResponse->rIxpResult, sizeof(IXPRESULT));
  1090. rResult.pszProblem = szMsg;
  1091. rResult.hrResult = SP_E_POP3_RETR;
  1092. // Insert the Error
  1093. TaskUtil_FBaseTransportError(IXP_POP3, m_eidEvent, &rResult, &m_rServer, NULL, m_pUI, !ISFLAGSET(m_dwFlags, DELIVER_NOUI), hwndParent);
  1094. // Close Current Folder
  1095. _CloseFolder();
  1096. // Retrieve the next message
  1097. _CatchResult(_HrRetrieveNextMessage(pResponse->rRetrInfo.dwPopId));
  1098. // Done
  1099. goto exit;
  1100. }
  1101. // Default Error Handler
  1102. else if (TASKRESULT_SUCCESS != _CatchResult(pResponse->command, &pResponse->rIxpResult))
  1103. goto exit;
  1104. }
  1105. // Handle Command Type
  1106. switch(pResponse->command)
  1107. {
  1108. case POP3_CONNECTED:
  1109. // Notify
  1110. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_CHECKING, 0);
  1111. // Logon Success
  1112. FLAGSET(m_dwState, POP3STATE_LOGONSUCCESS);
  1113. // Issue the STAT command
  1114. _CatchResult(m_pTransport->CommandSTAT());
  1115. break;
  1116. case POP3_STAT:
  1117. // Process the StatCommand
  1118. _CatchResult(_HrOnStatResponse(pResponse));
  1119. break;
  1120. case POP3_LIST:
  1121. // Process the List Command
  1122. _CatchResult(_HrOnListResponse(pResponse));
  1123. break;
  1124. case POP3_UIDL:
  1125. // Process the Uidl Command
  1126. _CatchResult(_HrOnUidlResponse(pResponse));
  1127. break;
  1128. case POP3_TOP:
  1129. // Process the Top Command
  1130. _CatchResult(_HrOnTopResponse(pResponse));
  1131. break;
  1132. case POP3_RETR:
  1133. // Process Retreive Response
  1134. _CatchResult(_HrOnRetrResponse(pResponse));
  1135. break;
  1136. case POP3_DELE:
  1137. // Process Delete Response
  1138. _CatchResult(_HrDeleteNextMessage(pResponse->dwPopId));
  1139. break;
  1140. }
  1141. exit:
  1142. // Thread Safety
  1143. LeaveCriticalSection(&m_cs);
  1144. // Done
  1145. return S_OK;
  1146. }
  1147. // --------------------------------------------------------------------------------
  1148. // CPop3Task::_HrLockUidlCache
  1149. // --------------------------------------------------------------------------------
  1150. HRESULT CPop3Task::_HrLockUidlCache(void)
  1151. {
  1152. // Locals
  1153. HRESULT hr=S_OK;
  1154. // No Cache yet ?
  1155. if (NULL == m_pUidlCache)
  1156. {
  1157. // Lets the the UID Cache
  1158. CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CUidlCache, (LPVOID *)&m_pUidlCache));
  1159. }
  1160. exit:
  1161. // Done
  1162. return hr;
  1163. }
  1164. // --------------------------------------------------------------------------------
  1165. // CPop3Task::_HrOnStatResponse
  1166. // --------------------------------------------------------------------------------
  1167. HRESULT CPop3Task::_HrOnStatResponse(LPPOP3RESPONSE pResponse)
  1168. {
  1169. // Locals
  1170. HRESULT hr=S_OK;
  1171. CHAR szRes[CCHMAX_RES];
  1172. CHAR szSize[CCHMAX_RES];
  1173. CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_RES];
  1174. BOOL fFound;
  1175. // Progress
  1176. LOADSTRING(IDS_SPS_POP3CHECKING, szRes);
  1177. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount);
  1178. m_pUI->SetGeneralProgress(szMsg);
  1179. // Update Event Status
  1180. LOADSTRING(IDS_SPS_POP3TOTAL, szRes);
  1181. StrFormatByteSizeA(pResponse->rStatInfo.cbMessages, szSize, ARRAYSIZE(szSize));
  1182. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount, pResponse->rStatInfo.cMessages, szSize);
  1183. m_pUI->UpdateEventState(m_eidEvent, -1, szMsg, NULL);
  1184. // No New Messages ?
  1185. if (0 == pResponse->rStatInfo.cMessages)
  1186. {
  1187. m_pTransport->Disconnect();
  1188. goto exit;
  1189. }
  1190. // Save total byte count
  1191. m_rMetrics.cbTotal = pResponse->rStatInfo.cbMessages;
  1192. // Assume no clean cache
  1193. FLAGCLEAR(m_dwState, POP3STATE_CLEANUPCACHE);
  1194. // If Leave on Server, return TRUE
  1195. if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER))
  1196. {
  1197. // Lock the tree
  1198. CHECKHR(hr = _HrLockUidlCache());
  1199. // We will need to get the uidls
  1200. FLAGSET(m_dwState, POP3STATE_GETUIDLS);
  1201. }
  1202. // Okay, we may still need to get the uidls if
  1203. else
  1204. {
  1205. // Locals
  1206. UIDLRECORD UidlInfo={0};
  1207. HROWSET hRowset=NULL;
  1208. // Lock the tree
  1209. CHECKHR(hr = _HrLockUidlCache());
  1210. // Create a Rowset
  1211. CHECKHR(hr = m_pUidlCache->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
  1212. // Delete Enumeration
  1213. while (S_OK == m_pUidlCache->QueryRowset(hRowset, 1, (LPVOID *)&UidlInfo, NULL))
  1214. {
  1215. // Delete this puppy ?
  1216. if (lstrcmpi(UidlInfo.pszServer, m_rServer.szServerName) == 0 &&
  1217. UidlInfo.pszAccountId != NULL &&
  1218. lstrcmpi(UidlInfo.pszAccountId, m_szAccountId) == 0)
  1219. {
  1220. // Get Uidls from the server
  1221. FLAGSET(m_dwState, POP3STATE_GETUIDLS);
  1222. // Cleanup the uidl cache when complete
  1223. FLAGSET(m_dwState, POP3STATE_CLEANUPCACHE);
  1224. // Free
  1225. m_pUidlCache->FreeRecord(&UidlInfo);
  1226. // Done
  1227. break;
  1228. }
  1229. // Free
  1230. m_pUidlCache->FreeRecord(&UidlInfo);
  1231. }
  1232. // Purge everthing that matches this
  1233. m_pUidlCache->CloseRowset(&hRowset);
  1234. }
  1235. // Allocate the Item Table
  1236. CHECKALLOC(m_rTable.prgItem = (LPPOP3ITEM)g_pMalloc->Alloc(sizeof(POP3ITEM) * pResponse->rStatInfo.cMessages));
  1237. // Set Counts
  1238. m_rTable.cAlloc = m_rTable.cItems = pResponse->rStatInfo.cMessages;
  1239. // Zeroinit Array
  1240. ZeroMemory(m_rTable.prgItem, sizeof(POP3ITEM) * pResponse->rStatInfo.cMessages);
  1241. // Initialize Progress
  1242. m_dwProgressMax = m_rTable.cItems;
  1243. // If we need to get the UIDL list, lets test for it...
  1244. if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS))
  1245. m_dwProgressMax += (m_rTable.cItems * 4);
  1246. // Otherwise
  1247. else
  1248. {
  1249. // Release the Uidl Cache Lock
  1250. SafeRelease(m_pUidlCache);
  1251. }
  1252. // Progress Current
  1253. m_dwProgressCur = 0;
  1254. // Predownload rules increases mprogress
  1255. if (ISFLAGSET(m_dwState, POP3STATE_PDR))
  1256. m_dwProgressMax += m_rTable.cItems;
  1257. // Set Specific Progress
  1258. LOADSTRING(IDS_SPS_POP3STAT, szRes);
  1259. m_pUI->SetSpecificProgress(szRes);
  1260. // Set the uidl command to see if the user supports it
  1261. CHECKHR(hr = m_pTransport->CommandLIST(POP3CMD_GET_ALL, 0));
  1262. exit:
  1263. // Done
  1264. return hr;
  1265. }
  1266. // --------------------------------------------------------------------------------
  1267. // CPop3Task::_HrOnTopResponse
  1268. // --------------------------------------------------------------------------------
  1269. HRESULT CPop3Task::_HrOnTopResponse(LPPOP3RESPONSE pResponse)
  1270. {
  1271. // Locals
  1272. HRESULT hr=S_OK;
  1273. DWORD dwPopId=pResponse->rTopInfo.dwPopId;
  1274. LPPOP3ITEM pItem;
  1275. IMimePropertySet *pHeader=NULL;
  1276. CHAR szRes[CCHMAX_RES];
  1277. CHAR szMsg[CCHMAX_RES+CCHMAX_RES];
  1278. // Validate the Item
  1279. Assert(ISVALIDPOPID(dwPopId));
  1280. // Get the current item
  1281. pItem = ITEMFROMPOPID(dwPopId);
  1282. // We should assume that were downloading this item at this point
  1283. Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD));
  1284. // No stream yet ?
  1285. if (NULL == m_pStream)
  1286. {
  1287. // Create a Stream
  1288. CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream));
  1289. }
  1290. // If this infor is valid
  1291. if (TRUE == pResponse->fValidInfo)
  1292. {
  1293. // Write the data into the stream
  1294. CHECKHR(hr = m_pStream->Write(pResponse->rTopInfo.pszLines, pResponse->rTopInfo.cbLines, NULL));
  1295. }
  1296. // Is the command done ?
  1297. if (TRUE == pResponse->fDone)
  1298. {
  1299. // Commit the stream
  1300. CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT));
  1301. // Getting UIDL
  1302. if (POP3STATE_GETTINGUIDLS == m_state)
  1303. {
  1304. // Better not have a uidl yet
  1305. Assert(NULL == pItem->pszUidl);
  1306. // Increment Progress
  1307. m_dwProgressCur+=2;
  1308. // Set Specific Progress
  1309. //LOADSTRING(IDS_SPS_POP3UIDL_TOP, szRes);
  1310. //wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, dwPopId, m_rTable.cItems);
  1311. //m_pUI->SetSpecificProgress(szMsg);
  1312. // Get Uidl From HeaderStream
  1313. CHECKHR(hr = _HrGetUidlFromHeaderStream(m_pStream, &pItem->pszUidl, &pHeader));
  1314. }
  1315. // Otherwise, just increment one
  1316. else
  1317. m_dwProgressCur++;
  1318. // Show Progress
  1319. _DoProgress();
  1320. // If we plan on downloading this thing
  1321. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD) && ISFLAGSET(m_dwState, POP3STATE_PDR))
  1322. {
  1323. // Check Inbox Rule for this item
  1324. _ComputeItemInboxRule(pItem, m_pStream, pHeader, NULL, TRUE);
  1325. }
  1326. // Release the current stream
  1327. SafeRelease(m_pStream);
  1328. // Totally Done ?
  1329. if (ISLASTPOPID(dwPopId))
  1330. {
  1331. // Start the download process
  1332. CHECKHR(hr = _HrStartDownloading());
  1333. }
  1334. // Otherwise, lets get the top of the next item
  1335. else if (POP3STATE_GETTINGUIDLS == m_state)
  1336. {
  1337. // Next Top
  1338. CHECKHR(hr = m_pTransport->CommandTOP(POP3CMD_GET_POPID, dwPopId + 1, 0));
  1339. }
  1340. // Otherwise, find next message marked for download to check against predownload rules
  1341. else
  1342. {
  1343. // NextTopForInboxRule
  1344. CHECKHR(hr = _HrNextTopForInboxRule(dwPopId));
  1345. }
  1346. }
  1347. exit:
  1348. // Cleanup
  1349. SafeRelease(pHeader);
  1350. // Done
  1351. return hr;
  1352. }
  1353. // --------------------------------------------------------------------------------
  1354. // CPop3Task::_HrOnUidlResponse
  1355. // --------------------------------------------------------------------------------
  1356. HRESULT CPop3Task::_HrOnUidlResponse(LPPOP3RESPONSE pResponse)
  1357. {
  1358. // Locals
  1359. HRESULT hr=S_OK;
  1360. DWORD dwPopId=pResponse->rUidlInfo.dwPopId;
  1361. LPPOP3ITEM pItem;
  1362. CHAR szRes[CCHMAX_RES];
  1363. CHAR szMsg[CCHMAX_RES + CCHMAX_RES];
  1364. // Is the command done ?
  1365. if (TRUE == pResponse->fDone)
  1366. {
  1367. // If there are pre-download rules that are not size only, get all the tops
  1368. if (ISFLAGSET(m_dwState, POP3STATE_PDR))
  1369. {
  1370. // Clear the state
  1371. m_state = POP3STATE_NONE;
  1372. // NextTopForInboxRule
  1373. CHECKHR(hr = _HrStartServerSideRules());
  1374. }
  1375. // Otherwise, do the list command
  1376. else
  1377. {
  1378. // Start the download process
  1379. CHECKHR(hr = _HrStartDownloading());
  1380. }
  1381. }
  1382. // Otherwise
  1383. else
  1384. {
  1385. // Make Sure PopId is on current iitem
  1386. Assert(ISVALIDPOPID(dwPopId) && pResponse->rUidlInfo.pszUidl);
  1387. // Get Current Item
  1388. pItem = ITEMFROMPOPID(dwPopId);
  1389. // Duplicate the Uidl
  1390. CHECKALLOC(pItem->pszUidl = PszDupA(pResponse->rUidlInfo.pszUidl));
  1391. // Increment Progress
  1392. m_dwProgressCur+=1;
  1393. // Do progress
  1394. _DoProgress();
  1395. }
  1396. exit:
  1397. // Done
  1398. return hr;
  1399. }
  1400. // --------------------------------------------------------------------------------
  1401. // CPop3Task::_HrOnListResponse
  1402. // --------------------------------------------------------------------------------
  1403. HRESULT CPop3Task::_HrOnListResponse(LPPOP3RESPONSE pResponse)
  1404. {
  1405. // Locals
  1406. HRESULT hr=S_OK;
  1407. DWORD dwPopId=pResponse->rListInfo.dwPopId;
  1408. LPPOP3ITEM pItem;
  1409. // Is the command done ?
  1410. if (TRUE == pResponse->fDone)
  1411. {
  1412. // If we need to get the UIDL list, lets test for it...
  1413. if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS))
  1414. {
  1415. // Set the uidl command to see if the user supports it
  1416. CHECKHR(hr = m_pTransport->CommandUIDL(POP3CMD_GET_POPID, 1));
  1417. // Set State
  1418. m_uidlsupport = UIDL_SUPPORT_TESTING_UIDL_COMMAND;
  1419. }
  1420. // Otherwise
  1421. else
  1422. {
  1423. // Predownload rules increases mprogress
  1424. if (ISFLAGSET(m_dwState, POP3STATE_PDR))
  1425. {
  1426. // Clear the state
  1427. m_state = POP3STATE_NONE;
  1428. // NextTopForInboxRule
  1429. CHECKHR(hr = _HrStartServerSideRules());
  1430. }
  1431. // Otherwise, do the list command
  1432. else
  1433. {
  1434. // Start the download process
  1435. CHECKHR(hr = _HrStartDownloading());
  1436. }
  1437. }
  1438. }
  1439. // Otherwise
  1440. else
  1441. {
  1442. // Make Sure PopId is on current iitem
  1443. if(!ISVALIDPOPID(dwPopId))
  1444. return(E_FAIL);
  1445. // Get Current Item
  1446. pItem = ITEMFROMPOPID(dwPopId);
  1447. // Duplicate the Uidl
  1448. pItem->cbSize = pResponse->rListInfo.cbSize;
  1449. // Assume we will download it
  1450. FLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER);
  1451. // Increment Progress
  1452. m_dwProgressCur++;
  1453. // Do progress
  1454. _DoProgress();
  1455. // This yields so that other threads can execute
  1456. //Sleep(0);
  1457. }
  1458. exit:
  1459. // Done
  1460. return hr;
  1461. }
  1462. // --------------------------------------------------------------------------------
  1463. // CPop3Task::_HrStartDownloading
  1464. // --------------------------------------------------------------------------------
  1465. HRESULT CPop3Task::_HrStartDownloading(void)
  1466. {
  1467. // Locals
  1468. HRESULT hr=S_OK;
  1469. ULONG i;
  1470. CHAR szRes[CCHMAX_RES];
  1471. CHAR szSize1[CCHMAX_RES];
  1472. CHAR szSize2[CCHMAX_RES];
  1473. CHAR szMsg[CCHMAX_RES + CCHMAX_ACCOUNT_NAME + CCHMAX_RES];
  1474. // State
  1475. Assert(m_rMetrics.cLeftByRule == 0 && m_rMetrics.cDownload == 0 && m_rMetrics.cDelete == 0 && m_rMetrics.cbDownload == 0);
  1476. // If we got uidls, then lets do the cache compare lookup
  1477. if (!ISFLAGSET(m_dwState, POP3STATE_PDR) && ISFLAGSET(m_dwState, POP3STATE_GETUIDLS))
  1478. {
  1479. // Returns FALSE if user cancel
  1480. CHECKHR(hr = _HrDoUidlSynchronize());
  1481. }
  1482. // Compute number of new messages to download
  1483. for (i=0; i<m_rTable.cItems; i++)
  1484. {
  1485. // Download ?
  1486. if (ISFLAGSET(m_rTable.prgItem[i].dwFlags, POP3ITEM_DOWNLOAD))
  1487. {
  1488. // Increment total number of bytes we will download
  1489. m_rMetrics.cbDownload += m_rTable.prgItem[i].cbSize;
  1490. // Increment count of messages we will download
  1491. m_rMetrics.cDownload++;
  1492. // Set running total in pop3 item
  1493. m_rTable.prgItem[i].dwProgressCur = m_rMetrics.cbDownload;
  1494. }
  1495. // Count Left By Rule in case we don't download anything
  1496. else if (ISFLAGSET(m_rTable.prgItem[i].dwFlags, POP3ITEM_LEFTBYRULE))
  1497. m_rMetrics.cLeftByRule++;
  1498. // Delete
  1499. if (ISFLAGSET(m_rTable.prgItem[i].dwFlags, POP3ITEM_DELETEOFFSERVER))
  1500. {
  1501. // Number of messages we will delete
  1502. m_rMetrics.cDelete++;
  1503. }
  1504. }
  1505. // Update Event Status
  1506. LOADSTRING(IDS_SPS_POP3NEW, szRes);
  1507. StrFormatByteSizeA(m_rMetrics.cbDownload, szSize1, ARRAYSIZE(szSize1));
  1508. StrFormatByteSizeA(m_rMetrics.cbTotal, szSize2, ARRAYSIZE(szSize2));
  1509. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rServer.szAccount, m_rMetrics.cDownload, szSize1, m_rTable.cItems, szSize2);
  1510. m_pUI->UpdateEventState(m_eidEvent, -1, szMsg, NULL);
  1511. // New Messages ?
  1512. if (m_rMetrics.cDownload > 0)
  1513. {
  1514. // Setup Progress
  1515. m_rMetrics.iCurrent = 0;
  1516. m_wProgress = 0;
  1517. m_dwProgressCur = 0;
  1518. m_dwProgressMax = m_rMetrics.cbDownload;
  1519. m_pUI->SetProgressRange(100);
  1520. m_rMetrics.cLeftByRule = 0;
  1521. // Notify
  1522. m_pSpoolCtx->Notify(DELIVERY_NOTIFY_RECEIVING, 0);
  1523. // State
  1524. m_state = POP3STATE_DOWNLOADING;
  1525. // Open the Inbox
  1526. Assert(NULL == m_pInbox);
  1527. CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreInbox, (LPVOID *)&m_pInbox));
  1528. // Download the Next Message
  1529. CHECKHR(hr = _HrRetrieveNextMessage(0));
  1530. }
  1531. // Otherwise if cDelete
  1532. else if (m_rMetrics.cDelete > 0)
  1533. {
  1534. // Delete the Next Message
  1535. CHECKHR(hr = _HrStartDeleteCycle());
  1536. }
  1537. // Otherwise, disconnect
  1538. else
  1539. {
  1540. // Disconnect
  1541. CHECKHR(hr = m_pTransport->Disconnect());
  1542. }
  1543. exit:
  1544. // Done
  1545. return hr;
  1546. }
  1547. // --------------------------------------------------------------------------------
  1548. // CPop3Task::_DoProgress
  1549. // --------------------------------------------------------------------------------
  1550. void CPop3Task::_DoProgress(void)
  1551. {
  1552. // Compute Current Progress Index
  1553. WORD wProgress;
  1554. if (m_dwProgressMax > 0)
  1555. wProgress = (WORD)((m_dwProgressCur * 100) / m_dwProgressMax);
  1556. else
  1557. wProgress = 0;
  1558. // Only if greater than
  1559. if (wProgress > m_wProgress)
  1560. {
  1561. // Compute Delta
  1562. WORD wDelta = wProgress - m_wProgress;
  1563. // Progress Delta
  1564. if (wDelta > 0)
  1565. {
  1566. // Incremenet Progress
  1567. m_pUI->IncrementProgress(wDelta);
  1568. // Increment my wProgress
  1569. m_wProgress += wDelta;
  1570. // Don't go above 100
  1571. if (m_wProgress > 100)
  1572. m_wProgress = 100;
  1573. }
  1574. }
  1575. }
  1576. // --------------------------------------------------------------------------------
  1577. // CPop3Task::_HrGetUidlFromHeaderStream
  1578. // --------------------------------------------------------------------------------
  1579. HRESULT CPop3Task::_HrGetUidlFromHeaderStream(IStream *pStream, LPSTR *ppszUidl, IMimePropertySet **ppHeader)
  1580. {
  1581. // Locals
  1582. HRESULT hr=S_OK;
  1583. IMimePropertySet *pHeader=NULL;
  1584. // Invalid Arg
  1585. Assert(pStream && ppszUidl);
  1586. // Init
  1587. *ppszUidl = NULL;
  1588. *ppHeader = NULL;
  1589. // Rewind Header Stream
  1590. CHECKHR(hr = HrRewindStream(pStream));
  1591. // Load the header
  1592. CHECKHR(hr = MimeOleCreatePropertySet(NULL, &pHeader));
  1593. // Load the header
  1594. CHECKHR(hr = pHeader->Load(pStream));
  1595. // Get the message Id...
  1596. if (FAILED(MimeOleGetPropA(pHeader, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, ppszUidl)))
  1597. {
  1598. // Try to use the received headers...
  1599. MimeOleGetPropA(pHeader, PIDTOSTR(PID_HDR_RECEIVED), NOFLAGS, ppszUidl);
  1600. }
  1601. // Returen the Header ?
  1602. *ppHeader = pHeader;
  1603. pHeader = NULL;
  1604. exit:
  1605. // Release the text stream
  1606. SafeRelease(pHeader);
  1607. // Done
  1608. return hr;
  1609. }
  1610. // --------------------------------------------------------------------------------
  1611. // CPop3Task::_HrDoUidlSynchronize
  1612. // --------------------------------------------------------------------------------
  1613. HRESULT CPop3Task::_HrDoUidlSynchronize(void)
  1614. {
  1615. // Locals
  1616. HRESULT hr=S_OK;
  1617. LPPOP3ITEM pItem;
  1618. ULONG i,j;
  1619. #ifdef DEBUG
  1620. DWORD dwTick = GetTickCount();
  1621. #endif
  1622. // Uidl Sync
  1623. m_state = POP3STATE_UIDLSYNC;
  1624. // Compute number of new messages to download
  1625. for (i=0,j=0; i<m_rTable.cItems; i++,j++)
  1626. {
  1627. // Readability
  1628. pItem = &m_rTable.prgItem[i];
  1629. // Get Uidl Falgs
  1630. _GetItemFlagsFromUidl(pItem);
  1631. // Progress
  1632. m_dwProgressCur+=3;
  1633. // Do Progress
  1634. _DoProgress();
  1635. // Pump Message
  1636. if (j >= 10)
  1637. {
  1638. //Sleep(0);
  1639. m_pSpoolCtx->PumpMessages();
  1640. j = 0;
  1641. }
  1642. // Cancel
  1643. if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING))
  1644. {
  1645. // Change State
  1646. m_state = POP3STATE_NONE;
  1647. // Drop the connection
  1648. if (m_pTransport)
  1649. m_pTransport->DropConnection();
  1650. // User Cancel
  1651. hr = IXP_E_USER_CANCEL;
  1652. // Done
  1653. break;
  1654. }
  1655. // OnDisconnect has been called
  1656. if (ISFLAGSET(m_dwState, POP3STATE_ONDISCONNECT))
  1657. {
  1658. // Change State
  1659. m_state = POP3STATE_NONE;
  1660. // Fake the call to OnStatus
  1661. OnStatus(IXP_DISCONNECTED, NULL);
  1662. // Done
  1663. break;
  1664. }
  1665. }
  1666. // Uidl Sync
  1667. m_state = POP3STATE_NONE;
  1668. // Cool tracing
  1669. #ifdef DEBUG
  1670. DebugTrace("CPop3Task::_HrDoUidlSynchronize took %d Milli-Seconds\n", GetTickCount() - dwTick);
  1671. #endif // DEBUG
  1672. // Done
  1673. return hr;
  1674. }
  1675. // --------------------------------------------------------------------------------
  1676. // CPop3Task::_GetItemFlagsFromUidl
  1677. // --------------------------------------------------------------------------------
  1678. void CPop3Task::_GetItemFlagsFromUidl(LPPOP3ITEM pItem)
  1679. {
  1680. // Locals
  1681. UIDLRECORD rUidlInfo={0};
  1682. // Invalid Arg
  1683. Assert(pItem && m_pUidlCache);
  1684. // If we are already not going to download this item, then return
  1685. if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD))
  1686. return;
  1687. // If there is no UIDL, we will download it...
  1688. if (NULL == pItem->pszUidl || '\0' == *pItem->pszUidl)
  1689. return;
  1690. // If not leaving on server, mark for delete
  1691. if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER))
  1692. FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER);
  1693. // Set Search Info
  1694. rUidlInfo.pszUidl = pItem->pszUidl;
  1695. rUidlInfo.pszServer = m_rServer.szServerName;
  1696. rUidlInfo.pszAccountId = m_szAccountId;
  1697. // This yields so that other threads can execute
  1698. //Sleep(0);
  1699. // Exist - if not, lets download it...
  1700. if (DB_S_NOTFOUND == m_pUidlCache->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &rUidlInfo, NULL))
  1701. {
  1702. if (ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER))
  1703. FLAGSET(pItem->dwFlags, POP3ITEM_CACHEUIDL);
  1704. return;
  1705. }
  1706. // Don't download it again
  1707. FLAGCLEAR(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER);
  1708. // If the message has been download, lets decide if we should delete it
  1709. if (rUidlInfo.fDownloaded)
  1710. {
  1711. // Expired or deleted from client, or remove when deleted from delete items folder.
  1712. if (!ISFLAGSET(m_dwState, POP3STATE_LEAVEONSERVER) || _FUidlExpired(&rUidlInfo) ||
  1713. (ISFLAGSET(m_dwState, POP3STATE_SYNCDELETED) && rUidlInfo.fDeleted))
  1714. {
  1715. FLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL);
  1716. FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER);
  1717. }
  1718. }
  1719. // Free The Dude
  1720. m_pUidlCache->FreeRecord(&rUidlInfo);
  1721. }
  1722. // ------------------------------------------------------------------------------------
  1723. // CPop3Task::_FUidlExpired
  1724. // ------------------------------------------------------------------------------------
  1725. BOOL CPop3Task::_FUidlExpired(LPUIDLRECORD pUidlInfo)
  1726. {
  1727. // Locals
  1728. SYSTEMTIME st;
  1729. FILETIME ft;
  1730. ULONG ulSeconds;
  1731. // If not expiring, return FALSE
  1732. if (!ISFLAGSET(m_dwState, POP3STATE_DELETEEXPIRED))
  1733. return FALSE;
  1734. // Get Current Time
  1735. GetSystemTime(&st);
  1736. SystemTimeToFileTime(&st, &ft);
  1737. // Convert st to seconds since Jan 1, 1996
  1738. ulSeconds = UlDateDiff(&pUidlInfo->ftDownload, &ft);
  1739. // Greater than expire days
  1740. if ((ulSeconds / SECONDS_INA_DAY) >= m_dwExpireDays)
  1741. return TRUE;
  1742. // Done
  1743. return FALSE;
  1744. }
  1745. // ------------------------------------------------------------------------------------
  1746. // CPop3Task::_ComputeItemInboxRule
  1747. // ------------------------------------------------------------------------------------
  1748. void CPop3Task::_ComputeItemInboxRule(LPPOP3ITEM pItem, LPSTREAM pStream,
  1749. IMimePropertySet *pHeaderIn, IMimeMessage * pIMMsg, BOOL fServerRules)
  1750. {
  1751. // Locals
  1752. HRESULT hr=S_OK;
  1753. IMimePropertySet *pHeader=NULL;
  1754. ACT_ITEM *pActions=NULL;
  1755. ULONG cActions=0;
  1756. // We should not have checked the inbox rule for this item yet
  1757. Assert(m_pIExecRules && pItem && (pStream || pHeaderIn || pIMMsg));
  1758. Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE));
  1759. // We've checked this inbox rule
  1760. FLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE);
  1761. // Assume we don't find an inbox rule for this item
  1762. FLAGCLEAR(pItem->dwFlags, POP3ITEM_HASINBOXRULE);
  1763. // Header was passed in ?
  1764. if (pHeaderIn)
  1765. {
  1766. pHeader = pHeaderIn;
  1767. pHeader->AddRef();
  1768. }
  1769. // Do we already have a Mime message?
  1770. else if (pIMMsg)
  1771. {
  1772. CHECKHR(hr = pIMMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pHeader));
  1773. }
  1774. // Otherwise, load the stream in to a header
  1775. else
  1776. {
  1777. // Rewind Header Stream
  1778. CHECKHR(hr = HrRewindStream(pStream));
  1779. // Load the header
  1780. CHECKHR(hr = MimeOleCreatePropertySet(NULL, &pHeader));
  1781. // Load the header
  1782. CHECKHR(hr = pHeader->Load(pStream));
  1783. }
  1784. // Check the inbox rule
  1785. // If we have pre-download rules,
  1786. if ((FALSE != fServerRules) && ISFLAGSET(m_dwState, POP3STATE_PDR))
  1787. {
  1788. // Check to see if we have any actions
  1789. hr = m_pIExecRules->ExecuteRules(ERF_ONLYSERVER | ERF_SKIPPARTIALS, m_szAccountId, NULL, NULL, pHeader, NULL, pItem->cbSize, &pActions, &cActions);
  1790. // If we don't have any actions, or
  1791. // this isn't a server side rule
  1792. if ((S_OK != hr) ||
  1793. ((ACT_TYPE_DONTDOWNLOAD != pActions[0].type) && (ACT_TYPE_DELETESERVER != pActions[0].type)))
  1794. {
  1795. // Make sure we can check rules again
  1796. FLAGCLEAR(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE);
  1797. hr = S_FALSE;
  1798. }
  1799. else
  1800. {
  1801. // _OnKnownRuleActions
  1802. _OnKnownRuleActions(pItem, pActions, cActions, fServerRules);
  1803. }
  1804. }
  1805. // If we don't have pre-download rules, then check rules normally.
  1806. else
  1807. {
  1808. hr = S_FALSE;
  1809. // Do block sender first
  1810. if (m_pIRuleSender)
  1811. {
  1812. hr = m_pIRuleSender->Evaluate(m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions);
  1813. }
  1814. // If we aren't blocking the sender
  1815. if (S_OK != hr)
  1816. {
  1817. hr = m_pIExecRules->ExecuteRules(ERF_SKIPPARTIALS, m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions);
  1818. }
  1819. // If we don't have a rule match
  1820. if ((S_OK != hr) && (NULL != m_pIRuleJunk))
  1821. {
  1822. hr = m_pIRuleJunk->Evaluate(m_szAccountId, NULL, NULL, pHeader, pIMMsg, pItem->cbSize, &pActions, &cActions);
  1823. }
  1824. // Did we have some actions to perform...
  1825. if (S_OK == hr)
  1826. {
  1827. // This item has an inbox rule
  1828. FLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE);
  1829. // Save off the actions list
  1830. pItem->pActList = pActions;
  1831. pActions = NULL;
  1832. pItem->cActList = cActions;
  1833. }
  1834. }
  1835. exit:
  1836. // Cleanup
  1837. RuleUtil_HrFreeActionsItem(pActions, cActions);
  1838. SafeMemFree(pActions);
  1839. SafeRelease(pHeader);
  1840. // Done
  1841. return;
  1842. }
  1843. // ------------------------------------------------------------------------------------
  1844. // CPop3Task::_OnKnownRuleActions
  1845. // ------------------------------------------------------------------------------------
  1846. void CPop3Task::_OnKnownRuleActions(LPPOP3ITEM pItem, ACT_ITEM * pActions, ULONG cActions, BOOL fServerRules)
  1847. {
  1848. // This item has an inbox rule
  1849. FLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE);
  1850. // If Action is to delete off sever
  1851. if ((FALSE != fServerRules) && (1 == cActions))
  1852. {
  1853. if (ACT_TYPE_DELETESERVER == pActions->type)
  1854. {
  1855. // Don't Cache the UIDL
  1856. FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL | POP3ITEM_CACHEUIDL | POP3ITEM_DOWNLOAD);
  1857. // Delete off the server
  1858. FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER | POP3ITEM_DELEBYRULE);
  1859. }
  1860. // Otherwise, don't download the message
  1861. else if (ACT_TYPE_DONTDOWNLOAD == pActions->type)
  1862. {
  1863. // Download It and Don't download it and delete it
  1864. FLAGCLEAR(pItem->dwFlags, POP3ITEM_DOWNLOAD | POP3ITEM_DELETEOFFSERVER);
  1865. // Set the Flag
  1866. FLAGSET(pItem->dwFlags, POP3ITEM_LEFTBYRULE);
  1867. }
  1868. }
  1869. }
  1870. // ------------------------------------------------------------------------------------
  1871. // CPop3Task::_HrStartServerSideRules
  1872. // ------------------------------------------------------------------------------------
  1873. HRESULT CPop3Task::_HrStartServerSideRules(void)
  1874. {
  1875. // Locals
  1876. HRESULT hr=S_OK;
  1877. ULONG i;
  1878. // If we got uidls, then lets do the cache compare lookup
  1879. if (ISFLAGSET(m_dwState, POP3STATE_GETUIDLS))
  1880. {
  1881. // Returns FALSE if user cancel
  1882. CHECKHR(hr = _HrDoUidlSynchronize());
  1883. }
  1884. // Check State
  1885. m_rMetrics.cTopMsgs = 0;
  1886. m_rMetrics.iCurrent = 0;
  1887. // Count the number of messages we will have to get a top for
  1888. for (i=0; i<m_rTable.cItems; i++)
  1889. {
  1890. if (ISFLAGSET(m_rTable.prgItem[i].dwFlags, POP3ITEM_DOWNLOAD))
  1891. m_rMetrics.cTopMsgs++;
  1892. }
  1893. // Adjust progress
  1894. m_dwProgressMax -= m_rTable.cItems;
  1895. // Add m_rMetrics.cTopMsgs back onto m_dwProgressMax
  1896. m_dwProgressMax += m_rMetrics.cTopMsgs;
  1897. // Do the first one
  1898. CHECKHR(hr = _HrNextTopForInboxRule(0));
  1899. exit:
  1900. // Done
  1901. return hr;
  1902. }
  1903. // ------------------------------------------------------------------------------------
  1904. // CPop3Task::_HrNextTopForInboxRule
  1905. // ------------------------------------------------------------------------------------
  1906. HRESULT CPop3Task::_HrNextTopForInboxRule(DWORD dwPopIdCurrent)
  1907. {
  1908. // Locals
  1909. HRESULT hr=S_OK;
  1910. CHAR szRes[CCHMAX_RES];
  1911. CHAR szMsg[CCHMAX_RES+CCHMAX_RES];
  1912. // State should be none
  1913. Assert(POP3STATE_NONE == m_state);
  1914. // Increment iCurrent
  1915. m_rMetrics.iCurrent++;
  1916. // Set Specific Progress
  1917. //LOADSTRING(IDS_SPS_PREDOWNRULES, szRes);
  1918. //wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.iCurrent, m_rMetrics.cTopMsgs);
  1919. //m_pUI->SetSpecificProgress(szMsg);
  1920. // Loop until we find the next message that we are downloading
  1921. while(1)
  1922. {
  1923. // Incremenet dwPopIdCurrent
  1924. dwPopIdCurrent++;
  1925. // Last PopId, start the download
  1926. if (dwPopIdCurrent > m_rTable.cItems)
  1927. {
  1928. // Start the download process
  1929. CHECKHR(hr = _HrStartDownloading());
  1930. // Done
  1931. break;
  1932. }
  1933. // If we are still downloading this item
  1934. if (ISFLAGSET(m_rTable.prgItem[dwPopIdCurrent - 1].dwFlags, POP3ITEM_DOWNLOAD))
  1935. {
  1936. // Try to top command
  1937. CHECKHR(hr = m_pTransport->CommandTOP(POP3CMD_GET_POPID, dwPopIdCurrent, 0));
  1938. // Done
  1939. break;
  1940. }
  1941. }
  1942. exit:
  1943. // Done
  1944. return hr;
  1945. }
  1946. // ------------------------------------------------------------------------------------
  1947. // CPop3Task::_HrRetrieveNextMessage
  1948. // ------------------------------------------------------------------------------------
  1949. HRESULT CPop3Task::_HrRetrieveNextMessage(DWORD dwPopIdCurrent)
  1950. {
  1951. // Locals
  1952. HRESULT hr=S_OK;
  1953. CHAR szRes[CCHMAX_RES];
  1954. CHAR szMsg[CCHMAX_RES + CCHMAX_RES];
  1955. LPPOP3ITEM pItem;
  1956. // Cancel Pending...
  1957. if (ISFLAGSET(m_dwState, POP3STATE_CANCELPENDING))
  1958. {
  1959. // Start the Delete Cycle
  1960. CHECKHR(hr = _HrStartDeleteCycle());
  1961. // Done
  1962. goto exit;
  1963. }
  1964. // Adjust progress
  1965. if (dwPopIdCurrent > 0)
  1966. {
  1967. // Get current item
  1968. pItem = ITEMFROMPOPID(dwPopIdCurrent);
  1969. Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD));
  1970. // Adjust progress Cur
  1971. m_dwProgressCur = pItem->dwProgressCur;
  1972. // Do progress
  1973. _DoProgress();
  1974. }
  1975. // Loop until we find the next message that we are downloading
  1976. while(1)
  1977. {
  1978. // Incremenet dwPopIdCurrent
  1979. dwPopIdCurrent++;
  1980. // Last PopId, start the download
  1981. if (dwPopIdCurrent > m_rTable.cItems)
  1982. {
  1983. // Start the download process
  1984. CHECKHR(hr = _HrStartDeleteCycle());
  1985. // Done
  1986. break;
  1987. }
  1988. // Readability
  1989. pItem = ITEMFROMPOPID(dwPopIdCurrent);
  1990. // Download this message ?
  1991. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD))
  1992. {
  1993. // Increment m_rMetrics.iCurrent
  1994. m_rMetrics.iCurrent++;
  1995. // Status
  1996. LOADSTRING(idsInetMailRecvStatus, szRes);
  1997. wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.iCurrent, m_rMetrics.cDownload);
  1998. m_pUI->SetSpecificProgress(szMsg);
  1999. // Retrieve this item
  2000. CHECKHR(hr = m_pTransport->CommandRETR(POP3CMD_GET_POPID, dwPopIdCurrent));
  2001. // Done
  2002. break;
  2003. }
  2004. // Count Number of items left by rule
  2005. else if (ISFLAGSET(pItem->dwFlags, POP3ITEM_LEFTBYRULE))
  2006. m_rMetrics.cLeftByRule++;
  2007. }
  2008. exit:
  2009. // Done
  2010. return hr;
  2011. }
  2012. // ------------------------------------------------------------------------------------
  2013. // CPop3Task::_HrOnRetrResponse
  2014. // ------------------------------------------------------------------------------------
  2015. HRESULT CPop3Task::_HrOnRetrResponse(LPPOP3RESPONSE pResponse)
  2016. {
  2017. // Locals
  2018. HRESULT hr=S_OK;
  2019. DWORD dwPopId=pResponse->rRetrInfo.dwPopId;
  2020. LPPOP3ITEM pItem;
  2021. // Get Current Item
  2022. pItem = ITEMFROMPOPID(dwPopId);
  2023. // Validate the item
  2024. Assert(ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD));
  2025. // Valid info
  2026. if (TRUE == pResponse->fValidInfo)
  2027. {
  2028. // Progress...
  2029. m_dwProgressCur += pResponse->rRetrInfo.cbLines;
  2030. // Don't let progress grow beyond what we estimated the ceiling for this message
  2031. if (m_dwProgressCur > pItem->dwProgressCur)
  2032. m_dwProgressCur = pItem->dwProgressCur;
  2033. // Show Progress
  2034. _DoProgress();
  2035. // Do we have a destination yet ?
  2036. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN))
  2037. {
  2038. // We better have a stream
  2039. Assert(m_rFolder.pStream && m_rFolder.pFolder);
  2040. // Simply write the data
  2041. CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
  2042. }
  2043. // Otherwise
  2044. else
  2045. {
  2046. // If there are no inbox rules
  2047. if (ISFLAGSET(m_dwState, POP3STATE_NOPOSTRULES))
  2048. {
  2049. // Use the Inbox
  2050. CHECKHR(hr = _HrOpenFolder(m_pInbox));
  2051. // Destination is known
  2052. FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN);
  2053. // Simply write the data
  2054. CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
  2055. }
  2056. // else if we have only body rules...
  2057. else if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES))
  2058. {
  2059. // No stream yet ?
  2060. if (NULL == m_pStream)
  2061. {
  2062. // Create a Stream
  2063. CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream));
  2064. }
  2065. // Simply write the data
  2066. CHECKHR(hr = m_pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
  2067. }
  2068. // Otherwise...
  2069. else
  2070. {
  2071. // Have I checked the inbox rule for this item yet ?
  2072. if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE))
  2073. {
  2074. // No stream yet ?
  2075. if (NULL == m_pStream)
  2076. {
  2077. // Create a Stream
  2078. CHECKHR(hr = MimeOleCreateVirtualStream(&m_pStream));
  2079. }
  2080. // Simply write the data
  2081. CHECKHR(hr = m_pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
  2082. // If I have the header, check the inbox rule
  2083. if (TRUE == pResponse->rRetrInfo.fHeader)
  2084. {
  2085. // Commit the stream
  2086. CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT));
  2087. // Check Inbox Rule for this item
  2088. _ComputeItemInboxRule(pItem, m_pStream, NULL, NULL, FALSE);
  2089. }
  2090. }
  2091. // Have I checked the inbox rule for this item yet ?
  2092. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE))
  2093. {
  2094. // Locals
  2095. IMessageFolder *pFolder;
  2096. // We must have the header
  2097. IxpAssert(pResponse->rRetrInfo.fHeader);
  2098. // Did we find an Inbox Rule
  2099. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE) && S_OK == _GetMoveFolder(pItem, &pFolder))
  2100. {
  2101. // Use the Inbox
  2102. CHECKHR(hr = _HrOpenFolder(pFolder));
  2103. }
  2104. // No Move To, just use the inbox
  2105. else
  2106. {
  2107. // Use the Inbox
  2108. CHECKHR(hr = _HrOpenFolder(m_pInbox));
  2109. }
  2110. // Destination is known
  2111. FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN);
  2112. // If m_pStream, then copy this to the folder
  2113. if (m_pStream)
  2114. {
  2115. // Rewind the stream
  2116. CHECKHR(hr = HrRewindStream(m_pStream));
  2117. // Copy this stream to the folder
  2118. CHECKHR(hr = HrCopyStream(m_pStream, m_rFolder.pStream, NULL));
  2119. // Relase m_pStream
  2120. SafeRelease(m_pStream);
  2121. }
  2122. // Otherwise, store the data into the folder
  2123. else
  2124. {
  2125. IxpAssert(FALSE);
  2126. // Simply write the data
  2127. CHECKHR(hr = m_rFolder.pStream->Write(pResponse->rRetrInfo.pszLines, pResponse->rRetrInfo.cbLines, NULL));
  2128. }
  2129. }
  2130. }
  2131. }
  2132. }
  2133. // Done ?
  2134. if (TRUE == pResponse->fDone)
  2135. {
  2136. // Finish this message download
  2137. CHECKHR(hr = _HrFinishMessageDownload(dwPopId));
  2138. }
  2139. exit:
  2140. // Done
  2141. return hr;
  2142. }
  2143. // ------------------------------------------------------------------------------------
  2144. // CPop3Task::_HrFinishMessageDownload
  2145. // ------------------------------------------------------------------------------------
  2146. HRESULT CPop3Task::_HrFinishMessageDownload(DWORD dwPopId)
  2147. {
  2148. // Locals
  2149. HRESULT hr=S_OK;
  2150. IMimeMessage *pMessage=NULL;
  2151. PROPVARIANT rUserData;
  2152. LPPOP3ITEM pItem;
  2153. SYSTEMTIME st;
  2154. UIDLRECORD rUidlInfo={0};
  2155. MESSAGEID idMessage;
  2156. DWORD dwMsgFlags;
  2157. IMessageFolder *pFolder;
  2158. ULONG ulIndex = 0;
  2159. IStream * pIStm = NULL;
  2160. BOOL fDelete=FALSE;
  2161. // Get Current Item
  2162. pItem = ITEMFROMPOPID(dwPopId);
  2163. // Create a New Mail Message
  2164. CHECKHR(hr = HrCreateMessage(&pMessage));
  2165. // Has Body rules
  2166. if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES))
  2167. {
  2168. // I should not have checked for a rule yet
  2169. IxpAssert(!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE));
  2170. // Better have a current folder
  2171. Assert(m_pStream);
  2172. // Check Params
  2173. CHECKHR(hr = m_pStream->Commit(STGC_DEFAULT));
  2174. pIStm = m_pStream;
  2175. }
  2176. else
  2177. {
  2178. // Better have a current folder
  2179. Assert(m_rFolder.pStream);
  2180. // Check Params
  2181. CHECKHR(hr = m_rFolder.pStream->Commit(STGC_DEFAULT));
  2182. // Change the Lock Type
  2183. CHECKHR(hr = m_rFolder.pFolder->ChangeStreamLock(m_rFolder.pStream, ACCESS_READ));
  2184. pIStm = m_rFolder.pStream;
  2185. }
  2186. // Rewind
  2187. CHECKHR(hr = HrRewindStream(pIStm));
  2188. // Stream in
  2189. CHECKHR(hr = pMessage->Load(pIStm));
  2190. // Count Partials
  2191. if (S_OK == pMessage->IsContentType(HBODY_ROOT, STR_CNT_MESSAGE, STR_SUB_PARTIAL))
  2192. m_rMetrics.cPartials++;
  2193. // Save Server
  2194. rUserData.vt = VT_LPSTR;
  2195. rUserData.pszVal = m_rServer.szServerName;
  2196. pMessage->SetProp(PIDTOSTR(PID_ATT_SERVER), NOFLAGS, &rUserData);
  2197. // Save Account Name
  2198. rUserData.vt = VT_LPSTR;
  2199. rUserData.pszVal = m_rServer.szAccount;
  2200. pMessage->SetProp(STR_ATT_ACCOUNTNAME, NOFLAGS, &rUserData);
  2201. // Save Account Name
  2202. rUserData.vt = VT_LPSTR;
  2203. rUserData.pszVal = m_szAccountId;
  2204. pMessage->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &rUserData);
  2205. // Save UIDL
  2206. if (pItem->pszUidl)
  2207. {
  2208. rUserData.vt = VT_LPSTR;
  2209. rUserData.pszVal = pItem->pszUidl;
  2210. pMessage->SetProp(PIDTOSTR(PID_ATT_UIDL), NOFLAGS, &rUserData);
  2211. }
  2212. // Save User Name
  2213. rUserData.vt = VT_LPSTR;
  2214. rUserData.pszVal = m_rServer.szUserName;
  2215. pMessage->SetProp(PIDTOSTR(PID_ATT_USERNAME), NOFLAGS, &rUserData);
  2216. // Initialize dwMsgFlags
  2217. dwMsgFlags = ARF_RECEIVED;
  2218. // Has Body rules
  2219. if (ISFLAGSET(m_dwState, POP3STATE_BODYRULES))
  2220. {
  2221. // I should not have checked for a rule yet
  2222. IxpAssert(!ISFLAGSET(pItem->dwFlags, POP3ITEM_CHECKEDINBOXRULE) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE));
  2223. // Compute the inbox rule
  2224. _ComputeItemInboxRule(pItem, NULL, NULL, pMessage, FALSE);
  2225. // Did we find an Inbox Rule
  2226. if (ISFLAGCLEAR(pItem->dwFlags, POP3ITEM_HASINBOXRULE) || (S_OK != _GetMoveFolder(pItem, &pFolder)))
  2227. {
  2228. pFolder = m_pInbox;
  2229. }
  2230. // Destination is known
  2231. FLAGSET(pItem->dwFlags, POP3ITEM_DESTINATIONKNOWN);
  2232. }
  2233. else
  2234. {
  2235. pFolder = m_rFolder.pFolder;
  2236. }
  2237. // Store the message into the folder
  2238. IF_FAILEXIT(hr = pFolder->SaveMessage(&idMessage, SAVE_MESSAGE_GENID, dwMsgFlags, pIStm, pMessage, NOSTORECALLBACK));
  2239. // Success
  2240. m_rFolder.fCommitted = TRUE;
  2241. // This message was successfully downloaded
  2242. FLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOADED);
  2243. // Do PostDownloadRule
  2244. _DoPostDownloadActions(pItem, idMessage, pFolder, pMessage, &fDelete);
  2245. // Release Folder Object
  2246. SafeRelease(m_rFolder.pStream);
  2247. // Relase m_pStream
  2248. SafeRelease(m_pStream);
  2249. // Release the Folder
  2250. SafeRelease(m_rFolder.pFolder);
  2251. // Clear the folder infor Struct
  2252. ZeroMemory(&m_rFolder, sizeof(POP3FOLDERINFO));
  2253. // If going to delete it...
  2254. if (fDelete)
  2255. {
  2256. // Mark it for deletion
  2257. FLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER);
  2258. // We will store its uidl, but lets delete it later
  2259. FLAGSET(pItem->dwFlags, POP3ITEM_DELETECACHEDUIDL);
  2260. }
  2261. // Cached the UIDL for this message ?
  2262. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_CACHEUIDL))
  2263. {
  2264. // Should have a pszUidl
  2265. Assert(pItem->pszUidl && m_pUidlCache);
  2266. // Don't fault
  2267. if (pItem->pszUidl)
  2268. {
  2269. // Set Key
  2270. GetSystemTime(&st);
  2271. SystemTimeToFileTime(&st, &rUidlInfo.ftDownload);
  2272. rUidlInfo.fDownloaded = TRUE;
  2273. rUidlInfo.fDeleted = FALSE;
  2274. rUidlInfo.pszUidl = pItem->pszUidl;
  2275. rUidlInfo.pszServer = m_rServer.szServerName;
  2276. rUidlInfo.pszAccountId = m_szAccountId;
  2277. // Set Propgs
  2278. m_pUidlCache->InsertRecord(&rUidlInfo);
  2279. }
  2280. }
  2281. // Successful download
  2282. m_rMetrics.cDownloaded++;
  2283. // Do smart log
  2284. if (m_pSmartLog && (lstrcmpi(m_pSmartLog->pszAccount, m_rServer.szAccount) == 0 || lstrcmpi("All", m_pSmartLog->pszAccount) == 0))
  2285. _DoSmartLog(pMessage);
  2286. // Retrieve the next message
  2287. CHECKHR(hr = _HrRetrieveNextMessage(dwPopId));
  2288. exit:
  2289. // Cleanup
  2290. SafeRelease(pMessage);
  2291. // Done
  2292. return hr;
  2293. }
  2294. // ------------------------------------------------------------------------------------
  2295. // CPop3Task::_DoPostDownloadActions
  2296. // ------------------------------------------------------------------------------------
  2297. void CPop3Task::_DoPostDownloadActions(LPPOP3ITEM pItem, MESSAGEID idMessage,
  2298. IMessageFolder *pFolder, IMimeMessage *pMessage, BOOL *pfDeleteOffServer)
  2299. {
  2300. // Locals
  2301. HRESULT hr;
  2302. MESSAGEINFO Message = {0};
  2303. HWND hwnd = NULL;
  2304. // Finish Applying the inbox rules
  2305. if (!ISFLAGSET(pItem->dwFlags, POP3ITEM_HASINBOXRULE))
  2306. {
  2307. goto exit;
  2308. }
  2309. // Get Window
  2310. if (FAILED(m_pUI->GetWindow(&hwnd)))
  2311. hwnd = NULL;
  2312. // Set the Id
  2313. Message.idMessage = idMessage;
  2314. // Get the message
  2315. hr = pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &Message, NULL);
  2316. if (FAILED(hr) || DB_S_NOTFOUND == hr)
  2317. {
  2318. goto exit;
  2319. }
  2320. if (FAILED(RuleUtil_HrApplyActions(hwnd, m_pIExecRules, &Message, pFolder, pMessage, 0, pItem->pActList,
  2321. pItem->cActList, &(m_rMetrics.cInfiniteLoopAutoGens), pfDeleteOffServer)))
  2322. {
  2323. goto exit;
  2324. }
  2325. exit:
  2326. // Free
  2327. if (NULL != pFolder)
  2328. {
  2329. pFolder->FreeRecord(&Message);
  2330. }
  2331. // Done
  2332. return;
  2333. }
  2334. // ------------------------------------------------------------------------------------
  2335. // CPop3Task::_HrOpenFolder
  2336. // ------------------------------------------------------------------------------------
  2337. HRESULT CPop3Task::_HrOpenFolder(IMessageFolder *pFolder)
  2338. {
  2339. // Locals
  2340. HRESULT hr=S_OK;
  2341. // Current folder better be empty
  2342. Assert(NULL == m_rFolder.pFolder && NULL == m_rFolder.pStream && 0 == m_rFolder.faStream);
  2343. // Bad Arguments
  2344. if (NULL == pFolder)
  2345. {
  2346. Assert(FALSE);
  2347. return TrapError(E_INVALIDARG);
  2348. }
  2349. // Save the folder
  2350. m_rFolder.pFolder = pFolder;
  2351. // AddRef
  2352. m_rFolder.pFolder->AddRef();
  2353. // Get a stream from the
  2354. CHECKHR(hr = m_rFolder.pFolder->CreateStream(&m_rFolder.faStream));
  2355. // Open the Stream
  2356. CHECKHR(hr = m_rFolder.pFolder->OpenStream(ACCESS_WRITE, m_rFolder.faStream, &m_rFolder.pStream));
  2357. exit:
  2358. // Done
  2359. return hr;
  2360. }
  2361. // ------------------------------------------------------------------------------------
  2362. // CPop3Task::_CloseFolder
  2363. // ------------------------------------------------------------------------------------
  2364. void CPop3Task::_CloseFolder(void)
  2365. {
  2366. // Release the Stream
  2367. SafeRelease(m_rFolder.pStream);
  2368. // Release the reference to the stream. If the stream was reused,
  2369. // it's refCount was incremented down below
  2370. if (m_rFolder.faStream != 0)
  2371. {
  2372. // Must have a folder
  2373. Assert(m_rFolder.pFolder);
  2374. // Delete the Stream
  2375. SideAssert(SUCCEEDED(m_rFolder.pFolder->DeleteStream(m_rFolder.faStream)));
  2376. // Nill
  2377. m_rFolder.faStream = 0;
  2378. }
  2379. // AddRef
  2380. SafeRelease(m_rFolder.pFolder);
  2381. }
  2382. // --------------------------------------------------------------------------------
  2383. // CPop3Task::_HrStartDeleteCycle
  2384. // --------------------------------------------------------------------------------
  2385. HRESULT CPop3Task::_HrStartDeleteCycle(void)
  2386. {
  2387. // Locals
  2388. HRESULT hr=S_OK;
  2389. ULONG i;
  2390. LPPOP3ITEM pItem;
  2391. // Release Folder Objects
  2392. _ReleaseFolderObjects();
  2393. // Check State
  2394. m_rMetrics.cDelete = 0;
  2395. m_rMetrics.iCurrent = 0;
  2396. // Count the number of messages we will have to get a top for
  2397. for (i=0; i<m_rTable.cItems; i++)
  2398. {
  2399. // Readability
  2400. pItem = &m_rTable.prgItem[i];
  2401. // If it was marked for download, and we didn't download it, don't delete it
  2402. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOAD) && !ISFLAGSET(pItem->dwFlags, POP3ITEM_DOWNLOADED))
  2403. FLAGCLEAR(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER);
  2404. // Is it marked for delete ?
  2405. else if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER))
  2406. m_rMetrics.cDelete++;
  2407. }
  2408. // Nothing to delete
  2409. if (0 == m_rMetrics.cDelete)
  2410. {
  2411. // Disconnect
  2412. m_pTransport->Disconnect();
  2413. // Done
  2414. goto exit;
  2415. }
  2416. // Setup Progress
  2417. m_rMetrics.iCurrent = 0;
  2418. m_wProgress = 0;
  2419. m_dwProgressCur = 0;
  2420. m_dwProgressMax = m_rMetrics.cDelete;
  2421. m_pUI->SetProgressRange(100);
  2422. // State
  2423. m_state = POP3STATE_DELETING;
  2424. // Do the first one
  2425. CHECKHR(hr = _HrDeleteNextMessage(0));
  2426. exit:
  2427. // Done
  2428. return hr;
  2429. }
  2430. // ------------------------------------------------------------------------------------
  2431. // CPop3Task::_HrDeleteNextMessage
  2432. // ------------------------------------------------------------------------------------
  2433. HRESULT CPop3Task::_HrDeleteNextMessage(DWORD dwPopIdCurrent)
  2434. {
  2435. // Locals
  2436. HRESULT hr=S_OK;
  2437. CHAR szRes[CCHMAX_RES];
  2438. CHAR szMsg[CCHMAX_RES + CCHMAX_RES];
  2439. LPPOP3ITEM pItem;
  2440. // Mark as deleted
  2441. if (dwPopIdCurrent > 0)
  2442. {
  2443. // Get the item
  2444. pItem = ITEMFROMPOPID(dwPopIdCurrent);
  2445. // Mark as deleted
  2446. FLAGSET(pItem->dwFlags, POP3ITEM_DELETED);
  2447. }
  2448. // Loop until we find the next message that we are downloading
  2449. while(1)
  2450. {
  2451. // Incremenet dwPopIdCurrent
  2452. dwPopIdCurrent++;
  2453. // Last PopId, start the download
  2454. if (dwPopIdCurrent > m_rTable.cItems)
  2455. {
  2456. // Disconnect
  2457. m_pTransport->Disconnect();
  2458. // Done
  2459. break;
  2460. }
  2461. // Readability
  2462. pItem = ITEMFROMPOPID(dwPopIdCurrent);
  2463. // Download this message ?
  2464. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELETEOFFSERVER))
  2465. {
  2466. // Increment m_rMetrics.iCurrent
  2467. m_rMetrics.iCurrent++;
  2468. // Status
  2469. //LOADSTRING(IDS_SPS_POP3DELE, szRes);
  2470. //wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, m_rMetrics.iCurrent, m_rMetrics.cDelete);
  2471. //m_pUI->SetSpecificProgress(szMsg);
  2472. // Retrieve this item
  2473. CHECKHR(hr = m_pTransport->CommandDELE(POP3CMD_GET_POPID, dwPopIdCurrent));
  2474. // Count number of items deleted by rule
  2475. if (ISFLAGSET(pItem->dwFlags, POP3ITEM_DELEBYRULE))
  2476. m_rMetrics.cDeleByRule++;
  2477. // Done
  2478. break;
  2479. }
  2480. }
  2481. exit:
  2482. // Done
  2483. return hr;
  2484. }
  2485. // ------------------------------------------------------------------------------------
  2486. // CPop3Task::_HrBuildFolderPartialMsgs
  2487. // ------------------------------------------------------------------------------------
  2488. HRESULT CPop3Task::_HrBuildFolderPartialMsgs(IMessageFolder *pFolder, LPPARTIALMSG *ppPartialMsgs,
  2489. ULONG *pcPartialMsgs, ULONG *pcTotalParts)
  2490. {
  2491. // Locals
  2492. HRESULT hr=S_OK;
  2493. LPPARTIALMSG pPartialMsgs=NULL;
  2494. ULONG cPartialMsgs=0,
  2495. iPartialMsg,
  2496. iMsgPart,
  2497. i,
  2498. cTotalParts=0;
  2499. ULONG cAlloc=0;
  2500. MESSAGEINFO MsgInfo={0};
  2501. HROWSET hRowset=NULL;
  2502. BOOL fKnownPartialId;
  2503. // Check Params
  2504. Assert(pFolder && ppPartialMsgs && pcPartialMsgs);
  2505. // Init
  2506. *ppPartialMsgs = NULL;
  2507. *pcPartialMsgs = 0;
  2508. *pcTotalParts = 0;
  2509. // Create a Rowset
  2510. CHECKHR(hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset));
  2511. // Loop
  2512. while (S_OK == pFolder->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL))
  2513. {
  2514. // Is this a partial, i.e. does it have a partial id...
  2515. if (!FIsEmptyA(MsgInfo.pszPartialId))
  2516. {
  2517. // Assume we don't know th id
  2518. fKnownPartialId = FALSE;
  2519. // See if I know this partial id
  2520. for (iPartialMsg=0; iPartialMsg<cPartialMsgs; iPartialMsg++)
  2521. {
  2522. if (lstrcmp(MsgInfo.pszPartialId, pPartialMsgs[iPartialMsg].pszId) == 0)
  2523. {
  2524. fKnownPartialId = TRUE;
  2525. break;
  2526. }
  2527. }
  2528. // Did we know this message...
  2529. if (fKnownPartialId == FALSE)
  2530. {
  2531. // Realloc my array ?
  2532. if (cPartialMsgs + 1 >= cAlloc)
  2533. {
  2534. // Realloc the array
  2535. if (!MemRealloc((LPVOID *)&pPartialMsgs, (cAlloc + 20) * sizeof(PARTIALMSG)))
  2536. {
  2537. hr = TrapError(hrMemory);
  2538. goto exit;
  2539. }
  2540. // Zero Init
  2541. ZeroMemory(pPartialMsgs + cAlloc, 20 * sizeof(PARTIALMSG));
  2542. // Realloc
  2543. cAlloc += 20;
  2544. }
  2545. // Set index into partial msgs lsit
  2546. iPartialMsg = cPartialMsgs;
  2547. // Set some stuff
  2548. if (MsgInfo.pszAcctName)
  2549. StrCpyN(pPartialMsgs[iPartialMsg].szAccount, MsgInfo.pszAcctName, ARRAYSIZE(pPartialMsgs[iPartialMsg].szAccount));
  2550. pPartialMsgs[iPartialMsg].pszId = PszDupA(MsgInfo.pszPartialId);
  2551. pPartialMsgs[iPartialMsg].cTotalParts = LOWORD(MsgInfo.dwPartial);
  2552. // Increment number of known partial messages
  2553. cPartialMsgs++;
  2554. }
  2555. // Otherwise, we know the partial id already...
  2556. else
  2557. {
  2558. // See if this message details the total number of parts
  2559. if (pPartialMsgs[iPartialMsg].cTotalParts == 0)
  2560. pPartialMsgs[iPartialMsg].cTotalParts = LOWORD(MsgInfo.dwPartial);
  2561. }
  2562. // Can I add one more msgpart into this list
  2563. if (pPartialMsgs[iPartialMsg].cMsgParts + 1 >= pPartialMsgs[iPartialMsg].cAlloc)
  2564. {
  2565. // Realloc the array
  2566. if (!MemRealloc((LPVOID *)&pPartialMsgs[iPartialMsg].pMsgParts, (pPartialMsgs[iPartialMsg].cAlloc + 20) * sizeof(MSGPART)))
  2567. {
  2568. hr = TrapError(hrMemory);
  2569. goto exit;
  2570. }
  2571. // Zero Init
  2572. ZeroMemory(pPartialMsgs[iPartialMsg].pMsgParts + pPartialMsgs[iPartialMsg].cAlloc, 20 * sizeof(MSGPART));
  2573. // Realloc
  2574. pPartialMsgs[iPartialMsg].cAlloc += 20;
  2575. }
  2576. // Set Message Part
  2577. iMsgPart = pPartialMsgs[iPartialMsg].cMsgParts;
  2578. // Set Message Info
  2579. pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].iPart = HIWORD(MsgInfo.dwPartial);
  2580. pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].msgid = MsgInfo.idMessage;
  2581. //pPartialMsgs[iPartialMsg].pMsgParts[iMsgPart].phi = phi;
  2582. //phi = NULL;
  2583. // Increment the number of parts in the list
  2584. pPartialMsgs[iPartialMsg].cMsgParts++;
  2585. }
  2586. // Free
  2587. pFolder->FreeRecord(&MsgInfo);
  2588. }
  2589. // Lets sort the list by pszId
  2590. for (i=0; i<cPartialMsgs; i++)
  2591. {
  2592. if (pPartialMsgs[i].pMsgParts && pPartialMsgs[i].cMsgParts > 0)
  2593. _QSortMsgParts(pPartialMsgs[i].pMsgParts, 0, pPartialMsgs[i].cMsgParts-1);
  2594. cTotalParts += pPartialMsgs[i].cMsgParts;
  2595. }
  2596. // Success
  2597. *pcPartialMsgs = cPartialMsgs;
  2598. *ppPartialMsgs = pPartialMsgs;
  2599. *pcTotalParts = cTotalParts;
  2600. exit:
  2601. // Cleanup
  2602. if (pFolder)
  2603. {
  2604. pFolder->CloseRowset(&hRowset);
  2605. pFolder->FreeRecord(&MsgInfo);
  2606. }
  2607. // If We failed, free stuff
  2608. if (FAILED(hr))
  2609. {
  2610. _FreePartialMsgs(pPartialMsgs, cPartialMsgs);
  2611. SafeMemFree(pPartialMsgs);
  2612. *ppPartialMsgs = NULL;
  2613. *pcPartialMsgs = 0;
  2614. *pcTotalParts = 0;
  2615. }
  2616. // Done
  2617. return hr;
  2618. }
  2619. // ------------------------------------------------------------------------------------
  2620. // CPop3Task::_QSortMsgParts
  2621. // ------------------------------------------------------------------------------------
  2622. void CPop3Task::_QSortMsgParts(LPMSGPART pMsgParts, LONG left, LONG right)
  2623. {
  2624. register long i, j;
  2625. WORD k;
  2626. MSGPART y;
  2627. i = left;
  2628. j = right;
  2629. k = pMsgParts[(left + right) / 2].iPart;
  2630. do
  2631. {
  2632. while(pMsgParts[i].iPart < k && i < right)
  2633. i++;
  2634. while (pMsgParts[j].iPart > k && j > left)
  2635. j--;
  2636. if (i <= j)
  2637. {
  2638. CopyMemory(&y, &pMsgParts[i], sizeof(MSGPART));
  2639. CopyMemory(&pMsgParts[i], &pMsgParts[j], sizeof(MSGPART));
  2640. CopyMemory(&pMsgParts[j], &y, sizeof(MSGPART));
  2641. i++; j--;
  2642. }
  2643. } while (i <= j);
  2644. if (left < j)
  2645. _QSortMsgParts(pMsgParts, left, j);
  2646. if (i < right)
  2647. _QSortMsgParts(pMsgParts, i, right);
  2648. }
  2649. // ------------------------------------------------------------------------------------
  2650. // CPop3Task::_FreePartialMsgs
  2651. // ------------------------------------------------------------------------------------
  2652. void CPop3Task::_FreePartialMsgs(LPPARTIALMSG pPartialMsgs, ULONG cPartialMsgs)
  2653. {
  2654. // Locals
  2655. ULONG i, j;
  2656. // Nothing to free
  2657. if (pPartialMsgs == NULL)
  2658. return;
  2659. // Loop the array
  2660. for (i=0; i<cPartialMsgs; i++)
  2661. {
  2662. SafeMemFree(pPartialMsgs[i].pszId);
  2663. #if 0
  2664. for (j=0; j<pPartialMsgs[i].cMsgParts; j++)
  2665. {
  2666. FreeHeaderInfo(pPartialMsgs[i].pMsgParts[j].phi);
  2667. }
  2668. #endif
  2669. SafeMemFree(pPartialMsgs[i].pMsgParts);
  2670. }
  2671. // Done
  2672. return;
  2673. }
  2674. // ------------------------------------------------------------------------------------
  2675. // CPop3Task::_HrStitchPartials
  2676. // ------------------------------------------------------------------------------------
  2677. HRESULT CPop3Task::_HrStitchPartials(void)
  2678. {
  2679. // Locals
  2680. HRESULT hr = S_OK;
  2681. IMessageFolder *pInbox=NULL,
  2682. *pDeletedItems=NULL;
  2683. LPPARTIALMSG pPartialMsgs=NULL;
  2684. ULONG cPartialMsgs=0,
  2685. i,
  2686. j,
  2687. cbCacheInfo,
  2688. cErrors=0,
  2689. cTotalParts;
  2690. IMimeMessageParts *pParts=NULL;
  2691. LPMSGPART pMsgParts;
  2692. IMimeMessage *pMailMsg=NULL,
  2693. *pMailMsgSingle=NULL;
  2694. TCHAR szRes[255];
  2695. PROPVARIANT rUserData;
  2696. ULONG cCombined=0;
  2697. MESSAGEIDLIST List;
  2698. HWND hwnd;
  2699. // Progress
  2700. AthLoadString(idsStitchingMessages, szRes, ARRAYSIZE(szRes));
  2701. m_pUI->SetSpecificProgress(szRes);
  2702. m_pUI->SetAnimation(idanDecode, TRUE);
  2703. m_pUI->SetProgressRange(100);
  2704. // Get Window
  2705. if (FAILED(m_pUI->GetWindow(&hwnd)))
  2706. hwnd = NULL;
  2707. // open the inbox
  2708. CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreInbox, (LPVOID *)&pInbox));
  2709. // deleted items folder
  2710. CHECKHR(hr = m_pSpoolCtx->BindToObject(IID_CLocalStoreDeleted, (LPVOID *)&pDeletedItems));
  2711. // Get array of message parts in this folder
  2712. CHECKHR(hr = _HrBuildFolderPartialMsgs(pInbox, &pPartialMsgs, &cPartialMsgs, &cTotalParts));
  2713. // If nothing, were done
  2714. if (pPartialMsgs == NULL || cPartialMsgs == 0)
  2715. goto exit;
  2716. // Setup Progress
  2717. m_rMetrics.iCurrent = 0;
  2718. m_wProgress = 0;
  2719. m_dwProgressCur = 0;
  2720. m_dwProgressMax = cTotalParts;
  2721. // Loop through partial messages list
  2722. for (i=0; i<cPartialMsgs; i++)
  2723. {
  2724. // If we don't know all of the parts yet, continue
  2725. if (pPartialMsgs[i].cTotalParts == 0)
  2726. continue;
  2727. // Or we don't have all of the parts yet...
  2728. if (pPartialMsgs[i].cTotalParts != pPartialMsgs[i].cMsgParts)
  2729. continue;
  2730. // Lets create a mail message list
  2731. Assert(pParts == NULL);
  2732. // Create Parts Object
  2733. CHECKHR(hr = MimeOleCreateMessageParts(&pParts));
  2734. // Set pMsgParts
  2735. pMsgParts = pPartialMsgs[i].pMsgParts;
  2736. // Ok, lets build a message list by opening the messages up out of the store...
  2737. for (j=0; j<pPartialMsgs[i].cMsgParts; j++)
  2738. {
  2739. // Progress
  2740. if (j > 0)
  2741. {
  2742. m_dwProgressCur++;
  2743. _DoProgress();
  2744. }
  2745. // Open this message
  2746. if (FAILED(pInbox->OpenMessage(pMsgParts[j].msgid, NOFLAGS, &pMailMsg, NOSTORECALLBACK)))
  2747. {
  2748. cErrors++;
  2749. hr = TrapError(E_FAIL);
  2750. goto NextPartialMessage;
  2751. }
  2752. // Add into pmml
  2753. pParts->AddPart(pMailMsg);
  2754. // Release It
  2755. SafeRelease(pMailMsg);
  2756. }
  2757. // Create a new message to combine everyting into
  2758. Assert(pMailMsgSingle == NULL);
  2759. // Create a Message
  2760. hr = pParts->CombineParts(&pMailMsgSingle);
  2761. if (FAILED(hr))
  2762. {
  2763. cErrors++;
  2764. TrapError(hr);
  2765. goto NextPartialMessage;
  2766. }
  2767. // Set Account
  2768. HrSetAccount(pMailMsgSingle, pPartialMsgs[i].szAccount);
  2769. // Set Combined Flag
  2770. rUserData.vt = VT_UI4;
  2771. rUserData.ulVal = MESSAGE_COMBINED;
  2772. pMailMsgSingle->SetProp(PIDTOSTR(PID_ATT_COMBINED), NOFLAGS, &rUserData);
  2773. // Save the message
  2774. hr = pMailMsgSingle->Commit(0);
  2775. if (FAILED(hr))
  2776. {
  2777. cErrors++;
  2778. TrapError(hr);
  2779. goto NextPartialMessage;
  2780. }
  2781. // Save It
  2782. hr = pInbox->SaveMessage(NULL, SAVE_MESSAGE_GENID, ARF_RECEIVED, 0, pMailMsgSingle, NOSTORECALLBACK);
  2783. if (FAILED(hr))
  2784. {
  2785. cErrors++;
  2786. TrapError(hr);
  2787. goto NextPartialMessage;
  2788. }
  2789. // Ok, now lets move those original messages to the deleted items folder...
  2790. for (j=0; j<pPartialMsgs[i].cMsgParts; j++)
  2791. {
  2792. // Setup the msgidlsit
  2793. List.cMsgs = 1;
  2794. List.prgidMsg = &pMsgParts[j].msgid;
  2795. // Move msgid to deleted items folder
  2796. CopyMessagesProgress(hwnd, pInbox, pDeletedItems, COPY_MESSAGE_MOVE, &List, NULL);
  2797. }
  2798. // Count Combined
  2799. cCombined++;
  2800. // Cleanup
  2801. NextPartialMessage:
  2802. SafeRelease(pMailMsg);
  2803. SafeRelease(pMailMsgSingle);
  2804. SafeRelease(pParts);
  2805. }
  2806. // If I combined parts, apply inbox rules to the inbox
  2807. if (cCombined)
  2808. {
  2809. // Apply to the inbox
  2810. RuleUtil_HrApplyRulesToFolder(RULE_APPLY_PARTIALS, 0, m_pIExecRules, pInbox, NULL, NULL);
  2811. }
  2812. exit:
  2813. // Cleanup
  2814. m_pUI->SetSpecificProgress(c_szEmpty);
  2815. m_pUI->SetProgressRange(100);
  2816. SafeRelease(pInbox);
  2817. SafeRelease(pDeletedItems);
  2818. SafeRelease(pParts);
  2819. SafeRelease(pMailMsg);
  2820. SafeRelease(pMailMsgSingle);
  2821. _FreePartialMsgs(pPartialMsgs, cPartialMsgs);
  2822. SafeMemFree(pPartialMsgs);
  2823. // Done
  2824. return hr;
  2825. }
  2826. // ------------------------------------------------------------------------------------
  2827. // CPop3Task::_GetMoveFolder
  2828. // ------------------------------------------------------------------------------------
  2829. HRESULT CPop3Task::_GetMoveFolder(LPPOP3ITEM pItem, IMessageFolder ** ppFolder)
  2830. {
  2831. HRESULT hr = S_OK;
  2832. IMessageFolder * pFolder = NULL;
  2833. ULONG ulIndex = 0;
  2834. FOLDERID idFolder = FOLDERID_INVALID;
  2835. FOLDERINFO infoFolder = {0};
  2836. SPECIALFOLDER tySpecial = FOLDER_NOTSPECIAL;
  2837. RULEFOLDERDATA * prfdData = NULL;
  2838. // Check incoming params
  2839. if ((NULL == pItem) || (NULL == ppFolder))
  2840. {
  2841. hr = E_INVALIDARG;
  2842. goto exit;
  2843. }
  2844. // Initialize the outgoing param
  2845. *ppFolder = NULL;
  2846. // Search for a Move actions
  2847. for (ulIndex = 0; ulIndex < pItem->cActList; ulIndex++)
  2848. {
  2849. switch (pItem->pActList[ulIndex].type)
  2850. {
  2851. case ACT_TYPE_MOVE:
  2852. Assert(VT_BLOB == pItem->pActList[ulIndex].propvar.vt);
  2853. if ((0 != pItem->pActList[ulIndex].propvar.blob.cbSize) && (NULL != pItem->pActList[ulIndex].propvar.blob.pBlobData))
  2854. {
  2855. // Make life simpler
  2856. prfdData = (RULEFOLDERDATA *) (pItem->pActList[ulIndex].propvar.blob.pBlobData);
  2857. // Validate the rule folder data
  2858. if (S_OK == RuleUtil_HrValidateRuleFolderData(prfdData))
  2859. {
  2860. idFolder = prfdData->idFolder;
  2861. }
  2862. }
  2863. break;
  2864. case ACT_TYPE_DELETE:
  2865. case ACT_TYPE_JUNKMAIL:
  2866. Assert(VT_EMPTY == pItem->pActList[ulIndex].propvar.vt);
  2867. tySpecial = (ACT_TYPE_JUNKMAIL == pItem->pActList[ulIndex].type) ? FOLDER_JUNK : FOLDER_DELETED;
  2868. hr = g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, tySpecial, &infoFolder);
  2869. if (FAILED(hr))
  2870. {
  2871. goto exit;;
  2872. }
  2873. idFolder = infoFolder.idFolder;
  2874. break;
  2875. }
  2876. // Are we through?
  2877. if (idFolder != FOLDERID_INVALID)
  2878. {
  2879. break;
  2880. }
  2881. }
  2882. // Did we find anything?
  2883. if (ulIndex >= pItem->cActList)
  2884. {
  2885. hr = S_FALSE;
  2886. goto exit;
  2887. }
  2888. // Get the message folder
  2889. hr = m_pIExecRules->GetRuleFolder(idFolder, (DWORD_PTR *) (&pFolder));
  2890. if (FAILED(hr))
  2891. {
  2892. goto exit;
  2893. }
  2894. // Use the new folder
  2895. *ppFolder = pFolder;
  2896. pFolder = NULL;
  2897. // NULL out the actions
  2898. pItem->pActList[ulIndex].type = ACT_TYPE_NULL;
  2899. // Set the return value
  2900. hr = S_OK;
  2901. exit:
  2902. SafeRelease(pFolder);
  2903. g_pStore->FreeRecord(&infoFolder);
  2904. return hr;
  2905. }
  2906. // --------------------------------------------------------------------------------
  2907. // CPop3Task::Cancel
  2908. // --------------------------------------------------------------------------------
  2909. STDMETHODIMP CPop3Task::Cancel(void)
  2910. {
  2911. // Thread Safety
  2912. EnterCriticalSection(&m_cs);
  2913. // Canceled
  2914. FLAGSET(m_dwState, POP3STATE_CANCELPENDING);
  2915. // Am I in a state where I can drop the connection???
  2916. if (POP3STATE_UIDLSYNC != m_state)
  2917. {
  2918. if (POP3STATE_UIDLSYNC != m_state && POP3STATE_DOWNLOADING != m_state && POP3STATE_DELETING != m_state)
  2919. {
  2920. // Simply drop the connection
  2921. //If a dialer UI is not dismissed, before changing the identities or shutting down OE,
  2922. //the transport object would not have been created. This happens only when the dialer UI is not
  2923. //modal to the window. Right now IE dialer is modal and MSN dialer is not.
  2924. //See Bug# 53679
  2925. if (m_pTransport)
  2926. m_pTransport->DropConnection();
  2927. }
  2928. // Otherwise, let the state handle the disconnect
  2929. else
  2930. {
  2931. // Finishing last message...
  2932. m_pUI->SetSpecificProgress(MAKEINTRESOURCE(idsSpoolerDisconnect));
  2933. }
  2934. }
  2935. // Thread Safety
  2936. LeaveCriticalSection(&m_cs);
  2937. // Done
  2938. return S_OK;
  2939. }
  2940. // --------------------------------------------------------------------------------
  2941. // CPop3Task::OnTimeoutResponse
  2942. // --------------------------------------------------------------------------------
  2943. STDMETHODIMP CPop3Task::OnTimeoutResponse(TIMEOUTRESPONSE eResponse)
  2944. {
  2945. // Thread Safety
  2946. EnterCriticalSection(&m_cs);
  2947. // Should have a handle to the timeout window
  2948. Assert(m_hwndTimeout);
  2949. // No timeout window handle
  2950. m_hwndTimeout = NULL;
  2951. // Stop ?
  2952. if (TIMEOUT_RESPONSE_STOP == eResponse)
  2953. {
  2954. // Canceled
  2955. FLAGSET(m_dwState, POP3STATE_CANCELPENDING);
  2956. // Report error and drop connection
  2957. _CatchResult(IXP_E_TIMEOUT);
  2958. }
  2959. // Thread Safety
  2960. LeaveCriticalSection(&m_cs);
  2961. // Done
  2962. return S_OK;
  2963. }
  2964. // --------------------------------------------------------------------------------
  2965. // CPop3Task::IsDialogMessage
  2966. // --------------------------------------------------------------------------------
  2967. STDMETHODIMP CPop3Task::IsDialogMessage(LPMSG pMsg)
  2968. {
  2969. HRESULT hr=S_FALSE;
  2970. EnterCriticalSection(&m_cs);
  2971. if (m_hwndTimeout && IsWindow(m_hwndTimeout))
  2972. hr = (TRUE == ::IsDialogMessage(m_hwndTimeout, pMsg)) ? S_OK : S_FALSE;
  2973. LeaveCriticalSection(&m_cs);
  2974. return hr;
  2975. }
  2976. // --------------------------------------------------------------------------------
  2977. // CPop3Task::OnFlagsChanged
  2978. // --------------------------------------------------------------------------------
  2979. STDMETHODIMP CPop3Task::OnFlagsChanged(DWORD dwFlags)
  2980. {
  2981. EnterCriticalSection(&m_cs);
  2982. m_dwFlags = dwFlags;
  2983. LeaveCriticalSection(&m_cs);
  2984. return (S_OK);
  2985. }