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.

1081 lines
38 KiB

  1. // P2EWorker.cpp: implementation of the CP2EWorker class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "P2EWorker.h"
  6. #include "resource.h"
  7. #include "resource2.h"
  8. #include <sbs6base.h>
  9. #include <P3Admin.h>
  10. #include <pop3server.h>
  11. #include <logutil.h>
  12. #include <mailbox.h>
  13. #include "UserInfo.h"
  14. #include <AuthID.h>
  15. #include <FormatMessage.h>
  16. #include <atlbase.h>
  17. #include <comdef.h>
  18. #include <dsgetdc.h>
  19. #include <lm.h>
  20. #include <tchar.h>
  21. #include <stdio.h>
  22. #include <ws2tcpip.h>
  23. //#include <mswsock.h>
  24. #include <AuthUtil.h>
  25. #ifndef ASSERT
  26. #define ASSERT assert
  27. #endif
  28. LOGFILE(L"Pop2ExchLog.txt");
  29. #define SMTP_BUFFERSIZE 2048
  30. #define SMTP_QUIT "QUIT\r\n"
  31. #define SMTP_DATA "DATA\r\n"
  32. #define SMTP_DATA_END "\r\n.\r\n"
  33. #define SMTP_RSET "RSET\r\n"
  34. #define SMTP_MSG220 "220" // 220 <domain> Service ready
  35. #define SMTP_MSG221 "221" // 221 <domain> Service ready
  36. #define SMTP_MSG250 "250" // 250 Requested mail action okay, completed
  37. #define SMTP_MSG354 "354" // 354 Start mail input; end with <CRLF>.<CRLF>
  38. //////////////////////////////////////////////////////////////////////
  39. // Construction/Destruction
  40. //////////////////////////////////////////////////////////////////////
  41. CP2EWorker::CP2EWorker() :
  42. m_bSuppressPrintError( false )
  43. {
  44. }
  45. CP2EWorker::~CP2EWorker()
  46. {
  47. }
  48. //////////////////////////////////////////////////////////////////////
  49. // Implementation : public
  50. //////////////////////////////////////////////////////////////////////
  51. int CP2EWorker::CreateUser(int argc, wchar_t *argv[], const bool bCreateUser, const bool bCreateMailbox)
  52. {
  53. USES_CONVERSION;
  54. HRESULT hr;
  55. VARIANT v;
  56. BSTR bstrName, bstrEmailName;
  57. _bstr_t _bstrDomainName;
  58. CComPtr<IP3Config> spIConfig;
  59. CComPtr<IP3Domains> spIDomains;
  60. IP3Domain *pIDomain = NULL;
  61. CComPtr<IEnumVARIANT> spIEnumVARIANT;
  62. bool bErrors = false, bIgnoreErrors = false, bUnregisterDependencies = false;
  63. char sPassword[MAX_PATH];
  64. CUserInfo userInfoX;
  65. if ( 4 != argc && 3 != argc )
  66. return -1;
  67. if ( 2 < argc ) // Since domain name is now required this is no longer a valid option
  68. { // But I'm going to leave the code in case we ever reverse this decision
  69. if ( 0 == wcscmp( L"/i", argv[2] ) || ( 0 == wcscmp( L"-i", argv[2] )))
  70. bIgnoreErrors = true;
  71. else
  72. _bstrDomainName = argv[2];
  73. }
  74. if ( 4 == argc )
  75. {
  76. if ( bIgnoreErrors )
  77. _bstrDomainName = argv[3];
  78. else if ( 0 == wcscmp( L"/i", argv[3] ) || ( 0 == wcscmp( L"-i", argv[3] )))
  79. bIgnoreErrors = true;
  80. else
  81. return -1;
  82. }
  83. if ( 0 == _bstrDomainName.length() )
  84. return -1;
  85. { // Log the command
  86. LPWSTR ps2 = argv[2], ps3 = argv[3];
  87. if ( NULL == ps2 )
  88. {
  89. ps2 = L"";
  90. ps3 = NULL;
  91. }
  92. if ( NULL == ps3 )
  93. {
  94. ps3 = L"";
  95. }
  96. LOG( L"%s %s %s %s", argv[0], argv[1], ps2, ps3 );
  97. }
  98. VariantInit( &v );
  99. hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
  100. if ( REGDB_E_CLASSNOTREG == hr )
  101. {
  102. hr = RegisterDependencies();
  103. if ( S_OK == hr )
  104. hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
  105. bUnregisterDependencies = true;
  106. }
  107. if ( S_OK == hr )
  108. {
  109. if ( bCreateUser ) // Only valid for the MD5 Authentication method
  110. {
  111. CComPtr<IAuthMethods> spIAuthMethods;
  112. CComPtr<IAuthMethod> spIAuthMethod;
  113. BSTR bstrID;
  114. _variant_t _v;
  115. long lValue;
  116. WCHAR sBuffer[MAX_PATH];
  117. hr = spIConfig->get_Authentication( &spIAuthMethods );
  118. if ( REGDB_E_CLASSNOTREG == hr )
  119. {
  120. PrintMessage( IDS_ERROR_POP3REQUIRED );
  121. m_bSuppressPrintError = true;
  122. }
  123. if ( S_OK == hr )
  124. hr = spIAuthMethods->get_CurrentAuthMethod( &_v );
  125. if ( S_OK == hr )
  126. hr = spIAuthMethods->get_Item( _v, &spIAuthMethod );
  127. if ( S_OK == hr )
  128. hr = spIAuthMethod->get_ID( &bstrID );
  129. if ( S_OK == hr )
  130. {
  131. if ( 0 != _wcsicmp( bstrID, SZ_AUTH_ID_MD5_HASH ))
  132. hr = HRESULT_FROM_WIN32( ERROR_DS_INAPPROPRIATE_AUTH );
  133. SysFreeString( bstrID );
  134. }
  135. }
  136. }
  137. if ( S_OK == hr )
  138. hr = spIConfig->get_Domains( &spIDomains );
  139. if ( S_OK == hr )
  140. {
  141. CComPtr<IP3Users> spIUsers;
  142. CComPtr<IP3User> spIUser;
  143. if ( 0 == _bstrDomainName.length() )
  144. { // For each domain
  145. hr = spIDomains->get__NewEnum( &spIEnumVARIANT );
  146. if ( S_OK == hr )
  147. {
  148. hr = spIEnumVARIANT->Next( 1, &v, NULL );
  149. }
  150. }
  151. else
  152. { // Just for this domain
  153. _variant_t _v( _bstrDomainName );
  154. hr = spIDomains->get_Item( _v, &pIDomain );
  155. }
  156. while ( S_OK == hr )
  157. {
  158. if ( NULL != spIEnumVARIANT.p )
  159. {
  160. if ( VT_DISPATCH != V_VT( &v ))
  161. hr = E_UNEXPECTED;
  162. if ( S_OK == hr )
  163. hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3Domain ), reinterpret_cast<void**>( &pIDomain ));
  164. VariantClear( &v );
  165. }
  166. if ( S_OK == hr )
  167. hr = pIDomain->get_Name( &bstrName );
  168. if ( S_OK == hr )
  169. {
  170. LOG( L"Domain: %s ", bstrName );
  171. SysFreeString( bstrName );
  172. }
  173. // Enumerate the users
  174. if ( S_OK == hr )
  175. {
  176. hr = pIDomain->get_Users( &spIUsers );
  177. if ( S_OK == hr )
  178. { // List users
  179. CComPtr<IEnumVARIANT> spIEnumVARIANT2;
  180. hr = spIUsers->get__NewEnum( &spIEnumVARIANT2 );
  181. if ( S_OK == hr )
  182. hr = spIEnumVARIANT2->Next( 1, &v, NULL );
  183. while ( S_OK == hr )
  184. {
  185. if ( VT_DISPATCH != V_VT( &v ))
  186. hr = E_UNEXPECTED;
  187. if ( S_OK == hr )
  188. hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3User ), reinterpret_cast<void**>( &spIUser ));
  189. VariantClear( &v );
  190. hr = spIUser->get_Name( &bstrName );
  191. if ( S_OK == hr )
  192. {
  193. if ( S_OK == hr )
  194. hr = userInfoX.SetUserName( bstrName );
  195. if ( S_OK == hr )
  196. {
  197. hr = spIUser->get_EmailName( &bstrEmailName );
  198. if ( S_OK == hr )
  199. {
  200. hr = GetMD5Password( bstrEmailName, sPassword );
  201. if ( S_OK == hr )
  202. hr = userInfoX.SetPassword( A2W( sPassword ));
  203. }
  204. }
  205. if ( S_OK == hr )
  206. {
  207. if ( bCreateUser )
  208. { // Create the user
  209. hr = userInfoX.CreateAccount();
  210. if ( S_OK == hr )
  211. LOG( L"Create user: %s succeeded.", bstrName );
  212. else
  213. {
  214. LOG( L"ERROR!: Create user %s failed. %s", bstrName, CFormatMessage(hr).c_str() );
  215. if ( bIgnoreErrors )
  216. {
  217. hr = S_OK;
  218. bErrors = true;
  219. }
  220. }
  221. }
  222. if ( bCreateMailbox )
  223. { // Create the mailbox
  224. hr = userInfoX.CreateMailbox();
  225. if ( S_OK == hr )
  226. LOG( L"Create mailbox: %s succeeded.", bstrName );
  227. else
  228. {
  229. LOG( L"ERROR!: Create mailbox %s failed. %s", bstrName, CFormatMessage(hr).c_str() );
  230. if ( bIgnoreErrors )
  231. {
  232. hr = S_OK;
  233. bErrors = true;
  234. }
  235. }
  236. }
  237. }
  238. SysFreeString( bstrName );
  239. }
  240. if ( S_OK == hr )
  241. hr = spIEnumVARIANT2->Next( 1, &v, NULL );
  242. }
  243. if ( S_FALSE == hr )
  244. hr = S_OK; // Reached end of user enumeration
  245. }
  246. }
  247. if ( S_OK == hr )
  248. {
  249. if ( NULL != spIEnumVARIANT.p )
  250. {
  251. hr = spIEnumVARIANT->Next( 1, &v, NULL );
  252. if ( S_OK == hr )
  253. pIDomain->Release();
  254. }
  255. else
  256. hr = S_FALSE; // Were done.
  257. }
  258. }
  259. if ( S_FALSE == hr )
  260. hr = S_OK; // Reached end of domain enumeration
  261. }
  262. if ( NULL != pIDomain )
  263. pIDomain->Release();
  264. if ( bCreateUser )
  265. {
  266. if ( S_OK == hr )
  267. {
  268. PrintMessage( IDS_SUCCESS_CREATEUSER );
  269. if ( bErrors )
  270. PrintMessage( IDS_WARNING_ERRORSIGNORED );
  271. }
  272. else
  273. PrintMessage( IDS_ERROR_CREATEUSER_FAILED );
  274. }
  275. if ( bCreateMailbox )
  276. {
  277. if ( S_OK == hr )
  278. {
  279. PrintMessage( IDS_SUCCESS_CREATEMAILBOX );
  280. if ( bErrors )
  281. PrintMessage( IDS_WARNING_ERRORSIGNORED );
  282. }
  283. else
  284. PrintMessage( IDS_ERROR_CREATEMAILBOX_FAILED );
  285. }
  286. if ( bUnregisterDependencies )
  287. UnRegisterDependencies();
  288. return hr;
  289. }
  290. #define LOCALHOST L"localhost"
  291. int CP2EWorker::Mail(int argc, wchar_t *argv[], bool bDelete /*= FALSE*/ )
  292. {
  293. USES_CONVERSION;
  294. HRESULT hr = S_OK;
  295. VARIANT v;
  296. DWORD dwCount, dwIndex;
  297. BSTR bstrName, bstrEmailName;
  298. WSTRING sEmailDomain;
  299. ASTRING sASCFROM;
  300. _bstr_t _bstrDomainName;
  301. CComPtr<IP3Config> spIConfig;
  302. CComPtr<IP3Domains> spIDomains;
  303. IP3Domain *pIDomain = NULL;
  304. CComPtr<IEnumVARIANT> spIEnumVARIANT;
  305. bool bErrors = false, bIgnoreErrors = false, bLocked = false, bUnregisterDependencies = false;
  306. CMailBox mailboxX;
  307. WCHAR sFilename[MAX_PATH];
  308. ASTRING sASCComputerName;
  309. WSTRING sComputerName;
  310. DWORD dwFileNameSize = MAX_PATH;
  311. LPWSTR psArgv;
  312. LPSTR pszComputerName;
  313. if ( 5 < argc || 3 > argc )
  314. return -1;
  315. for ( int i = 2; i < argc; i++ )
  316. {
  317. psArgv = argv[i];
  318. if ( 0 == wcscmp( L"/i", psArgv ) || ( 0 == wcscmp( L"-i", psArgv )))
  319. {
  320. if ( bIgnoreErrors )
  321. return -1;
  322. bIgnoreErrors = true;
  323. }
  324. else if ( 0 == _wcsnicmp( L"/S:", psArgv, 3 ) || 0 == _wcsnicmp( L"-S:", psArgv, 3 ))
  325. {
  326. if ( 3 < wcslen( psArgv ))
  327. {
  328. if ( sComputerName.empty() )
  329. sComputerName = psArgv + 3;
  330. else
  331. return -1;
  332. }
  333. else
  334. return -1;
  335. }
  336. else
  337. {
  338. if ( 0 == _bstrDomainName.length() )
  339. _bstrDomainName = psArgv;
  340. else
  341. return -1;
  342. }
  343. }
  344. if ( 0 == _bstrDomainName.length() )
  345. return -1;
  346. if ( sComputerName.empty() )
  347. sComputerName = LOCALHOST;
  348. sASCComputerName = W2A(sComputerName.c_str());
  349. {
  350. LPWSTR ps2 = argv[2], ps3 = argv[3], ps4 = argv[4];
  351. if ( NULL == ps2 )
  352. {
  353. ps2 = L"";
  354. ps3 = L"";
  355. ps4 = L"";
  356. }
  357. if ( NULL == ps3 )
  358. {
  359. ps3 = L"";
  360. ps4 = L"";
  361. }
  362. if ( NULL == ps4 )
  363. ps4 = L"";
  364. LOG( L"%s %s %s %s %s", argv[0], argv[1], ps2, ps3, ps4 );
  365. }
  366. VariantInit( &v );
  367. // Socket Initialization
  368. WSADATA wsaData;
  369. SOCKET socket = INVALID_SOCKET;
  370. int iErr, iSize;
  371. LPSTR psSendBuffer = new CHAR[SMTP_BUFFERSIZE];
  372. if ( NULL == psSendBuffer )
  373. return E_OUTOFMEMORY;
  374. iErr = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
  375. if( 0 != iErr )
  376. {
  377. wsaData.wVersion = 0;
  378. hr = HRESULT_FROM_WIN32( iErr );
  379. LOG( L"ERROR!: WSAStartup. %s", CFormatMessage(iErr).c_str() );
  380. }
  381. else
  382. { // Confirm that the WinSock DLL supports 2.2.
  383. // Note that if the DLL supports versions greater than 2.2 in addition to 2.2, it will still return
  384. // 2.2 in wVersion since that is the version we requested.
  385. if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
  386. { /* Tell the user that we could not find a usable WinSock DLL. */
  387. LOG( L"ERROR!: WSAStartup. Unexpected version returned" );
  388. hr = E_UNEXPECTED;
  389. }
  390. }
  391. // Connect to port 25
  392. if ( S_OK == hr )
  393. {
  394. socket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0 );
  395. if( INVALID_SOCKET == socket )
  396. {
  397. iErr = WSAGetLastError();
  398. hr = HRESULT_FROM_WIN32( iErr );
  399. LOG( L"ERROR!: WSASocket. %s", CFormatMessage(iErr).c_str() );
  400. }
  401. else
  402. {
  403. addrinfo stHints;
  404. addrinfo *pstAIHead = NULL, *pstAINext;
  405. sockaddr_in stSAInServer;
  406. ZeroMemory( &stSAInServer, sizeof( stSAInServer ));
  407. ZeroMemory( &stHints, sizeof( stHints ));
  408. stHints.ai_family = PF_INET;
  409. stHints.ai_flags = AI_CANONNAME;
  410. iErr = getaddrinfo( sASCComputerName.c_str(), "SMTP", &stHints, &pstAIHead );
  411. if( 0 != iErr )
  412. {
  413. iErr = WSAGetLastError();
  414. hr = HRESULT_FROM_WIN32( iErr );
  415. LOG( L"ERROR!: getaddrinfo. %s", CFormatMessage(iErr).c_str() );
  416. }
  417. else
  418. {
  419. memcpy( &stSAInServer, pstAIHead->ai_addr, sizeof( stSAInServer ));
  420. pstAINext = pstAIHead;
  421. while ( NULL != pstAINext )
  422. {
  423. pstAINext = pstAIHead->ai_next;
  424. freeaddrinfo( pstAIHead );
  425. pstAIHead = pstAINext;
  426. }
  427. iErr = connect( socket, reinterpret_cast<sockaddr*>( &stSAInServer ), sizeof( stSAInServer ));
  428. if( 0 != iErr )
  429. {
  430. iErr = WSAGetLastError();
  431. hr = HRESULT_FROM_WIN32( iErr );
  432. LOG( L"ERROR!: connect. %s", CFormatMessage(iErr).c_str() );
  433. }
  434. hr = RecvResp( socket, SMTP_MSG220 );
  435. }
  436. }
  437. }
  438. // Get the domain name we are sending to
  439. if ( S_OK == hr )
  440. { // Get domain controller name
  441. PDOMAIN_CONTROLLER_INFO pstDomainControllerInfo = NULL;
  442. LPCWSTR psComputerName = ( sComputerName == LOCALHOST ) ? NULL:sComputerName.c_str();
  443. DWORD dwRC = DsGetDcName( psComputerName, NULL, NULL, NULL, DS_RETURN_DNS_NAME, &pstDomainControllerInfo );
  444. if ( NO_ERROR != dwRC )
  445. {
  446. hr = HRESULT_FROM_WIN32( dwRC );
  447. LOG( L"ERROR!: DsGetDcName. %s", CFormatMessage(dwRC).c_str() );
  448. }
  449. ASSERT(hr == S_OK && "DsGetDcName failed");
  450. // cache the domain
  451. if ( pstDomainControllerInfo )
  452. {
  453. sEmailDomain = pstDomainControllerInfo->DomainName;
  454. // free memory
  455. NetApiBufferFree( pstDomainControllerInfo );
  456. }
  457. }
  458. // SMTP:HELO
  459. if ( S_OK == hr )
  460. {
  461. iSize = _snprintf( psSendBuffer, 2048, "HELO %s\r\n", W2A( sEmailDomain.c_str() ));
  462. if ( 0 < iSize )
  463. hr = SendRecv( socket, psSendBuffer, iSize, SMTP_MSG250 );
  464. else
  465. hr = E_UNEXPECTED;
  466. }
  467. // Process domains and mailboxes
  468. if ( S_OK == hr )
  469. hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
  470. if ( REGDB_E_CLASSNOTREG == hr )
  471. {
  472. hr = RegisterDependencies();
  473. if ( S_OK == hr )
  474. hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
  475. bUnregisterDependencies = true;
  476. }
  477. if ( S_OK == hr )
  478. hr = spIConfig->get_Domains( &spIDomains );
  479. if ( S_OK == hr )
  480. {
  481. CComPtr<IP3Users> spIUsers;
  482. CComPtr<IP3User> spIUser;
  483. if ( 0 == _bstrDomainName.length() )
  484. { // For each domain
  485. hr = spIDomains->get__NewEnum( &spIEnumVARIANT );
  486. if ( S_OK == hr )
  487. {
  488. hr = spIEnumVARIANT->Next( 1, &v, NULL );
  489. }
  490. }
  491. else
  492. { // Just for this domain
  493. _variant_t _v( _bstrDomainName );
  494. hr = spIDomains->get_Item( _v, &pIDomain );
  495. }
  496. while ( S_OK == hr )
  497. {
  498. if ( NULL != spIEnumVARIANT.p )
  499. {
  500. if ( VT_DISPATCH != V_VT( &v ))
  501. hr = E_UNEXPECTED;
  502. if ( S_OK == hr )
  503. hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3Domain ), reinterpret_cast<void**>( &pIDomain ));
  504. VariantClear( &v );
  505. }
  506. if ( S_OK == hr )
  507. hr = pIDomain->get_Name( &bstrName );
  508. if ( S_OK == hr )
  509. {
  510. LOG( L"Domain: %s ", bstrName );
  511. SysFreeString( bstrName );
  512. }
  513. // Enumerate the users
  514. if ( S_OK == hr )
  515. {
  516. hr = pIDomain->get_Users( &spIUsers );
  517. if ( S_OK == hr )
  518. { // List users
  519. CComPtr<IEnumVARIANT> spIEnumVARIANT2;
  520. hr = spIUsers->get__NewEnum( &spIEnumVARIANT2 );
  521. if ( S_OK == hr )
  522. hr = spIEnumVARIANT2->Next( 1, &v, NULL );
  523. while ( S_OK == hr )
  524. {
  525. if ( VT_DISPATCH != V_VT( &v ))
  526. hr = E_UNEXPECTED;
  527. if ( S_OK == hr )
  528. hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3User ), reinterpret_cast<void**>( &spIUser ));
  529. VariantClear( &v );
  530. if ( S_OK == hr )
  531. hr = spIUser->get_Name( &bstrName );
  532. if ( S_OK == hr )
  533. {
  534. hr = spIUser->get_EmailName( &bstrEmailName );
  535. if ( S_OK == hr )
  536. {
  537. hr = mailboxX.OpenMailBox( bstrEmailName ) ? S_OK : E_UNEXPECTED;
  538. if ( S_OK == hr )
  539. {
  540. bLocked = mailboxX.LockMailBox() ? true : false;
  541. hr = mailboxX.EnumerateMailBox() ? S_OK : E_UNEXPECTED;
  542. }
  543. if ( S_OK == hr )
  544. dwCount = mailboxX.GetMailCount();
  545. for ( dwIndex = 0; (S_OK == hr) && (dwIndex < dwCount); dwIndex++ )
  546. {
  547. if ( !mailboxX.GetMailFileName( dwIndex, sFilename, dwFileNameSize ))
  548. hr = E_UNEXPECTED;
  549. if ( S_OK == hr )
  550. {
  551. hr = GetMailFROM( sFilename, sASCFROM );
  552. if ( S_OK != hr )
  553. sASCFROM.erase();
  554. }
  555. if ( S_OK == hr )
  556. { // SMTP:MAIL
  557. iSize = _snprintf( psSendBuffer, SMTP_BUFFERSIZE, "MAIL FROM:<%s>\r\n", sASCFROM.c_str() );
  558. if ( 0 < iSize )
  559. hr = SendRecv( socket, psSendBuffer, iSize, SMTP_MSG250 );
  560. else
  561. hr = E_UNEXPECTED;
  562. }
  563. if ( S_OK == hr )
  564. { // SMTP:RCPT
  565. iSize = _snprintf( psSendBuffer, SMTP_BUFFERSIZE, "RCPT TO:%s@%s\r\n", W2A( bstrName ), W2A( sEmailDomain.c_str() ));
  566. if ( 0 < iSize )
  567. hr = SendRecv( socket, psSendBuffer, iSize, SMTP_MSG250 );
  568. else
  569. hr = E_UNEXPECTED;
  570. }
  571. if ( S_OK == hr )
  572. { // SMTP:DATA
  573. hr = SendRecv( socket, SMTP_DATA, iSize, SMTP_MSG354 );
  574. }
  575. if ( S_OK == hr )
  576. {
  577. iErr = mailboxX.TransmitMail( socket, dwIndex );
  578. if ( ERROR_SUCCESS != iErr )
  579. {
  580. hr = HRESULT_FROM_WIN32( iErr );
  581. LOG( L"ERROR!: TransmitMail failed. %s", CFormatMessage(iErr).c_str() );
  582. // Data probably wasn't terminated since TransmitMail failed.
  583. SendRecv( socket, SMTP_DATA_END, iSize, SMTP_MSG250 );
  584. }
  585. else
  586. { // There should be a 250 OK reply waiting.
  587. hr = RecvResp( socket, SMTP_MSG250 );
  588. }
  589. }
  590. if ( S_OK != hr && bIgnoreErrors )
  591. {
  592. SendRecv( socket, SMTP_RSET, strlen( SMTP_RSET ), SMTP_MSG250 );
  593. hr = S_OK;
  594. bErrors = true;
  595. }
  596. }
  597. if ( bLocked )
  598. {
  599. mailboxX.UnlockMailBox();
  600. bLocked = false;
  601. }
  602. SysFreeString( bstrEmailName );
  603. mailboxX.QuitAndClose();
  604. }
  605. SysFreeString( bstrName );
  606. }
  607. if ( S_OK == hr )
  608. hr = spIEnumVARIANT2->Next( 1, &v, NULL );
  609. }
  610. if ( S_FALSE == hr )
  611. hr = S_OK; // Reached end of user enumeration
  612. }
  613. }
  614. if ( S_OK == hr )
  615. {
  616. if ( NULL != spIEnumVARIANT.p )
  617. {
  618. hr = spIEnumVARIANT->Next( 1, &v, NULL );
  619. if ( S_OK == hr )
  620. pIDomain->Release();
  621. }
  622. else
  623. hr = S_FALSE; // Were done.
  624. }
  625. }
  626. if ( S_FALSE == hr )
  627. hr = S_OK; // Reached end of domain enumeration
  628. }
  629. if ( NULL != pIDomain )
  630. pIDomain->Release();
  631. // Cleanup
  632. if( INVALID_SOCKET != socket )
  633. {
  634. // SMTP:QUIT
  635. HRESULT hr2 = SendRecv( socket, SMTP_QUIT, strlen( SMTP_QUIT ), SMTP_MSG221 );
  636. if ( S_OK == hr ) hr = hr2;
  637. iErr = closesocket( socket );
  638. if ( 0 != iErr ) LOG( L"ERROR!: closesocket. %s", CFormatMessage(iErr).c_str() );
  639. assert( 0 == iErr );
  640. }
  641. if ( 0 != wsaData.wVersion )
  642. {
  643. iErr = WSACleanup( );
  644. if ( 0 != iErr ) LOG( L"ERROR!: WSACleanup. %s", CFormatMessage(iErr).c_str() );
  645. assert( 0 == iErr );
  646. }
  647. if ( S_OK == hr )
  648. {
  649. PrintMessage( IDS_SUCCESS_SENDMAIL );
  650. if ( bErrors )
  651. PrintMessage( IDS_WARNING_ERRORSIGNORED );
  652. }
  653. else
  654. PrintMessage( IDS_ERROR_SENDMAIL_FAILED );
  655. if ( bUnregisterDependencies )
  656. UnRegisterDependencies();
  657. return hr;
  658. }
  659. #define FROMFIELD "\r\nfrom:"
  660. #define FROMFIELDEND "\r\n"
  661. #define EOH "\r\n\r\n"
  662. HRESULT CP2EWorker::GetMailFROM( LPCWSTR sFileName, ASTRING &sFrom )
  663. {
  664. HRESULT hr = S_OK;
  665. bool isThereMoreToRead = true, isFromComplete = false;
  666. char sBuffer[LOCAL_FILE_BUFFER_SIZE+1];
  667. DWORD dwBytesToRead, dwBytesRead;
  668. LPSTR ps, psEOH, psFrom;
  669. DWORD dwStart;
  670. ASTRING sFromFULL;
  671. HANDLE hFile = CreateFile( sFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL );
  672. if ( INVALID_HANDLE_VALUE == hFile )
  673. hr = HRESULT_FROM_WIN32( GetLastError() );
  674. // Read till we find the "\r\nFrom:"
  675. dwStart = strlen( FROMFIELD );
  676. dwBytesToRead = LOCAL_FILE_BUFFER_SIZE - dwStart;
  677. if( ReadFile( hFile, sBuffer, LOCAL_FILE_BUFFER_SIZE, &dwBytesRead, NULL) )
  678. sBuffer[dwBytesRead] = 0;
  679. else
  680. hr = HRESULT_FROM_WIN32( GetLastError() );
  681. while( isThereMoreToRead && S_OK == hr )
  682. {
  683. if( dwBytesRead < dwBytesToRead )
  684. isThereMoreToRead = false;
  685. _strlwr( sBuffer );
  686. ps = sBuffer;
  687. psEOH = strstr( ps, EOH );
  688. if ( NULL != psEOH )
  689. {
  690. *psEOH = 0;
  691. isThereMoreToRead = false;
  692. }
  693. psFrom = strstr( ps, FROMFIELD );
  694. if ( NULL != psFrom )
  695. { // Found the From Field, do we have it all?
  696. psFrom += strlen( FROMFIELD );
  697. ps = strstr( psFrom, FROMFIELDEND );
  698. if ( NULL != ps )
  699. {
  700. *ps = 0;
  701. isFromComplete = true;
  702. }
  703. sFromFULL = psFrom;
  704. isThereMoreToRead = false;
  705. }
  706. if ( isThereMoreToRead )
  707. { // Copy end of buffer to beginning (to handle wrap around) then continue
  708. memcpy( sBuffer, &(sBuffer[dwBytesToRead]), dwStart );
  709. if( ReadFile( hFile, &(sBuffer[dwStart]), dwBytesToRead, &dwBytesRead, NULL) )
  710. sBuffer[dwBytesRead + dwStart] = 0;
  711. else
  712. hr = HRESULT_FROM_WIN32( GetLastError() );
  713. }
  714. }
  715. if ( !isFromComplete && NULL != psFrom )
  716. { // Should be able to get rest of FROM with next read
  717. // Copy end of buffer to beginning (to handle wrap around) then continue
  718. memcpy( sBuffer, &(sBuffer[dwBytesToRead]), dwStart );
  719. if( ReadFile( hFile, &(sBuffer[dwStart]), dwBytesToRead, &dwBytesRead, NULL) )
  720. {
  721. sBuffer[dwBytesRead + dwStart] = 0;
  722. ps = strstr( sBuffer, FROMFIELDEND );
  723. if ( NULL != ps )
  724. {
  725. *ps = 0;
  726. if ( ps > &(sBuffer[dwStart]) )
  727. sFromFULL += sBuffer[dwStart];
  728. else
  729. { // cleanup sFrom
  730. ASTRING::size_type iPos = sFromFULL.find( '\r' );
  731. if ( ASTRING::npos != iPos )
  732. sFromFULL.resize( iPos );
  733. }
  734. }
  735. }
  736. else
  737. hr = HRESULT_FROM_WIN32( GetLastError() );
  738. }
  739. if ( !sFromFULL.empty() && S_OK == hr )
  740. { // Look for the open bracket
  741. ASTRING::size_type iStart = sFromFULL.find( '<' );
  742. ASTRING::size_type iEnd = sFromFULL.find( '>' );
  743. if ( WSTRING::npos != iStart )
  744. {
  745. if ( ASTRING::npos != iEnd )
  746. sFrom = sFromFULL.substr( iStart + 1, iEnd - iStart - 1 );
  747. }
  748. else
  749. sFrom = sFromFULL;
  750. }
  751. if ( INVALID_HANDLE_VALUE != hFile )
  752. CloseHandle( hFile );
  753. return hr;
  754. }
  755. void CP2EWorker::PrintError( int iRC )
  756. {
  757. if ( m_bSuppressPrintError || (E_FAIL == iRC) )
  758. {
  759. m_bSuppressPrintError = false;
  760. return;
  761. }
  762. LPVOID lpMsgBuf;
  763. if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, iRC, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>( &lpMsgBuf ), 0, NULL ))
  764. {
  765. wprintf( reinterpret_cast<LPWSTR>( lpMsgBuf ) );
  766. LocalFree( lpMsgBuf );
  767. }
  768. else
  769. {
  770. WCHAR sBuffer[32];
  771. PrintMessage( IDS_ERROR_UNKNOWN );
  772. wsprintf( sBuffer, L"%x", iRC );
  773. PrintMessage( sBuffer );
  774. }
  775. }
  776. void CP2EWorker::PrintMessage( LPWSTR psMessage, bool bCRLF /*= true*/ )
  777. {
  778. wprintf( psMessage );
  779. if ( bCRLF )
  780. wprintf( L"\r\n" );
  781. }
  782. void CP2EWorker::PrintMessage( int iID, bool bCRLF /*= true*/ )
  783. {
  784. WCHAR sBuffer[512];
  785. if ( LoadString( NULL, iID, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ))
  786. PrintMessage( sBuffer, bCRLF );
  787. else
  788. assert( false );
  789. }
  790. void CP2EWorker::PrintUsage()
  791. {
  792. WCHAR sBuffer[512];
  793. for ( int i = IDS_POP2EXCH_USAGE1; i < IDS_POP2EXCH_USAGEEND; i++ )
  794. {
  795. if ( LoadString( NULL, i, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ))
  796. {
  797. if ( IDS_POP2EXCH_USAGE2 == i )
  798. {
  799. WCHAR sBuffer2[512];
  800. if ( 0 > _snwprintf( sBuffer2, sizeof( sBuffer2 )/sizeof(WCHAR), sBuffer, POP3_SERVER_NAME_L ))
  801. sBuffer2[(sizeof( sBuffer2 )/sizeof(WCHAR))-1] = 0;
  802. wcscpy( sBuffer, sBuffer2 );
  803. }
  804. wprintf( sBuffer );
  805. }
  806. }
  807. }
  808. LPWSTR CP2EWorker::FormatLogString( LPWSTR psLogString )
  809. {
  810. if ( NULL == psLogString )
  811. return psLogString;
  812. LPWSTR psCRLF = wcsstr( psLogString, L"\r\n" );
  813. while ( NULL != psCRLF )
  814. {
  815. *psCRLF = L' ';
  816. *(psCRLF+1) = L' ';
  817. psCRLF = wcsstr( psLogString, L"\r\n" );
  818. }
  819. return psLogString;
  820. }
  821. HRESULT CP2EWorker::RecvResp( SOCKET socket, LPCSTR psExpectedResp )
  822. {
  823. if ( NULL == psExpectedResp )
  824. return E_INVALIDARG;
  825. if ( 3 > strlen( psExpectedResp ))
  826. return E_INVALIDARG;
  827. CHAR sRecvBuffer[SMTP_BUFFERSIZE + 1];
  828. USES_CONVERSION;
  829. HRESULT hr = S_OK;
  830. int iErr;
  831. iErr = recv( socket, sRecvBuffer, SMTP_BUFFERSIZE, 0 );
  832. if ( SOCKET_ERROR != iErr )
  833. {
  834. sRecvBuffer[iErr] = 0;
  835. if ( (3 > iErr) || (0 != strncmp( sRecvBuffer, psExpectedResp, 3 )))
  836. hr = E_UNEXPECTED;
  837. LPWSTR ps = FormatLogString( A2W( sRecvBuffer ));
  838. LOG( L"recv [%s].", ps );
  839. }
  840. else
  841. {
  842. iErr = WSAGetLastError();
  843. hr = HRESULT_FROM_WIN32( iErr );
  844. LOG( L"ERROR!: recv failed. %s", CFormatMessage(iErr).c_str() );
  845. }
  846. return hr;
  847. }
  848. HRESULT CP2EWorker::RegisterDependencies()
  849. {
  850. HRESULT hr = S_OK;
  851. HMODULE hDLL;
  852. HRESULT (STDAPICALLTYPE * lpDllEntryPoint)(void);
  853. tstring strPath = _T("") ;
  854. strPath = GetModulePath () ;
  855. if ( strPath != _T("") )
  856. strPath = strPath + _T("P3Admin.dll") ;
  857. else
  858. hr = E_FAIL ;
  859. if ( S_OK == hr )
  860. {
  861. hDLL = LoadLibrary( strPath.c_str() );
  862. if ( hDLL )
  863. {
  864. (FARPROC&)lpDllEntryPoint = GetProcAddress(hDLL,"DllRegisterServer");
  865. if (lpDllEntryPoint != NULL)
  866. hr = (*lpDllEntryPoint)();
  867. else
  868. hr = HRESULT_FROM_WIN32(GetLastError());
  869. FreeLibrary( hDLL );
  870. }
  871. else
  872. {
  873. PrintMessage( IDS_ERROR_MUSTBERUNFROMCURDIR );
  874. hr = HRESULT_FROM_WIN32(GetLastError());
  875. m_bSuppressPrintError = true;
  876. }
  877. }
  878. if ( S_OK == hr )
  879. {
  880. CComPtr<IP3Config> spIConfig;
  881. WCHAR sBuffer[MAX_PATH+1];
  882. hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
  883. if ( S_OK == hr )
  884. {
  885. DWORD dwRC = GetCurrentDirectoryW( sizeof(sBuffer)/sizeof(WCHAR), sBuffer );
  886. if (( 0 != dwRC ) && ( (sizeof(sBuffer)/sizeof(WCHAR)) > dwRC ))
  887. {
  888. HKEY hKey;
  889. long lRC = RegCreateKey( HKEY_LOCAL_MACHINE, POP3SERVER_SOFTWARE_SUBKEY, &hKey );
  890. if ( ERROR_SUCCESS == lRC )
  891. {
  892. lRC = RegSetDWORD( POP3SERVER_SOFTWARE_SUBKEY, VALUENAME_VERSION, 0 );
  893. if ( ERROR_SUCCESS != lRC )
  894. hr = HRESULT_FROM_WIN32( lRC );
  895. RegCloseKey( hKey );
  896. }
  897. else
  898. hr = HRESULT_FROM_WIN32( lRC );
  899. if ( S_OK == hr )
  900. {
  901. _bstr_t _bstrMailRoot = sBuffer;
  902. hr = spIConfig->put_MailRoot( _bstrMailRoot );
  903. }
  904. }
  905. else
  906. hr = E_FAIL;
  907. }
  908. }
  909. if ( S_OK != hr )
  910. {
  911. UnRegisterDependencies () ;
  912. }
  913. return hr;
  914. }
  915. HRESULT CP2EWorker::SendRecv( SOCKET socket, LPCSTR psSendBuffer, const int iSize, LPCSTR psExpectedResp )
  916. {
  917. if ( NULL == psSendBuffer )
  918. return E_INVALIDARG;
  919. USES_CONVERSION;
  920. HRESULT hr = S_OK;
  921. int iErr;
  922. LPWSTR ps = FormatLogString( A2W( psSendBuffer ));
  923. iErr = send( socket, psSendBuffer, iSize, 0 );
  924. if ( SOCKET_ERROR != iErr )
  925. {
  926. LOG( L"send [%s].", ps );
  927. }
  928. else
  929. {
  930. iErr = WSAGetLastError();
  931. hr = HRESULT_FROM_WIN32( iErr );
  932. LOG( L"ERROR!: send [%s] failed. %s", ps, CFormatMessage(iErr).c_str() );
  933. }
  934. if ( S_OK == hr )
  935. {
  936. hr = RecvResp( socket, psExpectedResp );
  937. }
  938. return hr;
  939. }
  940. HRESULT CP2EWorker::UnRegisterDependencies()
  941. {
  942. HRESULT hr = S_OK;
  943. HMODULE hDLL;
  944. HRESULT (STDAPICALLTYPE * lpDllEntryPoint)(void);
  945. tstring strPath = _T("") ;
  946. strPath = GetModulePath () ;
  947. if ( strPath != _T("") )
  948. strPath = strPath + _T("P3Admin.dll") ;
  949. else
  950. hr = E_FAIL ;
  951. if ( S_OK == hr )
  952. {
  953. hDLL = LoadLibrary( strPath.c_str() );
  954. if ( hDLL )
  955. {
  956. (FARPROC&)lpDllEntryPoint = GetProcAddress(hDLL,"DllUnregisterServer");
  957. if (lpDllEntryPoint != NULL)
  958. hr = (*lpDllEntryPoint)();
  959. else
  960. hr = HRESULT_FROM_WIN32(GetLastError());
  961. FreeLibrary( hDLL );
  962. }
  963. else
  964. hr = HRESULT_FROM_WIN32(GetLastError());
  965. }
  966. if ( S_OK == hr )
  967. {
  968. long lRC = RegDeleteKey( HKEY_LOCAL_MACHINE, POP3SERVER_SOFTWARE_SUBKEY );
  969. if ( ERROR_SUCCESS != lRC )
  970. hr = HRESULT_FROM_WIN32( lRC );
  971. }
  972. return hr;
  973. }
  974. tstring CP2EWorker::GetModulePath ()
  975. {
  976. tstring strDir = _T("");
  977. TCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFName[_MAX_FNAME], szExt[_MAX_EXT] ;
  978. DWORD dwSize = MAX_PATH;
  979. TCHAR *szPath = new TCHAR[dwSize+1];
  980. if (!szPath)
  981. return strDir;
  982. // Allocate more space if necessary
  983. while( dwSize == GetModuleFileName( NULL, szPath, dwSize ) )
  984. {
  985. delete [] szPath;
  986. dwSize *= 2;
  987. szPath = new TCHAR[dwSize+1];
  988. if (!szPath)
  989. return strDir;
  990. }
  991. _tsplitpath ( szPath, szDrive, szDir, szFName, szExt ) ;
  992. _tmakepath ( szPath, szDrive, szDir, _T(""), _T("") ) ; // Make the path without filename and extension.
  993. if (_tcslen( szPath ))
  994. strDir = szPath;
  995. if ( szPath[_tcslen(szPath)-1] != '\\' )
  996. strDir = strDir + _T("\\") ;
  997. delete [] szPath;
  998. return strDir;
  999. }