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.

1216 lines
36 KiB

  1. /************************************************************************************************
  2. Copyright (c) 2001 Microsoft Corporation
  3. File Name: MailBox.cpp
  4. Abstract: Implementation of the CMailBox class, abstraction of mailbox storage
  5. Notes:
  6. History: 08/01/2001 Created by Hao Yu (haoyu)
  7. ************************************************************************************************/
  8. #include <windows.h>
  9. #include <assert.h>
  10. #include <tchar.h>
  11. #include <process.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <atlbase.h>
  15. #include "Mailbox.h"
  16. #include "Ntioapi.hxx"
  17. #include <POP3Regkeys.h>
  18. long CMailBox::m_lMailRootGuard=1;
  19. WCHAR CMailBox::m_wszMailRoot[POP3_MAX_MAILROOT_LENGTH]=L"";
  20. CMailBox::CMailBox()
  21. {
  22. m_cMailCount=0;
  23. m_dwShowMailCount=0;
  24. m_dwTotalSize=0;
  25. m_dwSizeOfMailVector=0;
  26. m_MailVector=NULL;
  27. m_hMailBoxLock=NULL;
  28. m_bMailBoxOpened=FALSE;
  29. ZeroMemory(m_wszMailBoxPath, sizeof(m_wszMailBoxPath));
  30. }
  31. CMailBox::~CMailBox()
  32. {
  33. }
  34. /////////////////////////////////////////////////////////////////////////////
  35. // BuildFilePath, public
  36. //
  37. // Purpose:
  38. // common routine for building file paths
  39. //
  40. // Arguments:
  41. // LPSTR *ppFilePath : allocates buffer and returns the file path here, caller must free this buffer
  42. // LPSTR psFileName : file name to create path for
  43. //
  44. // Returns: true on success, false otherwise. Buffer must be freed by caller on success
  45. bool CMailBox::BuildFilePath( LPWSTR psFilePathBuffer, LPWSTR psFileName, DWORD dwSizeOfFilePathBuffer )
  46. {
  47. if ( NULL == psFilePathBuffer )
  48. return false;
  49. if ( NULL == psFileName )
  50. return false;
  51. if ( dwSizeOfFilePathBuffer > 1 + wcslen( m_wszMailBoxPath ) + wcslen( psFileName ) )
  52. {
  53. wcscpy( psFilePathBuffer, m_wszMailBoxPath );
  54. wcscat( psFilePathBuffer, L"\\" );
  55. wcscat( psFilePathBuffer, psFileName );
  56. return true;
  57. }
  58. return false;
  59. }
  60. /////////////////////////////////////////////////////////////////////////////
  61. // CreateMailBox, public
  62. //
  63. // Purpose:
  64. // Create a mail box in our store
  65. // This involves:
  66. // create the mailbox directory
  67. // create a lock file in the mailbox
  68. //
  69. // Arguments:
  70. // char *szEmailAddr : mailbox to add
  71. //
  72. // Returns: TRUE on success, FALSE otherwise
  73. bool CMailBox::CreateMailBox(WCHAR *wszEmailAddr)
  74. {
  75. bool bRC;
  76. WCHAR wszLockFilePath[POP3_MAX_PATH];
  77. bRC = SetMailBoxPath( wszEmailAddr );
  78. if ( bRC )
  79. bRC = (CreateDirectory( m_wszMailBoxPath, NULL ) ? true:false);
  80. if ( bRC )
  81. {
  82. wszLockFilePath[sizeof(wszLockFilePath)/sizeof(WCHAR)-1] = 0;
  83. if ( 0 > _snwprintf( wszLockFilePath, sizeof(wszLockFilePath)/sizeof(WCHAR) - 1, L"%s\\%s", m_wszMailBoxPath, LOCK_FILENAME_W ))
  84. bRC = false;
  85. if ( bRC )
  86. {
  87. m_hMailBoxLock = CreateFile( wszLockFilePath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, NULL );
  88. if ( INVALID_HANDLE_VALUE != m_hMailBoxLock )
  89. {
  90. CloseHandle(m_hMailBoxLock);
  91. m_hMailBoxLock=NULL;
  92. }
  93. else
  94. bRC = false;
  95. }
  96. if ( !bRC )
  97. RemoveDirectory( m_wszMailBoxPath ); // Don't care about return
  98. }
  99. return bRC;
  100. }
  101. /////////////////////////////////////////////////////////////////////////////
  102. // RepairMailBox, public
  103. //
  104. // Purpose:
  105. // Repair a mail box in our store
  106. // This involves:
  107. // create a lock file in the mailbox if it does not exist
  108. //
  109. // Returns: TRUE on success, FALSE otherwise
  110. BOOL CMailBox::RepairMailBox()
  111. {
  112. bool bRC = true;
  113. WCHAR wszLockFilePath[POP3_MAX_PATH];
  114. wszLockFilePath[sizeof(wszLockFilePath)/sizeof(WCHAR)-1] = 0;
  115. if ( 0 > _snwprintf( wszLockFilePath, sizeof(wszLockFilePath)/sizeof(WCHAR)-1, L"%s\\%s", m_wszMailBoxPath, LOCK_FILENAME_W ))
  116. bRC = false;
  117. if ( bRC )
  118. {
  119. m_hMailBoxLock = CreateFile( wszLockFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL );
  120. if ( INVALID_HANDLE_VALUE != m_hMailBoxLock )
  121. {
  122. CloseHandle(m_hMailBoxLock);
  123. m_hMailBoxLock=NULL;
  124. }
  125. else
  126. bRC = false;
  127. }
  128. return bRC;
  129. }
  130. BOOL CMailBox::OpenMailBox(WCHAR *wszEmailAddr)
  131. {
  132. if ( !SetMailBoxPath( wszEmailAddr ))
  133. return FALSE;
  134. if(ERROR_NO_FILE_ATTR == GetFileAttributes(m_wszMailBoxPath))
  135. { // Mailbox does not exist!
  136. return FALSE;
  137. }
  138. m_bMailBoxOpened=TRUE;
  139. return TRUE;
  140. }
  141. /////////////////////////////////////////////////////////////////////////////
  142. // isMailboxInUse, public
  143. //
  144. // Purpose:
  145. // Determine if someone is already logged on to the mailbox
  146. // This involves:
  147. // checking if the Lock file has been opened for WRITE access
  148. //
  149. // Returns: true if we determine it is in use, false otherwise
  150. bool CMailBox::isMailboxInUse()
  151. {
  152. bool bRC = true;
  153. if ( LockMailBox() )
  154. {
  155. UnlockMailBox();
  156. bRC = false;
  157. }
  158. return bRC;
  159. }
  160. BOOL CMailBox::LockMailBox()
  161. {
  162. WCHAR wszLockFilePath[POP3_MAX_PATH];
  163. assert(m_bMailBoxOpened);
  164. assert(m_wszMailRoot[0]!=L'\0');
  165. wszLockFilePath[sizeof(wszLockFilePath)/sizeof(WCHAR)-1] = 0;
  166. if ( 0 > _snwprintf(wszLockFilePath,
  167. sizeof(wszLockFilePath)/sizeof(WCHAR)-1,
  168. L"%s\\%s",
  169. m_wszMailBoxPath,
  170. LOCK_FILENAME_W ))
  171. return FALSE;
  172. m_hMailBoxLock=CreateFile(wszLockFilePath,
  173. GENERIC_READ | GENERIC_WRITE,
  174. FILE_SHARE_READ | FILE_SHARE_DELETE, // Only one writer (only one Locker via this method of locking)
  175. 0,
  176. OPEN_EXISTING,
  177. FILE_ATTRIBUTE_HIDDEN,
  178. NULL);
  179. if(INVALID_HANDLE_VALUE == m_hMailBoxLock)
  180. {
  181. //Can not open mail box
  182. return FALSE;
  183. }
  184. else
  185. {
  186. return TRUE;
  187. }
  188. }
  189. /////////////////////////////////////////////////////////////////////////////
  190. // UnlockMailBox, public
  191. //
  192. // Purpose:
  193. // Unlock a mail box in our store
  194. //
  195. // Returns: TRUE on success, FALSE otherwise
  196. void CMailBox::UnlockMailBox()
  197. {
  198. if(NULL != m_hMailBoxLock)
  199. {
  200. CloseHandle(m_hMailBoxLock);
  201. m_hMailBoxLock=NULL;
  202. }
  203. }
  204. BOOL CMailBox::EnumerateMailBox(DWORD dwMaxMsg)
  205. {
  206. PMAIL_ITEM pMail=NULL;
  207. WCHAR wszMailFilter[POP3_MAX_PATH+6];
  208. HANDLE hFind;
  209. DWORD dwLastErr;
  210. WIN32_FIND_DATA FileInfo;
  211. assert(m_bMailBoxOpened);
  212. assert(m_wszMailRoot[0]!=L'\0');
  213. wsprintf(wszMailFilter,
  214. L"%s\\*.eml",
  215. m_wszMailBoxPath);
  216. hFind=FindFirstFile(wszMailFilter,
  217. &(FileInfo));
  218. if(INVALID_HANDLE_VALUE == hFind)
  219. {
  220. dwLastErr= GetLastError();
  221. if(ERROR_FILE_NOT_FOUND == dwLastErr ||
  222. ERROR_SUCCESS == dwLastErr)
  223. {
  224. // No mail in the mail box
  225. m_cMailCount=0;
  226. return TRUE;
  227. }
  228. else
  229. {
  230. return FALSE;
  231. }
  232. }
  233. BOOL bMoreFile=TRUE;
  234. while(bMoreFile)
  235. {
  236. // To exclude hidden files
  237. // which are mails being delivered
  238. if( ! (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) )
  239. {
  240. pMail = new (MAIL_ITEM);
  241. if(NULL == pMail)
  242. {
  243. //Log mem err
  244. return FALSE;
  245. }
  246. pMail->hFile=NULL;
  247. pMail->dwStatus=NO_PENDING_OP;
  248. pMail->bstrFileName=SysAllocString(FileInfo.cFileName);
  249. if(NULL == pMail->bstrFileName )
  250. {
  251. FindClose(hFind);
  252. delete pMail;
  253. return FALSE;
  254. }
  255. pMail->dwFileSize=FileInfo.nFileSizeLow;
  256. if(!PushMailToVector(pMail))
  257. {
  258. assert(NULL != pMail->bstrFileName);
  259. SysFreeString(pMail->bstrFileName);
  260. delete pMail;
  261. return FALSE;
  262. }
  263. m_cMailCount++;
  264. m_dwTotalSize+=FileInfo.nFileSizeLow;
  265. }
  266. if( (!dwMaxMsg) || (m_cMailCount != dwMaxMsg) )
  267. {
  268. bMoreFile=FindNextFile(hFind,&FileInfo);
  269. }
  270. else
  271. {
  272. bMoreFile=FALSE;
  273. SetLastError(ERROR_NO_MORE_FILES);
  274. }
  275. }
  276. m_dwShowMailCount=m_cMailCount;
  277. dwLastErr= GetLastError();
  278. FindClose(hFind);
  279. if(ERROR_NO_MORE_FILES == dwLastErr)
  280. {
  281. return TRUE;
  282. }
  283. else
  284. {
  285. // Unexpected Error
  286. return FALSE;
  287. }
  288. }
  289. /////////////////////////////////////////////////////////////////////////////
  290. // GetMailboxFromStoreNameW, public
  291. //
  292. // Purpose:
  293. // Convert the Store Name to the Mailbox name
  294. //
  295. // Arguments:
  296. // LPWSTR psStoreName: The Store name for the mailbox, this string will be modified
  297. //
  298. // Returns: Mailbox name on success, NULL otherwise.
  299. LPWSTR CMailBox::GetMailboxFromStoreNameW( LPWSTR psStoreName )
  300. {
  301. if ( NULL == psStoreName )
  302. return NULL;
  303. if ( wcslen( psStoreName ) <= (wcslen( MAILBOX_PREFIX_W ) + wcslen( MAILBOX_EXTENSION_W )) )
  304. return NULL;
  305. // Validate psStoreName
  306. if ( 0 != _wcsnicmp( psStoreName, MAILBOX_PREFIX_W, wcslen( MAILBOX_PREFIX_W ) ))
  307. return NULL;
  308. if ( 0 != _wcsnicmp( psStoreName + wcslen( psStoreName ) - wcslen( MAILBOX_EXTENSION_W ), MAILBOX_EXTENSION_W, wcslen( MAILBOX_EXTENSION_W )))
  309. return NULL;
  310. psStoreName[wcslen( psStoreName ) - wcslen( MAILBOX_EXTENSION_W )] = 0;
  311. return psStoreName + wcslen( MAILBOX_PREFIX_W );
  312. }
  313. bool CMailBox::GetMailFileName( int iIndex, LPWSTR psFilename, DWORD dwSize )
  314. {
  315. bool bRC = false;
  316. if ( iIndex < 0 || iIndex >= m_cMailCount )
  317. return false;
  318. if ( DEL_PENDING == m_MailVector[iIndex]->dwStatus )
  319. return false;
  320. if ( 0 < _snwprintf( psFilename, dwSize, L"%s\\%s",
  321. m_wszMailBoxPath , m_MailVector[iIndex]->bstrFileName ))
  322. bRC = true;
  323. return bRC;
  324. }
  325. bool CMailBox::GetEncyptedPassword( LPBYTE pbBuffer, const DWORD dwBufferSize, LPDWORD pdwBytesRead )
  326. {
  327. if ( NULL == pbBuffer )
  328. return false;
  329. if ( NULL == pdwBytesRead )
  330. return false;
  331. if ( NULL == m_hMailBoxLock )
  332. return false;
  333. if ( !ReadFile( m_hMailBoxLock, pbBuffer, dwBufferSize, pdwBytesRead, NULL ) || (dwBufferSize == *pdwBytesRead) )
  334. return false;
  335. return true;
  336. }
  337. bool CMailBox::SetEncyptedPassword( LPBYTE pbBuffer, DWORD dwBytesToWrite, LPDWORD pdwBytesWritten )
  338. {
  339. if ( NULL == pbBuffer )
  340. return false;
  341. if ( NULL == pdwBytesWritten )
  342. return false;
  343. if ( NULL == m_hMailBoxLock )
  344. return false;
  345. if ( !WriteFile( m_hMailBoxLock, pbBuffer, dwBytesToWrite, pdwBytesWritten, NULL ))
  346. return false;
  347. // In case the file is shorter
  348. if ( !SetEndOfFile(m_hMailBoxLock) )
  349. return false;
  350. return true;
  351. }
  352. void CMailBox::Reset()
  353. {
  354. for(int i=0;i<m_cMailCount; i++)
  355. {
  356. if(m_MailVector[i]->dwStatus==DEL_PENDING)
  357. {
  358. m_MailVector[i]->dwStatus=NO_PENDING_OP;
  359. m_dwTotalSize+=m_MailVector[i]->dwFileSize;
  360. }
  361. }
  362. m_dwShowMailCount=m_cMailCount;
  363. }
  364. DWORD CMailBox::DeleteMail(int iIndex)
  365. {
  366. if(iIndex<0 || iIndex >= m_cMailCount)
  367. {
  368. return ERR_NO_SUCH_MSG;
  369. }
  370. if(m_MailVector[iIndex]->dwStatus==DEL_PENDING)
  371. {
  372. return ERR_MSG_ALREADY_DELETED;
  373. }
  374. else
  375. {
  376. ( m_MailVector[iIndex] )->dwStatus=DEL_PENDING;
  377. m_dwShowMailCount--;
  378. m_dwTotalSize-=m_MailVector[iIndex]->dwFileSize;
  379. return ERROR_SUCCESS;
  380. }
  381. }
  382. DWORD CMailBox::TransmitMail(PIO_CONTEXT pIoContext, int iIndex,int iLines)
  383. {
  384. assert(NULL!=pIoContext);
  385. WCHAR wszFileName[POP3_MAX_PATH];
  386. char szRespBuf[MAX_PATH];
  387. DWORD dwTotalBytesToSend=0;
  388. TRANSMIT_FILE_BUFFERS TransmitBuf;
  389. int iErr;
  390. if( iIndex < 0 ||
  391. iIndex >= m_cMailCount )
  392. {
  393. return ERR_NO_SUCH_MSG;
  394. }
  395. if( m_MailVector[iIndex]->dwStatus==DEL_PENDING)
  396. {
  397. return ERR_MSG_ALREADY_DELETED;
  398. }
  399. else
  400. {
  401. sprintf(szRespBuf,
  402. "+OK %d octects\r\n",
  403. m_MailVector[iIndex]->dwFileSize);
  404. TransmitBuf.Head = szRespBuf;
  405. TransmitBuf.HeadLength = strlen(szRespBuf);
  406. TransmitBuf.Tail = RESP_END_OF_MULTILINE;
  407. TransmitBuf.TailLength = strlen(RESP_END_OF_MULTILINE);
  408. //Send the mail through the network
  409. if(m_MailVector[iIndex]->hFile == NULL)
  410. {
  411. if(0>_snwprintf(wszFileName,
  412. sizeof(wszFileName)/sizeof(WCHAR)-1,
  413. L"%s\\%s",
  414. m_wszMailBoxPath,
  415. m_MailVector[iIndex]->bstrFileName))
  416. {
  417. return E_UNEXPECTED;
  418. }
  419. wszFileName[sizeof(wszFileName)/sizeof(WCHAR)-1]=0;
  420. m_MailVector[iIndex]->hFile=
  421. CreateFile( wszFileName,
  422. GENERIC_READ,
  423. 0,
  424. NULL,
  425. OPEN_EXISTING,
  426. FILE_FLAG_SEQUENTIAL_SCAN,
  427. NULL);
  428. if(INVALID_HANDLE_VALUE == m_MailVector[iIndex]->hFile )
  429. {
  430. //Error
  431. m_MailVector[iIndex]->hFile=NULL;
  432. return GetLastError();
  433. }
  434. }
  435. else
  436. {
  437. if( INVALID_SET_FILE_POINTER ==
  438. SetFilePointer(m_MailVector[iIndex]->hFile,
  439. 0,NULL, FILE_BEGIN))
  440. {
  441. //Error
  442. return GetLastError();
  443. }
  444. }
  445. if(iLines>=0)
  446. {
  447. //For TOP command, calculate bytes to send
  448. if(!ReadTopLines(iLines, m_MailVector[iIndex]->hFile, &dwTotalBytesToSend))
  449. {
  450. return GetLastError();
  451. }
  452. if( INVALID_SET_FILE_POINTER ==
  453. SetFilePointer(m_MailVector[iIndex]->hFile,
  454. 0,NULL, FILE_BEGIN))
  455. {
  456. //Error
  457. return GetLastError();
  458. }
  459. }
  460. if(!TransmitFile(pIoContext->m_hAsyncIO,
  461. m_MailVector[iIndex]->hFile,
  462. dwTotalBytesToSend,
  463. 0,
  464. &(pIoContext->m_Overlapped),
  465. &TransmitBuf,
  466. TF_USE_KERNEL_APC ) )
  467. {
  468. int iErr = WSAGetLastError();
  469. if(WSA_IO_PENDING!=iErr)
  470. {
  471. //Error
  472. return iErr;
  473. }
  474. }
  475. return ERROR_SUCCESS;
  476. }
  477. }
  478. DWORD CMailBox::TransmitMail(SOCKET hSocket, int iIndex)
  479. {
  480. WCHAR wszFileName[POP3_MAX_PATH];
  481. char szRespBuf[MAX_PATH];
  482. DWORD dwTotalBytesToSend=0;
  483. TRANSMIT_FILE_BUFFERS TransmitBuf;
  484. int iErr;
  485. if( iIndex < 0 ||
  486. iIndex >= m_cMailCount )
  487. {
  488. return ERR_NO_SUCH_MSG;
  489. }
  490. if( m_MailVector[iIndex]->dwStatus==DEL_PENDING)
  491. {
  492. return ERR_MSG_ALREADY_DELETED;
  493. }
  494. else
  495. {
  496. sprintf(szRespBuf,
  497. "+OK %d octects\r\n",
  498. m_MailVector[iIndex]->dwFileSize);
  499. TransmitBuf.Head = szRespBuf;
  500. TransmitBuf.HeadLength = strlen(szRespBuf);
  501. TransmitBuf.Tail = RESP_END_OF_MULTILINE;
  502. TransmitBuf.TailLength = strlen(RESP_END_OF_MULTILINE);
  503. //Send the mail through the network
  504. if(m_MailVector[iIndex]->hFile == NULL)
  505. {
  506. if(0>_snwprintf(wszFileName,
  507. sizeof(wszFileName)/sizeof(WCHAR)-1,
  508. L"%s\\%s\0",
  509. m_wszMailBoxPath,
  510. m_MailVector[iIndex]->bstrFileName))
  511. {
  512. return E_UNEXPECTED;
  513. }
  514. wszFileName[sizeof(wszFileName)/sizeof(WCHAR)-1]=0;
  515. m_MailVector[iIndex]->hFile=
  516. CreateFile( wszFileName,
  517. GENERIC_READ,
  518. 0,
  519. NULL,
  520. OPEN_EXISTING,
  521. FILE_FLAG_OVERLAPPED |
  522. FILE_FLAG_NO_BUFFERING ,
  523. NULL);
  524. if(INVALID_HANDLE_VALUE == m_MailVector[iIndex]->hFile )
  525. {
  526. //Error
  527. m_MailVector[iIndex]->hFile=NULL;
  528. return GetLastError();
  529. }
  530. }
  531. else
  532. {
  533. if( INVALID_SET_FILE_POINTER ==
  534. SetFilePointer(m_MailVector[iIndex]->hFile,
  535. 0,NULL, FILE_BEGIN))
  536. {
  537. //Error
  538. return GetLastError();
  539. }
  540. }
  541. if(!TransmitFile( hSocket,
  542. m_MailVector[iIndex]->hFile,
  543. dwTotalBytesToSend,
  544. 0,
  545. NULL,
  546. &TransmitBuf,
  547. TF_USE_KERNEL_APC ) )
  548. {
  549. int iErr = WSAGetLastError();
  550. if(WSA_IO_PENDING!=iErr)
  551. {
  552. //Error
  553. return iErr;
  554. }
  555. }
  556. return ERROR_SUCCESS;
  557. }
  558. }
  559. BOOL CMailBox::CommitAndClose()
  560. {
  561. BOOL bRetVal=TRUE;
  562. WCHAR wszFileName[POP3_MAX_PATH];
  563. for(int i=0; i<m_cMailCount; i++)
  564. {
  565. if(NULL != m_MailVector[i])
  566. {
  567. if(NULL != m_MailVector[i]->hFile)
  568. {
  569. CloseHandle( m_MailVector[i]->hFile );
  570. }
  571. if( m_MailVector[i]->dwStatus == DEL_PENDING )
  572. {
  573. wszFileName[sizeof(wszFileName)/sizeof(WCHAR)-1]=0;
  574. if(0> _snwprintf ( wszFileName,
  575. sizeof(wszFileName)/sizeof(WCHAR)-1,
  576. L"%s\\%s\0",
  577. m_wszMailBoxPath,
  578. m_MailVector[i]->bstrFileName))
  579. {
  580. bRetVal=FALSE;
  581. }
  582. else if(FALSE==DeleteFile( wszFileName ) )
  583. {
  584. //Error log
  585. bRetVal=FALSE;
  586. }
  587. }
  588. if(NULL != m_MailVector[i]->bstrFileName)
  589. {
  590. SysFreeString(m_MailVector[i]->bstrFileName);
  591. }
  592. delete (m_MailVector[i]);
  593. m_MailVector[i]=NULL;
  594. }
  595. }
  596. delete[] m_MailVector;
  597. m_MailVector=NULL;
  598. m_dwSizeOfMailVector=0;
  599. if(NULL != m_hMailBoxLock)
  600. {
  601. CloseHandle(m_hMailBoxLock);
  602. m_hMailBoxLock=NULL;
  603. }
  604. m_cMailCount=0;
  605. m_dwShowMailCount=0;
  606. m_dwTotalSize=0;
  607. ZeroMemory(m_wszMailBoxPath, sizeof(m_wszMailBoxPath));
  608. return bRetVal;
  609. }
  610. void CMailBox::CloseMailBox()
  611. {
  612. m_bMailBoxOpened=FALSE;
  613. }
  614. /////////////////////////////////////////////////////////////////////////////
  615. // CreateMail, public
  616. //
  617. // Purpose:
  618. // Create a new empty mail file and return the handle. The returned file handle
  619. // should be closed using CloseMail, unless special options are being used as documented
  620. // in the CloseMail function below.
  621. //
  622. // Arguments:
  623. // LPSTR *szTargetFileName: File name (just the file name path will be prepended)
  624. // DWORD dwFlagsAndAttributes: [in] Specifies the file attributes and flags for the CreateFile api.
  625. //
  626. // Returns: file handle on success, INVALID_HANDLE_VALUE otherwise
  627. HANDLE CMailBox::CreateMail( LPWSTR wszTargetFileName, DWORD dwFlagsAndAttributes /*= 0*/ )
  628. {
  629. if ( NULL == wszTargetFileName )
  630. return INVALID_HANDLE_VALUE;
  631. assert(TRUE == m_bMailBoxOpened);
  632. HANDLE hNewMail = INVALID_HANDLE_VALUE;
  633. HANDLE hf;
  634. DWORD dwBytes, dwSize;
  635. WCHAR wszFileNameBuffer[POP3_MAX_PATH];
  636. LPBYTE pSIDOwner = NULL;
  637. PSECURITY_ATTRIBUTES psa = NULL;
  638. SECURITY_ATTRIBUTES sa;
  639. SECURITY_DESCRIPTOR sd;
  640. // Set the Security Attributes to set the owner to the quota owner
  641. if ( BuildFilePath( wszFileNameBuffer, QUOTA_FILENAME, sizeof(wszFileNameBuffer)/sizeof(WCHAR) ))
  642. {
  643. hf = CreateFile( wszFileNameBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN, NULL );
  644. if ( INVALID_HANDLE_VALUE != hf )
  645. {
  646. dwSize = GetFileSize( hf, NULL );
  647. if ( INVALID_FILE_SIZE != dwSize )
  648. {
  649. pSIDOwner = new BYTE[dwSize];
  650. if ( NULL != pSIDOwner )
  651. {
  652. SetLastError( ERROR_SUCCESS );
  653. ReadFile( hf, pSIDOwner, dwSize, &dwBytes, NULL ); // No need to check return code here, the GetLastError check below covers it!
  654. } // |
  655. else // |
  656. SetLastError( ERROR_OUTOFMEMORY ); // |
  657. } // |
  658. CloseHandle( hf ); // |
  659. if ( ERROR_SUCCESS == GetLastError() ) // <--------------------+
  660. {
  661. if ( InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ))
  662. { // Set the ownership for a new file
  663. if ( SetSecurityDescriptorOwner( &sd, pSIDOwner, FALSE ))
  664. {
  665. sa.nLength = sizeof( sa );
  666. sa.lpSecurityDescriptor = &sd;
  667. sa.bInheritHandle = FALSE;
  668. psa = &sa;
  669. }
  670. }
  671. }
  672. }
  673. }
  674. if ( BuildFilePath( wszFileNameBuffer, wszTargetFileName, sizeof(wszFileNameBuffer)/sizeof(WCHAR) ))
  675. hNewMail = CreateFile( wszFileNameBuffer, GENERIC_ALL, 0, psa, CREATE_NEW, dwFlagsAndAttributes|FILE_ATTRIBUTE_HIDDEN, NULL );
  676. if ( NULL != pSIDOwner )
  677. delete [] pSIDOwner;
  678. return hNewMail;
  679. }
  680. /////////////////////////////////////////////////////////////////////////////
  681. // CloseMail, public
  682. //
  683. // Purpose:
  684. // Close the mail file created using CreateMail.
  685. //
  686. // Arguments:
  687. // LPSTR *szTargetFileName: File name (just the file name path will be prepended)
  688. // DWORD dwFlagsAndAttributes: If the FILE_FLAG_OVERLAPPED bit is set the file handle will not be closed.
  689. // In this case it is the responsibility of the calling process to ReleaseContext( PFIO_CONTEXT* )
  690. // which also closes the file handle.
  691. //
  692. // Returns: ERROR_SUCCESS on success, the applicable error otherwise.
  693. DWORD CMailBox::CloseMail(HANDLE hMailFile,DWORD dwFlagsAndAttributes /*= 0*/)
  694. {
  695. assert( !(INVALID_HANDLE_VALUE == hMailFile));
  696. if (INVALID_HANDLE_VALUE == hMailFile)
  697. {
  698. return ERROR_INVALID_HANDLE;
  699. }
  700. DWORD dwRC;
  701. IO_STATUS_BLOCK IoStatusBlock;
  702. dwRC = NtFlushBuffersFile( hMailFile, &IoStatusBlock );
  703. if ( ERROR_SUCCESS == dwRC )
  704. { // Remove the FILE_ATTRIBUTE_HIDDEN
  705. FILE_BASIC_INFORMATION BasicInfo;
  706. ZeroMemory( &BasicInfo, sizeof(BasicInfo) );
  707. BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  708. dwRC = NtSetInformationFile( hMailFile, &IoStatusBlock, &BasicInfo, sizeof(BasicInfo), FileBasicInformation );
  709. }
  710. // Now close the handle, if appropriate
  711. if (!(FILE_FLAG_OVERLAPPED & dwFlagsAndAttributes))
  712. {
  713. if( !CloseHandle(hMailFile) )
  714. dwRC = GetLastError();
  715. }
  716. return dwRC;
  717. }
  718. /////////////////////////////////////////////////////////////////////////////
  719. // DeleteMail, public
  720. //
  721. // Purpose:
  722. // Delete a mail file. This method is really meant for deleting files that were
  723. // created but not successfully delivered.
  724. //
  725. // Arguments:
  726. // LPSTR *szTargetFileName: File name (just the file name path will be prepended)
  727. //
  728. // Returns: true on success, false otherwise
  729. bool CMailBox::DeleteMail( LPWSTR wszTargetFileName )
  730. {
  731. if ( NULL == wszTargetFileName )
  732. return false;
  733. if ( 0 == wcslen( wszTargetFileName ))
  734. return false;
  735. if ( !m_bMailBoxOpened )
  736. return false;
  737. bool bRC = false;
  738. WCHAR wszFileNameBuffer[POP3_MAX_PATH];
  739. if ( BuildFilePath( wszFileNameBuffer, wszTargetFileName, sizeof(wszFileNameBuffer)/sizeof(WCHAR) ))
  740. {
  741. bRC = DeleteFile( wszFileNameBuffer ) ? true : false;
  742. }
  743. return bRC;
  744. }
  745. void CMailBox::QuitAndClose()
  746. {
  747. for(int i=0; i<m_cMailCount; i++ )
  748. {
  749. if(NULL != m_MailVector[i])
  750. {
  751. if(NULL != m_MailVector[i]->hFile)
  752. {
  753. CloseHandle( m_MailVector[i]->hFile );
  754. m_MailVector[i]->hFile=NULL;
  755. }
  756. if(NULL != m_MailVector[i]->bstrFileName )
  757. {
  758. SysFreeString(m_MailVector[i]->bstrFileName);
  759. }
  760. delete (m_MailVector[i]);
  761. m_MailVector[i]=NULL;
  762. }
  763. }
  764. if(NULL != m_hMailBoxLock)
  765. {
  766. CloseHandle(m_hMailBoxLock);
  767. m_hMailBoxLock=NULL;
  768. }
  769. delete[] m_MailVector;
  770. m_MailVector=NULL;
  771. m_dwSizeOfMailVector=0;
  772. m_cMailCount=0;
  773. m_dwShowMailCount=0;
  774. m_dwTotalSize=0;
  775. ZeroMemory(m_wszMailBoxPath, sizeof(m_wszMailBoxPath));
  776. }
  777. DWORD CMailBox::ListMail(int iIndex, char *szBuf, DWORD dwSize)
  778. {
  779. assert(NULL!=szBuf);
  780. if( iIndex<0 ||
  781. iIndex >= m_cMailCount)
  782. {
  783. return ERR_NO_SUCH_MSG;
  784. }
  785. if(m_MailVector[iIndex]->dwStatus==DEL_PENDING)
  786. {
  787. return ERR_MSG_ALREADY_DELETED;
  788. }
  789. else
  790. {
  791. if(0> _snprintf(szBuf,
  792. dwSize-1,
  793. "%d %d\r\n",
  794. iIndex+1,
  795. m_MailVector[iIndex]->dwFileSize))
  796. {
  797. return ERROR_INVALID_DATA;
  798. }
  799. szBuf[dwSize-1]=0;
  800. return ERROR_SUCCESS;
  801. }
  802. }
  803. DWORD CMailBox::UidlMail(int iIndex, char *szBuf, DWORD dwSize)
  804. {
  805. assert(NULL!=szBuf);
  806. if( iIndex<0 ||
  807. iIndex >= m_cMailCount)
  808. {
  809. return ERR_NO_SUCH_MSG;
  810. }
  811. if(m_MailVector[iIndex]->dwStatus==DEL_PENDING)
  812. {
  813. return ERR_MSG_ALREADY_DELETED;
  814. }
  815. else
  816. {
  817. if( 0>_snprintf(szBuf,
  818. dwSize-1,
  819. "%d %S",
  820. iIndex+1,
  821. (m_MailVector[iIndex]->bstrFileName)+3))
  822. {
  823. return ERROR_INVALID_DATA;
  824. }
  825. szBuf[dwSize-1]=0;
  826. //To cut the .eml file extention
  827. int iFileExt=strlen(szBuf)-4;
  828. szBuf[iFileExt++]='\r';
  829. szBuf[iFileExt++]='\n';
  830. szBuf[iFileExt]='\0';
  831. return ERROR_SUCCESS;
  832. }
  833. }
  834. BOOL CMailBox::SetMailRoot(const WCHAR *wszMailRoot)
  835. {
  836. BOOL bRtVal=FALSE;
  837. if(1==InterlockedExchange(&m_lMailRootGuard, 0))
  838. {
  839. WCHAR sMailRoot[POP3_MAX_PATH];
  840. if ( wszMailRoot )
  841. {
  842. if ( sizeof(sMailRoot)/sizeof(WCHAR) > wcslen( wszMailRoot ))
  843. {
  844. wcscpy( sMailRoot, wszMailRoot );
  845. bRtVal=TRUE;
  846. }
  847. }
  848. else
  849. { // Read the mailroot from the registry
  850. if ( ERROR_SUCCESS == RegQueryMailRoot( sMailRoot, sizeof( sMailRoot )/sizeof(WCHAR) ) )
  851. {
  852. bRtVal=TRUE;
  853. }
  854. }
  855. if ( bRtVal )
  856. {
  857. if ( 0 == wcsncmp( sMailRoot, L"\\\\", 2 ))
  858. {
  859. if ( sizeof( m_wszMailRoot )/sizeof(WCHAR) > wcslen( sMailRoot ) + 7 )
  860. {
  861. wcscpy( m_wszMailRoot, L"\\\\?\\UNC" );
  862. wcscat( m_wszMailRoot, &( sMailRoot[1] ));
  863. }
  864. else
  865. bRtVal = FALSE;
  866. }
  867. else
  868. {
  869. if ( sizeof( m_wszMailRoot )/sizeof(WCHAR) > wcslen( sMailRoot ) + 5 )
  870. {
  871. wcscpy( m_wszMailRoot, L"\\\\?\\" );
  872. wcscat( m_wszMailRoot, sMailRoot );
  873. }
  874. else
  875. bRtVal = FALSE;
  876. }
  877. }
  878. InterlockedExchange(&m_lMailRootGuard, 1);
  879. }
  880. else
  881. {
  882. //Some other thread is doing the job
  883. while(0==m_lMailRootGuard)
  884. {
  885. Sleep(100);
  886. }
  887. if(L'\0'!=m_wszMailRoot[0])
  888. {
  889. bRtVal=TRUE;
  890. }
  891. }
  892. return bRtVal;
  893. }
  894. ///////////////////////////////////////////////////////////////
  895. // Implementation: private
  896. ///////////////////////////////////////////////////////////////
  897. /////////////////////////////////////////////////////////////////////////////
  898. // SetMailBoxPath, private
  899. //
  900. // Purpose:
  901. // Build the Mailbox Path, validate the EmailAddr.
  902. //
  903. // Arguments:
  904. // char *szEmailAddr : mailbox to build path for
  905. //
  906. // Returns: true on success, false otherwise
  907. bool CMailBox::SetMailBoxPath(WCHAR *wszEmailAddr)
  908. {
  909. WCHAR *wszDomain=NULL;
  910. WCHAR *wszAccount=NULL;
  911. WCHAR wszNotAllowedSet[]=L"\\/:*?\",>|";
  912. WCHAR wszMailBox[POP3_MAX_ADDRESS_LENGTH];
  913. WCHAR wszMailDomain[POP3_MAX_DOMAIN_LENGTH];
  914. int iLen;
  915. while(iswspace(*wszEmailAddr))
  916. {
  917. wszEmailAddr++;
  918. }
  919. wszDomain=wcschr(wszEmailAddr, '@');
  920. if(wszDomain==NULL)
  921. { //Error
  922. return false;
  923. }
  924. iLen=wcslen(wszDomain);
  925. if( 1 == iLen || iLen>=POP3_MAX_DOMAIN_LENGTH ) // Is there anything after the @?
  926. { //Error
  927. return false;
  928. }
  929. wcscpy(wszMailDomain, wszDomain+1);
  930. wszMailDomain[iLen]='\0';
  931. iLen=(int)(wszDomain-wszEmailAddr);
  932. wcsncpy(wszMailBox, wszEmailAddr,iLen);
  933. wszMailBox[iLen]='\0';
  934. if(L'\0'==m_wszMailRoot[0])
  935. {
  936. if(!SetMailRoot())
  937. {
  938. return false;
  939. }
  940. }
  941. //Check if the mail domain and account is valid
  942. if( (NULL != wcspbrk(wszMailDomain, wszNotAllowedSet))
  943. || (NULL != wcspbrk(wszMailBox, wszNotAllowedSet))
  944. || (sizeof(m_wszMailBoxPath)/sizeof(WCHAR) <= wcslen(m_wszMailRoot) +
  945. wcslen(wszMailDomain) +
  946. wcslen(wszMailBox) +
  947. wcslen(MAILBOX_PREFIX_W) +
  948. wcslen(MAILBOX_EXTENSION_W) + 3 /*2 \\ and \0 */ ) )
  949. {
  950. return false;
  951. }
  952. //build the path to the mail dir
  953. m_bMailBoxOpened = FALSE;
  954. m_wszMailBoxPath[sizeof(m_wszMailBoxPath)/sizeof(WCHAR)-1] = 0;
  955. if ( 0 > _snwprintf(m_wszMailBoxPath,
  956. sizeof(m_wszMailBoxPath)/sizeof(WCHAR) - 1,
  957. L"%s\\%s\\%s%s%s",
  958. m_wszMailRoot,
  959. wszMailDomain,
  960. MAILBOX_PREFIX_W,
  961. wszMailBox,
  962. MAILBOX_EXTENSION_W ))
  963. return false;
  964. return true;
  965. }
  966. bool CMailBox::ReadTopLines(int iLines, HANDLE hFile, DWORD *pdwBytesToRead)
  967. {
  968. assert(INVALID_HANDLE_VALUE!=hFile);
  969. assert(NULL != pdwBytesToRead);
  970. assert(NULL != hFile);
  971. assert(iLines>=0);
  972. BOOL bHeadersDone=FALSE;
  973. (*pdwBytesToRead)=0;
  974. BOOL bMoreToRead=TRUE;
  975. char szBuffer[LOCAL_FILE_BUFFER_SIZE+1];
  976. char *pLastNewLine=NULL;
  977. char chLastChr[3];
  978. DWORD dwBytesRead;
  979. DWORD dwIndex=0;
  980. char szEmpLine[5];
  981. chLastChr[0]='\0';
  982. chLastChr[1]='\0';
  983. chLastChr[2]='\0';
  984. szEmpLine[4]='\0';
  985. while(bMoreToRead)
  986. {
  987. if( !ReadFile(hFile,
  988. szBuffer,
  989. LOCAL_FILE_BUFFER_SIZE,
  990. &dwBytesRead,
  991. NULL) )
  992. {
  993. return FALSE;
  994. }
  995. szBuffer[dwBytesRead]='\0';
  996. if(dwBytesRead < LOCAL_FILE_BUFFER_SIZE)
  997. {
  998. bMoreToRead=FALSE;
  999. }
  1000. for( dwIndex=0;dwIndex<dwBytesRead && (!bHeadersDone || iLines >0); dwIndex++)
  1001. {
  1002. if('\n'==szBuffer[dwIndex])
  1003. {
  1004. if(bHeadersDone)
  1005. {
  1006. //The headers are done
  1007. //Count the lines now
  1008. if(dwIndex>0)
  1009. {
  1010. if('\r'==szBuffer[dwIndex-1])
  1011. {
  1012. iLines--;
  1013. }
  1014. }
  1015. else
  1016. {
  1017. if('\r'==chLastChr[2])
  1018. {
  1019. iLines--;
  1020. chLastChr[2]='\0';
  1021. }
  1022. }
  1023. }
  1024. else
  1025. {
  1026. int i=4;
  1027. do
  1028. {
  1029. i--;
  1030. szEmpLine[i]=szBuffer[dwIndex+i-3];
  1031. }while((dwIndex+i-3>0) && i>0 );
  1032. if(i>0)
  1033. {
  1034. i--;
  1035. for(int j=2; i>=0 && j>=0; j--,i--)
  1036. {
  1037. szEmpLine[i]=chLastChr[j];
  1038. }
  1039. }
  1040. if(0==strcmp(szEmpLine, "\r\n\r\n"))
  1041. {
  1042. bHeadersDone=TRUE;
  1043. }
  1044. }
  1045. }
  1046. }
  1047. if(iLines==0)
  1048. {
  1049. (*pdwBytesToRead)+=dwIndex;
  1050. bMoreToRead=FALSE;
  1051. }
  1052. else
  1053. {
  1054. (*pdwBytesToRead)+=dwBytesRead;
  1055. chLastChr[2]=szBuffer[dwIndex-1];
  1056. if(!bHeadersDone)
  1057. {
  1058. chLastChr[1]=szBuffer[dwIndex-2];
  1059. chLastChr[0]=szBuffer[dwIndex-3];
  1060. }
  1061. }
  1062. }
  1063. if(iLines>0)
  1064. {
  1065. (*pdwBytesToRead)=0;
  1066. }
  1067. return TRUE;
  1068. }
  1069. bool CMailBox::PushMailToVector(PMAIL_ITEM pMail)
  1070. {
  1071. PMAIL_ITEM *pTemp;
  1072. DWORD dwNewMailVectorSize=0;
  1073. if(pMail==NULL)
  1074. {
  1075. return false;
  1076. }
  1077. if(m_cMailCount>=m_dwSizeOfMailVector)
  1078. {
  1079. if(m_MailVector)
  1080. {
  1081. dwNewMailVectorSize=m_dwSizeOfMailVector*2;
  1082. pTemp=new PMAIL_ITEM[dwNewMailVectorSize];
  1083. if(pTemp)
  1084. {
  1085. memset(pTemp, 0, dwNewMailVectorSize*sizeof(PMAIL_ITEM));
  1086. memcpy(pTemp, m_MailVector, m_dwSizeOfMailVector*sizeof(PMAIL_ITEM));
  1087. delete[] m_MailVector;
  1088. m_MailVector=pTemp;
  1089. m_dwSizeOfMailVector=dwNewMailVectorSize;
  1090. m_MailVector[m_cMailCount]=pMail;
  1091. }
  1092. else
  1093. {
  1094. return false;
  1095. }
  1096. }
  1097. else
  1098. {
  1099. m_MailVector=new PMAIL_ITEM[DEFAULT_MAIL_VECTOR_SIZE];
  1100. if(m_MailVector)
  1101. {
  1102. memset(m_MailVector, 0, DEFAULT_MAIL_VECTOR_SIZE*sizeof(PMAIL_ITEM));
  1103. m_MailVector[m_cMailCount]=pMail;
  1104. m_dwSizeOfMailVector=DEFAULT_MAIL_VECTOR_SIZE;
  1105. }
  1106. else
  1107. {
  1108. return false;
  1109. }
  1110. }
  1111. return true;
  1112. }
  1113. else
  1114. {
  1115. m_MailVector[m_cMailCount]=pMail;
  1116. return true;
  1117. }
  1118. }