Source code of Windows XP (NT5)
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.

651 lines
14 KiB

  1. // SendMail.cpp: implementation of the CSendMail class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "amisafe.h"
  6. #include "SendMail.h"
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char THIS_FILE[]=__FILE__;
  10. #define new DEBUG_NEW
  11. #endif
  12. //////////////////////////////////////////////////////////////////////
  13. // Construction/Destruction
  14. //////////////////////////////////////////////////////////////////////
  15. CSendMail::CSendMail(CInitMapi &_mapi) : pmsg(NULL), pmapi(_mapi)
  16. {
  17. }
  18. CSendMail::~CSendMail()
  19. {
  20. if (pmsg != NULL)
  21. UlRelease(pmsg);
  22. }
  23. //
  24. // Create an outbound message, put data in it.
  25. //
  26. HRESULT CSendMail::CreateMail(LPSTR szSubject)
  27. {
  28. HRESULT hr;
  29. hr = HrCreateOutMessage(pmapi.pfldOutBox, &pmsg);
  30. if(hr)
  31. return hr;
  32. hr = HrInitMsg(pmsg, pmapi.pvalSentMailEID, szSubject);
  33. if(HR_FAILED(hr)) {
  34. UlRelease(pmsg);
  35. return hr;
  36. }
  37. return hr;
  38. }
  39. HRESULT CSendMail::Transmit()
  40. {
  41. HRESULT hr;
  42. if (pmsg != NULL)
  43. hr = pmsg->SubmitMessage(0);
  44. return hr;
  45. }
  46. //
  47. // Create a message in the outbox
  48. //
  49. HRESULT CSendMail::HrCreateOutMessage(LPMAPIFOLDER pfldOutBox, LPMESSAGE FAR * ppmM)
  50. {
  51. LPMESSAGE lpmResM = NULL;
  52. HRESULT hr;
  53. Assert(pfldOutBox);
  54. hr = pfldOutBox->CreateMessage(NULL, MAPI_DEFERRED_ERRORS, &lpmResM);
  55. if(HR_FAILED(hr))
  56. {
  57. return hr;
  58. }
  59. *ppmM = lpmResM;
  60. return hrSuccess;
  61. }
  62. //
  63. // Put the data from globals in the message
  64. //
  65. HRESULT CSendMail::HrInitMsg(LPMESSAGE pmsg, LPSPropValue pvalSentMailEID, LPSTR szSubject)
  66. {
  67. HRESULT hr;
  68. enum {iSubj, iSentMail, iConvTopic, iConvIdx, iMsgClass, cProps};
  69. // PR_SUBJECT, PR_SENTMAIL_ENTRYID,
  70. // PR_CONVERSATION_TOPIC, PR_COVERSATION_INDEX
  71. SPropValue props[cProps];
  72. ULONG cbConvIdx = 0;
  73. LPBYTE lpbConvIdx = NULL;
  74. //subject and conversation topic
  75. if(szSubject)
  76. {
  77. props[iSubj].ulPropTag = PR_SUBJECT;
  78. props[iSubj].Value.LPSZ = szSubject;
  79. props[iConvTopic].ulPropTag = PR_CONVERSATION_TOPIC;
  80. props[iConvTopic].Value.LPSZ = szSubject;
  81. }
  82. else
  83. {
  84. props[iSubj].ulPropTag = PR_NULL;
  85. props[iConvTopic].ulPropTag = PR_NULL;
  86. }
  87. // conversaton index
  88. //if(!ScAddConversationIndex(0, NULL, &cbConvIdx, &lpbConvIdx))
  89. //{
  90. // props[iConvIdx].ulPropTag = PR_CONVERSATION_INDEX;
  91. // props[iConvIdx].Value.bin.lpb = lpbConvIdx;
  92. // props[iConvIdx].Value.bin.cb = cbConvIdx;
  93. //}
  94. //else
  95. //{
  96. props[iConvIdx].ulPropTag = PR_NULL;
  97. //}
  98. // sent mail entry id (we want to leave a copy in the "Sent Items" folder)
  99. props[iSentMail] = *pvalSentMailEID;
  100. props[iMsgClass].ulPropTag = PR_MESSAGE_CLASS;
  101. props[iMsgClass].Value.lpszA = "IPM.Note";
  102. hr = pmsg->SetProps(cProps, (LPSPropValue)&props, NULL);
  103. if(HR_FAILED(hr))
  104. {
  105. goto err;
  106. }
  107. err:
  108. if (lpbConvIdx != NULL)
  109. MAPIFreeBuffer(lpbConvIdx);
  110. return hr;
  111. }
  112. HRESULT CSendMail::SetRecipients(LPSTR szRecipients)
  113. {
  114. LPADRLIST pal = NULL;
  115. HRESULT hr;
  116. //recipients
  117. hr = HrCreateAddrList(pmapi.pabAddrB, &pal, szRecipients);
  118. if(HR_FAILED(hr))
  119. goto err;
  120. Assert(pal);
  121. hr = pmsg->ModifyRecipients(0, pal);
  122. if(HR_FAILED(hr))
  123. {
  124. goto err;
  125. }
  126. err:
  127. FreePadrlist(pal);
  128. return hr;
  129. }
  130. //
  131. // Create an adrlist with resolved recipients
  132. //
  133. HRESULT CSendMail::HrCreateAddrList(LPADRBOOK pabAddrB, LPADRLIST * ppal, LPSTR szToRecips)
  134. {
  135. HRESULT hr;
  136. LPADRLIST pal = NULL;
  137. int ind;
  138. #define chDELIMITER ';'
  139. int nToRecips = 1;
  140. LPSTR strToken = szToRecips;
  141. while (strToken = strchr(strToken, chDELIMITER))
  142. {
  143. ++strToken;
  144. ++nToRecips;
  145. }
  146. int cb = CbNewADRLIST(nToRecips);
  147. hr = MAPIAllocateBuffer(cb, (LPVOID FAR *) &pal);
  148. if(hr)
  149. {
  150. goto err;
  151. }
  152. ZeroMemory(pal, cb);
  153. hr = MAPIAllocateBuffer(2 * sizeof(SPropValue),
  154. (LPVOID FAR *)&pal->aEntries[0].rgPropVals);
  155. if(hr)
  156. {
  157. goto err;
  158. }
  159. pal->aEntries[0].rgPropVals[0].ulPropTag = PR_DISPLAY_NAME;
  160. pal->aEntries[0].rgPropVals[0].Value.LPSZ = szToRecips;
  161. pal->aEntries[0].rgPropVals[1].ulPropTag = PR_RECIPIENT_TYPE;
  162. pal->aEntries[0].rgPropVals[1].Value.l= MAPI_TO;
  163. pal->aEntries[0].cValues = 2;
  164. strToken = szToRecips;
  165. for(ind = 1; ind < nToRecips; ++ind)
  166. {
  167. LPADRENTRY pae = &pal->aEntries[ind];
  168. hr = MAPIAllocateBuffer(2 * sizeof(SPropValue),
  169. (LPVOID FAR *)&pae->rgPropVals);
  170. if(hr)
  171. {
  172. goto err;
  173. }
  174. strToken = strchr(strToken, chDELIMITER);
  175. Assert(strToken);
  176. *strToken++ = '\0';
  177. pae->rgPropVals[0].ulPropTag = PR_DISPLAY_NAME;
  178. pae->rgPropVals[0].Value.LPSZ = strToken;
  179. pae->rgPropVals[1].ulPropTag = PR_RECIPIENT_TYPE;
  180. pae->rgPropVals[1].Value.l = MAPI_TO;
  181. pae->cValues = 2;
  182. }
  183. pal->cEntries = nToRecips;
  184. hr = pabAddrB->ResolveName(0, 0, NULL, pal);
  185. if(HR_FAILED(hr))
  186. {
  187. goto err;
  188. }
  189. *ppal = pal;
  190. return hrSuccess;
  191. err:
  192. FreePadrlist(pal);
  193. return hr;
  194. }
  195. //////////////////////////////////////////////////////////////////////
  196. // CInitMapi Class
  197. //////////////////////////////////////////////////////////////////////
  198. //////////////////////////////////////////////////////////////////////
  199. // Construction/Destruction
  200. //////////////////////////////////////////////////////////////////////
  201. CInitMapi::CInitMapi() : fMAPIInited(FALSE), pabAddrB(NULL),
  202. pfldOutBox(NULL), pmdb(NULL), pses(NULL), pvalSentMailEID(NULL)
  203. {
  204. }
  205. CInitMapi::~CInitMapi()
  206. {
  207. DeInitMapi();
  208. }
  209. //
  210. // Init MAPI. Open address book, default message store, outbox
  211. //
  212. HRESULT CInitMapi::InitMapi(void)
  213. {
  214. HRESULT hr;
  215. hr = MAPIInitialize(NULL);
  216. if(hr)
  217. {
  218. return hr;
  219. }
  220. fMAPIInited = TRUE;
  221. hr = MAPILogonEx( NULL, NULL /* szProfile */ , NULL /* szPassword */,
  222. MAPI_EXTENDED | MAPI_NEW_SESSION | MAPI_USE_DEFAULT,
  223. &pses);
  224. if(hr)
  225. {
  226. goto err;
  227. }
  228. hr = HrOpenDefaultStore(pses, &pmdb);
  229. if(HR_FAILED(hr))
  230. goto err;
  231. hr = HrOpenAddressBook(pses, &pabAddrB);
  232. if(HR_FAILED(hr))
  233. goto err;
  234. hr = HrOpenOutFolder(pses, pmdb, &pfldOutBox);
  235. if(HR_FAILED(hr))
  236. goto err;
  237. /* retrieve the EntryID of the sentmail folder and change the property tag
  238. so that it is ready to use on a message*/
  239. hr = HrGetOneProp((LPMAPIPROP)pmdb, PR_IPM_SENTMAIL_ENTRYID, &pvalSentMailEID);
  240. if(hr)
  241. {
  242. goto err;
  243. }
  244. pvalSentMailEID->ulPropTag = PR_SENTMAIL_ENTRYID;
  245. return hrSuccess;
  246. err:
  247. DeInitMapi();
  248. return hr;
  249. }
  250. //
  251. // Release MAPI interfaces and logoff
  252. //
  253. void CInitMapi::DeInitMapi(void)
  254. {
  255. if (pfldOutBox != NULL)
  256. {
  257. UlRelease(pfldOutBox);
  258. pfldOutBox = NULL;
  259. }
  260. if(pmdb != NULL)
  261. {
  262. //get our message out of the outbox
  263. ULONG ulFlags = LOGOFF_PURGE;
  264. HRESULT hr;
  265. hr = pmdb->StoreLogoff(&ulFlags);
  266. UlRelease(pmdb);
  267. pmdb = NULL;
  268. }
  269. if (pabAddrB != NULL) {
  270. UlRelease(pabAddrB);
  271. pabAddrB = NULL;
  272. }
  273. if (pvalSentMailEID != NULL) {
  274. MAPIFreeBuffer(pvalSentMailEID);
  275. pvalSentMailEID = NULL;
  276. }
  277. if(pses != NULL)
  278. {
  279. pses->Logoff(0, 0, 0);
  280. UlRelease(pses);
  281. pses = NULL;
  282. }
  283. if(fMAPIInited)
  284. {
  285. MAPIUninitialize();
  286. fMAPIInited = FALSE;
  287. }
  288. }
  289. //
  290. // Open the default message store. (The one that has PR_DEFAULT_STORE set to
  291. // TRUE in the message store table.
  292. //
  293. HRESULT CInitMapi::HrOpenDefaultStore(LPMAPISESSION pses, LPMDB * ppmdb)
  294. {
  295. HRESULT hr;
  296. LPMDB lpmdb = NULL;
  297. LPMAPITABLE ptable = NULL;
  298. LPSRowSet prows = NULL;
  299. LPSPropValue pvalProp = NULL;
  300. static SizedSPropTagArray(2, columns) =
  301. { 2, { PR_DEFAULT_STORE, PR_ENTRYID} };
  302. SPropValue valDefStore;
  303. SRestriction restDefStore;
  304. valDefStore.ulPropTag = PR_DEFAULT_STORE;
  305. valDefStore.dwAlignPad = 0;
  306. valDefStore.Value.b = TRUE;
  307. restDefStore.rt = RES_PROPERTY;
  308. restDefStore.res.resProperty.relop = RELOP_EQ;
  309. restDefStore.res.resProperty.ulPropTag = PR_DEFAULT_STORE;
  310. restDefStore.res.resProperty.lpProp = &valDefStore;
  311. Assert(pses);
  312. hr = pses->GetMsgStoresTable(0, &ptable);
  313. if (HR_FAILED(hr))
  314. {
  315. goto ret;
  316. }
  317. hr = HrQueryAllRows(ptable, (LPSPropTagArray) &columns, &restDefStore, NULL, 0, &prows);
  318. if (HR_FAILED(hr))
  319. {
  320. goto ret;
  321. }
  322. if (prows == NULL || prows->cRows == 0
  323. || prows->aRow[0].lpProps[1].ulPropTag != PR_ENTRYID)
  324. {
  325. ::MessageBox(NULL, "No default store", NULL, MB_OK);
  326. goto ret;
  327. }
  328. Assert(prows->cRows == 1);
  329. hr = pses->OpenMsgStore(0,
  330. prows->aRow[0].lpProps[1].Value.bin.cb,
  331. (LPENTRYID)prows->aRow[0].lpProps[1].Value.bin.lpb,
  332. NULL, MDB_WRITE | MAPI_DEFERRED_ERRORS, &lpmdb);
  333. if (HR_FAILED(hr))
  334. {
  335. //if (GetScode(hr) != MAPI_E_USER_CANCEL)
  336. // TraceFnResult(OpenMsgStore, hr);
  337. goto ret;
  338. }
  339. #if 0
  340. if(hr) /*if we have a warning, display it and succeed */
  341. {
  342. LPMAPIERROR perr = NULL;
  343. pses->lpVtbl->GetLastError(pses, hr, 0, &perr);
  344. MakeMessageBox(hWnd, GetScode(hr), IDS_OPENSTOREWARN, perr, MBS_ERROR);
  345. MAPIFreeBuffer(perr);
  346. }
  347. #endif
  348. Assert(lpmdb != NULL);
  349. *ppmdb = lpmdb;
  350. ret:
  351. FreeProws(prows);
  352. UlRelease(ptable);
  353. return hr;
  354. }
  355. //
  356. // Open MAPI address book
  357. //
  358. HRESULT CInitMapi::HrOpenAddressBook(LPMAPISESSION pses, LPADRBOOK * ppAddrBook)
  359. {
  360. HRESULT hr;
  361. LPADRBOOK pabAddrBook = NULL;
  362. Assert(pses);
  363. hr = pses->OpenAddressBook(0, NULL, 0, &pabAddrBook);
  364. if(HR_FAILED(hr))
  365. {
  366. return hr;
  367. }
  368. #if 0
  369. if(hr) /*if we have a warning*/
  370. {
  371. LPMAPIERROR perr = NULL;
  372. pses->lpVtbl->GetLastError(pses, hr, 0, &perr);
  373. MakeMessageBox(hwnd, GetScode(hr), IDS_OPENABWARN, perr, MBS_ERROR);
  374. MAPIFreeBuffer(perr);
  375. }
  376. #endif
  377. *ppAddrBook = pabAddrBook;
  378. return hrSuccess;
  379. }
  380. //
  381. // Open the outbox of the default store.
  382. // Assumes the default message store has been opened.
  383. //
  384. HRESULT CInitMapi::HrOpenOutFolder(LPMAPISESSION pses, LPMDB pmdb, LPMAPIFOLDER FAR * lppF)
  385. {
  386. LPMAPIFOLDER lpfOutF = NULL;
  387. HRESULT hr;
  388. LPSPropValue lpspvFEID = NULL;
  389. ULONG ulObjType = 0;
  390. Assert(pmdb);
  391. *lppF = NULL;
  392. hr = HrGetOneProp((LPMAPIPROP) pmdb, PR_IPM_OUTBOX_ENTRYID, &lpspvFEID);
  393. if(hr)
  394. {
  395. goto err;
  396. }
  397. Assert(lpspvFEID->ulPropTag == PR_IPM_OUTBOX_ENTRYID);
  398. hr = pmdb->OpenEntry(lpspvFEID->Value.bin.cb,
  399. (LPENTRYID)lpspvFEID->Value.bin.lpb, NULL,
  400. MAPI_MODIFY | MAPI_DEFERRED_ERRORS,
  401. &ulObjType, (LPUNKNOWN FAR *) &lpfOutF);
  402. if(HR_FAILED(hr))
  403. {
  404. goto err;
  405. }
  406. *lppF = lpfOutF;
  407. err:
  408. MAPIFreeBuffer(lpspvFEID);
  409. return hr;
  410. }
  411. //////////////////////////////////////////////////////////////////////
  412. // CAddressEnum Class
  413. //////////////////////////////////////////////////////////////////////
  414. //////////////////////////////////////////////////////////////////////
  415. // Construction/Destruction
  416. //////////////////////////////////////////////////////////////////////
  417. CAddressEnum::CAddressEnum(CInitMapi &_mapi): pmapi(_mapi)
  418. {
  419. }
  420. CAddressEnum::~CAddressEnum()
  421. {
  422. }
  423. HRESULT CAddressEnum::HrLookupSingleAddr(LPADRBOOK pabAddrB,
  424. LPSTR szInputName,
  425. LPSTR szResultBuffer, DWORD dwBufferSize)
  426. {
  427. HRESULT hr;
  428. LPADRLIST pal = NULL;
  429. int cb = CbNewADRLIST(1);
  430. hr = MAPIAllocateBuffer(cb, (LPVOID FAR *) &pal);
  431. if(hr) {
  432. goto err;
  433. }
  434. ZeroMemory(pal, cb);
  435. hr = MAPIAllocateBuffer(2 * sizeof(SPropValue),
  436. (LPVOID FAR *)&pal->aEntries[0].rgPropVals);
  437. if(hr) {
  438. goto err;
  439. }
  440. pal->aEntries[0].rgPropVals[0].ulPropTag = PR_DISPLAY_NAME;
  441. pal->aEntries[0].rgPropVals[0].Value.lpszA = szInputName;
  442. pal->aEntries[0].rgPropVals[1].ulPropTag = PR_RECIPIENT_TYPE;
  443. pal->aEntries[0].rgPropVals[1].Value.l= MAPI_TO;
  444. pal->aEntries[0].cValues = 2;
  445. pal->cEntries = 1;
  446. hr = pabAddrB->ResolveName(0, 0, NULL, pal);
  447. if(HR_FAILED(hr)) {
  448. goto err;
  449. }
  450. for (int ind = 0; ind < (int) pal->cEntries; ind++) {
  451. for (int prop = 0; prop < (int) pal->aEntries[ind].cValues; prop++) {
  452. if (pal->aEntries[ind].rgPropVals[prop].ulPropTag == PR_DISPLAY_NAME ||
  453. pal->aEntries[ind].rgPropVals[prop].ulPropTag == PR_EMAIL_ADDRESS) {
  454. strncpy(szResultBuffer,
  455. pal->aEntries[ind].rgPropVals[prop].Value.lpszA,
  456. dwBufferSize);
  457. szResultBuffer[dwBufferSize - 1] = '\0';
  458. hr = S_OK;
  459. goto err;
  460. }
  461. }
  462. }
  463. hr = MAPI_E_NOT_FOUND;
  464. err:
  465. FreePadrlist(pal);
  466. return hr;
  467. }
  468. HRESULT CAddressEnum::LookupAddress(LPSTR szInputName, LPSTR szResultBuffer, DWORD dwBufferSize)
  469. {
  470. return HrLookupSingleAddr(pmapi.pabAddrB, szInputName, szResultBuffer, dwBufferSize);
  471. }
  472. #if 0
  473. HRESULT hr;
  474. LPABCONT pabRootCont; // IABContainer
  475. LPMAPITABLE pMapiTable;
  476. // LPADRBOOK IAddrBook
  477. // Open the address book's root container
  478. hr = pmapi.pabAddrB->OpenEntry(0, NULL, IABContainer, MAPI_BEST_ACCESS,
  479. NULL, (LPUNKNOWN FAR *) &pabRootCont);
  480. if (HR_FAILED(hr)) {
  481. return hr;
  482. }
  483. hr = pabRootCont->GetContentsTable(0, &pMapiTable);
  484. if (HR_FAILED(hr)) {
  485. UlRelease(pabRootCont);
  486. return hr;
  487. }
  488. hr = HrQueryAllRows(pMapiTable,
  489. LPSPropTagArray ptaga,
  490. LPSRestriction pres,
  491. NULL, // sort order
  492. 10, // maximum records to return
  493. LPSRowSet FAR * pprows
  494. );
  495. GetContentsTable
  496. IMAPITable::SortTable,
  497. IMAPITable::QueryRows
  498. #endif