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.

878 lines
25 KiB

  1. #define INCL_INETSRV_INCS
  2. #include "smtpinc.h"
  3. #include "remoteq.hxx"
  4. #include "dropdir.hxx"
  5. DWORD g_dwDropFileCounter = 0;
  6. CPool CDropDir::m_Pool(DROPDIR_SIG);
  7. //////////////////////////////////////////////////////////////////////////////
  8. VOID
  9. DropDirWriteCompletion(
  10. PVOID pvContext,
  11. DWORD cbWritten,
  12. DWORD dwCompletionStatus,
  13. OVERLAPPED * lpo
  14. )
  15. {
  16. DECL_TRACE((LPARAM) 0xC0DEC0DE, "DropDirWriteCompletion");
  17. BOOL WasProcessed = TRUE;
  18. CDropDir *pCC = (CDropDir *) pvContext;
  19. _ASSERT(pCC);
  20. pCC->SetHr( pCC->OnIoWriteCompletion(cbWritten, dwCompletionStatus, lpo) );
  21. SAFE_RELEASE( pCC );
  22. }
  23. //////////////////////////////////////////////////////////////////////////////
  24. VOID
  25. DropDirReadCompletion(
  26. PFIO_CONTEXT pContext,
  27. PFH_OVERLAPPED lpo,
  28. DWORD cbRead,
  29. DWORD dwCompletionStatus
  30. )
  31. {
  32. DECL_TRACE((LPARAM) 0xC0DEC0DE, "DropDirReadCompletion");
  33. BOOL WasProcessed = TRUE;
  34. DROPDIR_READ_OVERLAPPED *p = (DROPDIR_READ_OVERLAPPED *) lpo;
  35. CDropDir *pCC = (CDropDir*) p->ThisPtr;
  36. _ASSERT(pCC);
  37. pCC->SetHr( pCC->OnIoReadCompletion(cbRead, dwCompletionStatus, (LPOVERLAPPED)lpo) );
  38. SAFE_RELEASE( pCC );
  39. }
  40. //////////////////////////////////////////////////////////////////////////////
  41. CDropDir::CDropDir()
  42. {
  43. DECL_TRACE((LPARAM) this, "CDropDir::CDropDir");
  44. m_dwSig = DROPDIR_SIG;
  45. m_cRef = 1;
  46. m_NumRcpts = 0;
  47. m_hDrop = INVALID_HANDLE_VALUE;
  48. m_hMail = NULL;
  49. m_AdvContext = NULL;
  50. m_rgRcptIndexList = NULL;
  51. m_pIMsg = NULL;
  52. m_pBindInterface = NULL;
  53. m_pAtqContext = NULL;
  54. CopyMemory( m_acCrLfDotCrLf, "\r\n.\r\n", 5 );
  55. ZeroMemory( m_acLastBytes, 5 );
  56. m_pIMsgRecips = NULL;
  57. m_hr = S_OK;
  58. m_cbWriteOffset = 0;
  59. m_cbReadOffset = 0;
  60. m_cbMsgWritten = 0;
  61. m_idxRecips = 0;
  62. ZeroMemory( &m_WriteOverlapped, sizeof( m_WriteOverlapped ) );
  63. ZeroMemory( &m_ReadOverlapped, sizeof( m_ReadOverlapped ) );
  64. m_szDropDir[0] = '\0';
  65. m_pISMTPConnection = NULL;
  66. m_ReadState = DROPDIR_READ_NULL;
  67. m_WriteState = DROPDIR_WRITE_NULL;
  68. m_pParentInst = NULL;
  69. }
  70. //////////////////////////////////////////////////////////////////////////////
  71. CDropDir::~CDropDir()
  72. {
  73. DECL_TRACE((LPARAM) this, "CDropDir::~CDropDir");
  74. SAFE_RELEASE( m_pIMsgRecips );
  75. if(m_pBindInterface)
  76. {
  77. m_pBindInterface->ReleaseContext();
  78. SAFE_RELEASE(m_pBindInterface);
  79. }
  80. m_MsgAck.pIMailMsgProperties = m_pIMsg;
  81. m_MsgAck.pvMsgContext = (DWORD *) m_AdvContext;
  82. if(SUCCEEDED(m_hr))
  83. {
  84. m_MsgAck.dwMsgStatus = MESSAGE_STATUS_ALL_DELIVERED;
  85. }
  86. else
  87. {
  88. m_MsgAck.dwMsgStatus = MESSAGE_STATUS_RETRY_ALL;
  89. }
  90. m_MsgAck.dwStatusCode = 0;
  91. m_pISMTPConnection->AckMessage(&m_MsgAck);
  92. SAFE_RELEASE(m_pIMsg);
  93. if(SUCCEEDED(m_hr))
  94. {
  95. BUMP_COUNTER( m_pParentInst, DirectoryDrops);
  96. }
  97. if(SUCCEEDED(m_hr))
  98. {
  99. m_pISMTPConnection->AckConnection(CONNECTION_STATUS_OK);
  100. }
  101. else
  102. {
  103. SetLastError( 0x0000FFFF & m_hr );
  104. m_pISMTPConnection->AckConnection(CONNECTION_STATUS_FAILED);
  105. }
  106. PATQ_CONTEXT pAtqContext = (PATQ_CONTEXT)InterlockedExchangePointer( (PVOID *)&m_pAtqContext, NULL);
  107. if ( pAtqContext != NULL )
  108. {
  109. if(m_hDrop != INVALID_HANDLE_VALUE)
  110. AtqCloseFileHandle( pAtqContext );
  111. AtqFreeContext( pAtqContext, TRUE );
  112. }
  113. // If we failed to completely write the message, delete the drop file
  114. if (FAILED(m_hr))
  115. {
  116. DeleteFile(m_szDropFile);
  117. }
  118. //
  119. // Now get the next message on this connection and
  120. // copy it to drop directory.
  121. //
  122. if (m_szDropDir[0])
  123. AsyncCopyMailToDropDir( m_pISMTPConnection, m_szDropDir, m_pParentInst );
  124. SAFE_RELEASE( m_pISMTPConnection );
  125. m_dwSig = DROPDIR_SIG_FREE;
  126. }
  127. //---[ CDropDir::CopyMailToDropDir ]-------------------------------------------
  128. //
  129. //
  130. // Description:
  131. //
  132. // Entry point to the Async writing to the mail file. When this is called
  133. // it sets up a series of alternating reads and writes (read from the queue
  134. // and write to the mail file). The (rough description of the) algorithm is
  135. // as follows:
  136. //
  137. // WriteHeaders()
  138. // Post Async Read from MailFile
  139. // return
  140. //
  141. // Read Completion function()
  142. // Post Async Write of Data to DropDir
  143. // return
  144. //
  145. // Write Completion function()
  146. // Post Async Read from MailFile
  147. // return
  148. //
  149. // Called by
  150. // AsyncCopyMailToDropDir()
  151. //
  152. // Parameters:
  153. //
  154. // Returns:
  155. //
  156. // History:
  157. // Created by PGOPI
  158. // 3/25/99 - MikeSwa modified for checkin
  159. //
  160. //-----------------------------------------------------------------------------
  161. HRESULT CDropDir::CopyMailToDropDir(
  162. ISMTPConnection *pISMTPConnection,
  163. const char *DropDirectory,
  164. IMailMsgProperties *pIMsg,
  165. PVOID AdvContext,
  166. DWORD NumRcpts,
  167. DWORD *rgRcptIndexList,
  168. SMTP_SERVER_INSTANCE *pParentInst)
  169. {
  170. DECL_TRACE((LPARAM) this, "CDropDir::CopyMailToDropDir");
  171. HRESULT hr = S_OK;
  172. m_pISMTPConnection = pISMTPConnection;
  173. SAFE_ADDREF( m_pISMTPConnection );
  174. m_pIMsg = pIMsg;
  175. SAFE_ADDREF( m_pIMsg );
  176. m_pParentInst = pParentInst;
  177. m_AdvContext = AdvContext;
  178. m_NumRcpts = NumRcpts;
  179. m_rgRcptIndexList = rgRcptIndexList;
  180. if (!DropDirectory)
  181. {
  182. hr = E_INVALIDARG;
  183. goto error_exit;
  184. }
  185. //Copy drop directory now... so we have a copy in the destructor
  186. //even if this message cannot be dropped
  187. lstrcpy(m_szDropDir, DropDirectory);
  188. hr = m_pIMsg->QueryInterface(IID_IMailMsgBind, (void **)&m_pBindInterface);
  189. if(FAILED(hr))
  190. {
  191. ErrorTrace( (LPARAM)this, "m_pIMsg->QueryInterface for IID_IMailMsgBind return hr = 0x%x", hr );
  192. goto error_exit;
  193. }
  194. hr = m_pBindInterface->GetBinding(&m_hMail, NULL);
  195. if(FAILED(hr))
  196. {
  197. ErrorTrace( (LPARAM)this, "GetBinding return hr = 0x%x", hr );
  198. goto error_exit;
  199. }
  200. hr = m_pIMsg->QueryInterface( IID_IMailMsgRecipients, (PVOID *) &m_pIMsgRecips);
  201. if( FAILED( hr ) )
  202. {
  203. ErrorTrace( (LPARAM)this, "QueryInterface for IID_IMailMsgRecipients failed hr = 0x%x", hr );
  204. goto error_exit;
  205. }
  206. if( CheckIfAllRcptsHandled() )
  207. {
  208. goto exit;
  209. }
  210. DebugTrace((LPARAM)this, "Dropping file to: %s", DropDirectory);
  211. m_hDrop = CreateDropFile(DropDirectory);
  212. if (m_hDrop == INVALID_HANDLE_VALUE)
  213. {
  214. hr = HRESULT_FROM_WIN32( GetLastError() );
  215. ErrorTrace( (LPARAM)this, "Unable to create drop directory (%s) : 0x%x", DropDirectory, hr);
  216. goto error_exit;
  217. }
  218. if (!AtqAddAsyncHandle( &m_pAtqContext,
  219. NULL,
  220. (LPVOID) this,
  221. DropDirWriteCompletion,
  222. INFINITE,
  223. m_hDrop))
  224. {
  225. hr = HRESULT_FROM_WIN32( GetLastError() );
  226. ErrorTrace((LPARAM)this, "Error 0x%x while adding async handle to ATQ", hr);
  227. goto error_exit;
  228. }
  229. // Output the x-headers
  230. if (FAILED( hr = CreateXHeaders() ) )
  231. {
  232. ErrorTrace( (LPARAM)this, " Error while creating x-headers hr = 0x%x", hr);
  233. goto error_exit;
  234. }
  235. exit:
  236. return( hr );
  237. error_exit:
  238. // If we failed here we must make sure we bubble up the failure so
  239. // it will be seen in the destructor - if we succeeded it is dangerous
  240. // to set this since we could overwrite a failure code written in the
  241. // async path resulting from CreateXHeaders (so we don't do that!)
  242. SetHr(hr);
  243. goto exit;
  244. }
  245. //////////////////////////////////////////////////////////////////////////////
  246. HANDLE CDropDir::CreateDropFile(const char * DropDir)
  247. {
  248. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  249. DWORD dwStrLen;
  250. FILETIME ftTime;
  251. DWORD Error = 0;
  252. DECL_TRACE((LPARAM)this, "CDropDir::CreateDropFile");
  253. dwStrLen = lstrlen(DropDir);
  254. lstrcpy(m_szDropFile, DropDir);
  255. do
  256. {
  257. GetSystemTimeAsFileTime(&ftTime);
  258. wsprintf(&m_szDropFile[dwStrLen],
  259. "%08x%08x%08x%s",
  260. ftTime.dwLowDateTime,
  261. ftTime.dwHighDateTime,
  262. InterlockedIncrement((PLONG)&g_dwDropFileCounter),
  263. ".eml");
  264. FileHandle = CreateFile(m_szDropFile,
  265. GENERIC_READ | GENERIC_WRITE,
  266. FILE_SHARE_READ | FILE_SHARE_WRITE,
  267. NULL,
  268. CREATE_NEW,
  269. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED,
  270. NULL);
  271. if (FileHandle != INVALID_HANDLE_VALUE)
  272. break;
  273. if((Error = GetLastError()) != ERROR_FILE_EXISTS)
  274. {
  275. FileHandle = INVALID_HANDLE_VALUE;
  276. ErrorTrace( (LPARAM)this, "CreateFile returns err = %u", Error );
  277. break;
  278. }
  279. } while( (FileHandle == INVALID_HANDLE_VALUE) && !m_pParentInst->IsShuttingDown());
  280. return (FileHandle);
  281. }
  282. //////////////////////////////////////////////////////////////////////////////
  283. HRESULT CDropDir::ReadFile(
  284. IN LPVOID pBuffer,
  285. IN DWORD cbSize
  286. )
  287. {
  288. DECL_TRACE((LPARAM) this, "CDropDir::ReadFile");
  289. HRESULT hr = S_OK;
  290. _ASSERT(pBuffer != NULL);
  291. m_ReadOverlapped.Overlapped.Offset = LODWORD( m_cbReadOffset );
  292. m_ReadOverlapped.Overlapped.OffsetHigh = HIDWORD( m_cbReadOffset );
  293. m_ReadOverlapped.Overlapped.pfnCompletion = DropDirReadCompletion;
  294. m_ReadOverlapped.ThisPtr = (PVOID)this;
  295. AddRef();
  296. BOOL fRet = FIOReadFile( m_hMail,
  297. pBuffer, // Buffer
  298. cbSize, // BytesToRead
  299. (PFH_OVERLAPPED)&m_ReadOverlapped) ;
  300. if(!fRet)
  301. {
  302. DWORD err = GetLastError();
  303. if( err != ERROR_IO_PENDING )
  304. {
  305. hr = HRESULT_FROM_WIN32( err );
  306. ErrorTrace( (LPARAM)this, "FIOReadFile return hr = 0x%x", hr );
  307. }
  308. }
  309. if( FAILED( hr ) )
  310. {
  311. Release();
  312. }
  313. return hr;
  314. }
  315. //////////////////////////////////////////////////////////////////////////////
  316. HRESULT CDropDir::WriteFile(
  317. IN LPVOID pBuffer,
  318. IN DWORD cbSize
  319. )
  320. {
  321. DECL_TRACE((LPARAM) this, "CDropDir::WriteFile");
  322. CDropDir *p = this;
  323. _ASSERT(pBuffer != NULL);
  324. _ASSERT(cbSize > 0);
  325. HRESULT hr = S_OK;
  326. m_WriteOverlapped.Offset = LODWORD( m_cbWriteOffset );
  327. m_WriteOverlapped.OffsetHigh = HIDWORD( m_cbWriteOffset );
  328. AddRef();
  329. BOOL fRet = AtqWriteFile( m_pAtqContext, // Atq context
  330. pBuffer, // Buffer
  331. cbSize, // BytesToRead
  332. (OVERLAPPED *) &m_WriteOverlapped) ;
  333. if(!fRet)
  334. {
  335. DWORD err = GetLastError();
  336. if( err != ERROR_IO_PENDING )
  337. {
  338. hr = HRESULT_FROM_WIN32( err );
  339. ErrorTrace( (LPARAM)this, "AtqWriteFile return hr = 0x%x", hr );
  340. }
  341. }
  342. if( FAILED( hr ) )
  343. {
  344. Release();
  345. }
  346. return( hr );
  347. }
  348. //////////////////////////////////////////////////////////////////////////////
  349. HRESULT CDropDir::OnIoWriteCompletion( DWORD cbSize, DWORD dwErr, OVERLAPPED *lpo )
  350. {
  351. DECL_TRACE((LPARAM) this, "CDropDir::OnIoWriteCompletion");
  352. HRESULT hr = S_OK;
  353. if( dwErr != NO_ERROR )
  354. {
  355. ErrorTrace( (LPARAM)this, "OnIoWriteCompletion got err = %u", dwErr );
  356. return( HRESULT_FROM_WIN32( dwErr ) );
  357. }
  358. m_cbWriteOffset += cbSize;
  359. switch( m_ReadState )
  360. {
  361. case DROPDIR_READ_X_SENDER:
  362. _ASSERT(!"Invalid State READ_X_SENDER");
  363. hr = E_INVALIDARG;
  364. break;
  365. case DROPDIR_READ_X_RECEIVER:
  366. hr = CreateXRecvHeaders();
  367. break;
  368. case DROPDIR_READ_DATA:
  369. hr = OnCopyMessageWrite( cbSize);
  370. break;
  371. default:
  372. _ASSERT(!"INVALID read STATE");
  373. hr = E_INVALIDARG;
  374. ErrorTrace( (LPARAM)this, "Invalid ReadState" );
  375. break;
  376. }
  377. return( hr );
  378. }
  379. //////////////////////////////////////////////////////////////////////////////
  380. HRESULT CDropDir::OnIoReadCompletion( DWORD cbSize, DWORD dwErr, OVERLAPPED *lpo )
  381. {
  382. DECL_TRACE((LPARAM) this, "CDropDir::OnIoReadCompletion");
  383. HRESULT hr = S_OK;
  384. if( ( dwErr != NO_ERROR ) && ( dwErr != ERROR_HANDLE_EOF ) )
  385. {
  386. hr = HRESULT_FROM_WIN32( dwErr );
  387. ErrorTrace( (LPARAM)this, "OnIOReadCompletion got hr = 0x%x", hr );
  388. }
  389. else
  390. {
  391. m_cbReadOffset += cbSize;
  392. hr = OnCopyMessageRead( cbSize, dwErr );
  393. }
  394. return( hr );
  395. }
  396. ///////////////////////////////////////////////////////////////////////////
  397. HRESULT CDropDir::CreateXHeaders()
  398. {
  399. DECL_TRACE(((LPARAM) this), "CDropDir::CreateXHeaders");
  400. HRESULT hr = S_OK;
  401. DebugTrace( (LPARAM)this, "Setting m_ReadState = DROPDIR_READ_X_SENDER" );
  402. m_ReadState = DROPDIR_READ_X_SENDER;
  403. strcpy( m_szBuffer, X_SENDER_HEADER );
  404. hr = m_pIMsg->GetStringA( IMMPID_MP_SENDER_ADDRESS_SMTP, MAX_INTERNET_NAME, &m_szBuffer[ sizeof(X_SENDER_HEADER) - 1] );
  405. if(SUCCEEDED(hr))
  406. {
  407. strcat( m_szBuffer, X_HEADER_EOLN);
  408. //
  409. // this WriteFile will complete async, so set the next read state.
  410. // Make Sure that no class member variables are acessed after calling
  411. // WriteFile or ReadFile as they complete async & there is no critical
  412. // section protecting access.To do this trace through all paths
  413. // thru which ReadFile and WriteFile are called and make sure no member
  414. // variables are accessed.
  415. m_ReadState = DROPDIR_READ_X_RECEIVER;
  416. DebugTrace( (LPARAM)this, "Setting m_ReadState = DROPDIR_READ_X_RECEIVER" );
  417. //
  418. if( FAILED( hr = WriteFile( m_szBuffer, strlen( m_szBuffer ) ) ) )
  419. {
  420. ErrorTrace((LPARAM)this, "Error %d writing x-sender line %s", hr, m_szBuffer);
  421. return( hr );
  422. }
  423. }
  424. else
  425. {
  426. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  427. ErrorTrace((LPARAM)this, "Could not get Sender Address returning hr = 0x%x", hr);
  428. return( hr );
  429. }
  430. return( hr );
  431. }
  432. ///////////////////////////////////////////////////////////////////////////
  433. HRESULT CDropDir::CreateXRecvHeaders()
  434. {
  435. DECL_TRACE((LPARAM) this, "CDropDir::CreateXRecvHeaders");
  436. HRESULT hr = S_OK;
  437. DWORD dwRecipientFlags = 0;
  438. BOOL fPendingWrite = FALSE;
  439. strcpy( m_szBuffer, X_RECEIVER_HEADER );
  440. while( m_idxRecips < m_NumRcpts )
  441. {
  442. hr = m_pIMsgRecips->GetDWORD( m_rgRcptIndexList[m_idxRecips], IMMPID_RP_RECIPIENT_FLAGS,&dwRecipientFlags);
  443. if( SUCCEEDED( hr ) )
  444. {
  445. if( RP_HANDLED != ( dwRecipientFlags & RP_HANDLED ) )
  446. {
  447. hr = m_pIMsgRecips->GetStringA( m_rgRcptIndexList[m_idxRecips],
  448. IMMPID_RP_ADDRESS_SMTP,
  449. MAX_INTERNET_NAME,
  450. &m_szBuffer[ sizeof(X_RECEIVER_HEADER) - 1 ]);
  451. if (SUCCEEDED(hr))
  452. {
  453. strcat(m_szBuffer, X_HEADER_EOLN);
  454. // Make Sure that no class member variables are acessed after calling
  455. // WriteFile or ReadFile as they complete async & there is no critical
  456. // section protecting access.To do this trace through all paths
  457. // thru which ReadFile and WriteFile are called and make sure no member
  458. // variables are accessed.
  459. m_idxRecips++;
  460. if(FAILED( hr = WriteFile(m_szBuffer, strlen(m_szBuffer) ) ) )
  461. {
  462. ErrorTrace( (LPARAM)this, "WriteFile return hr = 0x%x", hr );
  463. return( hr );
  464. }
  465. fPendingWrite = TRUE;
  466. break;
  467. }
  468. else
  469. {
  470. ErrorTrace( (LPARAM)this, "GetStringA for IMMPID_RP_ADDRESS_SMTP returns hr = 0x%x", hr );
  471. return( hr );
  472. }
  473. }
  474. else
  475. {
  476. m_idxRecips++;
  477. }
  478. }
  479. else
  480. {
  481. ErrorTrace( (LPARAM)this, "GetDWORD for IMMPID_RP_RECIPIENT_FLAGS returns hr = 0x%x", hr );
  482. return( hr );
  483. }
  484. }
  485. if( !fPendingWrite )
  486. {
  487. m_ReadState = DROPDIR_READ_DATA;
  488. m_WriteState = DROPDIR_WRITE_DATA;
  489. DebugTrace( (LPARAM)this, "Setting m_WriteState & m_ReadState to WRITE_DATA & READ_DATA respectively" );
  490. return( CopyMessage() );
  491. }
  492. return( hr );
  493. }
  494. ///////////////////////////////////////////////////////////////////////////
  495. HRESULT CDropDir::CopyMessage()
  496. {
  497. DECL_TRACE((LPARAM) this, "CDropDir::CopyMessage");
  498. // Make Sure that no class member variables are acessed after calling
  499. // WriteFile or ReadFile as they complete async & there is no critical
  500. // section protecting access.To do this trace through all paths
  501. // thru which ReadFile and WriteFile are called and make sure no member
  502. // variables are accessed.
  503. HRESULT hr = ReadFile( m_szBuffer, sizeof( m_szBuffer ) );
  504. if( hr == HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) )
  505. {
  506. m_WriteState = DROPDIR_WRITE_CRLF;
  507. DebugTrace( (LPARAM)this, "ReadFile returns err = ERROR_HANDLE_EOF, Setting m_WriteState = DROPDIR_WRITE_CRLF" );
  508. return( DoLastFileOp() );
  509. }
  510. return( hr );
  511. }
  512. ///////////////////////////////////////////////////////////////////////////
  513. HRESULT CDropDir::OnCopyMessageRead( DWORD dwBytesRead, DWORD dwErr )
  514. {
  515. DECL_TRACE((LPARAM) this, "CDropDir::OnCopyMessageRead");
  516. HRESULT hr = S_OK;
  517. if (dwBytesRead )
  518. {
  519. if (dwBytesRead > 4)
  520. {
  521. CopyMemory(m_acLastBytes, &m_szBuffer[dwBytesRead-5], 5);
  522. }
  523. else
  524. {
  525. MoveMemory(m_acLastBytes, &m_acLastBytes[dwBytesRead], 5-dwBytesRead);
  526. CopyMemory(&m_acLastBytes[5-dwBytesRead], m_szBuffer, dwBytesRead);
  527. }
  528. //
  529. // the write file will complete async & then we'll do the
  530. // last fileop.
  531. //
  532. if( dwErr == ERROR_HANDLE_EOF )
  533. {
  534. DebugTrace( (LPARAM)this, " Interesting case err = ERROR_HANDLE_EOF, Setting m_WriteState = DROPDIR_WRITE_CRLF" );
  535. m_WriteState = DROPDIR_WRITE_CRLF;
  536. }
  537. // Make Sure that no class member variables are acessed after calling
  538. // WriteFile or ReadFile as they complete async & there is no critical
  539. // section protecting access.To do this trace through all paths
  540. // thru which ReadFile and WriteFile are called and make sure no member
  541. // variables are accessed.
  542. if ( FAILED( hr = WriteFile(m_szBuffer, dwBytesRead ) ) )
  543. {
  544. ErrorTrace( (LPARAM)this, "WriteFile return hr = 0x%x", hr );
  545. return( hr );
  546. }
  547. }
  548. else
  549. {
  550. m_WriteState = DROPDIR_WRITE_CRLF;
  551. DebugTrace( (LPARAM)this, "Setting m_WriteState = DROPDIR_WRITE_CRLF" );
  552. return( DoLastFileOp() );
  553. }
  554. return( hr );
  555. }
  556. ///////////////////////////////////////////////////////////////////////////
  557. HRESULT CDropDir::OnCopyMessageWrite( DWORD cbWritten )
  558. {
  559. DECL_TRACE((LPARAM) this, "CDropDir::OnCopyMessageWrite");
  560. HRESULT hr = S_OK;
  561. m_cbMsgWritten += cbWritten;
  562. switch( m_WriteState )
  563. {
  564. case DROPDIR_WRITE_DATA:
  565. return( CopyMessage() );
  566. break;
  567. case DROPDIR_WRITE_CRLF:
  568. return( DoLastFileOp() );
  569. break;
  570. case DROPDIR_WRITE_SETPOS:
  571. return( AdjustFilePos() );
  572. break;
  573. default:
  574. _ASSERT(!"Invalid WriteState");
  575. ErrorTrace( (LPARAM)this, "Invalid WriteState" );
  576. hr = E_INVALIDARG;
  577. break;
  578. }
  579. return( hr );
  580. }
  581. ///////////////////////////////////////////////////////////////////////////
  582. HRESULT CDropDir::DoLastFileOp()
  583. {
  584. DECL_TRACE((LPARAM) this, "CDropDir::DoLastFileOp");
  585. HRESULT hr = S_OK;
  586. DebugTrace( (LPARAM)this, "DoLastFileOp called" );
  587. // Now, see if the file ends with a CRLF, if not, add it
  588. if ((m_cbMsgWritten > 1) && memcmp(&m_acLastBytes[3], &m_acCrLfDotCrLf[3], 2))
  589. {
  590. //
  591. // the write will complete async. set next write state
  592. //
  593. DebugTrace( (LPARAM)this, "Setting m_WriteState = DROPDIR_WRITE_SETPOS" );
  594. m_WriteState = DROPDIR_WRITE_SETPOS;
  595. // Make Sure that no class member variables are acessed after calling
  596. // WriteFile or ReadFile as they complete async & there is no critical
  597. // section protecting access.To do this trace through all paths
  598. // thru which ReadFile and WriteFile are called and make sure no member
  599. // variables are accessed.
  600. // Add the trailing CRLF
  601. if(FAILED( hr = WriteFile(m_acCrLfDotCrLf, 2 ) ) )
  602. {
  603. ErrorTrace( (LPARAM)this, "WriteFile returns hr = 0x%x", hr );
  604. return(hr);
  605. }
  606. }
  607. else
  608. {
  609. DebugTrace( (LPARAM)this, "Setting m_WriteState = DROPDIR_WRITE_SETPOS" );
  610. m_WriteState = DROPDIR_WRITE_SETPOS;
  611. return( AdjustFilePos() );
  612. }
  613. return( hr );
  614. }
  615. ///////////////////////////////////////////////////////////////////////////
  616. HRESULT CDropDir::AdjustFilePos()
  617. {
  618. DECL_TRACE((LPARAM) this, "CDropDir::AdjustFilePos");
  619. HRESULT hr = S_OK;
  620. DebugTrace( (LPARAM)this, "AdjustFilePos called" );
  621. //If file ends with CRLF.CRLF, remove the trailing .CRLF
  622. //Do not modify the file otherwise
  623. DWORD dwLo = LODWORD( m_cbWriteOffset );
  624. DWORD dwHi = HIDWORD( m_cbWriteOffset );
  625. if ((m_cbMsgWritten > 4) && !memcmp(m_acLastBytes, m_acCrLfDotCrLf, 5))
  626. {
  627. DebugTrace( (LPARAM)this, "Removing the trailing CRLF-DOT-CRLF" );
  628. // Remove the trailing .CRLF
  629. if ((SetFilePointer(m_hDrop, dwLo-3, (LONG*)&dwHi, FILE_BEGIN) == 0xffffffff) ||
  630. !SetEndOfFile(m_hDrop))
  631. {
  632. hr = HRESULT_FROM_WIN32( GetLastError() );
  633. ErrorTrace( (LPARAM)this, "SetFilePointer or SetEndofFile return hr = 0x%x", hr );
  634. return( hr );
  635. }
  636. }
  637. //We need to flush the context before ACK'ing the message
  638. if (!FlushFileBuffers(m_hDrop))
  639. {
  640. hr = HRESULT_FROM_WIN32( GetLastError() );
  641. if (SUCCEEDED(hr))
  642. hr = E_FAIL;
  643. ErrorTrace( (LPARAM)this, "FlushFileBuffers failed with hr = 0x%x", hr );
  644. return( hr );
  645. }
  646. hr = SetAllRcptsHandled();
  647. if( FAILED( hr ) )
  648. {
  649. ErrorTrace( (LPARAM)this, "SetAllRcptsHandledreturn hr = 0x%x", hr );
  650. return( hr );
  651. }
  652. return( hr );
  653. }
  654. //////////////////////////////////////////////////////////////////////////////
  655. BOOL CDropDir::CheckIfAllRcptsHandled()
  656. {
  657. DECL_TRACE((LPARAM) this, "CDropDir::CheckIfAllRcptsHandled");
  658. BOOL fRet = TRUE;
  659. for( DWORD i = 0; i < m_NumRcpts; i++ )
  660. {
  661. if ( m_rgRcptIndexList[i] != INVALID_RCPT_IDX_VALUE)
  662. {
  663. DWORD dwRecipientFlags = 0;
  664. HRESULT hr = m_pIMsgRecips->GetDWORD(m_rgRcptIndexList[i], IMMPID_RP_RECIPIENT_FLAGS,&dwRecipientFlags);
  665. if (FAILED(hr))
  666. {
  667. fRet = FALSE;
  668. break;
  669. }
  670. if( RP_HANDLED != ( dwRecipientFlags & RP_HANDLED ) )
  671. {
  672. fRet = FALSE;
  673. break;
  674. }
  675. }
  676. }
  677. return( fRet );
  678. }
  679. //////////////////////////////////////////////////////////////////////////////
  680. HRESULT CDropDir::SetAllRcptsHandled()
  681. {
  682. DECL_TRACE((LPARAM) this, "CDropDir::SetAllRcptsHandled");
  683. HRESULT hr = S_OK;
  684. for( DWORD i = 0; i < m_NumRcpts; i++ )
  685. {
  686. if (m_rgRcptIndexList[i] != INVALID_RCPT_IDX_VALUE)
  687. {
  688. DWORD dwRecipientFlags = 0;
  689. hr = m_pIMsgRecips->GetDWORD(m_rgRcptIndexList[i], IMMPID_RP_RECIPIENT_FLAGS,&dwRecipientFlags);
  690. if (FAILED(hr))
  691. {
  692. break;
  693. }
  694. if( RP_HANDLED != ( dwRecipientFlags & RP_HANDLED ) )
  695. {
  696. dwRecipientFlags |= RP_DELIVERED;
  697. hr = m_pIMsgRecips->PutDWORD(m_rgRcptIndexList[i], IMMPID_RP_RECIPIENT_FLAGS,dwRecipientFlags);
  698. if (FAILED(hr))
  699. {
  700. break;
  701. }
  702. }
  703. }
  704. }
  705. return( hr );
  706. }