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.

2320 lines
68 KiB

  1. // --------------------------------------------------------------------------------
  2. // Ixppop3.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "dllmain.h"
  8. #include "ixppop3.h"
  9. #include "asynconn.h"
  10. #include "ixputil.h"
  11. #include "strconst.h"
  12. #include <shlwapi.h>
  13. #include <ntverp.h>
  14. #include "demand.h"
  15. // --------------------------------------------------------------------------------
  16. // Usefule C++ pointer casting
  17. // --------------------------------------------------------------------------------
  18. #define POP3THISIXP ((IPOP3Transport *)(CIxpBase *)this)
  19. #define STR_HOTMAILAUTH "Outlook Express V" VER_PRODUCTVERSION_STR
  20. // --------------------------------------------------------------------------------
  21. // FreeAuthInfo
  22. // --------------------------------------------------------------------------------
  23. void FreeAuthInfo(LPAUTHINFO pAuth)
  24. {
  25. for (UINT i=0; i<pAuth->cAuthToken; i++)
  26. {
  27. ZeroMemory(pAuth->rgpszAuthTokens[i], sizeof(pAuth->rgpszAuthTokens[i][0]) * lstrlen(pAuth->rgpszAuthTokens[i]));
  28. SafeMemFree(pAuth->rgpszAuthTokens[i]);
  29. }
  30. pAuth->iAuthToken = pAuth->cAuthToken = 0;
  31. if (pAuth->pPackages && pAuth->cPackages)
  32. {
  33. SSPIFreePackages(&pAuth->pPackages, pAuth->cPackages);
  34. pAuth->pPackages = NULL;
  35. pAuth->cPackages = 0;
  36. }
  37. SSPIFreeContext(&pAuth->rSicInfo);
  38. ZeroMemory(pAuth, sizeof(*pAuth));
  39. }
  40. // --------------------------------------------------------------------------------
  41. // CPOP3Transport::CPOP3Transport
  42. // --------------------------------------------------------------------------------
  43. CPOP3Transport::CPOP3Transport(void) : CIxpBase(IXP_POP3)
  44. {
  45. DllAddRef();
  46. ZeroMemory(&m_rInfo, sizeof(POP3INFO));
  47. m_rInfo.rAuth.authstate = AUTH_NONE;
  48. m_command = POP3_NONE;
  49. m_fHotmail = FALSE;
  50. }
  51. // --------------------------------------------------------------------------------
  52. // CPOP3Transport::~CPOP3Transport
  53. // --------------------------------------------------------------------------------
  54. CPOP3Transport::~CPOP3Transport(void)
  55. {
  56. ResetBase();
  57. DllRelease();
  58. }
  59. // --------------------------------------------------------------------------------
  60. // CPOP3Transport::ResetBase
  61. // --------------------------------------------------------------------------------
  62. void CPOP3Transport::ResetBase(void)
  63. {
  64. EnterCriticalSection(&m_cs);
  65. FreeAuthInfo(&m_rInfo.rAuth);
  66. SafeMemFree(m_rInfo.prgMarked);
  67. ZeroMemory(&m_rInfo, sizeof(m_rInfo));
  68. m_command = POP3_NONE;
  69. LeaveCriticalSection(&m_cs);
  70. }
  71. // --------------------------------------------------------------------------------
  72. // CPOP3Transport::QueryInterface
  73. // --------------------------------------------------------------------------------
  74. STDMETHODIMP CPOP3Transport::QueryInterface(REFIID riid, LPVOID *ppv)
  75. {
  76. // Locals
  77. HRESULT hr=S_OK;
  78. // Bad param
  79. if (ppv == NULL)
  80. {
  81. hr = TrapError(E_INVALIDARG);
  82. goto exit;
  83. }
  84. // Init
  85. *ppv=NULL;
  86. // IID_IUnknown
  87. if (IID_IUnknown == riid)
  88. *ppv = ((IUnknown *)(IPOP3Transport *)this);
  89. // IID_IInternetTransport
  90. else if (IID_IInternetTransport == riid)
  91. *ppv = ((IInternetTransport *)(CIxpBase *)this);
  92. // IID_IPOP3Transport
  93. else if (IID_IPOP3Transport == riid)
  94. *ppv = (IPOP3Transport *)this;
  95. // If not null, addref it and return
  96. if (NULL != *ppv)
  97. {
  98. ((LPUNKNOWN)*ppv)->AddRef();
  99. goto exit;
  100. }
  101. // No Interface
  102. hr = TrapError(E_NOINTERFACE);
  103. exit:
  104. // Done
  105. return hr;
  106. }
  107. // --------------------------------------------------------------------------------
  108. // CPOP3Transport::AddRef
  109. // --------------------------------------------------------------------------------
  110. STDMETHODIMP_(ULONG) CPOP3Transport::AddRef(void)
  111. {
  112. return ++m_cRef;
  113. }
  114. // --------------------------------------------------------------------------------
  115. // CPOP3Transport::Release
  116. // --------------------------------------------------------------------------------
  117. STDMETHODIMP_(ULONG) CPOP3Transport::Release(void)
  118. {
  119. if (0 != --m_cRef)
  120. return m_cRef;
  121. delete this;
  122. return 0;
  123. }
  124. // --------------------------------------------------------------------------------
  125. // CPOP3Transport::InitNew
  126. // --------------------------------------------------------------------------------
  127. STDMETHODIMP CPOP3Transport::InitNew(LPSTR pszLogFilePath, IPOP3Callback *pCallback)
  128. {
  129. // Call Base Class
  130. return CIxpBase::OnInitNew("POP3", pszLogFilePath, FILE_SHARE_READ | FILE_SHARE_WRITE,
  131. (ITransportCallback *)pCallback);
  132. }
  133. // --------------------------------------------------------------------------------
  134. // CPOP3Transport::HandsOffCallback
  135. // --------------------------------------------------------------------------------
  136. STDMETHODIMP CPOP3Transport::HandsOffCallback(void)
  137. {
  138. return CIxpBase::HandsOffCallback();
  139. }
  140. // --------------------------------------------------------------------------------
  141. // CPOP3Transport::GetStatus
  142. // --------------------------------------------------------------------------------
  143. STDMETHODIMP CPOP3Transport::GetStatus(IXPSTATUS *pCurrentStatus)
  144. {
  145. return CIxpBase::GetStatus(pCurrentStatus);
  146. }
  147. // --------------------------------------------------------------------------------
  148. // CPOP3Transport::InetServerFromAccount
  149. // --------------------------------------------------------------------------------
  150. STDMETHODIMP CPOP3Transport::InetServerFromAccount(IImnAccount *pAccount, LPINETSERVER pInetServer)
  151. {
  152. return CIxpBase::InetServerFromAccount(pAccount, pInetServer);
  153. }
  154. // --------------------------------------------------------------------------------
  155. // CPOP3Transport::Connect
  156. // --------------------------------------------------------------------------------
  157. STDMETHODIMP CPOP3Transport::Connect(LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
  158. {
  159. // Does user want us to always prompt for his password? Prompt him here to avoid
  160. // inactivity timeouts while the prompt is up, unless a password was supplied
  161. if (ISFLAGSET(pInetServer->dwFlags, ISF_ALWAYSPROMPTFORPASSWORD) &&
  162. '\0' == pInetServer->szPassword[0])
  163. {
  164. HRESULT hr;
  165. if (NULL != m_pCallback)
  166. hr = m_pCallback->OnLogonPrompt(pInetServer, POP3THISIXP);
  167. if (NULL == m_pCallback || S_OK != hr)
  168. return IXP_E_USER_CANCEL;
  169. }
  170. return CIxpBase::Connect(pInetServer, fAuthenticate, fCommandLogging);
  171. }
  172. // --------------------------------------------------------------------------------
  173. // CPOP3Transport::DropConnection
  174. // --------------------------------------------------------------------------------
  175. STDMETHODIMP CPOP3Transport::DropConnection(void)
  176. {
  177. return CIxpBase::DropConnection();
  178. }
  179. // --------------------------------------------------------------------------------
  180. // CPOP3Transport::Disconnect
  181. // --------------------------------------------------------------------------------
  182. STDMETHODIMP CPOP3Transport::Disconnect(void)
  183. {
  184. return CIxpBase::Disconnect();
  185. }
  186. // --------------------------------------------------------------------------------
  187. // CPOP3Transport::IsState
  188. // --------------------------------------------------------------------------------
  189. STDMETHODIMP CPOP3Transport::IsState(IXPISSTATE isstate)
  190. {
  191. return CIxpBase::IsState(isstate);
  192. }
  193. // --------------------------------------------------------------------------------
  194. // CPOP3Transport::GetServerInfo
  195. // --------------------------------------------------------------------------------
  196. STDMETHODIMP CPOP3Transport::GetServerInfo(LPINETSERVER pInetServer)
  197. {
  198. return CIxpBase::GetServerInfo(pInetServer);
  199. }
  200. // --------------------------------------------------------------------------------
  201. // CPOP3Transport::GetIXPType
  202. // --------------------------------------------------------------------------------
  203. STDMETHODIMP_(IXPTYPE) CPOP3Transport::GetIXPType(void)
  204. {
  205. return CIxpBase::GetIXPType();
  206. }
  207. // --------------------------------------------------------------------------------
  208. // CPOP3Transport::OnEnterBusy
  209. // --------------------------------------------------------------------------------
  210. void CPOP3Transport::OnEnterBusy(void)
  211. {
  212. IxpAssert(m_command == POP3_NONE);
  213. }
  214. // --------------------------------------------------------------------------------
  215. // CPOP3Transport::OnLeaveBusy
  216. // --------------------------------------------------------------------------------
  217. void CPOP3Transport::OnLeaveBusy(void)
  218. {
  219. m_command = POP3_NONE;
  220. }
  221. // --------------------------------------------------------------------------------
  222. // CPOP3Transport::OnConnected
  223. // --------------------------------------------------------------------------------
  224. void CPOP3Transport::OnConnected(void)
  225. {
  226. m_command = POP3_BANNER;
  227. CIxpBase::OnConnected();
  228. }
  229. // --------------------------------------------------------------------------------
  230. // CPOP3Transport::OnDisconnect
  231. // --------------------------------------------------------------------------------
  232. void CPOP3Transport::OnDisconnected(void)
  233. {
  234. ResetBase();
  235. CIxpBase::OnDisconnected();
  236. }
  237. // --------------------------------------------------------------------------------
  238. // CPOP3Transport::OnNotify
  239. // --------------------------------------------------------------------------------
  240. void CPOP3Transport::OnNotify(ASYNCSTATE asOld, ASYNCSTATE asNew, ASYNCEVENT ae)
  241. {
  242. // Enter Critical Section
  243. EnterCriticalSection(&m_cs);
  244. // Handle Event
  245. switch(ae)
  246. {
  247. // --------------------------------------------------------------------------------
  248. case AE_RECV:
  249. OnSocketReceive();
  250. break;
  251. // --------------------------------------------------------------------------------
  252. default:
  253. CIxpBase::OnNotify(asOld, asNew, ae);
  254. break;
  255. }
  256. // Leave Critical Section
  257. LeaveCriticalSection(&m_cs);
  258. }
  259. // --------------------------------------------------------------------------------
  260. // CPOP3Transport::OnSocketReceive
  261. // --------------------------------------------------------------------------------
  262. void CPOP3Transport::OnSocketReceive(void)
  263. {
  264. // Locals
  265. HRESULT hr;
  266. // Enter Critical Section
  267. EnterCriticalSection(&m_cs);
  268. // Handle Current pop3 state
  269. switch(m_command)
  270. {
  271. // --------------------------------------------------------------------------------
  272. case POP3_BANNER:
  273. // Read Server Response...
  274. hr = HrGetResponse();
  275. if (IXP_E_INCOMPLETE == hr)
  276. goto exit;
  277. // Detect if the banner had the word hotmail in it
  278. Assert(m_pszResponse);
  279. m_fHotmail = (NULL == m_pszResponse || NULL == StrStrIA(m_pszResponse, "hotmail")) ? FALSE : TRUE;
  280. // Dispatch the response
  281. DispatchResponse(hr);
  282. // Authorizing
  283. if (m_fConnectAuth)
  284. StartLogon();
  285. // Ohterwise were connected
  286. else
  287. {
  288. m_command = POP3_CONNECTED;
  289. DispatchResponse(S_OK);
  290. }
  291. // Not yet auth'ed
  292. m_fAuthenticated = FALSE;
  293. break;
  294. // --------------------------------------------------------------------------------
  295. case POP3_USER:
  296. // Read Server Response...
  297. hr = HrGetResponse();
  298. if (IXP_E_INCOMPLETE == hr)
  299. goto exit;
  300. // Dispatch the response
  301. DispatchResponse(FAILED(hr) ? IXP_E_POP3_INVALID_USER_NAME : S_OK);
  302. // Authorizing
  303. if (m_fConnectAuth)
  304. {
  305. // Retry logon
  306. if (FAILED(hr))
  307. LogonRetry(IXP_E_POP3_INVALID_USER_NAME);
  308. // otherwise send the password
  309. else
  310. {
  311. hr = CommandPASS(m_rServer.szPassword);
  312. if (FAILED(hr))
  313. {
  314. OnError(hr);
  315. DropConnection();
  316. }
  317. }
  318. }
  319. break;
  320. // --------------------------------------------------------------------------------
  321. case POP3_PASS:
  322. // Read Server Response...
  323. hr = HrGetResponse();
  324. if (IXP_E_INCOMPLETE == hr)
  325. goto exit;
  326. // Dispatch the response
  327. DispatchResponse(FAILED(hr) ? IXP_E_POP3_INVALID_PASSWORD : S_OK);
  328. // Authorizing
  329. if (m_fConnectAuth)
  330. {
  331. // Retry if failed
  332. if (FAILED(hr))
  333. LogonRetry(IXP_E_POP3_INVALID_PASSWORD);
  334. // Otherwise, we're authorized
  335. else
  336. {
  337. OnStatus(IXP_AUTHORIZED);
  338. m_fConnectAuth = FALSE;
  339. m_command = POP3_CONNECTED;
  340. DispatchResponse(S_OK);
  341. }
  342. }
  343. break;
  344. // --------------------------------------------------------------------------------
  345. case POP3_AUTH:
  346. // If hotmail, then, we've identified ourselves, so lets send the user command
  347. if (m_fHotmail)
  348. {
  349. // Read Server Response...
  350. hr = HrGetResponse();
  351. if (IXP_E_INCOMPLETE == hr)
  352. goto exit;
  353. // Issue the user command
  354. hr = CommandUSER(m_rServer.szUserName);
  355. if (FAILED(hr))
  356. {
  357. OnError(hr);
  358. DropConnection();
  359. }
  360. }
  361. // Otherwise, lets continue DPA auth
  362. else if (m_rInfo.rAuth.authstate != AUTH_ENUMPACKS_DATA)
  363. {
  364. // Read Server Response...
  365. hr = HrGetResponse();
  366. if (IXP_E_INCOMPLETE == hr)
  367. goto exit;
  368. // Authenticating
  369. if (m_fConnectAuth)
  370. {
  371. ResponseAUTH(hr);
  372. }
  373. else
  374. {
  375. // Dispatch the response
  376. DispatchResponse(hr);
  377. }
  378. }
  379. // Otherwise, handle resposne
  380. else
  381. {
  382. // no HrGetResponse() because we are getting list data
  383. ResponseAUTH(0);
  384. }
  385. break;
  386. // --------------------------------------------------------------------------------
  387. case POP3_STAT:
  388. ResponseSTAT();
  389. break;
  390. // --------------------------------------------------------------------------------
  391. case POP3_NOOP:
  392. // Read Server Response...
  393. hr = HrGetResponse();
  394. if (IXP_E_INCOMPLETE == hr)
  395. goto exit;
  396. // Dispatch the response
  397. DispatchResponse(hr, TRUE);
  398. break;
  399. // --------------------------------------------------------------------------------
  400. case POP3_UIDL:
  401. case POP3_LIST:
  402. ResponseGenericList();
  403. break;
  404. // --------------------------------------------------------------------------------
  405. case POP3_DELE:
  406. ResponseDELE();
  407. break;
  408. // --------------------------------------------------------------------------------
  409. case POP3_RETR:
  410. case POP3_TOP:
  411. ResponseGenericRetrieve();
  412. break;
  413. // --------------------------------------------------------------------------------
  414. case POP3_QUIT:
  415. // Read Server Response...
  416. hr = HrGetResponse();
  417. if (IXP_E_INCOMPLETE == hr)
  418. goto exit;
  419. // Dispatch the response
  420. DispatchResponse(hr, FALSE);
  421. // Drop the socket
  422. m_pSocket->Close();
  423. break;
  424. }
  425. exit:
  426. // Done
  427. LeaveCriticalSection(&m_cs);
  428. }
  429. // ------------------------------------------------------------------------------------
  430. // CPOP3Transport::DispatchResponse
  431. // ------------------------------------------------------------------------------------
  432. void CPOP3Transport::DispatchResponse(HRESULT hrResult, BOOL fDone, LPPOP3RESPONSE pResponse)
  433. {
  434. // Locals
  435. POP3RESPONSE rResponse;
  436. // If a response was passed in, use it...
  437. if (pResponse)
  438. CopyMemory(&rResponse, pResponse, sizeof(POP3RESPONSE));
  439. else
  440. ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
  441. // Set the HRESULT
  442. rResponse.command = m_command;
  443. rResponse.rIxpResult.hrResult = hrResult;
  444. rResponse.rIxpResult.pszResponse = m_pszResponse;
  445. rResponse.rIxpResult.uiServerError = m_uiResponse;
  446. rResponse.rIxpResult.hrServerError = m_hrResponse;
  447. rResponse.rIxpResult.dwSocketError = m_pSocket->GetLastError();
  448. rResponse.rIxpResult.pszProblem = NULL;
  449. rResponse.fDone = fDone;
  450. rResponse.pTransport = this;
  451. // If Done...
  452. if (fDone)
  453. {
  454. // No current command
  455. m_command = POP3_NONE;
  456. // Leave Busy State
  457. LeaveBusy();
  458. }
  459. // Give the Response to the client
  460. if (m_pCallback)
  461. ((IPOP3Callback *)m_pCallback)->OnResponse(&rResponse);
  462. // Reset Last Response
  463. SafeMemFree(m_pszResponse);
  464. m_hrResponse = S_OK;
  465. m_uiResponse = 0;
  466. }
  467. // --------------------------------------------------------------------------------
  468. // CPOP3Transport::HrGetResponse
  469. // --------------------------------------------------------------------------------
  470. HRESULT CPOP3Transport::HrGetResponse(void)
  471. {
  472. // Locals
  473. INT cbLine;
  474. BOOL fComplete;
  475. // Clear current response
  476. IxpAssert(m_pszResponse == NULL && m_hrResponse == S_OK);
  477. // Set m_hrResponse
  478. m_hrResponse = S_OK;
  479. // Read Line
  480. m_hrResponse = HrReadLine(&m_pszResponse, &cbLine, &fComplete);
  481. if (FAILED(m_hrResponse))
  482. goto exit;
  483. // If not complete
  484. if (!fComplete)
  485. goto exit;
  486. // - Response
  487. if ('+' != m_pszResponse[0])
  488. {
  489. m_hrResponse = TrapError(IXP_E_POP3_RESPONSE_ERROR);
  490. if (m_pCallback && m_fCommandLogging)
  491. m_pCallback->OnCommand(CMD_RESP, m_pszResponse, m_hrResponse, POP3THISIXP);
  492. goto exit;
  493. }
  494. // Don't log UIDL or LIST response lines...
  495. else if (m_pCallback && m_fCommandLogging)
  496. m_pCallback->OnCommand(CMD_RESP, m_pszResponse, S_OK, POP3THISIXP);
  497. exit:
  498. // Exit
  499. return m_hrResponse;
  500. }
  501. // ------------------------------------------------------------------------------------
  502. // CPOP3Transport::StartLogon
  503. // ------------------------------------------------------------------------------------
  504. void CPOP3Transport::StartLogon(void)
  505. {
  506. // Locals
  507. HRESULT hr;
  508. // Progress
  509. OnStatus(IXP_AUTHORIZING);
  510. // If Not Using Sicily or its not installed, then send USER command
  511. if (FALSE == m_rServer.fTrySicily || FALSE == FIsSicilyInstalled())
  512. {
  513. // If Hotmail, send the AUTH OutlookExpress command
  514. if (m_fHotmail)
  515. {
  516. // Otherwise, send AUTH enumpacks command
  517. hr = CommandAUTH(STR_HOTMAILAUTH);
  518. if (FAILED(hr))
  519. {
  520. OnError(hr);
  521. DropConnection();
  522. }
  523. }
  524. // Otherwise
  525. else
  526. {
  527. // Issue the user command
  528. hr = CommandUSER(m_rServer.szUserName);
  529. if (FAILED(hr))
  530. {
  531. OnError(hr);
  532. DropConnection();
  533. }
  534. }
  535. // Done
  536. return;
  537. }
  538. // Turn Off HOtmail
  539. m_fHotmail = FALSE;
  540. // Otherwise, send AUTH enumpacks command
  541. hr = CommandAUTH((LPSTR)"");
  542. if (FAILED(hr))
  543. {
  544. OnError(hr);
  545. DropConnection();
  546. }
  547. // Otherwise, set the state
  548. m_rInfo.rAuth.authstate = AUTH_ENUMPACKS;
  549. }
  550. // ------------------------------------------------------------------------------------
  551. // CPOP3Transport::LogonRetry
  552. // ------------------------------------------------------------------------------------
  553. void CPOP3Transport::LogonRetry(HRESULT hrLogon)
  554. {
  555. // Locals
  556. HRESULT hr=S_OK;
  557. // Give logon failed status
  558. // OnError(hrLogon);
  559. // Auth Retry
  560. OnStatus(IXP_AUTHRETRY);
  561. // Enter Auth Retry State
  562. m_pSocket->Close();
  563. // Logon
  564. if (NULL == m_pCallback || m_pCallback->OnLogonPrompt(&m_rServer, POP3THISIXP) != S_OK)
  565. {
  566. // Go to terminal state, were done.
  567. OnDisconnected();
  568. return;
  569. }
  570. // Finding Host Progress
  571. OnStatus(IXP_FINDINGHOST);
  572. // Connect to server
  573. hr = m_pSocket->Connect();
  574. if (FAILED(hr))
  575. {
  576. OnError(TrapError(IXP_E_SOCKET_CONNECT_ERROR));
  577. OnDisconnected();
  578. return;
  579. }
  580. // Start WatchDog
  581. m_pSocket->StartWatchDog();
  582. }
  583. // ------------------------------------------------------------------------------------
  584. // CPOP3Transport::ResponseAUTH
  585. // ------------------------------------------------------------------------------------
  586. void CPOP3Transport::ResponseAUTH(HRESULT hrResponse)
  587. {
  588. // Locals
  589. HRESULT hr;
  590. BOOL fPackageInstalled;
  591. SSPIBUFFER Negotiate;
  592. SSPIBUFFER Challenge;
  593. SSPIBUFFER Response;
  594. ULONG i;
  595. // We better be in sicily
  596. Assert(FIsSicilyInstalled());
  597. // If we just started enumerating packages...
  598. if (m_rInfo.rAuth.authstate == AUTH_ENUMPACKS)
  599. {
  600. // Free old tokens
  601. for (i=0; i<m_rInfo.rAuth.cAuthToken; i++)
  602. {
  603. ZeroMemory(m_rInfo.rAuth.rgpszAuthTokens[i], sizeof(m_rInfo.rAuth.rgpszAuthTokens[i][0]) * lstrlen(m_rInfo.rAuth.rgpszAuthTokens[i]));
  604. SafeMemFree(m_rInfo.rAuth.rgpszAuthTokens[i]);
  605. }
  606. m_rInfo.rAuth.iAuthToken = m_rInfo.rAuth.cAuthToken = 0;
  607. if (SUCCEEDED(hrResponse))
  608. {
  609. m_rInfo.rAuth.authstate = AUTH_ENUMPACKS_DATA;
  610. goto EnumData;
  611. }
  612. OnError(IXP_E_SICILY_LOGON_FAILED);
  613. hr = CommandQUIT();
  614. if (FAILED(hr))
  615. DropConnection();
  616. return;
  617. }
  618. else if (m_rInfo.rAuth.authstate == AUTH_ENUMPACKS_DATA)
  619. {
  620. EnumData:
  621. int cbLine;
  622. BOOL fComplete;
  623. // Clear Response
  624. SafeMemFree(m_pszResponse);
  625. m_uiResponse = 0;
  626. m_hrResponse = S_OK;
  627. // Read a blob of lines
  628. while (m_rInfo.rAuth.cAuthToken < MAX_AUTH_TOKENS)
  629. {
  630. // Read the line
  631. hr = HrReadLine(&m_pszResponse, &cbLine, &fComplete);
  632. if (FAILED(hr))
  633. {
  634. OnError(hr);
  635. DropConnection();
  636. }
  637. // If not complete
  638. if (!fComplete)
  639. return;
  640. // Add Detail
  641. if (m_pCallback && m_fCommandLogging)
  642. m_pCallback->OnCommand(CMD_RESP, m_pszResponse, S_OK, POP3THISIXP);
  643. // StripCRLF
  644. StripCRLF(m_pszResponse, (ULONG *)&cbLine);
  645. // If its a dot, were done
  646. if (*m_pszResponse == '.')
  647. break;
  648. m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.cAuthToken++] = m_pszResponse;
  649. }
  650. if (!m_rInfo.rAuth.cAuthToken)
  651. {
  652. OnError(IXP_E_SICILY_LOGON_FAILED);
  653. hr = CommandQUIT();
  654. if (FAILED(hr))
  655. DropConnection();
  656. return;
  657. }
  658. // Free current packages...
  659. if (m_rInfo.rAuth.pPackages && m_rInfo.rAuth.cPackages)
  660. {
  661. SSPIFreePackages(&m_rInfo.rAuth.pPackages, m_rInfo.rAuth.cPackages);
  662. m_rInfo.rAuth.pPackages = NULL;
  663. m_rInfo.rAuth.cPackages = 0;
  664. }
  665. // Get installed security packages
  666. if (FAILED(SSPIGetPackages(&m_rInfo.rAuth.pPackages, &m_rInfo.rAuth.cPackages)))
  667. {
  668. OnError(IXP_E_LOAD_SICILY_FAILED);
  669. hr = CommandQUIT();
  670. if (FAILED(hr))
  671. DropConnection();
  672. return;
  673. }
  674. }
  675. // Otherwise, we must have just tryed a package
  676. else if (m_rInfo.rAuth.authstate == AUTH_TRYING_PACKAGE)
  677. {
  678. // Stop the WatchDog
  679. m_pSocket->StopWatchDog();
  680. // If Success Response
  681. if (SUCCEEDED(hrResponse))
  682. {
  683. // Do Sicily Logon
  684. Assert(m_rInfo.rAuth.iAuthToken < m_rInfo.rAuth.cAuthToken);
  685. if (SUCCEEDED(SSPILogon(&m_rInfo.rAuth.rSicInfo, m_rInfo.rAuth.fRetryPackage, SSPI_BASE64, m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken], &m_rServer, m_pCallback)))
  686. {
  687. if (m_rInfo.rAuth.fRetryPackage)
  688. {
  689. // Don't retry again
  690. m_rInfo.rAuth.fRetryPackage = FALSE;
  691. }
  692. // Get negotiation string
  693. if (SUCCEEDED(SSPIGetNegotiate(&m_rInfo.rAuth.rSicInfo, &Negotiate)))
  694. {
  695. // Send AUTH Respons
  696. if (SUCCEEDED(HrSendSicilyString(Negotiate.szBuffer)))
  697. {
  698. m_rInfo.rAuth.authstate = AUTH_NEGO_RESP;
  699. }
  700. }
  701. else
  702. {
  703. HrCancelAuthInProg();
  704. }
  705. }
  706. else
  707. {
  708. HrCancelAuthInProg();
  709. }
  710. // Start the WatchDog
  711. m_pSocket->StartWatchDog();
  712. // Done
  713. return;
  714. }
  715. // That failed, free sicinfo and go on with life
  716. SSPIFreeContext(&m_rInfo.rAuth.rSicInfo);
  717. // Goto Next Package
  718. m_rInfo.rAuth.iAuthToken++;
  719. }
  720. // Otherwise, we got a response from a negotiation string
  721. else if (m_rInfo.rAuth.authstate == AUTH_NEGO_RESP)
  722. {
  723. // Start the WatchDog
  724. m_pSocket->StopWatchDog();
  725. // Succeeded Response
  726. if (SUCCEEDED(hrResponse))
  727. {
  728. // Set Chal String - skip over "+ "
  729. SSPISetBuffer(m_pszResponse + 2, SSPI_STRING, 0, &Challenge);
  730. // Get response from challenge
  731. if (SUCCEEDED(SSPIResponseFromChallenge(&m_rInfo.rAuth.rSicInfo, &Challenge, &Response)))
  732. {
  733. // Send AUTH Respons
  734. if (SUCCEEDED(HrSendSicilyString(Response.szBuffer)))
  735. {
  736. // if we need to continue, we keep the state the same
  737. // else we transition to the AUTH_RESP_RESP state.
  738. if (!Response.fContinue)
  739. m_rInfo.rAuth.authstate = AUTH_RESP_RESP;
  740. }
  741. }
  742. else
  743. {
  744. HrCancelAuthInProg();
  745. }
  746. }
  747. else
  748. {
  749. // retry current package, with prompt
  750. m_rInfo.rAuth.fRetryPackage = TRUE;
  751. Assert(m_rInfo.rAuth.iAuthToken < m_rInfo.rAuth.cAuthToken);
  752. hr = CommandAUTH(m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken]);
  753. if (FAILED(hr))
  754. {
  755. OnError(hr);
  756. DropConnection();
  757. return;
  758. }
  759. // We are in the TRYING_PACKAGE state
  760. m_rInfo.rAuth.authstate = AUTH_TRYING_PACKAGE;
  761. SSPIFreeContext(&m_rInfo.rAuth.rSicInfo);
  762. }
  763. // Start the WatchDog
  764. m_pSocket->StartWatchDog();
  765. // Done
  766. return;
  767. }
  768. // Otherwise, we got a response from a challenge response string
  769. else if (m_rInfo.rAuth.authstate == AUTH_RESP_RESP)
  770. {
  771. // If that succeeded
  772. if (SUCCEEDED(hrResponse))
  773. {
  774. // We will free the context, but keep the credential handle
  775. SSPIReleaseContext(&m_rInfo.rAuth.rSicInfo);
  776. // Connected (Authorized) state
  777. OnStatus(IXP_AUTHORIZED);
  778. m_fConnectAuth = FALSE;
  779. m_command = POP3_CONNECTED;
  780. DispatchResponse(S_OK);
  781. }
  782. else
  783. {
  784. // retry current package, with prompt
  785. m_rInfo.rAuth.fRetryPackage = TRUE;
  786. Assert(m_rInfo.rAuth.iAuthToken < m_rInfo.rAuth.cAuthToken);
  787. hr = CommandAUTH(m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken]);
  788. if (FAILED(hr))
  789. {
  790. OnError(hr);
  791. DropConnection();
  792. return;
  793. }
  794. // We are in the TRYING_PACKAGE state
  795. m_rInfo.rAuth.authstate = AUTH_TRYING_PACKAGE;
  796. SSPIFreeContext(&m_rInfo.rAuth.rSicInfo);
  797. }
  798. return;
  799. }
  800. else if (m_rInfo.rAuth.authstate == AUTH_CANCELED)
  801. {
  802. SSPIFreeContext(&m_rInfo.rAuth.rSicInfo);
  803. // Goto Next Package
  804. m_rInfo.rAuth.iAuthToken++;
  805. }
  806. // Loop through the auth tokens, and try to authenticate with each one in order
  807. while(m_rInfo.rAuth.iAuthToken < m_rInfo.rAuth.cAuthToken)
  808. {
  809. // We will handle basic authentication
  810. if (lstrcmpi(m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken], "BASIC") != 0)
  811. {
  812. // Package not installed ?
  813. fPackageInstalled=FALSE;
  814. for (i=0; i<m_rInfo.rAuth.cPackages; i++)
  815. {
  816. // Null Package ??
  817. if (!m_rInfo.rAuth.pPackages[i].pszName)
  818. continue;
  819. // Is this the package I am looking for
  820. if (lstrcmpi(m_rInfo.rAuth.pPackages[i].pszName, m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken]) == 0)
  821. {
  822. fPackageInstalled = TRUE;
  823. break;
  824. }
  825. }
  826. // Package not installed ?
  827. if (fPackageInstalled)
  828. {
  829. m_rInfo.rAuth.fRetryPackage = FALSE;
  830. // If the package has a realm, send digest, otherwise, send normal
  831. hr = CommandAUTH(m_rInfo.rAuth.rgpszAuthTokens[m_rInfo.rAuth.iAuthToken]);
  832. if (FAILED(hr))
  833. {
  834. OnError(hr);
  835. DropConnection();
  836. return;
  837. }
  838. // We are in the TRYING_PACKAGE state
  839. m_rInfo.rAuth.authstate = AUTH_TRYING_PACKAGE;
  840. // Done
  841. return;
  842. }
  843. }
  844. // Goto Next Package String
  845. m_rInfo.rAuth.iAuthToken++;
  846. }
  847. // If we make it here, we have exhausted all packages, so it is time
  848. // to report an error and drop the connection
  849. OnError(IXP_E_SICILY_LOGON_FAILED);
  850. hr = CommandQUIT();
  851. if (FAILED(hr))
  852. DropConnection();
  853. }
  854. // ------------------------------------------------------------------------------------
  855. // CPOP3Transport::HrSendSicilyString
  856. // ------------------------------------------------------------------------------------
  857. HRESULT CPOP3Transport::HrSendSicilyString(LPSTR pszData)
  858. {
  859. // Locals
  860. LPSTR pszLine=NULL;
  861. HRESULT hr=S_OK;
  862. // Check Param
  863. Assert(pszData);
  864. // Allocate a line
  865. DWORD cchSize = (lstrlen(pszData) + 5);
  866. pszLine = PszAllocA(cchSize * sizeof(pszLine[0]));
  867. if (NULL == pszLine)
  868. {
  869. hr = TrapError(E_OUTOFMEMORY);
  870. return hr;
  871. }
  872. // Make Line
  873. wnsprintf(pszLine, cchSize, "%s\r\n", pszData);
  874. // Send the lin
  875. hr = HrSendLine(pszLine);
  876. ZeroMemory(pszLine, cchSize * sizeof(pszLine[0]));
  877. SafeMemFree(pszLine);
  878. // Done
  879. return hr;
  880. }
  881. // ------------------------------------------------------------------------------------
  882. // CPOP3Transport::CommandAUTH
  883. // ------------------------------------------------------------------------------------
  884. STDMETHODIMP CPOP3Transport::CommandAUTH(LPSTR pszAuthType)
  885. {
  886. // check params
  887. if (NULL == pszAuthType)
  888. return TrapError(E_INVALIDARG);
  889. // Do the command
  890. HRESULT hr = HrSendCommand((LPSTR)POP3_AUTH_STR, pszAuthType, !m_fConnectAuth);
  891. if (SUCCEEDED(hr))
  892. m_command = POP3_AUTH;
  893. // Done
  894. return hr;
  895. }
  896. // ------------------------------------------------------------------------------------
  897. // CPOP3Transport::HrCancelAuthInProg
  898. // ------------------------------------------------------------------------------------
  899. HRESULT CPOP3Transport::HrCancelAuthInProg()
  900. {
  901. // Locals
  902. HRESULT hr;
  903. // Send *, quit and die if it fails
  904. hr = HrSendCommand((LPSTR)POP3_AUTH_CANCEL_STR, NULL, FALSE);
  905. if (FAILED(hr))
  906. {
  907. OnError(hr);
  908. DropConnection();
  909. }
  910. else
  911. {
  912. // New state
  913. m_command = POP3_AUTH;
  914. m_rInfo.rAuth.authstate = AUTH_CANCELED;
  915. }
  916. return hr;
  917. }
  918. // ------------------------------------------------------------------------------------
  919. // CPOP3Transport::CommandUSER
  920. // ------------------------------------------------------------------------------------
  921. STDMETHODIMP CPOP3Transport::CommandUSER(LPSTR pszUserName)
  922. {
  923. // check params
  924. if (NULL == pszUserName)
  925. return TrapError(E_INVALIDARG);
  926. // Do the command
  927. HRESULT hr = HrSendCommand((LPSTR)POP3_USER_STR, pszUserName);
  928. if (SUCCEEDED(hr))
  929. m_command = POP3_USER;
  930. // Done
  931. return hr;
  932. }
  933. // ------------------------------------------------------------------------------------
  934. // CPOP3Transport::CommandPASS
  935. // ------------------------------------------------------------------------------------
  936. STDMETHODIMP CPOP3Transport::CommandPASS(LPSTR pszPassword)
  937. {
  938. // check params
  939. if (NULL == pszPassword)
  940. return TrapError(E_INVALIDARG);
  941. // Do the command
  942. HRESULT hr = HrSendCommand((LPSTR)POP3_PASS_STR, pszPassword);
  943. if (SUCCEEDED(hr))
  944. m_command = POP3_PASS;
  945. // Done
  946. return hr;
  947. }
  948. // ------------------------------------------------------------------------------------
  949. // CPOP3Transport::CommandSTAT
  950. // ------------------------------------------------------------------------------------
  951. STDMETHODIMP CPOP3Transport::CommandSTAT(void)
  952. {
  953. // Send Command
  954. HRESULT hr = HrSendCommand((LPSTR)POP3_STAT_STR, NULL);
  955. if (SUCCEEDED(hr))
  956. m_command = POP3_STAT;
  957. return hr;
  958. }
  959. // ------------------------------------------------------------------------------------
  960. // CPOP3Transport::DoQuit
  961. // ------------------------------------------------------------------------------------
  962. void CPOP3Transport::DoQuit(void)
  963. {
  964. CommandQUIT();
  965. }
  966. // ------------------------------------------------------------------------------------
  967. // CPOP3Transport::CommandQUIT
  968. // ------------------------------------------------------------------------------------
  969. STDMETHODIMP CPOP3Transport::CommandQUIT(void)
  970. {
  971. // Send Command
  972. OnStatus(IXP_DISCONNECTING);
  973. HRESULT hr = HrSendCommand((LPSTR)POP3_QUIT_STR, NULL);
  974. if (SUCCEEDED(hr))
  975. m_command = POP3_QUIT;
  976. return hr;
  977. }
  978. // ------------------------------------------------------------------------------------
  979. // CPOP3Transport::CommandRSET
  980. // ------------------------------------------------------------------------------------
  981. STDMETHODIMP CPOP3Transport::CommandRSET(void)
  982. {
  983. // Send Command
  984. HRESULT hr = HrSendCommand((LPSTR)POP3_RSET_STR, NULL);
  985. if (SUCCEEDED(hr))
  986. m_command = POP3_RSET;
  987. return hr;
  988. }
  989. // ------------------------------------------------------------------------------------
  990. // CPOP3Transport::CommandNOOP
  991. // ------------------------------------------------------------------------------------
  992. STDMETHODIMP CPOP3Transport::CommandNOOP(void)
  993. {
  994. // Locals
  995. HRESULT hr = S_OK;
  996. SYSTEMTIME stNow;
  997. FILETIME ftNow;
  998. static FILETIME ftNext = { 0, 0 };
  999. LARGE_INTEGER liNext;
  1000. // Thread Safety
  1001. EnterCriticalSection(&m_cs);
  1002. // Checks for need for NOOP
  1003. GetSystemTime (&stNow);
  1004. SystemTimeToFileTime (&stNow, &ftNow);
  1005. if (CompareFileTime (&ftNow, &ftNext) < 0)
  1006. goto exit;
  1007. // Sets the next NOOP time (+60 seconds)
  1008. liNext.HighPart = ftNow.dwHighDateTime;
  1009. liNext.LowPart = ftNow.dwLowDateTime;
  1010. liNext.QuadPart += 600000000i64;
  1011. ftNext.dwHighDateTime = liNext.HighPart;
  1012. ftNext.dwLowDateTime = liNext.LowPart;
  1013. // Send Command
  1014. hr = HrSendCommand((LPSTR)POP3_NOOP_STR, NULL);
  1015. if (SUCCEEDED(hr))
  1016. m_command = POP3_NOOP;
  1017. exit:
  1018. // Thread Safety
  1019. LeaveCriticalSection(&m_cs);
  1020. // Done
  1021. return hr;
  1022. }
  1023. // ------------------------------------------------------------------------------------
  1024. // CPOP3Transport::CommandLIST
  1025. // ------------------------------------------------------------------------------------
  1026. STDMETHODIMP CPOP3Transport::CommandLIST(POP3CMDTYPE cmdtype, DWORD dwPopId)
  1027. {
  1028. // Issue complex command
  1029. return HrComplexCommand(POP3_LIST, cmdtype, dwPopId, 0);
  1030. }
  1031. // ------------------------------------------------------------------------------------
  1032. // CPOP3Transport::CommandTOP
  1033. // ------------------------------------------------------------------------------------
  1034. STDMETHODIMP CPOP3Transport::CommandTOP (POP3CMDTYPE cmdtype, DWORD dwPopId, DWORD cPreviewLines)
  1035. {
  1036. // Issue complex command
  1037. return HrComplexCommand(POP3_TOP, cmdtype, dwPopId, cPreviewLines);
  1038. }
  1039. // ------------------------------------------------------------------------------------
  1040. // CPOP3Transport::CommandUIDL
  1041. // ------------------------------------------------------------------------------------
  1042. STDMETHODIMP CPOP3Transport::CommandUIDL(POP3CMDTYPE cmdtype, DWORD dwPopId)
  1043. {
  1044. // Issue complex command
  1045. return HrComplexCommand(POP3_UIDL, cmdtype, dwPopId, 0);
  1046. }
  1047. // ------------------------------------------------------------------------------------
  1048. // CPOP3Transport::CommandDELE
  1049. // ------------------------------------------------------------------------------------
  1050. STDMETHODIMP CPOP3Transport::CommandDELE(POP3CMDTYPE cmdtype, DWORD dwPopId)
  1051. {
  1052. // Issue complex command
  1053. return HrComplexCommand(POP3_DELE, cmdtype, dwPopId, 0);
  1054. }
  1055. // ------------------------------------------------------------------------------------
  1056. // CPOP3Transport::CommandRETR
  1057. // ------------------------------------------------------------------------------------
  1058. STDMETHODIMP CPOP3Transport::CommandRETR(POP3CMDTYPE cmdtype, DWORD dwPopId)
  1059. {
  1060. // Issue complex command
  1061. return HrComplexCommand(POP3_RETR, cmdtype, dwPopId, 0);
  1062. }
  1063. // ------------------------------------------------------------------------------------
  1064. // CPOP3Transport::MarkItem
  1065. // ------------------------------------------------------------------------------------
  1066. STDMETHODIMP CPOP3Transport::MarkItem(POP3MARKTYPE marktype, DWORD dwPopId, boolean fMarked)
  1067. {
  1068. // Locals
  1069. HRESULT hr=S_OK;
  1070. ULONG i;
  1071. // Thread Safety
  1072. EnterCriticalSection(&m_cs);
  1073. // No stat yet...
  1074. if (FALSE == m_rInfo.fStatDone)
  1075. {
  1076. hr = TrapError(IXP_E_POP3_NEED_STAT);
  1077. goto exit;
  1078. }
  1079. // No Messages...
  1080. if (0 == m_rInfo.cMarked || NULL == m_rInfo.prgMarked)
  1081. {
  1082. hr = TrapError(IXP_E_POP3_NO_MESSAGES);
  1083. goto exit;
  1084. }
  1085. // Bad PopId
  1086. if (0 == dwPopId || dwPopId > m_rInfo.cMarked)
  1087. {
  1088. hr = TrapError(E_INVALIDARG);
  1089. goto exit;
  1090. }
  1091. // Message Index
  1092. i = dwPopId - 1;
  1093. // Handle Mark Type
  1094. switch(marktype)
  1095. {
  1096. // Mark for Top
  1097. case POP3_MARK_FOR_TOP:
  1098. if (fMarked)
  1099. FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_TOP);
  1100. else
  1101. FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_TOP);
  1102. break;
  1103. // Mark for Retrieval
  1104. case POP3_MARK_FOR_RETR:
  1105. if (fMarked)
  1106. FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_RETR);
  1107. else
  1108. FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_RETR);
  1109. break;
  1110. // Mark for Delete
  1111. case POP3_MARK_FOR_DELE:
  1112. if (fMarked)
  1113. FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_DELE);
  1114. else
  1115. FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_DELE);
  1116. break;
  1117. // Mark for UIDL
  1118. case POP3_MARK_FOR_UIDL:
  1119. if (fMarked)
  1120. FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_UIDL);
  1121. else
  1122. FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_UIDL);
  1123. break;
  1124. // Mark for List
  1125. case POP3_MARK_FOR_LIST:
  1126. if (fMarked)
  1127. FLAGSET(m_rInfo.prgMarked[i], POP3_MARK_FOR_LIST);
  1128. else
  1129. FLAGCLEAR(m_rInfo.prgMarked[i], POP3_MARK_FOR_LIST);
  1130. break;
  1131. // E_INVALIDARG
  1132. default:
  1133. hr = TrapError(E_INVALIDARG);
  1134. goto exit;
  1135. }
  1136. exit:
  1137. // Thread Safety
  1138. LeaveCriticalSection(&m_cs);
  1139. // Done
  1140. return hr;
  1141. }
  1142. // ------------------------------------------------------------------------------------
  1143. // CPOP3Transport::HrComplexCommand
  1144. // ------------------------------------------------------------------------------------
  1145. HRESULT CPOP3Transport::HrComplexCommand(POP3COMMAND command, POP3CMDTYPE cmdtype, DWORD dwPopId, ULONG cPreviewLines)
  1146. {
  1147. // Locals
  1148. HRESULT hr=S_OK;
  1149. ULONG cMarked;
  1150. BOOL fDone;
  1151. // Thread Safety
  1152. EnterCriticalSection(&m_cs);
  1153. // go Busy
  1154. CHECKHR(hr = HrEnterBusy());
  1155. // Save top preview lines
  1156. m_rInfo.cPreviewLines = cPreviewLines;
  1157. // Save command type
  1158. m_rInfo.cmdtype = cmdtype;
  1159. // Locals
  1160. switch(cmdtype)
  1161. {
  1162. // Single command
  1163. case POP3CMD_GET_POPID:
  1164. // Bad PopId
  1165. if (0 == dwPopId)
  1166. {
  1167. hr = TrapError(IXP_E_POP3_POPID_OUT_OF_RANGE);
  1168. goto exit;
  1169. }
  1170. // Have we done a stat command
  1171. if (m_rInfo.fStatDone && dwPopId > m_rInfo.cMarked)
  1172. {
  1173. hr = TrapError(IXP_E_POP3_POPID_OUT_OF_RANGE);
  1174. goto exit;
  1175. }
  1176. // Save as Current
  1177. m_rInfo.dwPopIdCurrent = dwPopId;
  1178. // Do the command
  1179. CHECKHR(hr = HrCommandGetPopId(command, dwPopId));
  1180. // Done
  1181. break;
  1182. // Get marked items
  1183. case POP3CMD_GET_MARKED:
  1184. // No stat yet...
  1185. if (FALSE == m_rInfo.fStatDone)
  1186. {
  1187. hr = TrapError(IXP_E_POP3_NEED_STAT);
  1188. goto exit;
  1189. }
  1190. // No Messages...
  1191. if (0 == m_rInfo.cMarked || NULL == m_rInfo.prgMarked)
  1192. {
  1193. hr = TrapError(IXP_E_POP3_NO_MESSAGES);
  1194. goto exit;
  1195. }
  1196. // Are there any messages mared for this command...
  1197. cMarked = CountMarked(command);
  1198. if (0 == cMarked)
  1199. {
  1200. hr = TrapError(IXP_E_POP3_NO_MARKED_MESSAGES);
  1201. goto exit;
  1202. }
  1203. // Init Marked State
  1204. m_rInfo.dwPopIdCurrent = 0;
  1205. // Do next marked...
  1206. CHECKHR(hr = HrCommandGetNext(command, &fDone));
  1207. IxpAssert(fDone == FALSE);
  1208. // Done
  1209. break;
  1210. // Multiple commands or a list operation
  1211. case POP3CMD_GET_ALL:
  1212. // Do the command
  1213. CHECKHR(hr = HrCommandGetAll(command));
  1214. // done
  1215. break;
  1216. // E_INVALIDARG
  1217. default:
  1218. hr = TrapError(E_INVALIDARG);
  1219. goto exit;
  1220. }
  1221. exit:
  1222. // Failure
  1223. if (FAILED(hr))
  1224. LeaveBusy();
  1225. // Thread Safety
  1226. LeaveCriticalSection(&m_cs);
  1227. // Done
  1228. return hr;
  1229. }
  1230. // ------------------------------------------------------------------------------------
  1231. // CPOP3Transport::HrCommandGetPopId
  1232. // ------------------------------------------------------------------------------------
  1233. HRESULT CPOP3Transport::HrCommandGetPopId(POP3COMMAND command, DWORD dwPopId)
  1234. {
  1235. // Locals
  1236. HRESULT hr=S_OK;
  1237. CHAR szPopId[30];
  1238. // Handle command type
  1239. IxpAssert(dwPopId == m_rInfo.dwPopIdCurrent);
  1240. switch(command)
  1241. {
  1242. case POP3_DELE:
  1243. wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d", dwPopId);
  1244. CHECKHR(hr = HrSendCommand((LPSTR)POP3_DELE_STR, szPopId, FALSE));
  1245. m_command = POP3_DELE;
  1246. break;
  1247. case POP3_RETR:
  1248. ZeroMemory(&m_rInfo.rFetch, sizeof(FETCHINFO));
  1249. wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d", dwPopId);
  1250. CHECKHR(hr = HrSendCommand((LPSTR)POP3_RETR_STR, szPopId, FALSE));
  1251. m_command = POP3_RETR;
  1252. break;
  1253. case POP3_TOP:
  1254. ZeroMemory(&m_rInfo.rFetch, sizeof(FETCHINFO));
  1255. wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d %d", dwPopId, m_rInfo.cPreviewLines);
  1256. CHECKHR(hr = HrSendCommand((LPSTR)POP3_TOP_STR, szPopId, FALSE));
  1257. m_command = POP3_TOP;
  1258. break;
  1259. case POP3_LIST:
  1260. m_rInfo.cList = 0;
  1261. wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d", dwPopId);
  1262. CHECKHR(hr = HrSendCommand((LPSTR)POP3_LIST_STR, szPopId, FALSE));
  1263. m_command = POP3_LIST;
  1264. break;
  1265. case POP3_UIDL:
  1266. m_rInfo.cList = 0;
  1267. wnsprintf(szPopId, ARRAYSIZE(szPopId), "%d", dwPopId);
  1268. CHECKHR(hr = HrSendCommand((LPSTR)POP3_UIDL_STR, szPopId, FALSE));
  1269. m_command = POP3_UIDL;
  1270. break;
  1271. default:
  1272. hr = TrapError(E_INVALIDARG);
  1273. goto exit;
  1274. }
  1275. exit:
  1276. // Done
  1277. return hr;
  1278. }
  1279. // ------------------------------------------------------------------------------------
  1280. // CPOP3Transport::DwGetCommandMarkedFlag
  1281. // ------------------------------------------------------------------------------------
  1282. DWORD CPOP3Transport::DwGetCommandMarkedFlag(POP3COMMAND command)
  1283. {
  1284. DWORD dw;
  1285. switch(command)
  1286. {
  1287. case POP3_LIST:
  1288. dw = POP3_MARK_FOR_LIST;
  1289. break;
  1290. case POP3_DELE:
  1291. dw = POP3_MARK_FOR_DELE;
  1292. break;
  1293. case POP3_RETR:
  1294. dw = POP3_MARK_FOR_RETR;
  1295. break;
  1296. case POP3_TOP:
  1297. dw = POP3_MARK_FOR_TOP;
  1298. break;
  1299. case POP3_UIDL:
  1300. dw = POP3_MARK_FOR_UIDL;
  1301. break;
  1302. default:
  1303. IxpAssert(FALSE);
  1304. dw = 0;
  1305. break;
  1306. }
  1307. return dw;
  1308. }
  1309. // ------------------------------------------------------------------------------------
  1310. // CPOP3Transport::CountMarked
  1311. // ------------------------------------------------------------------------------------
  1312. ULONG CPOP3Transport::CountMarked(POP3COMMAND command)
  1313. {
  1314. // Locals
  1315. DWORD dw = 0;
  1316. ULONG c=0,
  1317. i;
  1318. // Check some stuff
  1319. IxpAssert(m_rInfo.cMarked && m_rInfo.prgMarked);
  1320. // Handle Command type
  1321. dw = DwGetCommandMarkedFlag(command);
  1322. if (0 == dw)
  1323. return 0;
  1324. // Count
  1325. for (i=0; i<m_rInfo.cMarked; i++)
  1326. if (dw & m_rInfo.prgMarked[i])
  1327. c++;
  1328. // Done
  1329. return c;
  1330. }
  1331. // ------------------------------------------------------------------------------------
  1332. // CPOP3Transport::HrCommandGetNext
  1333. // ------------------------------------------------------------------------------------
  1334. HRESULT CPOP3Transport::HrCommandGetNext(POP3COMMAND command, BOOL *pfDone)
  1335. {
  1336. // Locals
  1337. HRESULT hr=S_OK;
  1338. CHAR szPopId[30];
  1339. DWORD dw;
  1340. ULONG i;
  1341. // check params
  1342. IxpAssert(pfDone && m_rInfo.dwPopIdCurrent <= m_rInfo.cMarked);
  1343. // Init - Assume were done
  1344. *pfDone = TRUE;
  1345. // Doing all
  1346. if (POP3CMD_GET_ALL == m_rInfo.cmdtype)
  1347. {
  1348. // Done
  1349. IxpAssert(m_rInfo.fStatDone == TRUE);
  1350. if (m_rInfo.dwPopIdCurrent == m_rInfo.cMarked)
  1351. goto exit;
  1352. // Next Message..
  1353. m_rInfo.dwPopIdCurrent++;
  1354. *pfDone = FALSE;
  1355. CHECKHR(hr = HrCommandGetPopId(command, m_rInfo.dwPopIdCurrent));
  1356. }
  1357. // Doing Marked
  1358. else
  1359. {
  1360. // Check Parms
  1361. IxpAssert(POP3CMD_GET_MARKED == m_rInfo.cmdtype);
  1362. // Get marked flag
  1363. dw = DwGetCommandMarkedFlag(command);
  1364. if (0 == dw)
  1365. {
  1366. hr = TrapError(E_INVALIDARG);
  1367. goto exit;
  1368. }
  1369. // Step Over Last Marked Item
  1370. m_rInfo.dwPopIdCurrent++;
  1371. // Start comparing at iCurrent
  1372. for (i=m_rInfo.dwPopIdCurrent-1; i<m_rInfo.cMarked; i++)
  1373. {
  1374. // Is this item marked...
  1375. if (dw & m_rInfo.prgMarked[i])
  1376. {
  1377. // Send Command
  1378. m_rInfo.dwPopIdCurrent = i + 1;
  1379. *pfDone = FALSE;
  1380. CHECKHR(hr = HrCommandGetPopId(command, m_rInfo.dwPopIdCurrent));
  1381. break;
  1382. }
  1383. }
  1384. }
  1385. exit:
  1386. // Done
  1387. return hr;
  1388. }
  1389. // ------------------------------------------------------------------------------------
  1390. // CPOP3Transport::HrCommandGetAll
  1391. // ------------------------------------------------------------------------------------
  1392. HRESULT CPOP3Transport::HrCommandGetAll(POP3COMMAND command)
  1393. {
  1394. // Locals
  1395. HRESULT hr=S_OK;
  1396. CHAR szPopId[30];
  1397. BOOL fDone;
  1398. // Init current
  1399. m_rInfo.dwPopIdCurrent = 0;
  1400. // POP3_LIST
  1401. if (POP3_LIST == command)
  1402. {
  1403. m_rInfo.cList = 0;
  1404. CHECKHR(hr = HrSendCommand((LPSTR)POP3_LIST_ALL_STR, NULL, FALSE));
  1405. m_command = POP3_LIST;
  1406. }
  1407. // POP3_UIDL
  1408. else if (POP3_UIDL == command)
  1409. {
  1410. m_rInfo.cList = 0;
  1411. CHECKHR(hr = HrSendCommand((LPSTR)POP3_UIDL_ALL_STR, NULL, FALSE));
  1412. m_command = POP3_UIDL;
  1413. }
  1414. // Otherwise, we better have done the stat command
  1415. else
  1416. {
  1417. // No stat yet...
  1418. if (FALSE == m_rInfo.fStatDone)
  1419. {
  1420. hr = TrapError(IXP_E_POP3_NEED_STAT);
  1421. goto exit;
  1422. }
  1423. // No Messages...
  1424. if (0 == m_rInfo.cMarked || NULL == m_rInfo.prgMarked)
  1425. {
  1426. hr = TrapError(IXP_E_POP3_NO_MESSAGES);
  1427. goto exit;
  1428. }
  1429. // Next Command
  1430. CHECKHR(hr = HrCommandGetNext(command, &fDone));
  1431. IxpAssert(fDone == FALSE);
  1432. }
  1433. exit:
  1434. // Done
  1435. return hr;
  1436. }
  1437. // ------------------------------------------------------------------------------------
  1438. // CPOP3Transport::ResponseSTAT
  1439. // ------------------------------------------------------------------------------------
  1440. void CPOP3Transport::ResponseSTAT(void)
  1441. {
  1442. // Locals
  1443. HRESULT hr=S_OK;
  1444. DWORD cMessages=0,
  1445. cbMessages=0;
  1446. LPSTR pszPart1=NULL,
  1447. pszPart2=NULL;
  1448. POP3RESPONSE rResponse;
  1449. // Read Server Response...
  1450. hr = HrGetResponse();
  1451. if (IXP_E_INCOMPLETE == hr)
  1452. return;
  1453. // Init Response
  1454. ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
  1455. // Parse the response
  1456. CHECKHR(hr = HrSplitPop3Response(m_pszResponse, &pszPart1, &pszPart2));
  1457. // Convert
  1458. IxpAssert(pszPart1 && pszPart2);
  1459. cMessages = StrToInt(pszPart1);
  1460. cbMessages = StrToInt(pszPart2);
  1461. // Are there messages
  1462. if (FALSE == m_rInfo.fStatDone && cMessages > 0)
  1463. {
  1464. // Set Number of messages
  1465. IxpAssert(m_rInfo.prgMarked == NULL);
  1466. m_rInfo.cMarked = cMessages;
  1467. // Allocate message array
  1468. CHECKHR(hr = HrAlloc((LPVOID *)&m_rInfo.prgMarked, sizeof(DWORD) * m_rInfo.cMarked));
  1469. // Zero
  1470. ZeroMemory(m_rInfo.prgMarked, sizeof(DWORD) * m_rInfo.cMarked);
  1471. }
  1472. // Success
  1473. m_rInfo.fStatDone = TRUE;
  1474. exit:
  1475. // Cleanup
  1476. SafeMemFree(pszPart1);
  1477. SafeMemFree(pszPart2);
  1478. // Build Response
  1479. rResponse.fValidInfo = TRUE;
  1480. rResponse.rStatInfo.cMessages = cMessages;
  1481. rResponse.rStatInfo.cbMessages = cbMessages;
  1482. DispatchResponse(hr, TRUE, &rResponse);
  1483. // Done
  1484. return;
  1485. }
  1486. // ------------------------------------------------------------------------------------
  1487. // CPOP3Transport::HrSplitPop3Response
  1488. // ------------------------------------------------------------------------------------
  1489. HRESULT CPOP3Transport::HrSplitPop3Response(LPSTR pszLine, LPSTR *ppszPart1, LPSTR *ppszPart2)
  1490. {
  1491. // Locals
  1492. LPSTR psz,
  1493. pszStart;
  1494. CHAR ch;
  1495. HRESULT hr=IXP_E_POP3_PARSE_FAILURE;
  1496. // No Response...
  1497. IxpAssert(pszLine && pszLine[0] != '-' && ppszPart1 && ppszPart2);
  1498. if (NULL == pszLine)
  1499. goto exit;
  1500. // Parse: '+OK' 432 1234
  1501. psz = PszSkipWhiteA(pszLine);
  1502. if ('\0' == *psz)
  1503. goto exit;
  1504. // Parse response token
  1505. pszStart = psz;
  1506. if ('+' == *pszLine)
  1507. {
  1508. // Parse: '+OK' 432 1234
  1509. psz = PszScanToWhiteA(psz);
  1510. if ('\0' == *psz)
  1511. goto exit;
  1512. #ifdef DEBUG
  1513. IxpAssert(' ' == *psz);
  1514. *psz = '\0';
  1515. IxpAssert(lstrcmpi(pszStart, "+OK") == 0);
  1516. *psz = ' ';
  1517. #endif
  1518. // Parse: +OK '432' 1234
  1519. psz = PszSkipWhiteA(psz);
  1520. if ('\0' == *psz)
  1521. goto exit;
  1522. }
  1523. // Parse: +OK '432' 1234
  1524. pszStart = psz;
  1525. psz = PszScanToWhiteA(psz);
  1526. if ('\0' == *psz)
  1527. goto exit;
  1528. // Get Message Count
  1529. *psz = '\0';
  1530. *ppszPart1 = PszDupA(pszStart);
  1531. *psz = ' ';
  1532. // Parse: +OK 432 '1234'
  1533. psz = PszSkipWhiteA(psz);
  1534. if ('\0' == *psz)
  1535. {
  1536. // Raid 28435 - Outlook needs INETCOMM to accept empty UIDL responses
  1537. *ppszPart2 = PszDupA(c_szEmpty);
  1538. hr = S_OK;
  1539. goto exit;
  1540. }
  1541. // Parse: +OK 432 1234
  1542. pszStart = psz;
  1543. psz = PszScanToWhiteA(psz);
  1544. // Get Message Count
  1545. ch = *psz;
  1546. *psz = '\0';
  1547. *ppszPart2 = PszDupA(pszStart);
  1548. *psz = ch;
  1549. // Success
  1550. hr = S_OK;
  1551. exit:
  1552. // Done
  1553. return hr;
  1554. }
  1555. // ------------------------------------------------------------------------------------
  1556. // CPOP3Transport::ResponseGenericList
  1557. // ------------------------------------------------------------------------------------
  1558. void CPOP3Transport::ResponseGenericList(void)
  1559. {
  1560. // Locals
  1561. HRESULT hr;
  1562. INT cbLine;
  1563. BOOL fDone,
  1564. fComplete;
  1565. LPSTR pszPart1=NULL,
  1566. pszPart2=NULL;
  1567. POP3RESPONSE rResponse;
  1568. // Same response as single LIST x command, but then get next
  1569. if (POP3CMD_GET_MARKED == m_rInfo.cmdtype || POP3CMD_GET_POPID == m_rInfo.cmdtype)
  1570. {
  1571. // Read Server Response...
  1572. hr = HrGetResponse();
  1573. if (IXP_E_INCOMPLETE == hr)
  1574. goto exit;
  1575. // Otherwise, if failure...
  1576. else if (FAILED(hr))
  1577. {
  1578. DispatchResponse(hr, TRUE);
  1579. goto exit;
  1580. }
  1581. // Get the two parts from the line
  1582. hr = HrSplitPop3Response(m_pszResponse, &pszPart1, &pszPart2);
  1583. if (FAILED(hr))
  1584. {
  1585. DispatchResponse(hr, TRUE);
  1586. goto exit;
  1587. }
  1588. // Init Response
  1589. ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
  1590. // POP3_LIST
  1591. if (POP3_LIST == m_command)
  1592. {
  1593. rResponse.fValidInfo = TRUE;
  1594. rResponse.rListInfo.dwPopId = StrToInt(pszPart1);
  1595. rResponse.rListInfo.cbSize = StrToInt(pszPart2);
  1596. IxpAssert(rResponse.rListInfo.dwPopId == m_rInfo.dwPopIdCurrent);
  1597. }
  1598. // POP3_UIDL
  1599. else
  1600. {
  1601. rResponse.fValidInfo = TRUE;
  1602. rResponse.rUidlInfo.dwPopId = StrToInt(pszPart1);
  1603. rResponse.rUidlInfo.pszUidl = pszPart2;
  1604. IxpAssert(rResponse.rUidlInfo.dwPopId == m_rInfo.dwPopIdCurrent);
  1605. }
  1606. // Do Next
  1607. if (POP3CMD_GET_MARKED == m_rInfo.cmdtype)
  1608. {
  1609. // Give the response
  1610. DispatchResponse(S_OK, FALSE, &rResponse);
  1611. // Do the next marked list item
  1612. hr = HrCommandGetNext(m_command, &fDone);
  1613. if (FAILED(hr))
  1614. {
  1615. DispatchResponse(hr, TRUE);
  1616. goto exit;
  1617. }
  1618. // Done Response
  1619. if (fDone)
  1620. DispatchResponse(S_OK, TRUE);
  1621. }
  1622. // Dispatch Done or single item response
  1623. else
  1624. DispatchResponse(S_OK, TRUE, &rResponse);
  1625. }
  1626. // Full LIST response
  1627. else if (POP3CMD_GET_ALL == m_rInfo.cmdtype)
  1628. {
  1629. // First call...
  1630. if (m_rInfo.dwPopIdCurrent == 0)
  1631. {
  1632. // Read Server Response...
  1633. hr = HrGetResponse();
  1634. if (IXP_E_INCOMPLETE == hr)
  1635. goto exit;
  1636. // Otherwise, if failure...
  1637. else if (FAILED(hr))
  1638. {
  1639. DispatchResponse(hr, TRUE);
  1640. goto exit;
  1641. }
  1642. // Current
  1643. m_rInfo.dwPopIdCurrent = 1;
  1644. }
  1645. // Clear Response
  1646. SafeMemFree(m_pszResponse);
  1647. m_uiResponse = 0;
  1648. m_hrResponse = S_OK;
  1649. // Read a blob of lines
  1650. while(1)
  1651. {
  1652. // Read Line
  1653. hr = HrReadLine(&m_pszResponse, &cbLine, &fComplete);
  1654. if (FAILED(hr))
  1655. {
  1656. DispatchResponse(hr, TRUE);
  1657. goto exit;
  1658. }
  1659. // If not complete
  1660. if (!fComplete)
  1661. goto exit;
  1662. // Add Detail
  1663. if (m_pCallback && m_fCommandLogging)
  1664. m_pCallback->OnCommand(CMD_RESP, m_pszResponse, S_OK, POP3THISIXP);
  1665. // If its a dot, were done
  1666. if (*m_pszResponse == '.')
  1667. {
  1668. // If we haven't done a stat yet, we can use these totals...
  1669. IxpAssert(m_rInfo.fStatDone ? m_rInfo.cList == m_rInfo.cMarked : TRUE);
  1670. if (FALSE == m_rInfo.fStatDone && m_rInfo.cList > 0)
  1671. {
  1672. // Have I build my internal array of messages yet...
  1673. IxpAssert(m_rInfo.prgMarked == NULL);
  1674. m_rInfo.cMarked = m_rInfo.cList;
  1675. // Allocate message array
  1676. CHECKHR(hr = HrAlloc((LPVOID *)&m_rInfo.prgMarked, sizeof(DWORD) * m_rInfo.cMarked));
  1677. // Zero
  1678. ZeroMemory(m_rInfo.prgMarked, sizeof(DWORD) * m_rInfo.cMarked);
  1679. }
  1680. // Were Done
  1681. DispatchResponse(S_OK, TRUE);
  1682. // Stat Done
  1683. m_rInfo.fStatDone = TRUE;
  1684. // Done
  1685. break;
  1686. }
  1687. // Get the two parts from the line
  1688. hr = HrSplitPop3Response(m_pszResponse, &pszPart1, &pszPart2);
  1689. if (FAILED(hr))
  1690. {
  1691. DispatchResponse(hr, TRUE);
  1692. goto exit;
  1693. }
  1694. // Init Response
  1695. ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
  1696. // POP3_LIST
  1697. if (POP3_LIST == m_command)
  1698. {
  1699. rResponse.fValidInfo = TRUE;
  1700. rResponse.rListInfo.dwPopId = StrToInt(pszPart1);
  1701. rResponse.rListInfo.cbSize = StrToInt(pszPart2);
  1702. }
  1703. // POP3_UIDL
  1704. else
  1705. {
  1706. rResponse.fValidInfo = TRUE;
  1707. rResponse.rUidlInfo.dwPopId = StrToInt(pszPart1);
  1708. rResponse.rUidlInfo.pszUidl = pszPart2;
  1709. IxpAssert(rResponse.rUidlInfo.dwPopId == m_rInfo.dwPopIdCurrent);
  1710. }
  1711. // Count the number of messages
  1712. m_rInfo.cList++;
  1713. // Dispatch the response
  1714. DispatchResponse(S_OK, FALSE, &rResponse);
  1715. m_rInfo.dwPopIdCurrent++;
  1716. // Cleanup
  1717. SafeMemFree(pszPart1);
  1718. SafeMemFree(pszPart2);
  1719. // Clear Response
  1720. SafeMemFree(m_pszResponse);
  1721. m_uiResponse = 0;
  1722. m_hrResponse = S_OK;
  1723. }
  1724. }
  1725. // Otherwise failure...
  1726. else
  1727. {
  1728. IxpAssert(FALSE);
  1729. goto exit;
  1730. }
  1731. exit:
  1732. // Cleanup
  1733. SafeMemFree(pszPart1);
  1734. SafeMemFree(pszPart2);
  1735. // Done
  1736. return;
  1737. }
  1738. // ------------------------------------------------------------------------------------
  1739. // CPOP3Transport::FEndRetrRecvHeader
  1740. // ------------------------------------------------------------------------------------
  1741. BOOL CPOP3Transport::FEndRetrRecvHeader(LPSTR pszLines, ULONG cbRead)
  1742. {
  1743. // If we see CRLFCRLF
  1744. if (StrStr(pszLines, "\r\n\r\n"))
  1745. return TRUE;
  1746. // Otherwise, did last block end with a CRLF and this block begins with a crlf
  1747. else if (cbRead >= 2 &&
  1748. m_rInfo.rFetch.fLastLineCRLF &&
  1749. pszLines[0] == '\r' &&
  1750. pszLines[1] == '\n')
  1751. return TRUE;
  1752. // Header is not done
  1753. return FALSE;
  1754. }
  1755. // ------------------------------------------------------------------------------------
  1756. // CPOP3Transport::ResponseGenericRetrieve
  1757. // ------------------------------------------------------------------------------------
  1758. void CPOP3Transport::ResponseGenericRetrieve(void)
  1759. {
  1760. // Locals
  1761. HRESULT hr=S_OK;
  1762. LPSTR pszLines=NULL;
  1763. INT cbRead,
  1764. cLines;
  1765. ULONG cbSubtract;
  1766. BOOL fDone,
  1767. fMessageDone;
  1768. POP3RESPONSE rResponse;
  1769. // First call...
  1770. if (FALSE == m_rInfo.rFetch.fGotResponse)
  1771. {
  1772. // Read Server Response...
  1773. hr = HrGetResponse();
  1774. if (IXP_E_INCOMPLETE == hr)
  1775. goto exit;
  1776. // Otherwise, if failure...
  1777. else if (FAILED(hr))
  1778. {
  1779. FillRetrieveResponse(&rResponse, NULL, 0, &fMessageDone);
  1780. DispatchResponse(hr, TRUE, &rResponse);
  1781. goto exit;
  1782. }
  1783. // Current
  1784. m_rInfo.rFetch.fGotResponse = TRUE;
  1785. }
  1786. // While there are lines to read...
  1787. hr = m_pSocket->ReadLines(&pszLines, &cbRead, &cLines);
  1788. // Incomplete data available...
  1789. if (IXP_E_INCOMPLETE == hr)
  1790. goto exit;
  1791. // Or if we failed...
  1792. else if (FAILED(hr))
  1793. {
  1794. FillRetrieveResponse(&rResponse, NULL, 0, &fMessageDone);
  1795. DispatchResponse(hr, TRUE, &rResponse);
  1796. goto exit;
  1797. }
  1798. // Are we receiving the header...
  1799. if (FALSE == m_rInfo.rFetch.fHeader)
  1800. {
  1801. // Test for end of header found
  1802. if (FEndRetrRecvHeader(pszLines, cbRead))
  1803. m_rInfo.rFetch.fHeader = TRUE;
  1804. // $$BUG$$ Our good buddies on Exchange produced the following message:
  1805. //
  1806. // To: XXXXXXXXXXXXXXXXXXX
  1807. // From: XXXXXXXXXXXXXXXXX
  1808. // Subject: XXXXXXXXXXXXXX
  1809. // .
  1810. //
  1811. // As you can see there is not CRLFCRLF following the last header line which is very
  1812. // illegal. This message caused us to hange because we never saw the end of the header.
  1813. // So this is why I also test for the end of the body...
  1814. else if (FEndRetrRecvBody(pszLines, cbRead, &cbSubtract))
  1815. {
  1816. cbRead -= cbSubtract;
  1817. m_rInfo.rFetch.fHeader = TRUE;
  1818. m_rInfo.rFetch.fBody = TRUE;
  1819. }
  1820. // Otherwise, did this block end with a crlf
  1821. else if (cbRead >= 2 && pszLines[cbRead - 1] == '\n' && pszLines[cbRead - 2] == '\r')
  1822. m_rInfo.rFetch.fLastLineCRLF = TRUE;
  1823. else
  1824. m_rInfo.rFetch.fLastLineCRLF = FALSE;
  1825. }
  1826. // Also check to see if body was received in same set of lines
  1827. if (TRUE == m_rInfo.rFetch.fHeader)
  1828. {
  1829. // Test for end of header found
  1830. if (FEndRetrRecvBody(pszLines, cbRead, &cbSubtract))
  1831. {
  1832. cbRead -= cbSubtract;
  1833. m_rInfo.rFetch.fBody = TRUE;
  1834. }
  1835. // Otherwise, check for line ending with crlf
  1836. else if (cbRead >= 2 && pszLines[cbRead - 1] == '\n' && pszLines[cbRead - 2] == '\r')
  1837. m_rInfo.rFetch.fLastLineCRLF = TRUE;
  1838. else
  1839. m_rInfo.rFetch.fLastLineCRLF = FALSE;
  1840. }
  1841. // Count bytes downloaded on this fetch
  1842. m_rInfo.rFetch.cbSoFar += cbRead;
  1843. // UnStuff
  1844. UnStuffDotsFromLines(pszLines, &cbRead);
  1845. // Fill the response
  1846. FillRetrieveResponse(&rResponse, pszLines, cbRead, &fMessageDone);
  1847. // Dispatch This Resposne...
  1848. if (POP3CMD_GET_POPID == m_rInfo.cmdtype)
  1849. DispatchResponse(S_OK, fMessageDone, &rResponse);
  1850. // Otherwise
  1851. else
  1852. {
  1853. // Check command type
  1854. IxpAssert(POP3CMD_GET_MARKED == m_rInfo.cmdtype || POP3CMD_GET_ALL == m_rInfo.cmdtype);
  1855. // Dispatch current response
  1856. DispatchResponse(S_OK, FALSE, &rResponse);
  1857. // If done with current message...
  1858. if (fMessageDone)
  1859. {
  1860. // Get Next
  1861. hr = HrCommandGetNext(m_command, &fDone);
  1862. if (FAILED(hr))
  1863. {
  1864. DispatchResponse(hr, TRUE);
  1865. goto exit;
  1866. }
  1867. // If Done
  1868. if (fDone)
  1869. DispatchResponse(S_OK, TRUE);
  1870. }
  1871. }
  1872. exit:
  1873. // Cleanup
  1874. SafeMemFree(pszLines);
  1875. // Done
  1876. return;
  1877. }
  1878. // ------------------------------------------------------------------------------------
  1879. // CPOP3Transport::FillRetrieveResponse
  1880. // ------------------------------------------------------------------------------------
  1881. void CPOP3Transport::FillRetrieveResponse(LPPOP3RESPONSE pResponse, LPSTR pszLines, ULONG cbRead,
  1882. BOOL *pfMessageDone)
  1883. {
  1884. // Clear Response
  1885. ZeroMemory(pResponse, sizeof(POP3RESPONSE));
  1886. // POP3_TOP
  1887. if (POP3_TOP == m_command)
  1888. {
  1889. // Build Response
  1890. pResponse->fValidInfo = TRUE;
  1891. pResponse->rTopInfo.dwPopId = m_rInfo.dwPopIdCurrent;
  1892. pResponse->rTopInfo.cPreviewLines = m_rInfo.cPreviewLines;
  1893. pResponse->rTopInfo.cbSoFar = m_rInfo.rFetch.cbSoFar;
  1894. pResponse->rTopInfo.pszLines = pszLines;
  1895. pResponse->rTopInfo.cbLines = cbRead;
  1896. pResponse->rTopInfo.fHeader = m_rInfo.rFetch.fHeader;
  1897. pResponse->rTopInfo.fBody = m_rInfo.rFetch.fBody;
  1898. *pfMessageDone = (m_rInfo.rFetch.fHeader && m_rInfo.rFetch.fBody);
  1899. }
  1900. // POP3_RETR
  1901. else
  1902. {
  1903. IxpAssert(POP3_RETR == m_command);
  1904. pResponse->fValidInfo = TRUE;
  1905. pResponse->rRetrInfo.fHeader = m_rInfo.rFetch.fHeader;
  1906. pResponse->rRetrInfo.fBody = m_rInfo.rFetch.fBody;
  1907. pResponse->rRetrInfo.dwPopId = m_rInfo.dwPopIdCurrent;
  1908. pResponse->rRetrInfo.cbSoFar = m_rInfo.rFetch.cbSoFar;
  1909. pResponse->rRetrInfo.pszLines = pszLines;
  1910. pResponse->rRetrInfo.cbLines = cbRead;
  1911. *pfMessageDone = (m_rInfo.rFetch.fHeader && m_rInfo.rFetch.fBody);
  1912. }
  1913. }
  1914. // ------------------------------------------------------------------------------------
  1915. // CPOP3Transport::ResponseDELE
  1916. // ------------------------------------------------------------------------------------
  1917. void CPOP3Transport::ResponseDELE(void)
  1918. {
  1919. // Locals
  1920. HRESULT hr=S_OK;
  1921. BOOL fDone;
  1922. POP3RESPONSE rResponse;
  1923. // Read Server Response...
  1924. hr = HrGetResponse();
  1925. if (IXP_E_INCOMPLETE == hr)
  1926. goto exit;
  1927. // Otherwise, if failure...
  1928. else if (FAILED(hr))
  1929. {
  1930. DispatchResponse(hr, TRUE);
  1931. goto exit;
  1932. }
  1933. // Clear Response
  1934. ZeroMemory(&rResponse, sizeof(POP3RESPONSE));
  1935. rResponse.fValidInfo = TRUE;
  1936. rResponse.dwPopId = m_rInfo.dwPopIdCurrent;
  1937. // Dispatch This Resposne...
  1938. if (POP3CMD_GET_POPID == m_rInfo.cmdtype)
  1939. DispatchResponse(S_OK, TRUE, &rResponse);
  1940. // Otherwise
  1941. else
  1942. {
  1943. // Check command type
  1944. IxpAssert(POP3CMD_GET_MARKED == m_rInfo.cmdtype || POP3CMD_GET_ALL == m_rInfo.cmdtype);
  1945. // Dispatch current response
  1946. DispatchResponse(S_OK, FALSE, &rResponse);
  1947. // Get Next
  1948. hr = HrCommandGetNext(m_command, &fDone);
  1949. if (FAILED(hr))
  1950. {
  1951. DispatchResponse(hr, TRUE);
  1952. goto exit;
  1953. }
  1954. // If Done
  1955. if (fDone)
  1956. DispatchResponse(S_OK, TRUE);
  1957. }
  1958. exit:
  1959. // Done
  1960. return;
  1961. }