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.

1808 lines
60 KiB

  1. /* --- FIXES
  2. -- SMIME TEST
  3. fixed --- Can't do more than 4 || signers
  4. fixed --- Can't Sc(Ekt(B))
  5. - --- Sb(Sb(Sb(B))) only two layers are generated?
  6. - --- Unauthenticated attributes
  7. */
  8. /// http:iptdalpha3 - symbols for crypt32.
  9. /*-----------------------------------------
  10. SMimeTst.C -- Function Test of S/Mime
  11. -----------------------------------------*/
  12. #define INITGUID
  13. #define DEFINE_STRCONST
  14. #include "item.h"
  15. #include "smtpcall.h"
  16. #include "instring.h"
  17. #include "dbgutil.h"
  18. #include "sign.h"
  19. #include "maillist.h"
  20. #define WinMainT WinMain
  21. long FAR PASCAL WndProc (HWND, UINT, UINT, LONG);
  22. char szAppName [] = "SMimeTst";
  23. static const TCHAR c_szDebug[] = "mshtmdbg.dll";
  24. static const TCHAR c_szDebugUI[] = "DoTracePointsDialog";
  25. static const TCHAR c_szRegSpy[] = "DbgRegisterMallocSpy";
  26. static const TCHAR c_szInvokeUI1[] = "/d";
  27. static const TCHAR c_szInvokeUI2[] = "-d";
  28. HINSTANCE hInst;
  29. const int MAX_LAYERS = 100;
  30. extern const BYTE RgbSHA1AlgId[];
  31. extern const int CbSHA1AlgId;
  32. const GUID GuidCertValidate = CERT_CERTIFICATE_ACTION_VERIFY;
  33. HWND HdlgMsg;
  34. HWND HwndTree;
  35. BOOL CALLBACK DetailDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
  36. BOOL CALLBACK EncDataDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
  37. BOOL CALLBACK EncDataComposeDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
  38. BOOL CALLBACK EncTransCompDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
  39. BOOL CALLBACK EncAgreeCompDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
  40. BOOL CALLBACK EncInfoReadDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
  41. BOOL CALLBACK MailListDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
  42. enum {
  43. Dlg_Message,
  44. Dlg_Sign_Info_Compose,
  45. Dlg_Sign_Info_Read,
  46. Dlg_Sign_Data_Compose,
  47. Dlg_Sign_Data_Read,
  48. Dlg_Enc_Info_Compose,
  49. Dlg_Enc_Info_Read,
  50. Dlg_Enc_Data_Agree_Compose,
  51. Dlg_Enc_Data_Trans_Compose,
  52. Dlg_Enc_Data_MailList_Compose,
  53. Dlg_Max
  54. };
  55. struct {
  56. int id;
  57. DLGPROC proc;
  58. HWND hwnd;
  59. } RgDlgs[] = {
  60. {IDD_DETAIL, DetailDlgProc},
  61. {IDD_SIGN_INFO_COMPOSE, SignInfoDlgProc},
  62. {IDD_SIGN_INFO_COMPOSE, SignInfoDlgProc},
  63. {IDD_SIGN_DATA_COMPOSE, SignDataDlgProc},
  64. {IDD_SIGN_DATA_READ, SignDataReadDlgProc},
  65. {IDD_ENCRYPT_INFO_COMPOSE, EncDataDlgProc},
  66. {IDD_ENCRYPT_INFO_READ, EncInfoReadDlgProc},
  67. {IDD_ENC_AGREE_COMPOSE, EncAgreeCompDlgProc},
  68. {IDD_ENC_TRANS_COMPOSE, EncTransCompDlgProc},
  69. {IDD_ENC_ML_COMPOSE, EncMLComposeDlgProc}
  70. };
  71. HWND HdlgEncData;
  72. HWND HdlgSignInfo;
  73. HWND HwndDetail;
  74. CMessage RootMsg;
  75. BYTE RgbSignHash[20];
  76. HCERTSTORE HCertStoreMy = NULL;
  77. IImnAccountManager * PAcctMan = NULL;
  78. ISMTPTransport * PSmtp = NULL;
  79. extern DWORD MsgSMTP = 0;
  80. char RgchBody[] = "Now is the time for all good men (and women) to come to the aid of their country.\r\n";
  81. char RgchExample[] = "This is some sample content.";
  82. typedef void (STDAPICALLTYPE *PFNDEBUGUI)(BOOL);
  83. typedef void (STDAPICALLTYPE *PFNREGSPY)(void);
  84. void WaitForCompletion(UINT uiMsg, DWORD wparam)
  85. {
  86. MSG msg;
  87. while(GetMessage(&msg, NULL, 0, 0))
  88. {
  89. if ((msg.message == uiMsg) && (msg.wParam == wparam) ||
  90. (msg.wParam == IXP_DISCONNECTED))
  91. break;
  92. TranslateMessage(&msg);
  93. DispatchMessage(&msg);
  94. }
  95. }
  96. void ShowWindow(int id, LPARAM lparam)
  97. {
  98. int i;
  99. for (i=0; i<Dlg_Max; i++) {
  100. ShowWindow(RgDlgs[i].hwnd, SW_HIDE);
  101. }
  102. ShowWindow(RgDlgs[id].hwnd, SW_SHOWNORMAL);
  103. SendMessage(RgDlgs[id].hwnd, UM_SET_DATA, 0, lparam);
  104. }
  105. BOOL pfnFilter(PCCERT_CONTEXT pccert, long lCustData, DWORD, DWORD)
  106. {
  107. BOOL f = FALSE;
  108. LPCSTR pszObjId = pccert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
  109. if (lCustData & FILTER_RSA_KEYEX) {
  110. f |= (strcmp(pszObjId, szOID_RSA_RSA) == 0);
  111. }
  112. if (lCustData & FILTER_RSA_SIGN) {
  113. f |= (strcmp(pszObjId, szOID_RSA_RSA) == 0);
  114. }
  115. if (lCustData & FILTER_DSA_SIGN) {
  116. f |= (strcmp(pszObjId, szOID_X957_DSA) == 0);
  117. }
  118. if (lCustData & FILTER_DH_KEYEX) {
  119. f |= (strcmp(pszObjId, szOID_ANSI_X942_DH) == 0);
  120. }
  121. if (lCustData & FILTER_KEA_KEYEX) {
  122. f |= (strcmp(pszObjId, szOID_INFOSEC_keyExchangeAlgorithm) == 0);
  123. }
  124. return f;
  125. }
  126. BOOL DoCertDialog(HWND hwndOwner, LPTSTR szTitle, HCERTSTORE hCertStore, PCCERT_CONTEXT *ppCert, int iFilter)
  127. {
  128. DWORD cchEmail;
  129. CERT_SELECT_STRUCT css = {0};
  130. PCCERT_CONTEXT pCurCert;
  131. BOOL fRet = FALSE;
  132. pCurCert = CertDuplicateCertificateContext(*ppCert);
  133. css.dwSize = sizeof(CERT_SELECT_STRUCT);
  134. css.hwndParent = hwndOwner;
  135. css.hInstance = hInst;
  136. css.arrayCertStore = &hCertStore;
  137. css.szTitle = szTitle;
  138. css.cCertStore = 1;
  139. css.szPurposeOid = szOID_PKIX_KP_EMAIL_PROTECTION;
  140. css.arrayCertContext = ppCert;
  141. css.cCertContext = 1;
  142. css.lCustData = iFilter;
  143. css.pfnFilter = pfnFilter;
  144. if (CertSelectCertificate(&css) && (pCurCert != *ppCert)) {
  145. fRet = TRUE;
  146. }
  147. CertFreeCertificateContext(pCurCert);
  148. return fRet;
  149. }
  150. BOOL ViewCertDialog(HWND hwndOwner, LPTSTR szTitle, PCCERT_CONTEXT pCert)
  151. {
  152. CERT_VIEWPROPERTIES_STRUCT cvs = {0};
  153. char * psz = szOID_PKIX_KP_EMAIL_PROTECTION;
  154. cvs.dwSize = sizeof(cvs);
  155. cvs.hwndParent = hwndOwner;
  156. cvs.szTitle = szTitle;
  157. cvs.pCertContext = pCert;
  158. cvs.cArrayPurposes = 1;
  159. cvs.arrayPurposes = &psz;
  160. CertViewProperties(&cvs);
  161. return TRUE;
  162. }
  163. // HrValidateCert
  164. //
  165. // Description:
  166. // This routine is used to check the validity of a certificate, the codes
  167. // are modified from HrDoTrustWork in cryptdlg.dll, by xzhang
  168. //
  169. // Parameters:
  170. // pcert - Point to the certificate we want to validate
  171. // hstore - Extra store for searching certficates
  172. // pbd - Point to BinData for returning the certificate chain
  173. // pcCertsInChain - Point to DWORD for returning the # of certs in chain
  174. // pdwErrors - Returns the errors encountered in validating the cert
  175. //
  176. // Return Value:
  177. // Result code of operation.
  178. //
  179. // Returned in *pdwErrors;
  180. //
  181. // The return value consists of a set of flags about why we failed to
  182. // do the validation. Current reasons are:
  183. //
  184. // SIGFAILURE_INVALID_CERT - Certificate is internally inconsistant
  185. // SIGFAILURE_UNKNOWN_ROOT - Root certificate in chain is either unknown
  186. // or not self sign.
  187. // SIGFAILURE_CERT_EXPIRED - Certificate has expired
  188. // SIGFAILURE_CERT_REVOKED - Certificate has been revoked
  189. // SIGFAILURE_CRL_NOT_FOUND - CRL was not found for some Issuer
  190. // SIGFAILURE_INVALID_SIGNATURE - Invalid signature, not the above reason
  191. //
  192. HRESULT HrValidateCert(PCCERT_CONTEXT pccert, HCERTSTORE hstore, HCRYPTPROV hprov,
  193. HCERTSTORE * phcertstorOut, DWORD * pdwErrors)
  194. {
  195. WINTRUST_BLOB_INFO blob = {0};
  196. DWORD cCertsInChain = 0;
  197. DWORD cStores;
  198. WINTRUST_DATA data = {0};
  199. DWORD dwCAs = 0;
  200. DWORD dwErrors = 0;
  201. DWORD dwRet = 0;
  202. BOOL f;
  203. HCERTSTORE hcertstorOut;
  204. DWORD i;
  205. PCCERT_CONTEXT pccertOut = NULL;
  206. PCCERT_CONTEXT * rgCerts = NULL;
  207. DWORD * rgdwErrors = NULL;
  208. HCERTSTORE rghstoreCA[2] = {NULL};
  209. CERT_VERIFY_CERTIFICATE_TRUST trust = {0};
  210. HRESULT hr;
  211. Assert(pdwErrors != NULL);
  212. //
  213. // Make sure we have a place to store the output unless we are being
  214. // told to ignore it
  215. //
  216. if (phcertstorOut != NULL) {
  217. // Try to open an output store if we have not been given one
  218. if (*phcertstorOut == NULL) {
  219. hcertstorOut = CertOpenStore(CERT_STORE_PROV_MEMORY,
  220. X509_ASN_ENCODING, hprov,
  221. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  222. NULL);
  223. if (hcertstorOut == NULL) {
  224. hr = E_FAIL;
  225. goto ExitHere;
  226. }
  227. *phcertstorOut = hcertstorOut;
  228. }
  229. else {
  230. hcertstorOut = *phcertstorOut;
  231. }
  232. }
  233. else {
  234. // No output is being requested
  235. hcertstorOut = NULL;
  236. }
  237. //
  238. // Fill the WINTRUST_DATA
  239. //
  240. data.cbStruct = sizeof(WINTRUST_DATA);
  241. data.dwUIChoice = WTD_UI_NONE;
  242. data.fdwRevocationChecks = WTD_REVOKE_NONE;
  243. data.dwUnionChoice = WTD_CHOICE_BLOB;
  244. data.pBlob = &blob;
  245. //
  246. // Fill the trust blob information
  247. //
  248. blob.cbStruct = sizeof(WINTRUST_BLOB_INFO);
  249. blob.cbMemObject = sizeof(CERT_VERIFY_CERTIFICATE_TRUST);
  250. blob.pbMemObject = (LPBYTE)&trust;
  251. //
  252. // Fill the certificate trust information
  253. //
  254. trust.cbSize = sizeof(trust);
  255. trust.pccert = pccert;
  256. trust.dwFlags = (CERT_TRUST_DO_FULL_SEARCH | CERT_TRUST_PERMIT_MISSING_CRLS
  257. |CERT_TRUST_DO_FULL_TRUST | CERT_TRUST_ADD_CERT_STORES);
  258. trust.dwIgnoreErr = CERT_VALIDITY_NO_CRL_FOUND;
  259. trust.pdwErrors = &dwErrors;
  260. trust.pszUsageOid = szOID_PKIX_KP_EMAIL_PROTECTION;
  261. trust.hprov = hprov;
  262. //
  263. // If we have a store of certificates, then pass it in to give us additional
  264. // places to look
  265. //
  266. rghstoreCA[0] = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  267. hprov, (CERT_SYSTEM_STORE_CURRENT_USER |
  268. CERT_STORE_NO_CRYPT_RELEASE_FLAG),
  269. L"CA");
  270. if (rghstoreCA[0] == NULL) {
  271. hr = E_FAIL;
  272. goto ExitHere;
  273. }
  274. cStores = 1;
  275. trust.rghstoreCAs = rghstoreCA;
  276. if (hstore) {
  277. cStores = 2;
  278. rghstoreCA[1] = hstore;
  279. }
  280. trust.cStores = cStores;
  281. trust.pcChain = &cCertsInChain;
  282. trust.prgChain = &rgCerts;
  283. trust.prgdwErrors = &rgdwErrors;
  284. //
  285. // Call the brain function to verify the trust status of this certificate
  286. //
  287. hr = WinVerifyTrust(NULL, (GUID *)&GuidCertValidate, &data);
  288. if(FAILED(hr) || cCertsInChain == 0) {
  289. //
  290. // We completely failed the verificaiton
  291. //
  292. *pdwErrors = /*SIGFAILURE_OTHER*/ 1;
  293. //
  294. // But we still need to shove this certificate into the output store
  295. // if the user wants one
  296. //
  297. if (NULL != hcertstorOut) {
  298. // Add the certificate to the store. We need to remember the
  299. // new context so we can properly add CRLs
  300. f = CertAddCertificateContextToStore(hcertstorOut, pccert,
  301. CERT_STORE_ADD_NEW,
  302. &pccertOut);
  303. Assert(f || (NULL == pccertOut));
  304. // Look for any CRLs which might apply to the new context
  305. // and add them to the store as well
  306. if (NULL != pccertOut) {
  307. // hr = HrAddValidCRLsToStore(hcertstorOut, pccertOut,
  308. // rghstoreCA, cStores);
  309. Assert(S_OK == hr);
  310. }
  311. }
  312. hr = S_OK;
  313. goto ExitHere;
  314. }
  315. //
  316. // Now build the certificates chain for SSignature when requested
  317. //
  318. if (hcertstorOut != NULL) {
  319. if (cCertsInChain == 0) {
  320. // Store the certificate in the output store and remember the
  321. // new certificate context for checking the CRLs
  322. f = CertAddCertificateContextToStore(hcertstorOut, pccert,
  323. CERT_STORE_ADD_NEW,
  324. &pccertOut);
  325. Assert(f || (NULL == pccertOut));
  326. // Look for any CRLs which might apply and add them to the store
  327. // as well
  328. if (NULL != pccertOut) {
  329. // hr = HrAddValidCRLsToStore(hcertstorOut, pccertOut,
  330. // rghstoreCA, cStores);
  331. Assert(S_OK == hr);
  332. }
  333. }
  334. for (i=0; i<cCertsInChain; i++) {
  335. // Free any output certificate context we have already
  336. if (NULL != pccertOut) {
  337. CertFreeCertificateContext(pccertOut);
  338. pccertOut = NULL;
  339. }
  340. // Add the encoded certificate to the store
  341. f = CertAddEncodedCertificateToStore(hcertstorOut, X509_ASN_ENCODING,
  342. rgCerts[i]->pbCertEncoded,
  343. rgCerts[i]->cbCertEncoded,
  344. CERT_STORE_ADD_NEW, &pccertOut);
  345. Assert(f || (NULL == pccertOut));
  346. // Add any appropriate CRLs to the store as well
  347. if (NULL != pccertOut) {
  348. // hr = HrAddValidCRLsToStore(hcertstorOut, pccertOut,
  349. // rghstoreCA, cStores);
  350. Assert(S_OK == hr);
  351. }
  352. }
  353. }
  354. //
  355. // Setup the signuare error flags as used in ExSec32.dll
  356. //
  357. if(rgdwErrors == NULL) {
  358. *pdwErrors = /*SIGFAILURE_OTHER*/ 1;
  359. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  360. goto ExitHere;
  361. }
  362. // We only care about the trust status of the leaf certificate
  363. dwErrors = rgdwErrors[0];
  364. if (dwErrors != 0) {
  365. if(dwErrors & CERT_VALIDITY_SIGNATURE_FAILS) {
  366. dwRet |= /*SIGFAILURE_INVALID_CERT*/ 2;
  367. dwErrors &= ~CERT_VALIDITY_SIGNATURE_FAILS;
  368. }
  369. if(dwErrors & CERT_VALIDITY_CERTIFICATE_REVOKED) {
  370. dwRet |= /*SIGFAILURE_CERT_REVOKED*/ 4;
  371. dwErrors &= ~CERT_VALIDITY_CERTIFICATE_REVOKED;
  372. }
  373. if(dwErrors & CERT_VALIDITY_AFTER_END) {
  374. dwRet |= /*SIGFAILURE_CERT_EXPIRED*/ 8;
  375. dwErrors &= ~CERT_VALIDITY_AFTER_END;
  376. }
  377. if(dwErrors & CERT_VALIDITY_EXPLICITLY_DISTRUSTED) {
  378. dwRet |= /*SIGFAILURE_CERT_DISTRUSTED*/ 16;
  379. dwErrors &= ~CERT_VALIDITY_EXPLICITLY_DISTRUSTED;
  380. }
  381. if((dwErrors & CERT_VALIDITY_NO_ISSUER_CERT_FOUND) &&
  382. (cCertsInChain == 1)) {
  383. dwRet |= /*SIGFAILURE_CERT_DISTRUSTED*/ 128;
  384. dwErrors &= ~CERT_VALIDITY_NO_ISSUER_CERT_FOUND;
  385. }
  386. if((dwErrors & CERT_VALIDITY_NO_TRUST_DATA) &&
  387. (cCertsInChain == 1)) {
  388. dwRet |= /*SIGFAILURE_CERT_DISTRUSTED*/ 256;
  389. dwErrors &= ~CERT_VALIDITY_NO_TRUST_DATA;
  390. }
  391. if(dwErrors & CERT_VALIDITY_NO_TRUST_DATA) {
  392. dwRet |= /*SIGFAILURE_UNKNOWN_ROOT*/ 32;
  393. dwErrors &= ~CERT_VALIDITY_NO_TRUST_DATA;
  394. }
  395. if(dwErrors & CERT_VALIDITY_ISSUER_DISTRUST) {
  396. dwRet |= /*SIGFAILURE_ISSUER_DISTRUSTED*/ 64;
  397. dwErrors &= ~CERT_VALIDITY_ISSUER_DISTRUST;
  398. }
  399. if(dwErrors) { // catch all other non-specified case
  400. dwRet |= /*SIGFAILURE_OTHER*/ 1;
  401. }
  402. }
  403. *pdwErrors = dwRet;
  404. hr = S_OK;
  405. ExitHere:
  406. //
  407. // Clean up any items laying around
  408. //
  409. if (NULL != pccertOut) {
  410. CertFreeCertificateContext(pccertOut);
  411. }
  412. if (rghstoreCA[0] != NULL) {
  413. CertCloseStore(rghstoreCA[0], 0);
  414. }
  415. if(rgdwErrors)
  416. LocalFree(rgdwErrors);
  417. if(rgCerts != NULL) {
  418. for(i=0; i < cCertsInChain; ++i) {
  419. CertFreeCertificateContext(rgCerts[i]);
  420. }
  421. LocalFree(rgCerts);
  422. }
  423. return hr;
  424. }
  425. BOOL GetOpenEmailFileName(HWND hwnd, LPTSTR szInputFile, LPCSTR szTitle) {
  426. TCHAR szFileName[CCH_OPTION_STRING];
  427. OPENFILENAME ofn = {0};
  428. lstrcpy(szFileName, szInputFile);
  429. if (szInputFile[0] == '<') szInputFile[0] = 0;
  430. ofn.lStructSize = sizeof(ofn);
  431. ofn.hwndOwner = hwnd;
  432. ofn.hInstance = hInst;
  433. ofn.lpstrFilter = "Email File\0*.eml\0";
  434. ofn.lpstrCustomFilter = NULL;
  435. ofn.nMaxCustFilter = 0;
  436. ofn.nFilterIndex = 0;
  437. ofn.lpstrFile = szFileName;
  438. ofn.nMaxFile = CCH_OPTION_STRING;
  439. ofn.lpstrFileTitle = NULL;
  440. ofn.nMaxFileTitle = 0;
  441. ofn.lpstrInitialDir = NULL;
  442. ofn.lpstrTitle = szTitle;
  443. ofn.Flags = OFN_HIDEREADONLY;
  444. ofn.nFileOffset = 0;
  445. ofn.nFileExtension = 0;
  446. ofn.lpstrDefExt = "eml";
  447. ofn.lCustData = 0;
  448. ofn.lpfnHook = NULL;
  449. ofn.lpTemplateName = NULL;
  450. if (GetOpenFileName(&ofn)) {
  451. lstrcpy(szInputFile, szFileName);
  452. return(TRUE);
  453. }
  454. return(FALSE);
  455. }
  456. HRESULT InsertBody(IMimeMessage * pmm, HBODY hbody)
  457. {
  458. HRESULT hr;
  459. hr = pmm->ToMultipart(hbody, "y-security", NULL);
  460. if (FAILED(hr)) return hr;
  461. return S_OK;
  462. }
  463. int PASCAL
  464. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine,
  465. int nCmdShow)
  466. {
  467. BOOL f;
  468. HINSTANCE hInstDebug = NULL;
  469. HRESULT hr;
  470. HWND hwnd;
  471. INITCOMMONCONTROLSEX initCommCtrl = { 8, ICC_TREEVIEW_CLASSES };
  472. MSG msg;
  473. WNDCLASS wndclass;
  474. // OLE Init
  475. hr = CoInitialize(NULL);
  476. if (FAILED(hr))
  477. {
  478. exit(1);
  479. }
  480. InitDemandLoadedLibs();
  481. InitCommonControlsEx(&initCommCtrl);
  482. // Load options from the registry
  483. GetOptions();
  484. if (!hPrevInstance) {
  485. hInst = hInstance;
  486. wndclass.style = CS_HREDRAW | CS_VREDRAW ;
  487. wndclass.lpfnWndProc = WndProc ;
  488. wndclass.cbClsExtra = 0 ;
  489. wndclass.cbWndExtra = 0 ;
  490. wndclass.hInstance = hInstance ;
  491. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION) ;
  492. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW) ;
  493. wndclass.hbrBackground = CreateSolidBrush(0x00ffff);
  494. wndclass.lpszMenuName = szAppName ;
  495. wndclass.lpszClassName = szAppName ;
  496. RegisterClass (&wndclass) ;
  497. }
  498. MsgSMTP = RegisterWindowMessage("SMTPTransport_Notify");
  499. if (! hInstDebug) {
  500. // Load mshtmdbg.dll
  501. hInstDebug = LoadLibrary(c_szDebug);
  502. // Did it load ?
  503. if (NULL != hInstDebug) {
  504. // Locals
  505. PFNREGSPY pfnRegSpy;
  506. // If the user passed /d on the command line, lets configure mshtmdbg.dll
  507. if (0 == lstrcmpi(lpszCmdLine, c_szInvokeUI1) ||
  508. 0 == lstrcmpi(lpszCmdLine, c_szInvokeUI2)) {
  509. // Locals
  510. PFNDEBUGUI pfnDebugUI;
  511. // Get the proc address of the UI
  512. pfnDebugUI = (PFNDEBUGUI)GetProcAddress(hInstDebug, c_szDebugUI);
  513. if (NULL != pfnDebugUI) {
  514. (*pfnDebugUI)(TRUE);
  515. }
  516. }
  517. // Get the process address of the registration
  518. pfnRegSpy = (PFNREGSPY)GetProcAddress(hInstDebug, c_szRegSpy);
  519. if (NULL != pfnRegSpy)
  520. (*pfnRegSpy)();
  521. }
  522. }
  523. hwnd = CreateWindow (szAppName, "S/Mime Test", WS_OVERLAPPEDWINDOW,
  524. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  525. CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ;
  526. ShowWindow (hwnd, nCmdShow) ;
  527. UpdateWindow (hwnd) ;
  528. while (GetMessage(&msg, NULL, 0, 0)) {
  529. TranslateMessage (&msg) ;
  530. DispatchMessage (&msg) ;
  531. }
  532. f = CertCloseStore(HCertStoreMy, CERT_CLOSE_STORE_CHECK_FLAG);
  533. if (!f) {
  534. AssertSz(FALSE, "Global My Cert store did not close completely");
  535. }
  536. if (PSmtp) PSmtp->Release();
  537. if (PAcctMan) PAcctMan->Release();
  538. if (hInstDebug) {
  539. FreeLibrary(hInstDebug);
  540. }
  541. FreeDemandLoadedLibs();
  542. CoFreeUnusedLibraries();
  543. return(msg.wParam);
  544. }
  545. BOOL CALLBACK DetailDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  546. {
  547. switch (msg) {
  548. case WM_INITDIALOG:
  549. break;
  550. default:
  551. return FALSE;
  552. }
  553. return TRUE;
  554. }
  555. BOOL CALLBACK MsgDataDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
  556. {
  557. TCHAR rgchFileName[CCH_OPTION_STRING];
  558. switch (msg) {
  559. case WM_INITDIALOG:
  560. SetDlgItemText(hdlg, IDC_MD_PLAIN_NAME, RootMsg.GetPlainFile());
  561. SetDlgItemText(hdlg, IDC_MD_CIPHER_NAME, RootMsg.GetCipherFile());
  562. SetDlgItemInt(hdlg, IDC_MD_ITERATION, RootMsg.GetIterationCount(), FALSE);
  563. SendDlgItemMessage(hdlg, IDC_MD_TOFILE, BM_SETCHECK, FALSE, 0);
  564. break;
  565. case WM_COMMAND:
  566. switch (wParam) {
  567. case IDC_MD_PLAIN_CHOOSE:
  568. if (GetOpenEmailFileName(hdlg, RootMsg.GetPlainFile(),
  569. "Select Plain Text File")) {
  570. SetDlgItemText(hdlg, IDC_MD_PLAIN_NAME, RootMsg.GetPlainFile());
  571. }
  572. break;
  573. case IDC_MD_CIPHER_CHOOSE:
  574. if (GetOpenEmailFileName(hdlg, RootMsg.GetCipherFile(),
  575. "Select Cipher Text File")) {
  576. SetDlgItemText(hdlg, IDC_MD_CIPHER_NAME, RootMsg.GetCipherFile());
  577. }
  578. break;
  579. case MAKELONG(IDC_MD_PLAIN_NAME, EN_CHANGE):
  580. GetDlgItemText(hdlg, IDC_MD_PLAIN_NAME, RootMsg.GetPlainFile(),
  581. RootMsg.GetFileNameSize());
  582. break;
  583. case MAKELONG(IDC_MD_CIPHER_NAME, EN_CHANGE):
  584. GetDlgItemText(hdlg, IDC_MD_CIPHER_NAME, RootMsg.GetCipherFile(),
  585. RootMsg.GetFileNameSize());
  586. break;
  587. case MAKELONG(IDC_MD_ITERATION, EN_CHANGE):
  588. RootMsg.GetIterationCount() = GetDlgItemInt(hdlg, IDC_MD_ITERATION,
  589. NULL, FALSE);
  590. break;
  591. case MAKELONG(IDC_MD_TOFILE, BN_CLICKED):
  592. RootMsg.SetToFile(!SendDlgItemMessage(hdlg, IDC_MD_TOFILE, BM_GETCHECK, 0, 0));
  593. break;
  594. default:
  595. return FALSE;
  596. }
  597. default:
  598. return FALSE;
  599. }
  600. return TRUE;
  601. }
  602. BOOL InsertNode(LPSTR pszLayerName, int iImage, DWORD iDlg, DWORD dwData)
  603. {
  604. HTREEITEM hitem;
  605. CItem * pitem;
  606. TV_INSERTSTRUCT tvins;
  607. TV_ITEM tvitm;
  608. hitem = TreeView_GetSelection(HwndTree);
  609. tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
  610. tvins.hParent = TreeView_GetParent(HwndTree, hitem);
  611. if (tvins.hParent == NULL) {
  612. tvins.hParent = hitem;
  613. tvins.hInsertAfter = TVI_FIRST;
  614. pitem = NULL;
  615. }
  616. else {
  617. tvins.hInsertAfter = hitem;
  618. tvitm.mask = TVIF_PARAM;
  619. tvitm.hItem = hitem;
  620. TreeView_GetItem(HwndTree, &tvitm);
  621. pitem = (CItem *) tvitm.lParam;
  622. }
  623. tvins.item.pszText = pszLayerName;
  624. tvins.item.cchTextMax = strlen(pszLayerName);
  625. tvins.item.iImage = iImage;
  626. tvins.item.iSelectedImage = tvins.item.iImage;
  627. tvins.item.lParam = dwData;
  628. hitem = TreeView_InsertItem(HwndTree, &tvins);
  629. TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
  630. TreeView_SelectItem(HwndTree, hitem);
  631. SendMessage(RgDlgs[iDlg].hwnd, UM_SET_DATA, 0, tvins.item.lParam);
  632. RootMsg.MakeChild((CItem *) tvins.item.lParam, pitem);
  633. return TRUE;
  634. }
  635. BOOL InsertNode2(int typeParent, LPSTR pszTitle, DWORD iImage, DWORD iDlg,
  636. CItem * pItemNew)
  637. {
  638. HTREEITEM hitem;
  639. HTREEITEM hitemParent;
  640. CItem * pitem;
  641. CItem * pitemParent;
  642. TV_ITEM tvitm;
  643. TV_INSERTSTRUCT tvins;
  644. hitem = TreeView_GetSelection(HwndTree);
  645. hitemParent = TreeView_GetParent(HwndTree, hitem);
  646. tvitm.mask = TVIF_PARAM;
  647. tvitm.hItem = hitem;
  648. TreeView_GetItem(HwndTree, &tvitm);
  649. pitemParent = (CItem *) tvitm.lParam;
  650. if (pitemParent->GetType() == typeParent) {
  651. tvins.hParent = hitemParent;
  652. tvins.hInsertAfter = hitem;
  653. pitem = pitemParent;
  654. pitemParent = ((CSignData *) pitemParent)->GetParent();
  655. }
  656. else {
  657. tvins.hParent = hitem;
  658. tvins.hInsertAfter = TVI_FIRST;
  659. pitem = NULL;
  660. }
  661. tvins.item.lParam = (DWORD) pItemNew;
  662. pItemNew->SetParent(pitemParent);
  663. tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
  664. tvins.hInsertAfter = hitem;
  665. tvins.item.pszText = pszTitle;
  666. tvins.item.cchTextMax = strlen(pszTitle);
  667. tvins.item.iImage = iImage;
  668. tvins.item.iSelectedImage = tvins.item.iImage;
  669. hitem = TreeView_InsertItem(HwndTree, &tvins);
  670. TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
  671. TreeView_SelectItem(HwndTree, hitem);
  672. SendMessage(RgDlgs[iDlg].hwnd, UM_SET_DATA, 0, tvins.item.lParam);
  673. pitemParent->MakeChild((CItem *) tvins.item.lParam, pitem);
  674. return 0;
  675. }
  676. long FAR PASCAL WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
  677. {
  678. HTREEITEM hitem;
  679. HTREEITEM hitemRoot;
  680. HRESULT hr;
  681. int i;
  682. CItem * pitem;
  683. CItem * pitemParent;
  684. LPNMTREEVIEW ptv;
  685. char rgch[300];
  686. TV_ITEM tvitm;
  687. TV_INSERTSTRUCT tvins;
  688. switch (message) {
  689. case WM_CREATE:
  690. // Create our child windows -- we only have one top level window so use
  691. // some globals
  692. HdlgMsg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MSG_DATA), hwnd,
  693. MsgDataDlgProc);
  694. HwndTree = CreateWindow(WC_TREEVIEW, "Tree",
  695. WS_CHILD | WS_CLIPCHILDREN | WS_HSCROLL |
  696. WS_VSCROLL | WS_VISIBLE | TVS_HASBUTTONS |
  697. TVS_HASLINES , 0, 0, 0, 0,
  698. hwnd, NULL, hInst, NULL);
  699. for (i=0; i<Dlg_Max; i++) {
  700. RgDlgs[i].hwnd = CreateDialog(hInst, MAKEINTRESOURCE(RgDlgs[i].id),
  701. hwnd, RgDlgs[i].proc);
  702. AssertSz(RgDlgs[i].hwnd != NULL, "Missed creating a window");
  703. }
  704. // Initialize Tree with an item
  705. tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
  706. tvins.hParent = TVI_ROOT;
  707. tvins.hInsertAfter = TVI_FIRST;
  708. tvins.item.pszText = "Message";
  709. tvins.item.cchTextMax = 7;
  710. tvins.item.iImage = 0;
  711. tvins.item.iSelectedImage = tvins.item.iImage;
  712. tvins.item.lParam = (DWORD) &RootMsg;
  713. hitem = TreeView_InsertItem(HwndTree, &tvins);
  714. TreeView_SelectItem(HwndTree, hitem);
  715. TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
  716. // LoadWAB();
  717. break;
  718. case WM_COMMAND :
  719. switch (wParam) {
  720. case IDM_EXIT :
  721. SendMessage (hwnd, WM_CLOSE, 0, 0L) ;
  722. return 0 ;
  723. case IDM_E_INSERT_SIGN:
  724. InsertNode("Signature Layer", 1, Dlg_Sign_Info_Compose,
  725. (DWORD) new CSignInfo(STATE_COMPOSE, &RootMsg));
  726. return 0;
  727. case IDM_E_INSERT_SIGNATURE:
  728. pitem = new CSignData(STATE_COMPOSE);
  729. InsertNode2(TYPE_SIGN_DATA, "Signature", 2, Dlg_Sign_Data_Compose,
  730. pitem);
  731. ((CSignData *) pitem)->SetDefaultCert();
  732. return 0;
  733. case IDM_E_INSERT_ENCRYPT:
  734. InsertNode("Encryption Layer", 3, Dlg_Enc_Info_Compose,
  735. (DWORD) new CEnvData(STATE_COMPOSE, &RootMsg));
  736. return 0;
  737. case IDM_E_INSERT_TRANSPORT:
  738. InsertNode2(TYPE_ENV_MAILLIST, "Transport", 3, Dlg_Enc_Data_Trans_Compose,
  739. new CEnvCertTrans(STATE_COMPOSE));
  740. break;
  741. case IDM_E_INSERT_AGREEMENT:
  742. InsertNode2(TYPE_ENV_MAILLIST, "Agree", 3, Dlg_Enc_Data_Agree_Compose,
  743. new CEnvCertAgree(STATE_COMPOSE));
  744. break;
  745. case IDM_E_INSERT_MAILLIST:
  746. InsertNode2(TYPE_ENV_MAILLIST, "Mail List", 3, Dlg_Enc_Data_MailList_Compose,
  747. new CEnvMailList(STATE_COMPOSE));
  748. break;
  749. case IDM_ENCODE:
  750. SendMessage(RgDlgs[Dlg_Sign_Data_Compose].hwnd, UM_SET_DATA, 0, NULL);
  751. SendMessage(RgDlgs[Dlg_Enc_Info_Compose].hwnd, UM_SET_DATA, 0, NULL);
  752. SendMessage(RgDlgs[Dlg_Enc_Data_Agree_Compose].hwnd, UM_SET_DATA, 0, NULL);
  753. SendMessage(RgDlgs[Dlg_Enc_Data_Trans_Compose].hwnd, UM_SET_DATA, 0, NULL);
  754. SendMessage(RgDlgs[Dlg_Enc_Data_MailList_Compose].hwnd, UM_SET_DATA, 0, NULL);
  755. for (i=0; i<RootMsg.GetIterationCount(); i++) {
  756. hr = RootMsg.Encode(hwnd);
  757. if (FAILED(hr)) {
  758. wsprintf(rgch, "Encode failed with 0x%08x on iteration %d",
  759. hr, i);
  760. MessageBox(hwnd, rgch, szAppName, MB_OK);
  761. break;
  762. }
  763. CoFreeUnusedLibraries();
  764. }
  765. SendMessage(hwnd, UM_RESET, 0, 0);
  766. RootMsg.ResetMessage();
  767. return 0;
  768. case IDM_DECODE:
  769. for (i=0; i<RootMsg.GetIterationCount(); i++) {
  770. SendMessage(hwnd, UM_RESET, 0, 0);
  771. RootMsg.ResetMessage();
  772. hr = RootMsg.Decode(hwnd);
  773. if (FAILED(hr)) {
  774. wsprintf(rgch, "Decode failed with 0x%08x on iteration %d",
  775. hr, i);
  776. MessageBox(hwnd, rgch, szAppName, MB_OK);
  777. RootMsg.ResetMessage();
  778. break;
  779. }
  780. CoFreeUnusedLibraries();
  781. }
  782. SendMessage(hwnd, UM_FILL, 0, 0);
  783. return(0);
  784. case IDM_RESET:
  785. SendMessage(hwnd, UM_RESET, 0, 0);
  786. RootMsg.ResetMessage();
  787. return 0;
  788. case IDM_VALIDATE:
  789. for (i=0; i<Dlg_Max; i++) {
  790. if (IsWindowVisible(RgDlgs[i].hwnd)) {
  791. SendMessage(RgDlgs[i].hwnd, message, wParam, lParam);
  792. break;
  793. }
  794. }
  795. break;
  796. case IDM_F_OPTIONS:
  797. DialogBox(hInst, MAKEINTRESOURCE(idd_Options), hwnd, OptionsDlgProc);
  798. return(0);
  799. case IDM_F_MAILLIST:
  800. DialogBox(hInst, MAKEINTRESOURCE(IDD_FILE_MAILLIST), hwnd, MailListDlgProc);
  801. return 0;
  802. case IDM_ABOUT:
  803. MessageBox (hwnd, "S/Mime Function Test.",
  804. szAppName, MB_ICONINFORMATION | MB_OK);
  805. return(0);
  806. }
  807. break ;
  808. case WM_SIZE:
  809. {
  810. int cx = LOWORD(lParam);
  811. int cy = HIWORD(lParam);
  812. MoveWindow(HdlgMsg, 0, 1, cx, (cy/3)-2, TRUE);
  813. MoveWindow(HwndTree, 0, (cy/3)+1, (cx/3-1), cy-((cy/3)+1), TRUE);
  814. for (i=0; i<Dlg_Max; i++) {
  815. MoveWindow(RgDlgs[i].hwnd, (cx/3)+1, (cy/3+1), cx-(cx/3)+1,
  816. cy-((cy/3)+1), TRUE);
  817. }
  818. }
  819. break;
  820. case WM_SETFOCUS:
  821. SetFocus(HwndTree);
  822. return 0;
  823. case WM_NOTIFY:
  824. switch (((NMHDR *) lParam)->code) {
  825. case TVN_SELCHANGEDA:
  826. case TVN_SELCHANGEDW:
  827. ptv = (LPNMTREEVIEW) lParam;
  828. switch (((CItem *) ptv->itemNew.lParam)->GetType() |
  829. ((CItem *) ptv->itemNew.lParam)->GetState()) {
  830. case TYPE_SIGN_DATA | STATE_COMPOSE:
  831. ShowWindow(Dlg_Sign_Data_Compose, ptv->itemNew.lParam);
  832. break;
  833. case TYPE_SIGN_DATA | STATE_READ:
  834. ShowWindow(Dlg_Sign_Data_Read, ptv->itemNew.lParam);
  835. break;
  836. case TYPE_ENV_INFO | STATE_COMPOSE:
  837. ShowWindow(Dlg_Enc_Info_Compose, ptv->itemNew.lParam);
  838. break;
  839. case TYPE_ENV_INFO | STATE_READ:
  840. Assert(FALSE);
  841. break;
  842. case TYPE_ENV_AGREE | STATE_COMPOSE:
  843. ShowWindow(Dlg_Enc_Data_Agree_Compose, ptv->itemNew.lParam);
  844. break;
  845. case TYPE_ENV_AGREE | STATE_READ:
  846. Assert(FALSE);
  847. break;
  848. case TYPE_ENV_TRANS | STATE_COMPOSE:
  849. ShowWindow(Dlg_Enc_Data_Trans_Compose, ptv->itemNew.lParam);
  850. break;
  851. case TYPE_ENV_TRANS | STATE_READ:
  852. Assert(FALSE);
  853. break;
  854. case TYPE_ENV_MAILLIST | STATE_COMPOSE:
  855. ShowWindow(Dlg_Enc_Data_MailList_Compose, ptv->itemNew.lParam);
  856. break;
  857. case TYPE_ENV_MAILLIST | STATE_READ:
  858. Assert(FALSE);
  859. break;
  860. case TYPE_MSG | STATE_COMPOSE:
  861. case TYPE_MSG | STATE_READ:
  862. ShowWindow(Dlg_Message, NULL);
  863. break;
  864. case TYPE_SIGN_INFO | STATE_COMPOSE:
  865. case TYPE_SIGN_INFO | STATE_READ:
  866. ShowWindow(Dlg_Sign_Info_Compose, ptv->itemNew.lParam);
  867. break;
  868. }
  869. }
  870. return 0;
  871. case WM_INITMENU:
  872. tvitm.mask = TVIF_PARAM | TVIF_CHILDREN;
  873. tvitm.hItem = TreeView_GetSelection(HwndTree);
  874. TreeView_GetItem(HwndTree, &tvitm);
  875. i = ((CItem *) tvitm.lParam)->GetType();
  876. EnableMenuItem(GetMenu(hwnd), IDM_E_INSERT_SIGN, MF_BYCOMMAND |
  877. (i == TYPE_SIGN_DATA) ? MF_GRAYED : MF_ENABLED);
  878. EnableMenuItem(GetMenu(hwnd), IDM_E_INSERT_ENCRYPT, MF_BYCOMMAND |
  879. (i == TYPE_SIGN_DATA) ? MF_GRAYED : MF_ENABLED);
  880. EnableMenuItem(GetMenu(hwnd), IDM_E_INSERT_SIGNATURE, MF_BYCOMMAND |
  881. ((i == TYPE_SIGN_DATA) || (i == TYPE_SIGN_INFO)) ?
  882. MF_ENABLED : MF_GRAYED);
  883. EnableMenuItem(GetMenu(hwnd), IDM_E_INSERT_TRANSPORT, MF_BYCOMMAND |
  884. ((i == TYPE_ENV_INFO) || (i == TYPE_ENV_AGREE) ||
  885. (i == TYPE_ENV_TRANS) || (i == TYPE_ENV_MAILLIST)) ?
  886. MF_ENABLED : MF_GRAYED);
  887. EnableMenuItem(GetMenu(hwnd), IDM_E_DELETE_LAYER, MF_BYCOMMAND |
  888. (((i == TYPE_SIGN_INFO) || (i == TYPE_ENV_INFO)) &&
  889. (tvitm.cChildren == 0)) ? MF_ENABLED : MF_GRAYED);
  890. EnableMenuItem(GetMenu(hwnd), IDM_E_DELETE_SIGNATURE, MF_BYCOMMAND |
  891. (i == TYPE_SIGN_DATA) ? MF_ENABLED : MF_GRAYED);
  892. break;
  893. case WM_DESTROY:
  894. // Reset the message object to have no contents
  895. SendMessage(hwnd, UM_RESET, 0, 0);
  896. RootMsg.ResetMessage();
  897. SaveOptions();
  898. CleanupOptions();
  899. // UnloadWAB();
  900. for (i=0; i<Dlg_Max; i++) {
  901. DestroyWindow(RgDlgs[i].hwnd);
  902. }
  903. DestroyWindow(HwndTree);
  904. DestroyWindow(HdlgMsg);
  905. PostQuitMessage(0);
  906. return(0);
  907. case UM_RESET:
  908. hitemRoot = TreeView_GetRoot(HwndTree);
  909. while (TRUE) {
  910. TVITEM tvitem;
  911. tvitem.hItem = TreeView_GetChild(HwndTree, hitemRoot);
  912. if (tvitem.hItem == NULL) {
  913. break;
  914. }
  915. tvitem.mask = TVIF_PARAM | TVIF_CHILDREN;
  916. TreeView_GetItem(HwndTree, &tvitem);
  917. if (tvitem.cChildren != 0) {
  918. for (i=0; i<tvitem.cChildren; i++) {
  919. TVITEM tvitem2;
  920. tvitem2.hItem = TreeView_GetChild(HwndTree, tvitem.hItem);
  921. tvitem2.mask = TVIF_PARAM | TVIF_CHILDREN;
  922. TreeView_GetItem(HwndTree, &tvitem2);
  923. delete (CItem *) tvitem2.lParam;
  924. TreeView_DeleteItem(HwndTree, tvitem2.hItem);
  925. }
  926. }
  927. delete (CItem *) tvitem.lParam;
  928. TreeView_DeleteItem(HwndTree, tvitem.hItem);
  929. }
  930. }
  931. return(DefWindowProc (hwnd, message, wParam, lParam));
  932. }
  933. int _stdcall WinMainCRTStartup (void)
  934. {
  935. int i;
  936. STARTUPINFOA si;
  937. PTSTR pszCmdLine = GetCommandLine();
  938. SetErrorMode(SEM_FAILCRITICALERRORS);
  939. if (*pszCmdLine == TEXT ('\"'))
  940. {
  941. // Scan, and skip over, subsequent characters until
  942. // another double-quote or a null is encountered.
  943. while (*++pszCmdLine && (*pszCmdLine != TEXT ('\"')));
  944. // If we stopped on a double-quote (usual case), skip over it.
  945. if (*pszCmdLine == TEXT ('\"')) pszCmdLine++;
  946. }
  947. else
  948. {
  949. while (*pszCmdLine > TEXT (' ')) pszCmdLine++;
  950. }
  951. // Skip past any white space preceeding the second token.
  952. while (*pszCmdLine && (*pszCmdLine <= TEXT (' '))) pszCmdLine++;
  953. si.dwFlags = 0;
  954. GetStartupInfo (&si);
  955. i = WinMainT(GetModuleHandle (NULL), NULL, pszCmdLine,
  956. si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  957. ExitProcess(i);
  958. return i;
  959. }
  960. //////////////////////////////////////////////////////////////////////////
  961. void CItem::MakeChild(CItem * pChild, CItem * pAfter)
  962. {
  963. if (pAfter == NULL) {
  964. pChild->m_pSibling = m_pChild;
  965. m_pChild = pChild;
  966. }
  967. else if (m_pChild == pAfter) {
  968. pChild->m_pSibling = pAfter;
  969. m_pChild = pChild;
  970. }
  971. else {
  972. CItem * pItem = m_pChild;
  973. while (pItem != NULL) {
  974. if (pItem == pAfter) {
  975. pChild->m_pSibling = pItem->m_pSibling;
  976. pItem->m_pSibling = pChild;
  977. break;
  978. }
  979. pItem = pItem->m_pSibling;
  980. }
  981. }
  982. }
  983. void CItem::RemoveAsChild(CItem * pChild)
  984. {
  985. if (m_pChild == pChild) {
  986. m_pChild = pChild->m_pSibling;
  987. pChild->m_pSibling = NULL;
  988. }
  989. else {
  990. CItem * pItem = m_pChild;
  991. while (pItem != NULL) {
  992. if (pItem->m_pSibling == pChild) {
  993. pItem->m_pSibling = pChild->m_pSibling;
  994. pChild->m_pSibling = NULL;
  995. break;
  996. }
  997. pItem = pItem->m_pSibling;
  998. }
  999. }
  1000. }
  1001. HCERTSTORE CMessage::GetAllStore()
  1002. {
  1003. HCERTSTORE hCertStore;
  1004. if (m_hCertStoreAll == NULL) {
  1005. m_hCertStoreAll = CertOpenStore(CERT_STORE_PROV_COLLECTION,
  1006. X509_ASN_ENCODING, NULL, 0, NULL);
  1007. AssertSz(m_hCertStoreAll != NULL, "Open Collection Store");
  1008. hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1009. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  1010. L"MY");
  1011. AssertSz(hCertStore != NULL, "Open My Cert Store failed");
  1012. CertAddStoreToCollection(m_hCertStoreAll, hCertStore, 0, 0);
  1013. CertCloseStore(hCertStore, 0);
  1014. hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1015. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  1016. L"AddressBook");
  1017. AssertSz(hCertStore != NULL, "Open Address Book Cert Store failed");
  1018. CertAddStoreToCollection(m_hCertStoreAll, hCertStore, 0, 0);
  1019. CertCloseStore(hCertStore, 0);
  1020. hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1021. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  1022. L"CA");
  1023. AssertSz(hCertStore != NULL, "Open CA Cert Store failed");
  1024. CertAddStoreToCollection(m_hCertStoreAll, hCertStore, 0, 0);
  1025. CertCloseStore(hCertStore, 0);
  1026. }
  1027. return m_hCertStoreAll;
  1028. }
  1029. HCERTSTORE CMessage::GetMyStore()
  1030. {
  1031. if (m_hCertStoreMy == NULL) {
  1032. m_hCertStoreMy = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1033. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  1034. L"MY");
  1035. AssertSz(m_hCertStoreMy != NULL, "Open My Cert Store failed");
  1036. }
  1037. return m_hCertStoreMy;
  1038. }
  1039. BOOL CMessage::ResetMessage(void)
  1040. {
  1041. BOOL f;
  1042. CItem * pItem;
  1043. CItem * pItemNext;
  1044. AssertSz(Head() == NULL, "Failed to release all children");
  1045. AssertSz(Next() == NULL, "Should never have ANY siblings");
  1046. for (pItem = Head(); pItem != NULL; pItem = pItemNext) {
  1047. pItemNext = pItem->Next();
  1048. delete pItem;
  1049. }
  1050. if (m_hCertStoreMy != NULL) {
  1051. f = CertCloseStore(m_hCertStoreMy, CERT_CLOSE_STORE_CHECK_FLAG);
  1052. if (!f) {
  1053. AssertSz(FALSE, "My Cert store did not close completely");
  1054. }
  1055. m_hCertStoreMy = NULL;
  1056. }
  1057. return TRUE;
  1058. }
  1059. HRESULT CMessage::AddToMessage(DWORD * pulLayer, IMimeMessage * pmm, HWND hwnd)
  1060. {
  1061. *pulLayer = 0;
  1062. return AddToMessage(pulLayer, pmm, hwnd, Head());
  1063. }
  1064. HRESULT CMessage::AddToMessage(DWORD * pulLayer, IMimeMessage * pmm,
  1065. HWND hwnd, CItem * pitem)
  1066. {
  1067. HRESULT hr;
  1068. if (pitem == NULL) {
  1069. return S_OK;
  1070. }
  1071. hr = pitem->AddToMessage(pulLayer, pmm, hwnd);
  1072. if (FAILED(hr)) return hr;
  1073. return AddToMessage(pulLayer, pmm, hwnd, pitem->Next());
  1074. }
  1075. HRESULT CMessage::Decode(HWND hwnd)
  1076. {
  1077. DWORD cLayers;
  1078. HBODY hNode;
  1079. HRESULT hr;
  1080. DWORD iLayer;
  1081. PCCERT_CONTEXT pccert = NULL;
  1082. IMimeBody * pmb = NULL;
  1083. IMimeBody * pmbReceipt = NULL;
  1084. IMimeMessage * pmm = NULL;
  1085. IMimeMessage * pmmReceipt = NULL;
  1086. IMimeSecurity * pms = NULL;
  1087. IMimeSecurity2 * pms2 = NULL;
  1088. IPersistFile * pfile = NULL;
  1089. IPersistFile * pfileOut = NULL;
  1090. WCHAR rgchW[MAX_PATH];
  1091. DWORD * rgdwSecurityType = NULL;
  1092. DWORD * rgdwValidity = NULL;
  1093. PCCERT_CONTEXT * rgpccert = NULL;
  1094. PROPVARIANT * rgpvAlgHash = NULL;
  1095. ULONG ulType;
  1096. PROPVARIANT var;
  1097. // Build the message tree and attach the input file
  1098. hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER,
  1099. IID_IMimeMessage, (LPVOID *) &pmm);
  1100. if (FAILED(hr)) goto exit;
  1101. hr = pmm->InitNew();
  1102. if (FAILED(hr)) goto exit;
  1103. // Load the file
  1104. hr = pmm->QueryInterface(IID_IPersistFile, (LPVOID *) &pfile);
  1105. if (FAILED(hr)) goto exit;
  1106. MultiByteToWideChar(CP_ACP, 0, GetCipherFile(), -1,
  1107. rgchW, sizeof(rgchW)/sizeof(rgchW[0]));
  1108. hr = pfile->Load(rgchW, STGM_READ | STGM_SHARE_EXCLUSIVE);
  1109. if (FAILED(hr)) goto exit;
  1110. //
  1111. // Try using the IMimeSecurity2 interface if it exists and will work
  1112. hr = pmm->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pms2);
  1113. if (FAILED(hr)) {
  1114. if (hr == E_NOINTERFACE) goto TryOldCode;
  1115. goto exit;
  1116. }
  1117. hr = pms2->Decode(hwnd, 0, this);
  1118. if (FAILED(hr)) {
  1119. if (hr != E_FAIL) goto exit;
  1120. TryOldCode:
  1121. // Start up the S/MIME engine
  1122. hr = CoCreateInstance(CLSID_IMimeSecurity, NULL, CLSCTX_INPROC_SERVER,
  1123. IID_IMimeSecurity, (LPVOID *) &pms);
  1124. if (FAILED(hr)) goto exit;
  1125. hr = pms->InitNew();
  1126. if (FAILED(hr)) goto exit;
  1127. // Bind in the HWND
  1128. hr = pmm->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pmb);
  1129. if (FAILED(hr)) goto exit;
  1130. var.vt = VT_UI4;
  1131. var.ulVal = (DWORD) hwnd;
  1132. hr = pmb->SetOption(OID_SECURITY_HWND_OWNER, &var);
  1133. if (FAILED(hr)) goto exit;
  1134. pmb->Release(); pmb = NULL;
  1135. // Now decode the message
  1136. hr = pms->DecodeMessage(pmm, 0);
  1137. if (FAILED(hr)) goto exit;
  1138. }
  1139. //
  1140. hNode = HBODY_ROOT;
  1141. while (TRUE) {
  1142. hr = pmm->BindToObject(hNode, IID_IMimeBody, (LPVOID *) &pmb);
  1143. if (FAILED(hr)) goto exit;
  1144. // Create the fun objects from the properties
  1145. hr = pmb->GetOption(OID_SECURITY_TYPE, &var);
  1146. if (FAILED(hr)) goto exit;
  1147. ulType = var.ulVal;
  1148. if (ulType & MST_THIS_SIGN) {
  1149. HTREEITEM hitem;
  1150. TV_INSERTSTRUCT tvins;
  1151. CSignInfo * psi = new CSignInfo(STATE_READ, &RootMsg);
  1152. CSignData * psd = new CSignData(STATE_READ);
  1153. psd->SetParent(psi);
  1154. tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
  1155. tvins.hParent = TreeView_GetRoot(HwndTree);
  1156. tvins.hInsertAfter = TVI_LAST;
  1157. tvins.item.pszText = "Signature Layer";
  1158. tvins.item.cchTextMax = 15;
  1159. tvins.item.iImage = 1;
  1160. tvins.item.iSelectedImage = tvins.item.iImage;
  1161. tvins.item.lParam = (DWORD) psi;
  1162. if (ulType & MST_BLOB_FLAG) {
  1163. psi->m_fBlob = TRUE;
  1164. }
  1165. hitem = TreeView_InsertItem(HwndTree, &tvins);
  1166. TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
  1167. tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
  1168. tvins.hParent = hitem;
  1169. tvins.hInsertAfter = TVI_LAST;
  1170. tvins.item.pszText = "Signature";
  1171. tvins.item.cchTextMax = 15;
  1172. tvins.item.iImage = 2;
  1173. tvins.item.iSelectedImage = tvins.item.iImage;
  1174. tvins.item.lParam = (DWORD) psd;
  1175. TreeView_InsertItem(HwndTree, &tvins);
  1176. TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
  1177. hr = pmb->GetOption(OID_SECURITY_RO_MSG_VALIDITY, &var);
  1178. if (FAILED(hr)) goto exit;
  1179. psd->m_ulValidity = var.ulVal;
  1180. // hr = pmb->GetOption(OID_SECURITY_HCERTSTORE, &var);
  1181. // if (FAILED(hr)) goto exit;
  1182. hr = pmb->GetOption(OID_SECURITY_CERT_SIGNING, &var);
  1183. if (FAILED(hr)) goto exit;
  1184. psd->m_pccert = (PCCERT_CONTEXT) var.ulVal;
  1185. // hr = pmb->GetOption(OID_SECURITY_ALG_HASH, &var);
  1186. // if (FAILED(hr)) goto exit;
  1187. }
  1188. if (ulType & MST_THIS_ENCRYPT) {
  1189. HTREEITEM hitem;
  1190. TV_INSERTSTRUCT tvins;
  1191. CEnvData * ped = new CEnvData(STATE_READ, &RootMsg);
  1192. tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
  1193. tvins.hParent = TreeView_GetRoot(HwndTree);
  1194. tvins.hInsertAfter = TVI_LAST;
  1195. tvins.item.pszText = "Envelope";
  1196. tvins.item.cchTextMax = 15;
  1197. tvins.item.iImage = 1;
  1198. tvins.item.iSelectedImage = tvins.item.iImage;
  1199. tvins.item.lParam = (DWORD) ped;
  1200. hitem = TreeView_InsertItem(HwndTree, &tvins);
  1201. hr = pmb->GetOption(OID_SECURITY_CERT_DECRYPTION, &var);
  1202. if (FAILED(hr)) goto exit;
  1203. Assert(FALSE);
  1204. // ped->m_pccert = (PCCERT_CONTEXT) var.ulVal;
  1205. }
  1206. if (ulType & MST_RECEIPT_REQUEST) {
  1207. CERT_ALT_NAME_ENTRY rgNames[1];
  1208. CERT_ALT_NAME_INFO myNames = {1, rgNames};
  1209. rgNames[0].dwAltNameChoice = CERT_ALT_NAME_RFC822_NAME;
  1210. rgNames[0].pwszRfc822Name = L"[email protected]";
  1211. if (HCertStoreMy == NULL) {
  1212. HCertStoreMy = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
  1213. NULL, CERT_SYSTEM_STORE_CURRENT_USER,
  1214. L"MY");
  1215. if (HCertStoreMy == NULL) goto exit;
  1216. }
  1217. if (SignHash.cbData != 0) {
  1218. pccert = CertFindCertificateInStore(HCertStoreMy,
  1219. X509_ASN_ENCODING, 0,
  1220. CERT_FIND_SHA1_HASH,
  1221. &SignHash, NULL);
  1222. if (pccert == NULL) goto exit;
  1223. }
  1224. // hr = MimeOleCreateReceipt(pmm, pccert, hwnd, &pmmReceipt,
  1225. // &myNames);
  1226. if (FAILED(hr)) goto exit;
  1227. // Get the root body
  1228. hr = pmmReceipt->BindToObject(HBODY_ROOT, IID_IMimeBody,
  1229. (LPVOID *) &pmbReceipt);
  1230. if (FAILED(hr)) goto exit;
  1231. // Set the HWND for CAPI calls
  1232. var.vt = VT_UI4;
  1233. var.ulVal = (ULONG) hwnd;
  1234. hr = pmbReceipt->SetOption(OID_SECURITY_HWND_OWNER, &var);
  1235. if (FAILED(hr)) goto exit;
  1236. var.vt = VT_UI4;
  1237. var.ulVal = MST_THIS_SIGN | MST_THIS_BLOBSIGN;
  1238. hr = pmbReceipt->SetOption(OID_SECURITY_TYPE, &var);
  1239. if (FAILED(hr)) goto exit;
  1240. var.vt = VT_BLOB;
  1241. var.blob.pBlobData = (LPBYTE) RgbSHA1AlgId;
  1242. var.blob.cbSize = CbSHA1AlgId;
  1243. hr = pmbReceipt->SetOption(OID_SECURITY_ALG_HASH, &var);
  1244. if (FAILED(hr)) goto exit;
  1245. var.vt = VT_UI4;
  1246. var.ulVal = (ULONG) pccert;
  1247. hr = pmbReceipt->SetOption(OID_SECURITY_CERT_SIGNING, &var);
  1248. if (hr == S_OK) {
  1249. hr = pmmReceipt->QueryInterface(IID_IPersistFile, (LPVOID *) &pfileOut);
  1250. if (FAILED(hr)) goto exit;
  1251. hr = pfileOut->Save(L"c:\\receipt.eml", FALSE);
  1252. if (FAILED(hr)) goto exit;
  1253. }
  1254. pmbReceipt->Release();
  1255. }
  1256. if (pmb->IsContentType(STR_CNT_MULTIPART, "y-security") != S_OK) {
  1257. break;
  1258. }
  1259. if (hNode == HBODY_ROOT) {
  1260. pmb->GetHandle(&hNode);
  1261. }
  1262. pmb->Release(); pmb = NULL;
  1263. hr = pmm->GetBody(IBL_FIRST, hNode, &hNode);
  1264. if (FAILED(hr)) goto exit;
  1265. }
  1266. hr = S_OK;
  1267. exit:
  1268. if (pfileOut != NULL) pfileOut->Release();
  1269. if (pfile != NULL) pfile->Release();
  1270. if (pmb != NULL) pmb->Release();
  1271. if (pms != NULL) pms->Release();
  1272. if (pmm != NULL) pmm->Release();
  1273. if (pmmReceipt != NULL) pmmReceipt->Release();
  1274. if (pccert != NULL) CertFreeCertificateContext(pccert);
  1275. return hr;
  1276. }
  1277. HRESULT CMessage::Encode(HWND hwnd)
  1278. {
  1279. DWORD cLayers;
  1280. HBODY hbody;
  1281. HRESULT hr;
  1282. HCERTSTORE hstore = NULL;
  1283. IImnAccount * pAccount = NULL;
  1284. PCCERT_CONTEXT pccertEncrypt = NULL;
  1285. LPSTR pchBody;
  1286. IPersistFile * pfileIn = NULL;
  1287. IPersistFile * pfileOut = NULL;
  1288. IMimeBody * pmb = NULL;
  1289. IMimeMessage * pmm = NULL;
  1290. IMimeSecurity * pms = NULL;
  1291. IMimeSecurity2 * pms2 = NULL;
  1292. LPSTREAM pstmBody = NULL;
  1293. LPSTREAM pstmFile = NULL;
  1294. WCHAR rgchW[CCH_OPTION_STRING];
  1295. DWORD ulLayers = 0;
  1296. PROPVARIANT var;
  1297. // Build the message tree and attach the body
  1298. hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER,
  1299. IID_IMimeMessage, (LPVOID *) &pmm);
  1300. if (FAILED(hr)) goto exit;
  1301. hr = pmm->InitNew();
  1302. if (FAILED(hr)) goto exit;
  1303. pchBody = GetPlainFile();
  1304. if ((*pchBody == 0) || (_stricmp(pchBody, "<none>") == 0)) {
  1305. // Create the body stream
  1306. hr = CreateStreamOnHGlobal( NULL, TRUE, &pstmBody);
  1307. if (FAILED(hr)) goto exit;
  1308. hr = pstmBody->Write(RgchBody, lstrlen(RgchBody), NULL);
  1309. if (FAILED(hr)) goto exit;
  1310. // Attach the body to the message
  1311. hr = pmm->SetTextBody(TXT_PLAIN, IET_8BIT, NULL, pstmBody, &hbody);
  1312. if (FAILED(hr)) goto exit;
  1313. //
  1314. }
  1315. else if (_stricmp(pchBody, "<example>") == 0) {
  1316. // Create the body stream
  1317. hr = CreateStreamOnHGlobal( NULL, TRUE, &pstmBody);
  1318. if (FAILED(hr)) goto exit;
  1319. hr = pstmBody->Write(RgchExample, lstrlen(RgchExample), NULL);
  1320. if (FAILED(hr)) goto exit;
  1321. // Get the root body
  1322. hr = pmm->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pmb);
  1323. if (FAILED(hr)) goto exit;
  1324. hr = pmb->SetData(IET_BINARY, "OID", szOID_RSA_data,
  1325. IID_IStream, pstmBody);
  1326. if (FAILED(hr)) goto exit;
  1327. pmb->Release(); pmb = NULL;
  1328. }
  1329. else {
  1330. MultiByteToWideChar(CP_ACP, 0, pchBody, -1,
  1331. rgchW, sizeof(rgchW)/sizeof(rgchW[0]));
  1332. // Load the file
  1333. hr = pmm->QueryInterface(IID_IPersistFile, (LPVOID *) &pfileIn);
  1334. if (FAILED(hr)) goto exit;
  1335. hr = pfileIn->Load(rgchW, STGM_READ | STGM_SHARE_EXCLUSIVE);
  1336. if (FAILED(hr)) goto exit;
  1337. }
  1338. var.vt = VT_BOOL;
  1339. var.boolVal = TRUE;
  1340. hr = pmm->SetOption(OID_SAVEBODY_KEEPBOUNDARY, &var);
  1341. if (hr) goto exit;
  1342. // Find out what goes where for initialization
  1343. hr = AddToMessage(&cLayers, pmm, hwnd);
  1344. if (FAILED(hr)) goto exit;
  1345. if (1) {
  1346. hr = pmm->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pms2);
  1347. if (FAILED(hr)) goto exit;
  1348. hr = pms2->Encode(hwnd, SEF_SENDERSCERTPROVIDED |
  1349. SEF_ENCRYPTWITHNOSENDERCERT);
  1350. if (FAILED(hr)) goto exit;
  1351. pms2->Release(); pms2 = NULL;
  1352. }
  1353. else {
  1354. // Get the root body
  1355. hr = pmm->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pmb);
  1356. if (FAILED(hr)) goto exit;
  1357. // Set the HWND for CAPI calls
  1358. var.vt = VT_UI4;
  1359. var.ulVal = (ULONG) hwnd;
  1360. hr = pmb->SetOption(OID_SECURITY_HWND_OWNER, &var);
  1361. if (FAILED(hr)) goto exit;
  1362. pmb->Release(); pmb = NULL;
  1363. // Sometimes we must force the encode outside of the Save call
  1364. if (1) {
  1365. hr = CoCreateInstance(CLSID_IMimeSecurity, NULL, CLSCTX_INPROC_SERVER,
  1366. IID_IMimeSecurity, (LPVOID *) &pms);
  1367. if (FAILED(hr)) goto exit;
  1368. hr = pms->InitNew();
  1369. if (FAILED(hr)) goto exit;
  1370. hr = pms->EncodeBody(pmm, HBODY_ROOT, EBF_RECURSE |
  1371. SEF_SENDERSCERTPROVIDED |
  1372. SEF_ENCRYPTWITHNOSENDERCERT |
  1373. EBF_COMMITIFDIRTY);
  1374. if (FAILED(hr)) goto exit;
  1375. pms->Release(); pms = NULL;
  1376. }
  1377. }
  1378. // Set the subject
  1379. var.vt = VT_LPSTR;
  1380. var.pszVal = "Test subject";
  1381. hr = pmm->SetBodyProp(HBODY_ROOT, STR_HDR_SUBJECT, 0, &var);
  1382. if (FAILED(hr)) goto exit;
  1383. // Deal with either dump to file or send via SMTP
  1384. if (m_fToFile) {
  1385. // Dump to a file
  1386. hr = pmm->QueryInterface(IID_IPersistFile, (LPVOID *) &pfileOut);
  1387. if (FAILED(hr)) goto exit;
  1388. MultiByteToWideChar(CP_ACP, 0, GetCipherFile(), -1,
  1389. rgchW, sizeof(rgchW)/sizeof(rgchW[0]));
  1390. hr = pfileOut->Save(rgchW, FALSE);
  1391. if (FAILED(hr)) goto exit;
  1392. }
  1393. else {
  1394. SMTPMESSAGE rMessage = {0};
  1395. INETSERVER rServer;
  1396. char szAccount[] = "SMimeTst";
  1397. INETADDR rgAddress[11];
  1398. if (PAcctMan == NULL) {
  1399. hr = CoCreateInstance(CLSID_ImnAccountManager, NULL, CLSCTX_INPROC_SERVER,
  1400. IID_IImnAccountManager, (LPVOID *) &PAcctMan);
  1401. if (FAILED(hr)) goto exit;
  1402. hr = PAcctMan->Init(NULL);
  1403. if (FAILED(hr)) goto exit;
  1404. }
  1405. if (PSmtp == NULL) {
  1406. // Create smtp transport
  1407. hr = HrCreateSMTPTransport(&PSmtp);
  1408. if (FAILED(hr)) goto exit;
  1409. }
  1410. memset(&rgAddress, 0, sizeof(rgAddress));
  1411. rMessage.rAddressList.prgAddress = rgAddress;
  1412. rMessage.rAddressList.cAddress = 2;
  1413. strcpy(rgAddress[0].szEmail, szSenderEmail);
  1414. rgAddress[0].addrtype = ADDR_FROM;
  1415. strcpy(rgAddress[1].szEmail, szRecipientEmail);
  1416. rgAddress[1].addrtype = ADDR_TO;
  1417. pmm->GetMessageSource(&rMessage.pstmMsg, 0);
  1418. pmm->GetMessageSize(&rMessage.cbSize, 0);
  1419. hr = PAcctMan->FindAccount(AP_ACCOUNT_NAME, szAccount, &pAccount);
  1420. if (FAILED(hr)) goto exit;
  1421. hr = PSmtp->InetServerFromAccount(pAccount, &rServer);
  1422. if (FAILED(hr)) goto exit;
  1423. hr = PSmtp->Connect(&rServer, TRUE, TRUE);
  1424. if (FAILED(hr)) goto exit;
  1425. WaitForCompletion(MsgSMTP, SMTP_CONNECTED);
  1426. pAccount->Release(); pAccount = NULL;
  1427. hr = PSmtp->SendMessage(&rMessage);
  1428. WaitForCompletion(MsgSMTP, SMTP_SEND_MESSAGE);
  1429. hr = PSmtp->CommandQUIT();
  1430. if (FAILED(hr)) goto exit;
  1431. WaitForCompletion(MsgSMTP, SMTP_QUIT);
  1432. }
  1433. hr = NULL;
  1434. exit:
  1435. if (pAccount != NULL) pAccount->Release();
  1436. if (pfileIn != NULL) pfileIn->Release();
  1437. if (pfileOut != NULL) pfileOut->Release();
  1438. if (pstmBody != NULL) pstmBody->Release();
  1439. if (pstmFile != NULL) pstmFile->Release();
  1440. if (pms2 != NULL) pms2->Release();
  1441. if (pms != NULL) pms->Release();
  1442. if (pmb != NULL) pmb->Release();
  1443. if (pmm != NULL) pmm->Release();
  1444. return hr;
  1445. }
  1446. STDMETHODIMP CMessage::QueryInterface(REFIID riid, LPVOID *ppv)
  1447. {
  1448. return E_FAIL;
  1449. }
  1450. STDMETHODIMP_(ULONG) CMessage::AddRef(void)
  1451. {
  1452. return E_FAIL;
  1453. }
  1454. STDMETHODIMP_(ULONG) CMessage::Release(void)
  1455. {
  1456. return E_FAIL;
  1457. }
  1458. STDMETHODIMP CMessage::FindKeyFor(HWND hwnd, DWORD dwFlags, DWORD dwRecipIndex,
  1459. const CMSG_CMS_RECIPIENT_INFO * pRecipInfo,
  1460. DWORD * pdwCtrl, CMS_CTRL_DECRYPT_INFO * pDecryptInfo,
  1461. PCCERT_CONTEXT * ppcert)
  1462. {
  1463. // Only support mail list recipients
  1464. if (pRecipInfo->dwRecipientChoice != CMSG_MAIL_LIST_RECIPIENT) {
  1465. return S_FALSE;
  1466. }
  1467. *pdwCtrl = CMSG_CTRL_MAIL_LIST_DECRYPT;
  1468. return CMailListKey::FindKeyFor(hwnd, dwFlags, dwRecipIndex,
  1469. pRecipInfo, pDecryptInfo);
  1470. }
  1471. STDMETHODIMP CMessage::GetParameters(PCCERT_CONTEXT, LPVOID, DWORD *, LPBYTE *)
  1472. {
  1473. return E_FAIL;
  1474. }