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.

2998 lines
90 KiB

  1. //
  2. // SMAPI.CPP - Simple MAPI implementation
  3. //
  4. #include "pch.hxx"
  5. #include "note.h"
  6. #include <mapi.h>
  7. #include <mapicode.h>
  8. #include <mimeutil.h>
  9. #include <resource.h>
  10. #include <ipab.h>
  11. #include <error.h>
  12. #include <strconst.h>
  13. #include "smapimem.h"
  14. #include <bodyutil.h>
  15. #include <goptions.h>
  16. #include <spoolapi.h>
  17. #include "instance.h"
  18. #include "msgfldr.h"
  19. #include <mailutil.h>
  20. #include <storecb.h>
  21. #include "multiusr.h"
  22. #include <..\help\mailnews.h>
  23. #include <inetcfg.h>
  24. #include "mapidlg.h"
  25. #include "demand.h"
  26. ASSERTDATA
  27. static LPWAB s_lpWab;
  28. static LPWABOBJECT s_lpWabObject;
  29. static IAddrBook* s_lpAddrBook;
  30. extern HANDLE hSmapiEvent;
  31. HINITREF hInitRef=NULL;
  32. HRESULT HrAdrlistFromRgrecip(ULONG nRecips, lpMapiRecipDesc lpRecips, LPADRLIST *ppadrlist);
  33. HRESULT HrRgrecipFromAdrlist(LPADRLIST lpAdrList, lpMapiRecipDesc * lppRecips);
  34. void ParseEmailAddress(LPSTR pszEmail, LPSTR *ppszAddrType, LPSTR *ppszAddress);
  35. void FreePadrlist(LPADRLIST padrlist);
  36. ULONG HrFillMessage(LPMIMEMESSAGE *pmsg, lpMapiMessage lpMessage, BOOL *pfWebPage, BOOL bValidateRecips, BOOL fOriginator);
  37. BOOL HrReadMail (IMessageFolder *pFolder, LPSTR lpszMessageID, lpMapiMessage FAR *lppMessage, FLAGS flFlags);
  38. ULONG HrValidateMessage(lpMapiMessage lpMessage);
  39. BOOL HrSMAPISend(HWND hWnd, IMimeMessage *pMsg);
  40. HRESULT HrFromIDToNameAndAddress(LPTSTR *pszLocalName, LPTSTR *pszLocalAddress, ULONG cbEID, LPENTRYID lpEID);
  41. INT_PTR CALLBACK WarnSendMailDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  42. // Fix for Bug #62129 (v-snatar)
  43. HRESULT HrSendAndRecv();
  44. typedef enum tagINTERACTIVESTATE
  45. {
  46. IS_UNINIT,
  47. IS_INTERACTIVE,
  48. IS_NOTINTERACTIVE,
  49. } INTERACTIVESTATE;
  50. // Determine if the current process is a service or not
  51. BOOL IsProcessInteractive(void);
  52. ///////////////////////////////////////////////////////////////////////
  53. //
  54. // UlSimpleMAPIInit
  55. //
  56. ///////////////////////////////////////////////////////////////////////
  57. ULONG UlSimpleMAPIInit(BOOL fInit, HWND hwnd, BOOL fLogonUI)
  58. {
  59. ULONG ulRet = SUCCESS_SUCCESS;
  60. BOOL bCoIncrementFailure = FALSE;
  61. if (fInit)
  62. {
  63. // [PaulHi] 5/17/99 @todo @bug
  64. // The "SimpleMAPIInit" name is used in debug only builds to track users of
  65. // OE. However, if this function (CoIncrementInit) fails (if user doesn't
  66. // provide identity) then a memory leak will occur because CoDecrementInit()
  67. // is called with "COutlookExpress" and so the "SimpleMAPIInit" node isn't
  68. // free'd. Again, this is for debug binaries only.
  69. /*
  70. Yet more cludgyness:
  71. If SMAPI is not allowed to show logon UI, we ask OE to use the default
  72. identity. However, the default identity could have a password on it.
  73. In this case, SMAPI would like to fail the logon. Unfortunately, the
  74. identity manager does not make it easy to discover if an identity has a
  75. a password (we would need to grok the registry). This limitation is
  76. currently moot as OE will logon to the default identity without requiring
  77. the user to supply the required password. If this is fixed, we will have
  78. to change this code.
  79. */
  80. if (FAILED(CoIncrementInit("SimpleMAPIInit", MSOEAPI_START_SHOWERRORS |
  81. ((fLogonUI) ? 0 : MSOEAPI_START_DEFAULTIDENTITY ), NULL, &hInitRef)))
  82. {
  83. ulRet = MAPI_E_FAILURE;
  84. bCoIncrementFailure = TRUE;
  85. goto exit;
  86. }
  87. if (S_OK != ProcessICW(hwnd, FOLDER_LOCAL, TRUE, fLogonUI))
  88. {
  89. ulRet = MAPI_E_LOGON_FAILURE;
  90. goto exit;
  91. }
  92. if (NULL == s_lpWab)
  93. {
  94. if (FAILED(HrCreateWabObject(&s_lpWab)))
  95. {
  96. ulRet = MAPI_E_FAILURE;
  97. goto exit;
  98. }
  99. Assert(s_lpWab);
  100. if (FAILED(s_lpWab->HrGetAdrBook(&s_lpAddrBook)))
  101. {
  102. ulRet = MAPI_E_FAILURE;
  103. goto exit;
  104. }
  105. Assert(s_lpAddrBook);
  106. if (FAILED(s_lpWab->HrGetWabObject(&s_lpWabObject)))
  107. {
  108. ulRet = MAPI_E_FAILURE;
  109. goto exit;
  110. }
  111. Assert(s_lpWabObject);
  112. }
  113. else
  114. {
  115. if (FAILED(s_lpWab->HrGetWabObject(&s_lpWabObject)))
  116. {
  117. ulRet = MAPI_E_FAILURE;
  118. goto exit;
  119. }
  120. Assert(s_lpWabObject);
  121. }
  122. }
  123. exit:
  124. if (FALSE == fInit || (fInit && SUCCESS_SUCCESS != ulRet && !bCoIncrementFailure))
  125. {
  126. CoDecrementInit("SimpleMAPIInit", NULL);
  127. }
  128. return ulRet;
  129. }
  130. ///////////////////////////////////////////////////////////////////////
  131. //
  132. // SimpleMAPICleanup
  133. //
  134. ///////////////////////////////////////////////////////////////////////
  135. void SimpleMAPICleanup(void)
  136. {
  137. SafeRelease(s_lpWab);
  138. s_lpWabObject = NULL;
  139. s_lpAddrBook = NULL;
  140. }
  141. ///////////////////////////////////////////////////////////////////////
  142. //
  143. // Simple MAPI Session Implementation
  144. //
  145. ///////////////////////////////////////////////////////////////////////
  146. #define SESSION_MAGIC 0xEA030571
  147. class CSession
  148. {
  149. public:
  150. CSession();
  151. ~CSession();
  152. ULONG UlInit(HWND hwnd, BOOL fLogonUI);
  153. ULONG m_cRef;
  154. DWORD m_dwSessionMagic;
  155. IMessageFolder *m_pfldrInbox;
  156. BOOL m_fDllInited;
  157. };
  158. typedef CSession * PSESS;
  159. CSession::CSession()
  160. {
  161. m_cRef = 0;
  162. m_dwSessionMagic = SESSION_MAGIC;
  163. m_pfldrInbox = NULL;
  164. m_fDllInited = FALSE;
  165. }
  166. CSession::~CSession()
  167. {
  168. if (m_pfldrInbox)
  169. m_pfldrInbox->Release();
  170. if (m_fDllInited)
  171. {
  172. UlSimpleMAPIInit(FALSE, NULL, FALSE);
  173. }
  174. }
  175. ULONG CSession::UlInit(HWND hwnd, BOOL fLogonUI)
  176. {
  177. ULONG ulRet = SUCCESS_SUCCESS;
  178. ulRet = UlSimpleMAPIInit(TRUE, hwnd, fLogonUI);
  179. if (SUCCESS_SUCCESS == ulRet)
  180. {
  181. m_fDllInited = TRUE;
  182. }
  183. return ulRet;
  184. }
  185. ULONG UlGetSession(LHANDLE lhSession, PSESS *ppSession, ULONG_PTR ulUIParam, BOOL fLogonUI, BOOL fNeedInbox)
  186. {
  187. ULONG ulRet = SUCCESS_SUCCESS;
  188. PSESS pSession = NULL;
  189. if (lhSession && IsBadWritePtr((LPVOID)lhSession, sizeof(CSession)))
  190. {
  191. ulRet = MAPI_E_INVALID_SESSION;
  192. goto exit;
  193. }
  194. if (lhSession)
  195. {
  196. pSession = (PSESS)lhSession;
  197. if (pSession->m_dwSessionMagic != SESSION_MAGIC)
  198. {
  199. ulRet = MAPI_E_INVALID_SESSION;
  200. goto exit;
  201. }
  202. }
  203. else
  204. {
  205. pSession = new CSession();
  206. if (NULL == pSession)
  207. {
  208. ulRet = MAPI_E_INSUFFICIENT_MEMORY;
  209. goto exit;
  210. }
  211. ulRet = pSession->UlInit((HWND) ulUIParam, fLogonUI);
  212. if (SUCCESS_SUCCESS != ulRet)
  213. {
  214. delete pSession;
  215. goto exit;
  216. }
  217. }
  218. if (fNeedInbox && !pSession->m_pfldrInbox)
  219. {
  220. if (FAILED(g_pStore->OpenSpecialFolder(FOLDERID_LOCAL_STORE, NULL, FOLDER_INBOX, &pSession->m_pfldrInbox)))
  221. {
  222. ulRet = MAPI_E_FAILURE;
  223. goto exit;
  224. }
  225. }
  226. pSession->m_cRef++;
  227. *ppSession = pSession;
  228. // Set the return value
  229. ulRet = SUCCESS_SUCCESS;
  230. exit:
  231. return ulRet;
  232. }
  233. ULONG ReleaseSession(PSESS pSession)
  234. {
  235. HRESULT hr =S_OK;
  236. if (NULL == pSession)
  237. return MAPI_E_INVALID_SESSION;
  238. if (IsBadWritePtr(pSession, sizeof(CSession)))
  239. return MAPI_E_INVALID_SESSION;
  240. if (pSession->m_dwSessionMagic != SESSION_MAGIC)
  241. return MAPI_E_INVALID_SESSION;
  242. if (--pSession->m_cRef == 0)
  243. {
  244. delete pSession;
  245. /* if(hInitRef)
  246. IF_FAILEXIT(hr = CoDecrementInit("SimpleMAPIInit", &hInitRef));
  247. hInitRef = NULL;
  248. */
  249. }
  250. return SUCCESS_SUCCESS;
  251. // exit:
  252. return(hr);
  253. }
  254. ///////////////////////////////////////////////////////////////////////
  255. //
  256. // MAPILogon
  257. //
  258. ///////////////////////////////////////////////////////////////////////
  259. ULONG FAR PASCAL MAPILogon(ULONG_PTR ulUIParam,
  260. LPSTR lpszProfileName,
  261. LPSTR lpszPassword,
  262. FLAGS flFlags,
  263. ULONG ulReserved,
  264. LPLHANDLE lplhSession)
  265. {
  266. ULONG ulRet = SUCCESS_SUCCESS;
  267. PSESS pSession = NULL;
  268. BOOL fLogonUI;
  269. fLogonUI = (0 != (flFlags & MAPI_LOGON_UI));
  270. // If the process is not interactive, they should not have
  271. // allowed any UI
  272. if (!IsProcessInteractive() && fLogonUI)
  273. {
  274. ulRet = MAPI_E_FAILURE;
  275. goto exit;
  276. }
  277. ulRet = UlGetSession(NULL, &pSession, ulUIParam, fLogonUI, FALSE);
  278. if (SUCCESS_SUCCESS != ulRet)
  279. return ulRet;
  280. *lplhSession = (LHANDLE)pSession;
  281. // Fix for Bug #62129 (v-snatar)
  282. if (flFlags & MAPI_FORCE_DOWNLOAD)
  283. HrSendAndRecv();
  284. exit:
  285. return ulRet;
  286. }
  287. ///////////////////////////////////////////////////////////////////////
  288. //
  289. // MAPILogoff
  290. //
  291. ///////////////////////////////////////////////////////////////////////
  292. ULONG FAR PASCAL MAPILogoff(LHANDLE lhSession,
  293. ULONG_PTR ulUIParam,
  294. FLAGS flFlags,
  295. ULONG ulReserved)
  296. {
  297. return ReleaseSession((PSESS)lhSession);
  298. }
  299. ///////////////////////////////////////////////////////////////////////
  300. //
  301. // MAPIFreeBuffer
  302. //
  303. ///////////////////////////////////////////////////////////////////////
  304. ULONG FAR PASCAL MAPIFreeBuffer(LPVOID lpv)
  305. {
  306. LPBufInternal lpBufInt;
  307. LPBufInternal lpT;
  308. if (!lpv)
  309. return(0L); // for callers who don't check for NULL themselves.
  310. lpBufInt = LPBufIntFromLPBufExt(lpv);
  311. if (IsBadWritePtr(lpBufInt, sizeof(BufInternal)))
  312. {
  313. TellBadBlock(lpv, "fails address check");
  314. return MAPI_E_FAILURE;
  315. }
  316. if (GetFlags(lpBufInt->ulAllocFlags) != ALLOC_WITH_ALLOC)
  317. {
  318. TellBadBlock(lpv, "has invalid allocation flags");
  319. return MAPI_E_FAILURE;
  320. }
  321. #ifdef DEBUG
  322. if (!FValidAllocChain(lpBufInt))
  323. goto ret;
  324. #endif
  325. // Free the first block
  326. lpT = lpBufInt->pLink;
  327. g_pMalloc->Free(lpBufInt);
  328. lpBufInt = lpT;
  329. while (lpBufInt)
  330. {
  331. if (IsBadWritePtr(lpBufInt, sizeof(BufInternal)) || GetFlags(lpBufInt->ulAllocFlags) != ALLOC_WITH_ALLOC_MORE)
  332. goto ret;
  333. lpT = lpBufInt->pLink;
  334. g_pMalloc->Free(lpBufInt);
  335. lpBufInt = lpT;
  336. }
  337. ret:
  338. return SUCCESS_SUCCESS;
  339. }
  340. ///////////////////////////////////////////////////////////////////////
  341. //
  342. // MAPISendMail
  343. //
  344. ///////////////////////////////////////////////////////////////////////
  345. ULONG FAR PASCAL MAPISendMail(LHANDLE lhSession, // ignored
  346. ULONG_PTR ulUIParam,
  347. lpMapiMessage lpMessage,
  348. FLAGS flFlags,
  349. ULONG ulReserved)
  350. {
  351. ULONG ulRet = SUCCESS_SUCCESS;
  352. LPMIMEMESSAGE pMsg = NULL;
  353. HRESULT hr;
  354. BOOL fWebPage;
  355. PSESS pSession = NULL;
  356. BOOL fLogonUI;
  357. BOOL fOleInit = FALSE;
  358. // validate parameters
  359. if (NULL == lpMessage || IsBadReadPtr(lpMessage, sizeof(MapiMessage)))
  360. return MAPI_E_INVALID_MESSAGE;
  361. fLogonUI = (0 != (flFlags & MAPI_LOGON_UI));
  362. // If the process is not interactive, they should not allow any UI
  363. if (!IsProcessInteractive() && fLogonUI)
  364. {
  365. return MAPI_E_FAILURE;
  366. }
  367. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  368. ulUIParam = 0;
  369. if (!(flFlags & MAPI_DIALOG))
  370. {
  371. ulRet = HrValidateMessage(lpMessage);
  372. if (ulRet)
  373. return ulRet;
  374. }
  375. ulRet = UlGetSession(lhSession, &pSession, ulUIParam, fLogonUI, FALSE);
  376. if (SUCCESS_SUCCESS != ulRet)
  377. return ulRet;
  378. // display warning dialog if app is sending mail without ui and the users
  379. // wish to be alerted
  380. if (!(flFlags & MAPI_DIALOG) && !!DwGetOption(OPT_SECURITY_MAPI_SEND))
  381. {
  382. if (IDCANCEL == DialogBoxParam(g_hLocRes,MAKEINTRESOURCE(iddMapiSend),
  383. NULL, WarnSendMailDlgProc, (LPARAM)lpMessage))
  384. goto error;
  385. }
  386. // Make sure OLE is initialized
  387. OleInitialize(NULL);
  388. fOleInit = TRUE;
  389. // Fill IMimeMessage with the lpMessage structure members
  390. ulRet = HrFillMessage(&pMsg, lpMessage, &fWebPage, !(flFlags & MAPI_DIALOG), !(flFlags & MAPI_DIALOG));
  391. if (ulRet)
  392. goto error;
  393. if (flFlags & MAPI_DIALOG)
  394. {
  395. INIT_MSGSITE_STRUCT rInitSite;
  396. DWORD dwAction,
  397. dwCreateFlags = OENCF_SENDIMMEDIATE | OENCF_MODAL; // always on dllentry points...
  398. if (fWebPage)
  399. dwAction = OENA_WEBPAGE;
  400. else
  401. dwAction = OENA_COMPOSE;
  402. rInitSite.dwInitType = OEMSIT_MSG;
  403. rInitSite.pMsg = pMsg;
  404. rInitSite.folderID = FOLDERID_INVALID;
  405. hr = CreateAndShowNote(dwAction, dwCreateFlags, &rInitSite, (HWND)ulUIParam);
  406. hInitRef = NULL;
  407. }
  408. else
  409. hr = HrSMAPISend((HWND)ulUIParam, pMsg); // Send the Message without displaying it
  410. if (SUCCEEDED(hr))
  411. ulRet = SUCCESS_SUCCESS;
  412. else
  413. ulRet = MAPI_E_FAILURE;
  414. error:
  415. if (pMsg)
  416. pMsg->Release();
  417. ReleaseSession(pSession);
  418. // Make sure we clean up OLE afterwords
  419. if (fOleInit)
  420. OleUninitialize();
  421. return ulRet;
  422. }
  423. ///////////////////////////////////////////////////////////////////////
  424. //
  425. // MAPISendDocuments
  426. //
  427. ///////////////////////////////////////////////////////////////////////
  428. ULONG FAR PASCAL MAPISendDocuments(ULONG_PTR ulUIParam,
  429. LPSTR lpszDelimChar,
  430. LPSTR lpszFullPaths,
  431. LPSTR lpszFileNames,
  432. ULONG ulReserved)
  433. {
  434. ULONG ulRet = MAPI_E_FAILURE;
  435. int cch;
  436. LPMIMEMESSAGE pMsg = NULL;
  437. HRESULT hr;
  438. CStringParser spPath;
  439. int nCount=0; // Used to find the number of files to be attached
  440. PSESS pSession = NULL;
  441. INIT_MSGSITE_STRUCT rInitSite;
  442. DWORD dwAction,
  443. dwCreateFlags = OENCF_SENDIMMEDIATE | OENCF_MODAL; //always on dllentry points...
  444. // check for the Delimiter
  445. Assert(lpszDelimChar);
  446. if (lpszDelimChar == NULL)
  447. return MAPI_E_FAILURE;
  448. // check for the Paths
  449. Assert (lpszFullPaths);
  450. if (lpszFullPaths == NULL)
  451. return MAPI_E_FAILURE;
  452. // MAPISendDocuments is documented as always bringing up UI
  453. // A service should not call this function
  454. if (!IsProcessInteractive())
  455. return MAPI_E_LOGIN_FAILURE;
  456. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  457. ulUIParam = 0;
  458. ulRet = UlGetSession(NULL, &pSession, ulUIParam, TRUE, FALSE);
  459. if (SUCCESS_SUCCESS != ulRet)
  460. return ulRet;
  461. // create an empty message
  462. hr = HrCreateMessage(&pMsg);
  463. if (FAILED(hr))
  464. goto error;
  465. dwAction = OENA_COMPOSE;
  466. // ~~~ Do I need to do something with OEMSIT_VIRGIN?
  467. rInitSite.dwInitType = OEMSIT_MSG;
  468. rInitSite.pMsg = pMsg;
  469. rInitSite.folderID = FOLDERID_INVALID;
  470. // Determine the number of attachments (nCount), indiviual file names and pathnames
  471. // call pMsg->AttachFile with appropriate parameters nCount times
  472. // To parse the lpszFullPaths and lpszFileNames use CStringParser class
  473. spPath.Init(lpszFullPaths, lstrlen(lpszFullPaths), 0);
  474. //Parse the path for the delimiter
  475. spPath.ChParse(lpszDelimChar);
  476. while (spPath.CchValue())
  477. {
  478. // Add the attachment
  479. hr = pMsg->AttachFile(spPath.PszValue(), NULL, NULL);
  480. if (FAILED(hr))
  481. goto error;
  482. nCount++;
  483. //Parse the path for the delimiter
  484. spPath.ChParse(lpszDelimChar);
  485. }
  486. // set the subject on the message
  487. if (nCount == 1)
  488. {
  489. if (lpszFileNames)
  490. hr = MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, lpszFileNames);
  491. }
  492. else
  493. {
  494. TCHAR szBuf[CCHMAX_STRINGRES];
  495. AthLoadString(idsAttachedFiles, szBuf, ARRAYSIZE(szBuf));
  496. hr = MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, szBuf);
  497. }
  498. if (FAILED(hr))
  499. goto error;
  500. hr = CreateAndShowNote(dwAction, dwCreateFlags, &rInitSite, (HWND)ulUIParam);
  501. if (SUCCEEDED(hr))
  502. ulRet = SUCCESS_SUCCESS;
  503. error:
  504. if (pMsg)
  505. pMsg->Release();
  506. ReleaseSession(pSession);
  507. return ulRet;
  508. }
  509. ///////////////////////////////////////////////////////////////////////
  510. //
  511. // MAPIAddress
  512. //
  513. ///////////////////////////////////////////////////////////////////////
  514. ULONG FAR PASCAL MAPIAddress(LHANDLE lhSession,
  515. ULONG_PTR ulUIParam,
  516. LPTSTR lpszCaption,
  517. ULONG nEditFields,
  518. LPTSTR lpszLabels,
  519. ULONG nRecips,
  520. lpMapiRecipDesc lpRecips,
  521. FLAGS flFlags,
  522. ULONG ulReserved,
  523. LPULONG lpnNewRecips,
  524. lpMapiRecipDesc FAR * lppNewRecips)
  525. {
  526. ULONG ul, ulRet = MAPI_E_FAILURE;
  527. HRESULT hr;
  528. LPADRLIST lpAdrList = 0;
  529. ADRPARM AdrParms = {0};
  530. static ULONG rgulTypes[3] = {MAPI_TO, MAPI_CC, MAPI_BCC};
  531. PSESS pSession = NULL;
  532. BOOL fLogonUI;
  533. // Validate Parameters - Begin
  534. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  535. ulUIParam = 0;
  536. if (lpszCaption && IsBadStringPtr(lpszCaption, (UINT)0xFFFF))
  537. return MAPI_E_FAILURE;
  538. if (nEditFields > 4)
  539. return MAPI_E_INVALID_EDITFIELDS;
  540. if (nEditFields == 1 && lpszLabels && IsBadStringPtr(lpszLabels, (UINT)0xFFFF))
  541. return MAPI_E_INVALID_EDITFIELDS;
  542. if (nEditFields && IsBadWritePtr(lpnNewRecips, (UINT)sizeof(ULONG)))
  543. return MAPI_E_INVALID_EDITFIELDS;
  544. if (nEditFields && IsBadWritePtr(lppNewRecips, (UINT)sizeof(lpMapiRecipDesc)))
  545. return MAPI_E_INVALID_EDITFIELDS;
  546. if (nRecips && IsBadReadPtr(lpRecips, (UINT)nRecips * sizeof(MapiRecipDesc)))
  547. return MAPI_E_INVALID_RECIPS;
  548. fLogonUI = (0 != (flFlags & MAPI_LOGON_UI));
  549. // Services shouldn't ask for UI
  550. if (!IsProcessInteractive() && fLogonUI)
  551. return MAPI_E_LOGIN_FAILURE;
  552. // Validate parameters - End
  553. // init output parameters
  554. if (nEditFields)
  555. {
  556. *lppNewRecips = NULL;
  557. *lpnNewRecips = 0;
  558. }
  559. ulRet = UlGetSession(lhSession, &pSession, ulUIParam, fLogonUI, FALSE);
  560. if (SUCCESS_SUCCESS != ulRet)
  561. return ulRet;
  562. // build an adrlist from the lpRecips
  563. if (nRecips)
  564. {
  565. ULONG ulMax = MAPI_TO;
  566. hr = HrAdrlistFromRgrecip(nRecips, lpRecips, &lpAdrList);
  567. if (hr)
  568. goto exit;
  569. Assert(nRecips == lpAdrList->cEntries);
  570. // we need to grow nEditFields if it isn't big enough
  571. for (ul = 0; ul < nRecips; ul++)
  572. {
  573. if (ulMax < lpRecips[ul].ulRecipClass && lpRecips[ul].ulRecipClass <= MAPI_BCC)
  574. ulMax = lpRecips[ul].ulRecipClass;
  575. }
  576. Assert(ulMax >= MAPI_TO && ulMax <= MAPI_BCC);
  577. if (ulMax > nEditFields)
  578. {
  579. DOUT("MAPIAddress: growing nEditFields from %ld to %ld\r\n", nEditFields, ulMax);
  580. nEditFields = ulMax;
  581. }
  582. }
  583. // Fill the AdrParm structure
  584. AdrParms.ulFlags = DIALOG_MODAL;
  585. AdrParms.lpszCaption = lpszCaption;
  586. AdrParms.cDestFields = nEditFields == 4 ? 3 : nEditFields;
  587. if (nEditFields == 1 && lpszLabels && *lpszLabels)
  588. AdrParms.lppszDestTitles = &lpszLabels;
  589. AdrParms.lpulDestComps = rgulTypes;
  590. if (NULL == s_lpAddrBook)
  591. {
  592. ulRet = MAPI_E_FAILURE;
  593. goto exit;
  594. }
  595. hr = s_lpAddrBook->Address(&ulUIParam, &AdrParms, &lpAdrList);
  596. if (hr)
  597. {
  598. if (MAPI_E_USER_CANCEL == hr)
  599. ulRet = MAPI_E_USER_ABORT;
  600. else if (MAPI_E_NO_RECIPIENTS == hr || MAPI_E_AMBIGUOUS_RECIP == hr)
  601. ulRet = MAPI_E_INVALID_RECIPS;
  602. goto exit;
  603. }
  604. if (nEditFields && lpAdrList && lpAdrList->cEntries)
  605. {
  606. hr = HrRgrecipFromAdrlist(lpAdrList, lppNewRecips);
  607. if (hr)
  608. goto exit;
  609. *lpnNewRecips = lpAdrList->cEntries;
  610. }
  611. ulRet = SUCCESS_SUCCESS;
  612. exit:
  613. FreePadrlist(lpAdrList);
  614. ReleaseSession(pSession);
  615. return ulRet;
  616. }
  617. ///////////////////////////////////////////////////////////////////////
  618. //
  619. // MAPIDetails
  620. //
  621. ///////////////////////////////////////////////////////////////////////
  622. ULONG FAR PASCAL MAPIDetails(LHANDLE lhSession,
  623. ULONG_PTR ulUIParam,
  624. lpMapiRecipDesc lpRecip,
  625. FLAGS flFlags,
  626. ULONG ulReserved)
  627. {
  628. ULONG ulRet = MAPI_E_FAILURE;
  629. HRESULT hr;
  630. LPSTR pszAddrType = 0;
  631. LPSTR pszAddress = 0;
  632. ULONG cbEntryID;
  633. LPENTRYID lpEntryID = 0;
  634. PSESS pSession = NULL;
  635. BOOL fLogonUI;
  636. // Validate parameters - Begin
  637. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  638. ulUIParam = 0;
  639. if (IsBadReadPtr(lpRecip, (UINT)sizeof(MapiRecipDesc)))
  640. return MAPI_E_INVALID_RECIPS;
  641. if (lpRecip->ulEIDSize == 0 && !lpRecip->lpszAddress)
  642. return MAPI_E_INVALID_RECIPS;
  643. fLogonUI = (0 != (flFlags & MAPI_LOGON_UI));
  644. // Services shouldn't ask for UI
  645. if (!IsProcessInteractive() && fLogonUI)
  646. return MAPI_E_LOGIN_FAILURE;
  647. // Validate parameters - End
  648. ulRet = UlGetSession(lhSession, &pSession, ulUIParam, fLogonUI, FALSE);
  649. if (SUCCESS_SUCCESS != ulRet)
  650. return ulRet;
  651. if (NULL == s_lpAddrBook)
  652. {
  653. ulRet = MAPI_E_FAILURE;
  654. goto exit;
  655. }
  656. if (lpRecip->ulEIDSize)
  657. {
  658. cbEntryID = lpRecip->ulEIDSize;
  659. lpEntryID = (LPENTRYID)lpRecip->lpEntryID;
  660. }
  661. else
  662. {
  663. ParseEmailAddress(lpRecip->lpszAddress, &pszAddrType, &pszAddress);
  664. CHECKHR(hr = s_lpAddrBook->CreateOneOff(lpRecip->lpszName, pszAddrType, pszAddress, 0, &cbEntryID, &lpEntryID));
  665. }
  666. CHECKHR(hr = s_lpAddrBook->Details(&ulUIParam, NULL, NULL, cbEntryID, lpEntryID, NULL, NULL, NULL, DIALOG_MODAL));
  667. ulRet = SUCCESS_SUCCESS;
  668. exit:
  669. if (pszAddrType)
  670. MemFree(pszAddrType);
  671. if (pszAddress)
  672. MemFree(pszAddress);
  673. if (lpEntryID && lpEntryID != lpRecip->lpEntryID && NULL != s_lpWabObject)
  674. s_lpWabObject->FreeBuffer(lpEntryID);
  675. ReleaseSession(pSession);
  676. return ulRet;
  677. }
  678. ///////////////////////////////////////////////////////////////////////
  679. //
  680. // MAPIResolveName
  681. //
  682. ///////////////////////////////////////////////////////////////////////
  683. ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession,
  684. ULONG_PTR ulUIParam,
  685. LPSTR lpszName,
  686. FLAGS flFlags,
  687. ULONG ulReserved,
  688. lpMapiRecipDesc FAR *lppRecip)
  689. {
  690. ULONG ulRet = SUCCESS_SUCCESS, ulNew;
  691. LPADRLIST lpAdrList = 0;
  692. HRESULT hr;
  693. LPADRENTRY lpAdrEntry;
  694. PSESS pSession = NULL;
  695. BOOL fLogonUI;
  696. // Validate parameters - Begin
  697. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  698. ulUIParam = 0;
  699. /*
  700. HACK: #68119 Excel doesn't pass in a parent.
  701. This isn't the best thing to do, but this handle shouldn't be 0.
  702. The only thing to watch out for is fast actions while this processing
  703. is happening could make this dialog modal to the wrong window, but
  704. that us much more unlikely than the bug this fixes.
  705. */
  706. if(!ulUIParam)
  707. ulUIParam = (ULONG_PTR)GetForegroundWindow();
  708. if (!lpszName || IsBadStringPtr(lpszName, (UINT)0xFFFF) || !*lpszName)
  709. return MAPI_E_FAILURE;
  710. if (IsBadWritePtr(lppRecip, (UINT)sizeof(lpMapiRecipDesc)))
  711. return MAPI_E_FAILURE;
  712. fLogonUI = (0 != (flFlags & MAPI_LOGON_UI));
  713. // Services shouldn't ask for UI
  714. if (!IsProcessInteractive() && fLogonUI)
  715. return MAPI_E_LOGIN_FAILURE;
  716. // Validate parameters - End
  717. *lppRecip = NULL;
  718. ulRet = UlGetSession(lhSession, &pSession, ulUIParam, fLogonUI, FALSE);
  719. if (SUCCESS_SUCCESS != ulRet)
  720. return ulRet;
  721. // Allocate memory for lpAdrList
  722. // Determine number of bytes needed
  723. ulNew = sizeof(ADRLIST) + sizeof(ADRENTRY);
  724. // Allocate new buffer
  725. if (NULL == s_lpWabObject)
  726. {
  727. ulRet = MAPI_E_FAILURE;
  728. goto exit;
  729. }
  730. hr = s_lpWabObject->AllocateBuffer(ulNew, (LPVOID *)&lpAdrList);
  731. if (hr)
  732. goto exit;
  733. lpAdrList->cEntries = 1;
  734. lpAdrEntry = lpAdrList->aEntries;
  735. // Allocate memory for SPropValue
  736. hr = s_lpWabObject->AllocateBuffer(sizeof(SPropValue), (LPVOID *)&lpAdrEntry->rgPropVals);
  737. if (hr)
  738. goto exit;
  739. lpAdrEntry->cValues = 1;
  740. lpAdrEntry->rgPropVals[0].ulPropTag = PR_DISPLAY_NAME;
  741. ULONG cchName = lstrlen(lpszName) + 1;
  742. hr = s_lpWabObject->AllocateMore(cchName, lpAdrEntry->rgPropVals, (LPVOID*)(&(lpAdrEntry->rgPropVals[0].Value.lpszA)));
  743. if (FAILED (hr))
  744. goto exit;
  745. // Fill in the name
  746. StrCpyN(lpAdrEntry->rgPropVals[0].Value.lpszA, lpszName, cchName);
  747. // Call ResolveName of IAddrBook
  748. if (NULL == s_lpAddrBook)
  749. {
  750. ulRet = MAPI_E_FAILURE;
  751. goto exit;
  752. }
  753. hr = s_lpAddrBook->ResolveName(ulUIParam, flFlags & MAPI_DIALOG, NULL, lpAdrList);
  754. if (hr)
  755. {
  756. if ((hr == MAPI_E_NOT_FOUND) || (hr == MAPI_E_USER_CANCEL))
  757. ulRet = MAPI_E_UNKNOWN_RECIPIENT;
  758. else if (hr == MAPI_E_AMBIGUOUS_RECIP)
  759. ulRet = MAPI_E_AMBIGUOUS_RECIPIENT;
  760. else
  761. ulRet = MAPI_E_FAILURE;
  762. goto exit;
  763. }
  764. else if ((lpAdrList->cEntries != 1) || !lpAdrList->aEntries->cValues)
  765. {
  766. ulRet = MAPI_E_AMBIGUOUS_RECIPIENT;
  767. goto exit;
  768. }
  769. ulRet = HrRgrecipFromAdrlist(lpAdrList, lppRecip);
  770. exit:
  771. FreePadrlist(lpAdrList);
  772. ReleaseSession(pSession);
  773. return ulRet;
  774. }
  775. ///////////////////////////////////////////////////////////////////////
  776. //
  777. // MAPIFindNext
  778. //
  779. ///////////////////////////////////////////////////////////////////////
  780. ULONG FAR PASCAL MAPIFindNext(LHANDLE lhSession,
  781. ULONG_PTR ulUIParam,
  782. LPSTR lpszMessageType,
  783. LPSTR lpszSeedMessageID,
  784. FLAGS flFlags,
  785. ULONG ulReserved,
  786. LPSTR lpszMessageID)
  787. {
  788. MESSAGEINFO MsgInfo={0};
  789. ULONG ulRet = MAPI_E_FAILURE;
  790. HRESULT hr;
  791. MESSAGEID idMessage;
  792. MESSAGEID dwMsgIdPrev;
  793. PSESS pSession = NULL;
  794. HROWSET hRowset=NULL;
  795. // Validate parameters - begin
  796. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  797. ulUIParam = 0;
  798. if (lpszSeedMessageID && IsBadStringPtr(lpszSeedMessageID, (UINT)0xFFFF))
  799. return MAPI_E_INVALID_MESSAGE;
  800. if (lpszSeedMessageID && (!*lpszSeedMessageID || !IsDigit(lpszSeedMessageID)))
  801. lpszSeedMessageID = NULL;
  802. if (IsBadWritePtr(lpszMessageID, 64))
  803. return MAPI_E_INSUFFICIENT_MEMORY;
  804. // Validate parameters - end
  805. // We shouldn't need to show login UI, because the session must be valid
  806. // and a valid session would require a login
  807. ulRet = UlGetSession(lhSession, &pSession, ulUIParam, FALSE, TRUE);
  808. if (SUCCESS_SUCCESS != ulRet)
  809. return ulRet;
  810. hr = pSession->m_pfldrInbox->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
  811. if (FAILED(hr))
  812. {
  813. ulRet = MAPI_E_NO_MESSAGES;
  814. goto exit;
  815. }
  816. hr = pSession->m_pfldrInbox->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL);
  817. if (FAILED(hr) || S_FALSE == hr)
  818. {
  819. ulRet = MAPI_E_NO_MESSAGES;
  820. goto exit;
  821. }
  822. if (lpszSeedMessageID) // If the seed is NULL
  823. {
  824. idMessage = (MESSAGEID)((UINT_PTR)StrToUint(lpszSeedMessageID));
  825. while (1)
  826. {
  827. dwMsgIdPrev = MsgInfo.idMessage;
  828. pSession->m_pfldrInbox->FreeRecord(&MsgInfo);
  829. hr = pSession->m_pfldrInbox->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL);
  830. if (FAILED(hr) || S_FALSE == hr)
  831. {
  832. ulRet = MAPI_E_NO_MESSAGES;
  833. goto exit;
  834. }
  835. if (dwMsgIdPrev == idMessage)
  836. break;
  837. }
  838. }
  839. // Check for Read unread messages only flag
  840. if (flFlags & MAPI_UNREAD_ONLY)
  841. {
  842. while (ISFLAGSET(MsgInfo.dwFlags, ARF_READ))
  843. {
  844. // Free MsgInfo
  845. pSession->m_pfldrInbox->FreeRecord(&MsgInfo);
  846. // Get the next message
  847. hr = pSession->m_pfldrInbox->QueryRowset(hRowset, 1, (LPVOID *)&MsgInfo, NULL);
  848. // Not Found
  849. if (FAILED(hr) || S_FALSE == hr)
  850. {
  851. ulRet = MAPI_E_NO_MESSAGES;
  852. goto exit;
  853. }
  854. }
  855. }
  856. wnsprintf(lpszMessageID, 64, "%lu", MsgInfo.idMessage);
  857. ulRet = SUCCESS_SUCCESS;
  858. exit:
  859. if (pSession && pSession->m_pfldrInbox)
  860. {
  861. pSession->m_pfldrInbox->CloseRowset(&hRowset);
  862. pSession->m_pfldrInbox->FreeRecord(&MsgInfo);
  863. }
  864. ReleaseSession(pSession);
  865. return ulRet;
  866. }
  867. ///////////////////////////////////////////////////////////////////////
  868. //
  869. // MAPIReadMail
  870. //
  871. ///////////////////////////////////////////////////////////////////////
  872. ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession,
  873. ULONG_PTR ulUIParam,
  874. LPSTR lpszMessageID,
  875. FLAGS flFlags,
  876. ULONG ulReserved,
  877. lpMapiMessage FAR *lppMessage)
  878. {
  879. ULONG ulRet = MAPI_E_FAILURE;
  880. HRESULT hr;
  881. lpMapiMessage rgMessage = NULL;
  882. PSESS pSession = NULL;
  883. // Validate parameters - Begin
  884. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  885. ulUIParam = 0;
  886. if (!lpszMessageID)
  887. return MAPI_E_INVALID_MESSAGE;
  888. if (lpszMessageID && (!*lpszMessageID || !IsDigit(lpszMessageID)))
  889. return MAPI_E_INVALID_MESSAGE;
  890. if (IsBadWritePtr(lppMessage,(UINT)sizeof(lpMapiMessage)))
  891. return MAPI_E_FAILURE;
  892. // Validate parameters - End
  893. ulRet = UlGetSession(lhSession, &pSession, ulUIParam, FALSE, TRUE);
  894. if (SUCCESS_SUCCESS != ulRet)
  895. return ulRet;
  896. if (!HrReadMail(pSession->m_pfldrInbox, lpszMessageID, &rgMessage, flFlags))
  897. goto exit;
  898. ulRet = SUCCESS_SUCCESS;
  899. *lppMessage = rgMessage;
  900. exit:
  901. if (ulRet != SUCCESS_SUCCESS)
  902. if (rgMessage)
  903. MAPIFreeBuffer(rgMessage);
  904. ReleaseSession(pSession);
  905. return ulRet;
  906. }
  907. ///////////////////////////////////////////////////////////////////////
  908. //
  909. // MAPISaveMail
  910. //
  911. ///////////////////////////////////////////////////////////////////////
  912. ULONG FAR PASCAL MAPISaveMail(LHANDLE lhSession,
  913. ULONG_PTR ulUIParam,
  914. lpMapiMessage lpMessage,
  915. FLAGS flFlags,
  916. ULONG ulReserved,
  917. LPSTR lpszMessageID)
  918. {
  919. ULONG ulRet = MAPI_E_FAILURE;
  920. HRESULT hr;
  921. IMimeMessage *pMsg = NULL;
  922. MESSAGEID msgid;
  923. PSESS pSession = NULL;
  924. HWND hwnd = (HWND)ulUIParam;
  925. BOOL fLogonUI;
  926. // Validate parameters - Begin
  927. if (ulUIParam && !IsWindow(hwnd))
  928. hwnd = 0;
  929. if (!lpszMessageID)
  930. return MAPI_E_INVALID_MESSAGE;
  931. if (lpszMessageID && *lpszMessageID && !IsDigit(lpszMessageID))
  932. return MAPI_E_INVALID_MESSAGE;
  933. if (IsBadReadPtr(lpMessage, (UINT)sizeof(lpMapiMessage)))
  934. return MAPI_E_FAILURE;
  935. fLogonUI = (0 != (flFlags & MAPI_LOGON_UI));
  936. // Services shouldn't ask for UI
  937. if (!IsProcessInteractive() && fLogonUI)
  938. return MAPI_E_LOGIN_FAILURE;
  939. // Validate parameters - End
  940. ulRet = UlGetSession(lhSession, &pSession, ulUIParam, fLogonUI, TRUE);
  941. if (SUCCESS_SUCCESS != ulRet)
  942. return ulRet;
  943. #pragma prefast(suppress:11, "noise")
  944. if (*lpszMessageID)
  945. {
  946. MESSAGEIDLIST List;
  947. msgid = (MESSAGEID)((UINT_PTR)StrToUint(lpszMessageID));
  948. List.cMsgs = 1;
  949. List.prgidMsg = &msgid;
  950. if (FAILED(hr = pSession->m_pfldrInbox->DeleteMessages(DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT, &List, NULL, NOSTORECALLBACK)))
  951. {
  952. ulRet = MAPI_E_INVALID_MESSAGE;
  953. goto exit;
  954. }
  955. }
  956. // Fill IMimeMessage with the lpMessage structure members
  957. ulRet = HrFillMessage(&pMsg, lpMessage, NULL, FALSE, TRUE);
  958. if (ulRet)
  959. goto exit;
  960. if (FAILED(hr = HrSaveMessageInFolder(hwnd, pSession->m_pfldrInbox, pMsg, 0, &msgid, TRUE)))
  961. {
  962. ulRet = MAPI_E_FAILURE;
  963. goto exit;
  964. }
  965. ulRet = SUCCESS_SUCCESS;
  966. wnsprintf(lpszMessageID, 64, "%lu", msgid);
  967. exit:
  968. if (pMsg)
  969. pMsg->Release();
  970. ReleaseSession(pSession);
  971. return ulRet;
  972. }
  973. ///////////////////////////////////////////////////////////////////////
  974. //
  975. // MAPIDeleteMail
  976. //
  977. ///////////////////////////////////////////////////////////////////////
  978. ULONG FAR PASCAL MAPIDeleteMail(LHANDLE lhSession,
  979. ULONG_PTR ulUIParam,
  980. LPSTR lpszMessageID,
  981. FLAGS flFlags,
  982. ULONG ulReserved)
  983. {
  984. ULONG ulRet = MAPI_E_FAILURE;
  985. MESSAGEID dwMsgID;
  986. HRESULT hr;
  987. PSESS pSession = NULL;
  988. MESSAGEIDLIST List;
  989. // Validate parameters - Begin
  990. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  991. ulUIParam = 0;
  992. if (!lpszMessageID)
  993. return MAPI_E_INVALID_MESSAGE;
  994. if (!*lpszMessageID || !IsDigit(lpszMessageID))
  995. return MAPI_E_INVALID_MESSAGE;
  996. // Validate parameters - End
  997. // This function requires a valid session that must have been
  998. // logged in at some point so login UI is not allowed
  999. ulRet = UlGetSession(lhSession, &pSession, ulUIParam, FALSE, TRUE);
  1000. if (SUCCESS_SUCCESS != ulRet)
  1001. return ulRet;
  1002. dwMsgID = (MESSAGEID)((UINT_PTR)StrToUint(lpszMessageID));
  1003. List.cMsgs = 1;
  1004. List.prgidMsg = &dwMsgID;
  1005. hr = DeleteMessagesProgress((HWND)ulUIParam, pSession->m_pfldrInbox, DELETE_MESSAGE_NOPROMPT, &List);
  1006. if (FAILED(hr))
  1007. goto exit;
  1008. ulRet = SUCCESS_SUCCESS;
  1009. exit:
  1010. ReleaseSession(pSession);
  1011. return ulRet;
  1012. }
  1013. ///////////////////////////////////////////////////////////////////////
  1014. //
  1015. // INTERNAL FUNCTIONS
  1016. //
  1017. ///////////////////////////////////////////////////////////////////////
  1018. ///////////////////////////////////////////////////////////////////////
  1019. //
  1020. // SMAPIAllocateBuffer
  1021. //
  1022. // Purpose:
  1023. // Allocates a memory buffer that must be freed with MAPIFreeBuffer().
  1024. //
  1025. // Arguments:
  1026. // ulSize in Size, in bytes, of the buffer to be allocated.
  1027. // lppv out Pointer to variable where the address of the
  1028. // allocated memory will be returned.
  1029. //
  1030. // Returns:
  1031. // sc Indicating error if any (see below)
  1032. //
  1033. // Errors:
  1034. // MAPI_E_INSUFFICIENT_MEMORY Allocation failed.
  1035. //
  1036. ///////////////////////////////////////////////////////////////////////
  1037. SCODE SMAPIAllocateBuffer(ULONG ulSize, LPVOID * lppv)
  1038. {
  1039. SCODE sc = S_OK;
  1040. LPBufInternal lpBufInt;
  1041. // Don't allow allocation to wrap across 32 bits, or to exceed 64K
  1042. // under win16.
  1043. if (ulSize > INT_SIZE(ulSize))
  1044. {
  1045. DOUT("SMAPIAllocateBuffer: ulSize %ld is way too big\n", ulSize);
  1046. sc = MAPI_E_INSUFFICIENT_MEMORY;
  1047. goto ret;
  1048. }
  1049. lpBufInt = (LPBufInternal)g_pMalloc->Alloc((UINT)INT_SIZE(ulSize));
  1050. if (lpBufInt)
  1051. {
  1052. lpBufInt->pLink = NULL;
  1053. lpBufInt->ulAllocFlags = ALLOC_WITH_ALLOC;
  1054. *lppv = (LPVOID)LPBufExtFromLPBufInt(lpBufInt);
  1055. }
  1056. else
  1057. {
  1058. DOUT("SMAPIAllocateBuffer: not enough memory for %ld\n", ulSize);
  1059. sc = MAPI_E_INSUFFICIENT_MEMORY;
  1060. }
  1061. ret:
  1062. return sc;
  1063. }
  1064. ///////////////////////////////////////////////////////////////////////
  1065. //
  1066. // SMAPIAllocateMore
  1067. //
  1068. // Purpose:
  1069. // Allocates a linked memory buffer in such a way that it can be freed
  1070. // with one call to MAPIFreeBuffer (passing the buffer the client
  1071. // originally allocated with SMAPIAllocateBuffer).
  1072. //
  1073. // Arguments:
  1074. // ulSize in Size, in bytes, of the buffer to be allocated.
  1075. // lpv in Pointer to a buffer allocated with SMAPIAllocateBuffer.
  1076. // lppv out Pointer to variable where the address of the
  1077. // allocated memory will be returned.
  1078. //
  1079. // Assumes:
  1080. // Validates that lpBufOrig and lppv point to writable memory,
  1081. // and that lpBufOrig was allocated with SMAPIAllocateBuffer.
  1082. //
  1083. // Returns:
  1084. // sc Indicating error if any (see below)
  1085. //
  1086. // Side effects:
  1087. // None
  1088. //
  1089. // Errors:
  1090. // MAPI_E_INSUFFICIENT_MEMORY Allocation failed.
  1091. //
  1092. ///////////////////////////////////////////////////////////////////////
  1093. SCODE SMAPIAllocateMore(ULONG ulSize, LPVOID lpv, LPVOID * lppv)
  1094. {
  1095. SCODE sc = S_OK;
  1096. LPBufInternal lpBufInt;
  1097. LPBufInternal lpBufOrig;
  1098. lpBufOrig = LPBufIntFromLPBufExt(lpv);
  1099. #ifdef DEBUG
  1100. if (!FValidAllocChain(lpBufOrig))
  1101. {
  1102. sc = MAPI_E_FAILURE;
  1103. goto ret;
  1104. }
  1105. #endif
  1106. // Don't allow allocation to wrap across 32 bits, or to be
  1107. // greater than 64K under win16.
  1108. if (ulSize > INT_SIZE(ulSize))
  1109. {
  1110. DOUT("SMAPIAllocateMore: ulSize %ld is way too big\n", ulSize);
  1111. sc = MAPI_E_INSUFFICIENT_MEMORY;
  1112. goto ret;
  1113. }
  1114. // Allocate the chained block and hook it to the head of the chain.
  1115. lpBufInt = (LPBufInternal)g_pMalloc->Alloc((UINT)INT_SIZE(ulSize));
  1116. if (lpBufInt)
  1117. {
  1118. lpBufInt->ulAllocFlags = ALLOC_WITH_ALLOC_MORE;
  1119. // EnterCriticalSection(&csHeap);
  1120. lpBufInt->pLink = lpBufOrig->pLink;
  1121. lpBufOrig->pLink = lpBufInt;
  1122. // LeaveCriticalSection(&csHeap);
  1123. *lppv = (LPVOID)LPBufExtFromLPBufInt(lpBufInt);
  1124. }
  1125. else
  1126. {
  1127. DOUT("SMAPIAllocateMore: not enough memory for %ld\n", ulSize);
  1128. sc = MAPI_E_INSUFFICIENT_MEMORY;
  1129. }
  1130. ret:
  1131. return sc;
  1132. }
  1133. #ifdef DEBUG
  1134. BOOL FValidAllocChain(LPBufInternal lpBuf)
  1135. {
  1136. LPBufInternal lpBufTemp;
  1137. if (IsBadWritePtr(lpBuf, sizeof(BufInternal)))
  1138. {
  1139. TellBadBlockInt(lpBuf, "fails address check");
  1140. return FALSE;
  1141. }
  1142. if (GetFlags(lpBuf->ulAllocFlags) != ALLOC_WITH_ALLOC)
  1143. {
  1144. TellBadBlockInt(lpBuf, "has invalid flags");
  1145. return FALSE;
  1146. }
  1147. for (lpBufTemp = lpBuf->pLink; lpBufTemp; lpBufTemp = lpBufTemp->pLink)
  1148. {
  1149. if (IsBadWritePtr(lpBufTemp, sizeof(BufInternal)))
  1150. {
  1151. TellBadBlockInt(lpBufTemp, "(linked block) fails address check");
  1152. return FALSE;
  1153. }
  1154. if (GetFlags(lpBufTemp->ulAllocFlags) != ALLOC_WITH_ALLOC_MORE)
  1155. {
  1156. TellBadBlockInt(lpBufTemp, "(linked block) has invalid flags");
  1157. return FALSE;
  1158. }
  1159. }
  1160. return TRUE;
  1161. }
  1162. #endif // DEBUG
  1163. /*
  1164. - HrAdrentryFromPrecip
  1165. -
  1166. * Purpose:
  1167. * Copies data from a MapiRecipDesc structure to the property
  1168. * value array on an ADRENTRY structure.
  1169. *
  1170. * Arguments:
  1171. * precip in the input structure
  1172. * padrentry out the output structure
  1173. *
  1174. * Returns:
  1175. * HRESULT
  1176. *
  1177. * Errors:
  1178. * MAPI_E_INVALID_RECIPS
  1179. * MAPI_E_BAD_RECIPTYPE
  1180. * others passed through
  1181. */
  1182. HRESULT HrAdrentryFromPrecip(lpMapiRecipDesc precip, ADRENTRY *padrentry)
  1183. {
  1184. HRESULT hr;
  1185. LPSPropValue pprop;
  1186. LPSTR pszAddress = NULL;
  1187. // Validate lpMapiRecipDesc, ie, ensure that if there isn't an EntryID or
  1188. // an Address there had better be a Display Name, otherwise we fail
  1189. // like MAPI 0 with MAPI_E_FAILURE.
  1190. if ((!precip->lpszAddress || !precip->lpszAddress[0]) &&
  1191. (!precip->ulEIDSize || !precip->lpEntryID) &&
  1192. (!precip->lpszName || !precip->lpszName[0]))
  1193. {
  1194. hr = MAPI_E_INVALID_RECIPS;
  1195. goto ret;
  1196. }
  1197. if (NULL == s_lpWabObject)
  1198. {
  1199. hr = MAPI_E_FAILURE;
  1200. goto ret;
  1201. }
  1202. hr = s_lpWabObject->AllocateBuffer(4 * sizeof(SPropValue), (LPVOID*)&padrentry->rgPropVals);
  1203. if (hr)
  1204. goto ret;
  1205. pprop = padrentry->rgPropVals;
  1206. // Recipient type
  1207. switch ((short)precip->ulRecipClass)
  1208. {
  1209. case MAPI_TO:
  1210. case MAPI_CC:
  1211. case MAPI_BCC:
  1212. pprop->ulPropTag = PR_RECIPIENT_TYPE;
  1213. pprop->Value.ul = precip->ulRecipClass;
  1214. pprop++;
  1215. break;
  1216. default:
  1217. hr = MAPI_E_BAD_RECIPTYPE;
  1218. goto ret;
  1219. }
  1220. // Display Name
  1221. if (precip->lpszName && *precip->lpszName)
  1222. {
  1223. ULONG cchName = lstrlen(precip->lpszName)+1;
  1224. hr = s_lpWabObject->AllocateMore(cchName, padrentry->rgPropVals, (LPVOID*)&pprop->Value.lpszA);
  1225. if (hr)
  1226. goto ret;
  1227. pprop->ulPropTag = PR_DISPLAY_NAME;
  1228. StrCpyN(pprop->Value.lpszA, precip->lpszName, cchName);
  1229. pprop++;
  1230. }
  1231. // Email Address
  1232. if (precip->lpszAddress && *precip->lpszAddress)
  1233. {
  1234. ParseEmailAddress(precip->lpszAddress, NULL, &pszAddress);
  1235. ULONG cchAddress = lstrlen(pszAddress)+1;
  1236. hr = s_lpWabObject->AllocateMore(cchAddress, padrentry->rgPropVals, (LPVOID*)&pprop->Value.lpszA);
  1237. if (hr)
  1238. goto ret;
  1239. pprop->ulPropTag = PR_EMAIL_ADDRESS;
  1240. StrCpyN(pprop->Value.lpszA, pszAddress, cchAddress);
  1241. pprop++;
  1242. }
  1243. // EntryID
  1244. if (precip->ulEIDSize && precip->lpEntryID)
  1245. {
  1246. hr = s_lpWabObject->AllocateMore(precip->ulEIDSize, padrentry->rgPropVals, (LPVOID*)&pprop->Value.bin.lpb);
  1247. if (hr)
  1248. goto ret;
  1249. pprop->ulPropTag = PR_ENTRYID;
  1250. pprop->Value.bin.cb = precip->ulEIDSize;
  1251. CopyMemory(pprop->Value.bin.lpb, precip->lpEntryID, precip->ulEIDSize);
  1252. pprop++;
  1253. }
  1254. padrentry->cValues = (ULONG) (pprop - padrentry->rgPropVals);
  1255. Assert(padrentry->cValues <= 4);
  1256. ret:
  1257. if (pszAddress)
  1258. MemFree(pszAddress);
  1259. if ((hr) && (NULL != s_lpWabObject))
  1260. {
  1261. s_lpWabObject->FreeBuffer(padrentry->rgPropVals);
  1262. padrentry->rgPropVals = NULL;
  1263. }
  1264. return hr;
  1265. }
  1266. /*
  1267. - HrAdrlistFromRgrecip
  1268. -
  1269. * Purpose:
  1270. * Copies a list of simple MAPI recipients to a list of
  1271. * extended MAPI recipients.
  1272. *
  1273. * Arguments:
  1274. * nRecips in count of recipient in input list
  1275. * lpRecips in list of recipients to be converted
  1276. * ppadrlist out output list
  1277. *
  1278. * Returns:
  1279. * HRESULT
  1280. *
  1281. */
  1282. HRESULT HrAdrlistFromRgrecip(ULONG nRecips, lpMapiRecipDesc lpRecips, LPADRLIST *ppadrlist)
  1283. {
  1284. HRESULT hr;
  1285. LPADRLIST padrlist = NULL;
  1286. lpMapiRecipDesc precip;
  1287. ULONG i;
  1288. LPADRENTRY padrentry = NULL;
  1289. ULONG cbAdrList = sizeof(ADRLIST) + nRecips * sizeof(ADRENTRY);
  1290. *ppadrlist = NULL;
  1291. if (NULL == s_lpWabObject)
  1292. {
  1293. hr = E_FAIL;
  1294. goto exit;
  1295. }
  1296. hr = s_lpWabObject->AllocateBuffer(cbAdrList, (LPVOID*)&padrlist);
  1297. if (hr)
  1298. goto exit;
  1299. ZeroMemory(padrlist, cbAdrList);
  1300. // Copy each entry.
  1301. // Note that the memory for each recipient's properties must
  1302. // be linked so that Address() can free it using MAPIFreeBuffer.
  1303. for (i = 0, padrentry = padrlist->aEntries, precip = lpRecips; i < nRecips; i++, precip++, padrentry++)
  1304. {
  1305. // Copy the entry. Unresolved names will not be resolved.
  1306. hr = HrAdrentryFromPrecip(precip, padrentry);
  1307. if (hr)
  1308. goto exit;
  1309. // increment count so we can effectively blow away the list if a failure
  1310. // occurs.
  1311. padrlist->cEntries++;
  1312. }
  1313. *ppadrlist = padrlist;
  1314. exit:
  1315. Assert( !hr || (ULONG)hr > 26 );
  1316. if (hr)
  1317. FreePadrlist(padrlist);
  1318. return hr;
  1319. }
  1320. HRESULT HrRgrecipFromAdrlist(LPADRLIST lpAdrList, lpMapiRecipDesc * lppRecips)
  1321. {
  1322. HRESULT hr = S_OK;
  1323. lpMapiRecipDesc rgRecips = NULL;
  1324. lpMapiRecipDesc pRecip;
  1325. LPADRENTRY pAdrEntry;
  1326. LPSPropValue pProp;
  1327. ULONG ul, ulProp;
  1328. if (lpAdrList && lpAdrList->cEntries)
  1329. {
  1330. DWORD dwSize = sizeof(MapiRecipDesc) * lpAdrList->cEntries;
  1331. hr = SMAPIAllocateBuffer(dwSize, (LPVOID*)&rgRecips);
  1332. if (FAILED (hr))
  1333. goto exit;
  1334. ZeroMemory(rgRecips, dwSize);
  1335. // Initialize the Padding
  1336. for (ul = 0, pAdrEntry = lpAdrList->aEntries, pRecip = rgRecips; ul<lpAdrList->cEntries; ul++, pAdrEntry++, pRecip++)
  1337. {
  1338. for (ulProp = 0, pProp = pAdrEntry->rgPropVals; ulProp < pAdrEntry->cValues; ulProp++, pProp++)
  1339. {
  1340. ULONG cch;
  1341. switch (PROP_ID(pProp->ulPropTag))
  1342. {
  1343. case PROP_ID(PR_ENTRYID):
  1344. hr = SMAPIAllocateMore(pProp->Value.bin.cb, rgRecips, (LPVOID*)(&(pRecip->lpEntryID)));
  1345. if (FAILED (hr))
  1346. goto exit;
  1347. pRecip->ulEIDSize = pProp->Value.bin.cb;
  1348. CopyMemory(pRecip->lpEntryID, pProp->Value.bin.lpb, pProp->Value.bin.cb);
  1349. break;
  1350. case PROP_ID(PR_EMAIL_ADDRESS):
  1351. cch = lstrlen(pProp->Value.lpszA)+1;
  1352. hr = SMAPIAllocateMore(cch, rgRecips, (LPVOID*)(&(pRecip->lpszAddress)));
  1353. if (FAILED (hr))
  1354. goto exit;
  1355. StrCpyN(pRecip->lpszAddress, pProp->Value.lpszA, cch);
  1356. break;
  1357. case PROP_ID(PR_DISPLAY_NAME):
  1358. cch = lstrlen(pProp->Value.lpszA)+1;
  1359. hr = SMAPIAllocateMore(cch, rgRecips,(LPVOID*)(&(pRecip->lpszName)));
  1360. if (FAILED (hr))
  1361. goto exit;
  1362. StrCpyN(pRecip->lpszName, pProp->Value.lpszA, cch);
  1363. break;
  1364. case PROP_ID(PR_RECIPIENT_TYPE):
  1365. pRecip->ulRecipClass = pProp->Value.l;
  1366. break;
  1367. default:
  1368. break;
  1369. }
  1370. }
  1371. }
  1372. }
  1373. exit:
  1374. if (hr)
  1375. {
  1376. MAPIFreeBuffer(rgRecips);
  1377. rgRecips = NULL;
  1378. }
  1379. *lppRecips = rgRecips;
  1380. return hr;
  1381. }
  1382. void ParseEmailAddress(LPSTR pszEmail, LPSTR *ppszAddrType, LPSTR *ppszAddress)
  1383. {
  1384. CStringParser spAddress;
  1385. char chToken;
  1386. Assert(ppszAddress);
  1387. spAddress.Init(pszEmail, lstrlen(pszEmail), 0);
  1388. // Parse the address for the delimiter
  1389. chToken = spAddress.ChParse(":");
  1390. if (chToken == ':')
  1391. {
  1392. if (ppszAddrType)
  1393. *ppszAddrType = PszDup(spAddress.PszValue());
  1394. spAddress.ChParse(c_szEmpty);
  1395. *ppszAddress = PszDup(spAddress.PszValue());
  1396. }
  1397. else
  1398. {
  1399. if (ppszAddrType)
  1400. *ppszAddrType = PszDup(c_szSMTP);
  1401. *ppszAddress = PszDup(pszEmail);
  1402. }
  1403. }
  1404. void FreePadrlist(LPADRLIST lpAdrList)
  1405. {
  1406. if ((lpAdrList) && (NULL != s_lpWabObject))
  1407. {
  1408. for (ULONG ul = 0; ul < lpAdrList->cEntries; ul++)
  1409. s_lpWabObject->FreeBuffer(lpAdrList->aEntries[ul].rgPropVals);
  1410. s_lpWabObject->FreeBuffer(lpAdrList);
  1411. }
  1412. }
  1413. ULONG AddMapiRecip(LPMIMEADDRESSTABLE pAddrTable, lpMapiRecipDesc lpRecip, BOOL bValidateRecips)
  1414. {
  1415. LPSTR pszName = NULL, pszAddress = NULL;
  1416. LPSTR pszNameFree = NULL, pszAddrFree = NULL;
  1417. LPADRLIST pAdrList = NULL;
  1418. ULONG ulPropCount;
  1419. ULONG ulRet = MAPI_E_FAILURE;
  1420. HRESULT hr;
  1421. if (lpRecip->ulRecipClass > 3 || lpRecip->ulRecipClass < 1)
  1422. return MAPI_E_BAD_RECIPTYPE;
  1423. if (lpRecip->ulEIDSize && lpRecip->lpEntryID && SUCCEEDED(HrFromIDToNameAndAddress(&pszName, &pszAddress, lpRecip->ulEIDSize, (ENTRYID*)lpRecip->lpEntryID)))
  1424. {
  1425. pszNameFree = pszName;
  1426. pszAddrFree = pszAddress;
  1427. }
  1428. else if (lpRecip->lpszAddress && *lpRecip->lpszAddress)
  1429. {
  1430. // we have an email address
  1431. ParseEmailAddress(lpRecip->lpszAddress, NULL, &pszAddress);
  1432. pszAddrFree = pszAddress;
  1433. if (lpRecip->lpszName && *lpRecip->lpszName)
  1434. pszName = lpRecip->lpszName;
  1435. else
  1436. // no name, so make it the same as the address
  1437. pszName = pszAddress;
  1438. }
  1439. else if (lpRecip->lpszName && *lpRecip->lpszName)
  1440. {
  1441. if (bValidateRecips)
  1442. {
  1443. // we have a name, but no address, so resolve it
  1444. hr = HrAdrlistFromRgrecip(1, lpRecip, &pAdrList);
  1445. if (FAILED(hr))
  1446. goto exit;
  1447. // Call ResolveName of IAddrBook
  1448. if (NULL == s_lpAddrBook)
  1449. {
  1450. ulRet = MAPI_E_FAILURE;
  1451. goto exit;
  1452. }
  1453. hr = s_lpAddrBook->ResolveName(NULL, NULL, NULL, pAdrList);
  1454. if (hr)
  1455. {
  1456. if (hr == MAPI_E_NOT_FOUND)
  1457. ulRet = MAPI_E_UNKNOWN_RECIPIENT;
  1458. else if (hr == MAPI_E_AMBIGUOUS_RECIP)
  1459. ulRet = MAPI_E_AMBIGUOUS_RECIPIENT;
  1460. else
  1461. ulRet = MAPI_E_FAILURE;
  1462. goto exit;
  1463. }
  1464. else if ((pAdrList->cEntries != 1) || !pAdrList->aEntries->cValues)
  1465. {
  1466. ulRet = MAPI_E_AMBIGUOUS_RECIPIENT;
  1467. goto exit;
  1468. }
  1469. for (ulPropCount = 0; ulPropCount < pAdrList->aEntries->cValues; ulPropCount++)
  1470. {
  1471. switch (pAdrList->aEntries->rgPropVals[ulPropCount].ulPropTag)
  1472. {
  1473. case PR_EMAIL_ADDRESS:
  1474. pszAddress = pAdrList->aEntries->rgPropVals[ulPropCount].Value.lpszA;
  1475. break;
  1476. case PR_DISPLAY_NAME:
  1477. pszName = pAdrList->aEntries->rgPropVals[ulPropCount].Value.lpszA;
  1478. break;
  1479. default:
  1480. break;
  1481. }
  1482. }
  1483. }
  1484. else
  1485. pszName = lpRecip->lpszName;
  1486. }
  1487. else
  1488. {
  1489. return MAPI_E_INVALID_RECIPS;
  1490. }
  1491. hr = pAddrTable->Append(MapiRecipToMimeOle(lpRecip->ulRecipClass),
  1492. IET_DECODED,
  1493. pszName,
  1494. pszAddress,
  1495. NULL);
  1496. if (SUCCEEDED(hr))
  1497. ulRet = SUCCESS_SUCCESS;
  1498. exit:
  1499. if (pszNameFree)
  1500. MemFree(pszNameFree);
  1501. if (pszAddrFree)
  1502. MemFree(pszAddrFree);
  1503. if (pAdrList)
  1504. FreePadrlist(pAdrList);
  1505. return ulRet;
  1506. }
  1507. ///////////////////////////////////////////////////////////////////////////////////
  1508. // Given a MapiMessage structure, this function creates a IMimeMessage object and
  1509. // fills it with the appropriate structure members
  1510. //
  1511. // Arguments:
  1512. // pMsg out IMimeMessage pointer
  1513. // ppStream out Stream pointer
  1514. // lpMessage in Message structure
  1515. // nc in/out NCINFO structure
  1516. //
  1517. // Result
  1518. // BOOL - TRUE if successful FALSE if failed
  1519. ////////////////////////////////////////////////////////////////////////////////////
  1520. ULONG HrFillMessage(LPMIMEMESSAGE *pMsg, lpMapiMessage lpMessage, BOOL *pfWebPage, BOOL bValidateRecips, BOOL fOriginator)
  1521. {
  1522. BOOL bRet = FALSE;
  1523. LPSTREAM pStream = NULL;
  1524. LPMIMEADDRESSTABLE pAddrTable = NULL;
  1525. IImnAccount *pAccount = NULL;
  1526. HRESULT hr;
  1527. LPSTR pszAddress;
  1528. ULONG ulRet = MAPI_E_FAILURE;
  1529. if (pfWebPage)
  1530. *pfWebPage = FALSE;
  1531. // create an empty message
  1532. hr = HrCreateMessage(pMsg);
  1533. if (FAILED(hr))
  1534. goto error;
  1535. // set the subject on the message
  1536. if (lpMessage->lpszSubject)
  1537. {
  1538. hr = MimeOleSetBodyPropA(*pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, lpMessage->lpszSubject);
  1539. if (FAILED(hr))
  1540. goto error;
  1541. }
  1542. // set the body on the message
  1543. if (lpMessage->lpszNoteText && *(lpMessage->lpszNoteText))
  1544. {
  1545. hr = MimeOleCreateVirtualStream(&pStream);
  1546. if (FAILED(hr))
  1547. goto error;
  1548. hr = pStream->Write(lpMessage->lpszNoteText, lstrlen(lpMessage->lpszNoteText), NULL);
  1549. if (FAILED(hr))
  1550. goto error;
  1551. hr = (*pMsg)->SetTextBody(TXT_PLAIN, IET_DECODED, NULL, pStream, NULL);
  1552. if (FAILED(hr))
  1553. goto error;
  1554. }
  1555. // ignore lpMessage->lpszMessageType
  1556. // ignore lpMessage->lpszDateReceived
  1557. // ignore lpMessage->lpszConversationID
  1558. // ignore lpMessage->flFlags
  1559. // ignore lpMessage->lpOriginator
  1560. // set the recipients on the message
  1561. if (lpMessage->nRecipCount || fOriginator)
  1562. {
  1563. ULONG ulRecipRet;
  1564. hr = (*pMsg)->GetAddressTable(&pAddrTable);
  1565. if (FAILED(hr))
  1566. goto error;
  1567. for (ULONG i = 0; i < lpMessage->nRecipCount; i++)
  1568. {
  1569. ulRecipRet = AddMapiRecip(pAddrTable, &lpMessage->lpRecips[i], bValidateRecips);
  1570. if (ulRecipRet != SUCCESS_SUCCESS)
  1571. {
  1572. ulRet = ulRecipRet;
  1573. goto error;
  1574. }
  1575. }
  1576. }
  1577. // set the attachments on the message
  1578. if (lpMessage->nFileCount)
  1579. {
  1580. // special case: no body & one .HTM file - inline the HTML
  1581. if ((!lpMessage->lpszNoteText || !*(lpMessage->lpszNoteText)) &&
  1582. lpMessage->nFileCount == 1 &&
  1583. !(lpMessage->lpFiles->flFlags & MAPI_OLE) &&
  1584. !(lpMessage->lpFiles->flFlags & MAPI_OLE_STATIC) &&
  1585. FIsHTMLFile(lpMessage->lpFiles->lpszPathName))
  1586. {
  1587. #if 0
  1588. DWORD dwByteOrder;
  1589. DWORD cbRead;
  1590. #endif
  1591. Assert(NULL == pStream);
  1592. hr = CreateStreamOnHFile(lpMessage->lpFiles->lpszPathName,
  1593. GENERIC_READ,
  1594. FILE_SHARE_READ,
  1595. NULL,
  1596. OPEN_EXISTING,
  1597. FILE_ATTRIBUTE_NORMAL,
  1598. NULL,
  1599. &pStream);
  1600. if (FAILED(hr))
  1601. goto error;
  1602. #if 0
  1603. // SBAILEY: Raid-75400 - Try to detect the byte order mark in the html....
  1604. if (SUCCEEDED(pStream->Read(&dwByteOrder, sizeof(DWORD), &cbRead)) && cbRead == sizeof(DWORD))
  1605. {
  1606. // Byte Order
  1607. if (dwByteOrder == 0xfffe)
  1608. {
  1609. // Create a new stream
  1610. IStream *pStmTemp=NULL;
  1611. // Create it
  1612. if (SUCCEEDED(MimeOleCreateVirtualStream(&pStmTemp)))
  1613. {
  1614. // Copy pStream into pStmTemp
  1615. if (SUCCEEDED(HrCopyStream(pStream, pStmTemp, NULL)))
  1616. {
  1617. // Release pStream
  1618. pStream->Release();
  1619. // Assume pStmTemp
  1620. pStream = pStmTemp;
  1621. // Don't Release pStmTemp
  1622. pStmTemp = NULL;
  1623. // Should already be unicode
  1624. Assert(1200 == lpMessage->lpFiles->ulReserved);
  1625. // Make sure ulReserved is set to 1200
  1626. lpMessage->lpFiles->ulReserved = 1200;
  1627. }
  1628. }
  1629. // Cleanup
  1630. SafeRelease(pStmTemp);
  1631. }
  1632. }
  1633. // Rewind
  1634. HrRewindStream(pStream);
  1635. #endif
  1636. // intl hack. If the shell is calling us, then lpFiles->ulReserved contains the codepage of
  1637. // the webpage they're attaching. All other mapi clients should call us with 0 as this param.
  1638. // if ulReserved is a valid CP, we'll convert to a HCHARSET and use that for the message.
  1639. if (lpMessage->lpFiles->ulReserved)
  1640. HrSetMsgCodePage((*pMsg), lpMessage->lpFiles->ulReserved);
  1641. hr = (*pMsg)->SetTextBody(TXT_HTML, (1200 == lpMessage->lpFiles->ulReserved ? IET_UNICODE : IET_INETCSET), NULL, pStream, NULL);
  1642. if (FAILED(hr))
  1643. goto error;
  1644. // we're sending this as a web page
  1645. if (pfWebPage)
  1646. *pfWebPage = TRUE;
  1647. }
  1648. else
  1649. {
  1650. lpMapiFileDesc pFile;
  1651. LPSTREAM pStreamFile;
  1652. LPTSTR pszFileName;
  1653. for (ULONG i = 0; i < lpMessage->nFileCount; i++)
  1654. {
  1655. pFile = &lpMessage->lpFiles[i];
  1656. if (pFile->lpszPathName && *(pFile->lpszPathName))
  1657. {
  1658. hr = CreateStreamOnHFile(pFile->lpszPathName,
  1659. GENERIC_READ,
  1660. FILE_SHARE_READ,
  1661. NULL,
  1662. OPEN_EXISTING,
  1663. FILE_ATTRIBUTE_NORMAL,
  1664. NULL,
  1665. &pStreamFile);
  1666. if (FAILED(hr))
  1667. goto error;
  1668. if (pFile->lpszFileName && *pFile->lpszFileName)
  1669. pszFileName = pFile->lpszFileName;
  1670. else
  1671. pszFileName = pFile->lpszPathName;
  1672. hr = (*pMsg)->AttachFile(pszFileName, pStreamFile, NULL);
  1673. pStreamFile->Release();
  1674. if (FAILED(hr))
  1675. goto error;
  1676. }
  1677. }
  1678. }
  1679. }
  1680. if (fOriginator)
  1681. {
  1682. TCHAR szDisplayName[CCHMAX_DISPLAY_NAME];
  1683. TCHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS];
  1684. TCHAR szAccountName[CCHMAX_DISPLAY_NAME];
  1685. // Get the default account
  1686. if (FAILED(hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount)))
  1687. goto error;
  1688. // Get Originator Display Name
  1689. if (FAILED(hr = pAccount->GetPropSz(AP_SMTP_DISPLAY_NAME, szDisplayName, ARRAYSIZE(szDisplayName))))
  1690. goto error;
  1691. // Get Originator Email Name
  1692. if (FAILED(hr = pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, ARRAYSIZE(szEmailAddress))))
  1693. goto error;
  1694. // Get the account Name
  1695. if (FAILED(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccountName, ARRAYSIZE(szAccountName))))
  1696. goto error;
  1697. // Append Sender
  1698. if (FAILED(hr = pAddrTable->Append(IAT_FROM, IET_DECODED, szDisplayName, szEmailAddress, NULL)))
  1699. goto error;
  1700. if (FAILED(hr = HrSetAccount(*pMsg, szAccountName)))
  1701. goto error;
  1702. }
  1703. ulRet = SUCCESS_SUCCESS;
  1704. // If you're not a web page (whose charset can be sniffed), set the default charset...
  1705. if((NULL == pfWebPage) || (!(*pfWebPage)))
  1706. {
  1707. if (g_hDefaultCharsetForMail==NULL)
  1708. ReadSendMailDefaultCharset();
  1709. (*pMsg)->SetCharset(g_hDefaultCharsetForMail, CSET_APPLY_ALL);
  1710. }
  1711. error:
  1712. SafeRelease(pStream);
  1713. SafeRelease(pAddrTable);
  1714. SafeRelease(pAccount);
  1715. return ulRet;
  1716. }
  1717. HRESULT AddRecipient(lpMapiMessage pMessage, lpMapiRecipDesc pRecip, ADDRESSPROPS *pAddress, ULONG ulRecipType)
  1718. {
  1719. HRESULT hr;
  1720. ULONG cbEntryID;
  1721. LPENTRYID lpEntryID = NULL;
  1722. LPSTR pszAddrType = NULL;
  1723. LPSTR pszAddress = NULL;
  1724. ULONG cch;
  1725. cch = lstrlen(pAddress->pszFriendly)+1;
  1726. if (FAILED(hr = SMAPIAllocateMore(cch, pMessage, (LPVOID*)&(pRecip->lpszName))))
  1727. goto exit;
  1728. StrCpyN(pRecip->lpszName, pAddress->pszFriendly, cch);
  1729. cch = lstrlen(pAddress->pszEmail)+1;
  1730. if (FAILED(hr = SMAPIAllocateMore(cch, pMessage, (LPVOID*)&(pRecip->lpszAddress))))
  1731. goto exit;
  1732. StrCpyN(pRecip->lpszAddress, pAddress->pszEmail, cch);
  1733. pRecip->ulReserved = 0;
  1734. pRecip->ulRecipClass = ulRecipType;
  1735. ParseEmailAddress(pRecip->lpszAddress, &pszAddrType, &pszAddress);
  1736. if (NULL == s_lpAddrBook)
  1737. {
  1738. hr = E_FAIL;
  1739. goto exit;
  1740. }
  1741. if (FAILED(hr = s_lpAddrBook->CreateOneOff(pRecip->lpszName, pszAddrType, pszAddress, 0, &cbEntryID, &lpEntryID)))
  1742. goto exit;
  1743. if (FAILED(hr = SMAPIAllocateMore(cbEntryID, pMessage, (LPVOID*)&(pRecip->lpEntryID))))
  1744. goto exit;
  1745. pRecip->ulEIDSize = cbEntryID;
  1746. CopyMemory(pRecip->lpEntryID, lpEntryID, cbEntryID);
  1747. exit:
  1748. if ((lpEntryID) && (NULL != s_lpWabObject))
  1749. s_lpWabObject->FreeBuffer(lpEntryID);
  1750. if (pszAddrType)
  1751. MemFree(pszAddrType);
  1752. if (pszAddress)
  1753. MemFree(pszAddress);
  1754. return hr;
  1755. }
  1756. HRESULT AddRecipientType(lpMapiMessage pMessage, LPMIMEADDRESSTABLE pAddrTable, DWORD dwAdrType, ULONG ulRecipType)
  1757. {
  1758. IMimeEnumAddressTypes *pEnum;
  1759. ADDRESSPROPS rAddress;
  1760. HRESULT hr = S_OK;
  1761. if (FAILED(hr = pAddrTable->EnumTypes(dwAdrType, IAP_FRIENDLY|IAP_EMAIL, &pEnum)))
  1762. return MAPI_E_FAILURE;
  1763. while (S_OK == pEnum->Next(1, &rAddress, NULL))
  1764. {
  1765. if (SUCCEEDED(hr = AddRecipient(pMessage, &pMessage->lpRecips[pMessage->nRecipCount], &rAddress, ulRecipType)))
  1766. pMessage->nRecipCount++;
  1767. g_pMoleAlloc->FreeAddressProps(&rAddress);
  1768. }
  1769. pEnum->Release();
  1770. return hr;
  1771. }
  1772. HRESULT AddOriginator(lpMapiMessage pMessage, LPMIMEADDRESSTABLE pAddrTable)
  1773. {
  1774. IMimeEnumAddressTypes *pEnum;
  1775. ADDRESSPROPS rAddress;
  1776. HRESULT hr = S_OK;
  1777. if (FAILED(hr = pAddrTable->EnumTypes(IAT_FROM, IAP_FRIENDLY|IAP_EMAIL, &pEnum)))
  1778. return MAPI_E_FAILURE;
  1779. if (S_OK == pEnum->Next(1, &rAddress, NULL))
  1780. {
  1781. hr = AddRecipient(pMessage, pMessage->lpOriginator, &rAddress, MAPI_ORIG);
  1782. g_pMoleAlloc->FreeAddressProps(&rAddress);
  1783. }
  1784. else
  1785. {
  1786. if (SUCCEEDED(hr = SMAPIAllocateMore(1, pMessage, (LPVOID*)&(pMessage->lpOriginator->lpszName))))
  1787. {
  1788. pMessage->lpOriginator->lpszAddress = pMessage->lpOriginator->lpszName;
  1789. *pMessage->lpOriginator->lpszName = 0;
  1790. }
  1791. }
  1792. pEnum->Release();
  1793. return hr;
  1794. }
  1795. ///////////////////////////////////////////////////////////////////////////////////
  1796. // Called by MAPIReadMail to Read an existing message in the store
  1797. // and copy in a MapiMessage structure
  1798. //
  1799. // Arguments:
  1800. // pFolder in pointer to IMessageFolder
  1801. // lpszMessageID in Message ID
  1802. // lppMessage out pointer to lpMapiMessage structure/
  1803. //
  1804. // Result
  1805. // BOOL - TRUE if successful FALSE if failed
  1806. ////////////////////////////////////////////////////////////////////////////////////
  1807. BOOL HrReadMail(IMessageFolder *pFolder, LPSTR lpszMessageID, lpMapiMessage FAR *lppMessage, FLAGS flFlags)
  1808. {
  1809. ULONG nRecipCount=0, ulCount=0, nBody=0;
  1810. HRESULT hr;
  1811. MESSAGEID dwMsgID;
  1812. MESSAGEINFO MsgInfo={0};
  1813. IStream *pStream = NULL;
  1814. IStream *pStreamHTML = NULL;
  1815. IMimeMessage *pMsg = NULL;
  1816. LPMIMEADDRESSTABLE pAddrTable = NULL;
  1817. LPSTR pszTemp = 0;
  1818. lpMapiMessage rgMessage;
  1819. ULONG ulSize,ulRead;
  1820. PROPVARIANT rVariant;
  1821. FILETIME localfiletime;
  1822. SYSTEMTIME systemtime;
  1823. ULONG cAttach=0;
  1824. LPHBODY rghAttach = 0;
  1825. lpMapiFileDesc rgFiles = NULL;
  1826. BOOL bRet=FALSE;
  1827. dwMsgID = (MESSAGEID)((UINT_PTR)StrToUint(lpszMessageID));
  1828. MsgInfo.idMessage = dwMsgID;
  1829. if (FAILED(pFolder->FindRecord(IINDEX_PRIMARY, COLUMNS_ALL, &MsgInfo, NULL)))
  1830. goto exit;
  1831. if (FAILED(hr = pFolder->OpenMessage(dwMsgID, OPEN_MESSAGE_SECURE, &pMsg, NOSTORECALLBACK)))
  1832. goto exit;
  1833. // Allocate memory for rgMessage
  1834. if (FAILED(hr = SMAPIAllocateBuffer(sizeof(MapiMessage), (LPVOID*)&rgMessage)))
  1835. goto exit;
  1836. ZeroMemory(rgMessage, sizeof(MapiMessage));
  1837. // Get the subject
  1838. if (SUCCEEDED(hr = MimeOleGetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &pszTemp)))
  1839. {
  1840. ULONG cchTemp = lstrlen(pszTemp)+1;
  1841. if (FAILED(hr = SMAPIAllocateMore(cchTemp, rgMessage, (LPVOID*)&(rgMessage->lpszSubject))))
  1842. goto exit;
  1843. StrCpyN(rgMessage->lpszSubject, pszTemp, cchTemp);
  1844. SafeMimeOleFree(pszTemp);
  1845. }
  1846. // Get the body text
  1847. if (!(flFlags & MAPI_ENVELOPE_ONLY))
  1848. {
  1849. if (FAILED(hr = pMsg->GetTextBody(TXT_PLAIN, IET_DECODED, &pStream, NULL)))
  1850. {
  1851. if (SUCCEEDED(hr = pMsg->GetTextBody(TXT_HTML, IET_INETCSET, &pStreamHTML, NULL)))
  1852. {
  1853. if (FAILED(hr = HrConvertHTMLToPlainText(pStreamHTML, &pStream, CF_TEXT)))
  1854. goto exit;
  1855. }
  1856. }
  1857. if (pStream)
  1858. {
  1859. if (FAILED(hr = HrGetStreamSize(pStream, &ulSize)))
  1860. goto exit;
  1861. if (FAILED(hr = HrRewindStream(pStream)))
  1862. goto exit;
  1863. if (ulSize>0)
  1864. {
  1865. if (FAILED(hr = SMAPIAllocateMore(ulSize + 1, rgMessage, (LPVOID*)&(rgMessage->lpszNoteText))))
  1866. goto exit;
  1867. if (FAILED(hr = pStream->Read((LPVOID)rgMessage->lpszNoteText, ulSize, &ulRead)))
  1868. goto exit;
  1869. rgMessage->lpszNoteText[ulRead] = 0;
  1870. }
  1871. }
  1872. }
  1873. else
  1874. {
  1875. // if we don't call GetTextBody, then the GetAttachments call will consider the bodies as attachments
  1876. if (FAILED(pMsg->GetTextBody(TXT_PLAIN, IET_DECODED, NULL, NULL)))
  1877. pMsg->GetTextBody(TXT_HTML, IET_INETCSET, NULL, NULL);
  1878. }
  1879. // Set the message date / Received Time...
  1880. rVariant.vt = VT_FILETIME;
  1881. if (SUCCEEDED(hr = pMsg->GetProp(PIDTOSTR(PID_ATT_RECVTIME),0,&rVariant)))
  1882. {
  1883. if (!FileTimeToLocalFileTime(&rVariant.filetime, &localfiletime))
  1884. goto exit;
  1885. if (!FileTimeToSystemTime(&localfiletime, &systemtime))
  1886. goto exit;
  1887. if (FAILED(hr = SMAPIAllocateMore(20, rgMessage, (LPVOID*)&(rgMessage->lpszDateReceived))))
  1888. goto exit;
  1889. wnsprintf(rgMessage->lpszDateReceived,20,"%04.4d/%02.2d/%02.2d %02.2d:%02.2d", systemtime.wYear, systemtime.wMonth, systemtime.wDay, systemtime.wHour, systemtime.wMinute);
  1890. }
  1891. // Set the flags
  1892. if (ISFLAGSET(MsgInfo.dwFlags, ARF_READ))
  1893. rgMessage->flFlags = 0;
  1894. else
  1895. rgMessage->flFlags = MAPI_UNREAD;
  1896. // Get Address Table
  1897. CHECKHR(hr = pMsg->GetAddressTable(&pAddrTable));
  1898. if (FAILED(hr = SMAPIAllocateMore(sizeof(MapiRecipDesc), rgMessage, (LPVOID*)&(rgMessage->lpOriginator))))
  1899. goto exit;
  1900. ZeroMemory(rgMessage->lpOriginator, sizeof(MapiRecipDesc));
  1901. if (FAILED(AddOriginator(rgMessage, pAddrTable)))
  1902. goto exit;
  1903. // Allocate space for the recipients
  1904. if (FAILED(pAddrTable->CountTypes(IAT_RECIPS, &nRecipCount)))
  1905. goto exit;
  1906. if (nRecipCount)
  1907. {
  1908. if (FAILED(hr = SMAPIAllocateMore(nRecipCount * sizeof(MapiRecipDesc), rgMessage, (LPVOID*)&(rgMessage->lpRecips))))
  1909. goto exit;
  1910. ZeroMemory(rgMessage->lpRecips, nRecipCount * sizeof(MapiRecipDesc));
  1911. // Add the To
  1912. if (FAILED(AddRecipientType(rgMessage, pAddrTable, IAT_TO, MAPI_TO)))
  1913. goto exit;
  1914. // Add the Cc
  1915. if (FAILED(AddRecipientType(rgMessage, pAddrTable, IAT_CC, MAPI_CC)))
  1916. goto exit;
  1917. // Add the Bcc
  1918. if (FAILED(AddRecipientType(rgMessage, pAddrTable, IAT_BCC, MAPI_BCC)))
  1919. goto exit;
  1920. }
  1921. // Fill the lpFiles structure
  1922. if (FAILED(hr = pMsg->GetAttachments(&cAttach, &rghAttach)))
  1923. goto exit;
  1924. if (!(flFlags & (MAPI_SUPPRESS_ATTACH|MAPI_ENVELOPE_ONLY)))
  1925. {
  1926. if (flFlags & MAPI_BODY_AS_FILE)
  1927. nBody = 1;
  1928. if (cAttach + nBody)
  1929. {
  1930. if (FAILED(hr = SMAPIAllocateMore((cAttach + nBody) * sizeof(MapiFileDesc), rgMessage, (LPVOID*)&rgFiles)))
  1931. goto exit;
  1932. }
  1933. // Check if MAPI_BODY_AS_FILE is set in flFlags
  1934. if (flFlags & MAPI_BODY_AS_FILE)
  1935. {
  1936. TCHAR lpszPath[MAX_PATH];
  1937. // Create a temporary file
  1938. if (!FBuildTempPath ("msoenote.txt", lpszPath, MAX_PATH, FALSE))
  1939. goto exit;
  1940. if FAILED(hr = WriteStreamToFile(pStream, lpszPath, CREATE_ALWAYS, GENERIC_WRITE))
  1941. goto exit;
  1942. // Reset the body back to NULL
  1943. if (rgMessage->lpszNoteText)
  1944. rgMessage->lpszNoteText[0] = '\0';
  1945. // Make this file as the first attachment
  1946. ULONG cchPath = lstrlen(lpszPath) + 1;
  1947. if (FAILED(hr = SMAPIAllocateMore(cchPath, rgMessage, (LPVOID*)&(rgFiles[0].lpszFileName))))
  1948. goto exit;
  1949. if (FAILED(hr = SMAPIAllocateMore(cchPath, rgMessage, (LPVOID*)&(rgFiles[0].lpszPathName))))
  1950. goto exit;
  1951. StrCpyN(rgFiles[0].lpszPathName, lpszPath, cchPath);
  1952. StrCpyN(rgFiles[0].lpszFileName, lpszPath, cchPath);
  1953. rgFiles[0].ulReserved = 0;
  1954. rgFiles[0].flFlags = 0;
  1955. rgFiles[0].nPosition = 0;
  1956. rgFiles[0].lpFileType = NULL;
  1957. }
  1958. for (ulCount = 0; ulCount < cAttach; ulCount++)
  1959. {
  1960. LPMIMEBODY pBody=0;
  1961. TCHAR lpszPath[MAX_PATH];
  1962. LPTSTR lpszFileName;
  1963. // The file doesn't contain anything. Fill the file
  1964. // from the stream
  1965. if (FAILED(hr = MimeOleGetBodyPropA(pMsg, rghAttach[ulCount], PIDTOSTR(PID_ATT_GENFNAME), NOFLAGS, &lpszFileName)))
  1966. goto exit;
  1967. if (!FBuildTempPath (lpszFileName, lpszPath, MAX_PATH, FALSE))
  1968. goto exit;
  1969. SafeMimeOleFree(lpszFileName);
  1970. hr=pMsg->BindToObject(rghAttach[ulCount], IID_IMimeBody, (LPVOID *)&pBody);
  1971. if (FAILED(hr))
  1972. goto exit;
  1973. hr=pBody->SaveToFile(IET_INETCSET, lpszPath);
  1974. if (FAILED(hr))
  1975. goto exit;
  1976. ULONG cchPath = lstrlen(lpszPath) + 1;
  1977. if (FAILED(hr = SMAPIAllocateMore(cchPath, rgMessage, (LPVOID*)&rgFiles[ulCount+nBody].lpszPathName)))
  1978. goto exit;
  1979. if (FAILED(hr = SMAPIAllocateMore(cchPath, rgMessage, (LPVOID*)&rgFiles[ulCount+nBody].lpszFileName)))
  1980. goto exit;
  1981. StrCpyN(rgFiles[ulCount+nBody].lpszPathName, lpszPath, cchPath);
  1982. StrCpyN(rgFiles[ulCount+nBody].lpszFileName, lpszPath, cchPath);
  1983. rgFiles[ulCount+nBody].ulReserved = 0;
  1984. rgFiles[ulCount+nBody].flFlags = 0;
  1985. rgFiles[ulCount+nBody].nPosition = 0;
  1986. rgFiles[ulCount+nBody].lpFileType = NULL;
  1987. ReleaseObj(pBody);
  1988. }
  1989. }
  1990. else
  1991. { // else condition added in response to bug# 2716 (v-snatar)
  1992. if ((flFlags & MAPI_SUPPRESS_ATTACH) && !(flFlags & MAPI_ENVELOPE_ONLY))
  1993. {
  1994. if (cAttach)
  1995. {
  1996. // Allocate memory for rgFiles
  1997. if (FAILED(hr = SMAPIAllocateMore(cAttach * sizeof(MapiFileDesc), rgMessage, (LPVOID*)&rgFiles)))
  1998. goto exit;
  1999. // This is important as we don't fill any other structure
  2000. // member apart from lpszFileName
  2001. ZeroMemory((LPVOID)rgFiles,cAttach * sizeof(MapiFileDesc));
  2002. for (ulCount = 0; ulCount < cAttach; ulCount++)
  2003. {
  2004. LPTSTR lpszFileName;
  2005. if (FAILED(hr = MimeOleGetBodyPropA(pMsg, rghAttach[ulCount], PIDTOSTR(PID_ATT_GENFNAME), NOFLAGS, &lpszFileName)))
  2006. goto exit;
  2007. // Allocate memory for the filename
  2008. ULONG cchFileName = lstrlen(lpszFileName)+1;
  2009. if (FAILED(hr = SMAPIAllocateMore(cchFileName, rgMessage, (LPVOID*)&rgFiles[ulCount].lpszFileName)))
  2010. goto exit;
  2011. StrCpyN(rgFiles[ulCount].lpszFileName, lpszFileName, cchFileName);
  2012. SafeMimeOleFree(lpszFileName);
  2013. }
  2014. }
  2015. }
  2016. }
  2017. // Set other parameters of MapiMessage
  2018. rgMessage->ulReserved = 0;
  2019. rgMessage->lpszMessageType = NULL;
  2020. rgMessage->lpszConversationID = NULL;
  2021. rgMessage->lpFiles = rgFiles;
  2022. rgMessage->nFileCount = rgFiles ? cAttach + nBody : 0;
  2023. bRet = TRUE;
  2024. *lppMessage = rgMessage;
  2025. // Mark the message as Read
  2026. if (!(flFlags & MAPI_PEEK))
  2027. {
  2028. MESSAGEIDLIST List;
  2029. ADJUSTFLAGS Flags;
  2030. List.cMsgs = 1;
  2031. List.prgidMsg = &MsgInfo.idMessage;
  2032. Flags.dwAdd = ARF_READ;
  2033. Flags.dwRemove = 0;
  2034. pFolder->SetMessageFlags(&List, &Flags, NULL, NOSTORECALLBACK);
  2035. }
  2036. exit:
  2037. SafeRelease(pStreamHTML);
  2038. if (pFolder)
  2039. pFolder->FreeRecord(&MsgInfo);
  2040. SafeMimeOleFree(rghAttach);
  2041. if (FAILED(hr))
  2042. SafeRelease((pMsg));
  2043. if (pMsg)
  2044. pMsg->Release();
  2045. if (pAddrTable)
  2046. pAddrTable->Release();
  2047. return bRet;
  2048. }
  2049. ///////////////////////////////////////////////////////////////////////////////////
  2050. // This function is used to check if the parameters in the MapiMessage structure
  2051. // are sufficient to Send a mail using the structure details.
  2052. //
  2053. // Parameters:
  2054. // lpMessage in pointer to MapiMessage structure/
  2055. //
  2056. // Result
  2057. // BOOL - 0 if successful or appropriate error message
  2058. ///////////////////////////////////////////////////////////////////////////////////
  2059. ULONG HrValidateMessage(lpMapiMessage lpMessage)
  2060. {
  2061. ULONG ulCount=0;
  2062. if (lpMessage->lpszSubject && IsBadStringPtr(lpMessage->lpszSubject, (UINT)0xFFFF))
  2063. return MAPI_E_FAILURE;
  2064. if (lpMessage->lpszNoteText && IsBadStringPtr(lpMessage->lpszNoteText, (UINT)0xFFFF))
  2065. return MAPI_E_FAILURE;
  2066. if (lpMessage->nFileCount > 0)
  2067. {
  2068. for (ulCount=0; ulCount<lpMessage->nFileCount; ulCount++)
  2069. {
  2070. if (!lpMessage->lpFiles[ulCount].lpszPathName)
  2071. return MAPI_E_FAILURE;
  2072. }
  2073. }
  2074. return SUCCESS_SUCCESS;
  2075. }
  2076. BOOL HrSMAPISend(HWND hWnd, IMimeMessage *pMsg)
  2077. {
  2078. BOOL bRet = FALSE;
  2079. HRESULT hr;
  2080. ISpoolerEngine *pSpooler = NULL;
  2081. BOOL fSendImmediate = FALSE;
  2082. if (!g_pSpooler)
  2083. {
  2084. if (FAILED(hr = CreateThreadedSpooler(NULL, &pSpooler, TRUE)))
  2085. goto error;
  2086. g_pSpooler = pSpooler;
  2087. }
  2088. fSendImmediate = DwGetOption(OPT_SENDIMMEDIATE);
  2089. if (FAILED(hr = HrSendMailToOutBox(hWnd, pMsg, fSendImmediate, TRUE)))
  2090. goto error;
  2091. if (pSpooler)
  2092. {
  2093. CloseThreadedSpooler(pSpooler);
  2094. pSpooler = NULL;
  2095. g_pSpooler = NULL;
  2096. }
  2097. bRet = TRUE;
  2098. error:
  2099. if (pSpooler)
  2100. pSpooler->Release();
  2101. return bRet;
  2102. }
  2103. HRESULT HrFromIDToNameAndAddress(LPTSTR *ppszLocalName, LPTSTR *ppszLocalAddress, ULONG cbEID, LPENTRYID lpEID)
  2104. {
  2105. ULONG ulObjType = 0, ulcValues;
  2106. IMailUser *lpMailUser = NULL;
  2107. HRESULT hr = NOERROR;
  2108. SizedSPropTagArray(2, ptaEid) = { 2, {PR_DISPLAY_NAME, PR_EMAIL_ADDRESS} };
  2109. SPropValue *spValue = NULL;
  2110. // Validate the parameters - Begin
  2111. if (0 == cbEID || NULL == lpEID || ppszLocalName == NULL || ppszLocalAddress == NULL)
  2112. return E_INVALIDARG;
  2113. *ppszLocalName = NULL;
  2114. *ppszLocalAddress = NULL;
  2115. // Validate the parameters - End
  2116. if (NULL == s_lpAddrBook)
  2117. {
  2118. hr = MAPI_E_FAILURE;
  2119. goto error;
  2120. }
  2121. if FAILED(hr = s_lpAddrBook->OpenEntry(cbEID, (LPENTRYID)lpEID, NULL, 0, &ulObjType, (LPUNKNOWN *)&lpMailUser))
  2122. goto error;
  2123. if FAILED(hr = lpMailUser->GetProps((LPSPropTagArray)&ptaEid, NULL, &ulcValues, &spValue))
  2124. goto error;
  2125. if (ulcValues != 2)
  2126. {
  2127. hr = MAPI_E_FAILURE;
  2128. goto error;
  2129. }
  2130. if (spValue[0].ulPropTag == PR_DISPLAY_NAME)
  2131. {
  2132. ULONG cchLocalName = lstrlen(spValue[0].Value.lpszA) + 1;
  2133. if (!MemAlloc((LPVOID*)ppszLocalName, cchLocalName))
  2134. goto error;
  2135. StrCpyN(*ppszLocalName, spValue[0].Value.lpszA, cchLocalName);
  2136. }
  2137. if (spValue[1].ulPropTag == PR_EMAIL_ADDRESS)
  2138. {
  2139. ULONG cchLocalAddress = lstrlen(spValue[1].Value.lpszA) + 1;
  2140. if (!MemAlloc((LPVOID*)ppszLocalAddress, cchLocalAddress))
  2141. goto error;
  2142. StrCpyN(*ppszLocalAddress, spValue[1].Value.lpszA, cchLocalAddress);
  2143. }
  2144. hr = NOERROR;
  2145. error:
  2146. ReleaseObj(lpMailUser);
  2147. if ((spValue) && (NULL != s_lpWabObject))
  2148. s_lpWabObject->FreeBuffer(spValue);
  2149. return hr;
  2150. }
  2151. // Fix for Bug #62129 (v-snatar)
  2152. HRESULT HrSendAndRecv()
  2153. {
  2154. HRESULT hr=E_FAIL;
  2155. ISpoolerEngine *pSpooler = NULL;
  2156. if (!g_pSpooler)
  2157. {
  2158. if (FAILED(hr = CreateThreadedSpooler(NULL, &pSpooler, TRUE)))
  2159. goto error;
  2160. g_pSpooler = pSpooler;
  2161. }
  2162. g_pSpooler->StartDelivery(NULL, NULL, FOLDERID_INVALID, DELIVER_MAIL_RECV | DELIVER_NOUI );
  2163. WaitForSingleObject(hSmapiEvent, INFINITE);
  2164. if (pSpooler)
  2165. {
  2166. CloseThreadedSpooler(pSpooler);
  2167. pSpooler = NULL;
  2168. g_pSpooler = NULL;
  2169. }
  2170. error:
  2171. if (pSpooler)
  2172. pSpooler->Release();
  2173. return hr;
  2174. }
  2175. /*
  2176. This code was taken from OLK2000's RTM source code
  2177. Debug code was removed, the allocator was switched over to g_pMalloc,
  2178. the name was changed from IsServiceAnExe, and the static s_isState was
  2179. added.
  2180. */
  2181. BOOL WINAPI IsProcessInteractive( VOID )
  2182. {
  2183. static INTERACTIVESTATE s_isState = IS_UNINIT;
  2184. HANDLE hProcessToken = NULL;
  2185. HANDLE hThreadToken = NULL;
  2186. DWORD groupLength = 50;
  2187. DWORD dw;
  2188. PTOKEN_GROUPS groupInfo = NULL;
  2189. SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY;
  2190. PSID InteractiveSid = NULL;
  2191. PSID ServiceSid = NULL;
  2192. DWORD i;
  2193. BOOL fServiceSID = FALSE;
  2194. BOOL fInteractiveSID = FALSE;
  2195. // Start with assumption that process is a Service, not an EXE.
  2196. // This is the conservative assumption. If there's an error, we
  2197. // have to return an answer based on incomplete information. The
  2198. // consequences are less grave if we assume we're in a service:
  2199. // an interactive app might fail instead of putting up UI, but if
  2200. // a service mistakenly tries to put up UI it will hang.
  2201. BOOL fExe = FALSE;
  2202. // Bail out early if we have already been here
  2203. if (s_isState != IS_UNINIT)
  2204. {
  2205. return (IS_INTERACTIVE == s_isState);
  2206. }
  2207. // If we're not running on NT, the high bit of the version is set.
  2208. // In this case, it's always an EXE.
  2209. DWORD dwVersion = GetVersion();
  2210. if (dwVersion >= 0x80000000)
  2211. {
  2212. fExe = TRUE;
  2213. goto ret;
  2214. }
  2215. // The information we need is on the process token.
  2216. // If we're impersonating, we probably won't be able to open the process token.
  2217. // Revert now; we'll re-impersonate when we're done.
  2218. if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, TRUE, &hThreadToken))
  2219. {
  2220. RevertToSelf();
  2221. }
  2222. else
  2223. {
  2224. dw = GetLastError();
  2225. if (dw != ERROR_NO_TOKEN)
  2226. {
  2227. goto ret;
  2228. }
  2229. }
  2230. // Now open the process token.
  2231. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  2232. {
  2233. goto ret;
  2234. }
  2235. groupInfo = (PTOKEN_GROUPS)g_pMalloc->Alloc(groupLength);
  2236. if (groupInfo == NULL)
  2237. goto ret;
  2238. if (!GetTokenInformation(hProcessToken, TokenGroups, groupInfo,
  2239. groupLength, &groupLength))
  2240. {
  2241. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  2242. {
  2243. goto ret;
  2244. }
  2245. g_pMalloc->Free(groupInfo);
  2246. groupInfo = NULL;
  2247. groupInfo = (PTOKEN_GROUPS)g_pMalloc->Alloc(groupLength);
  2248. if (groupInfo == NULL)
  2249. goto ret;
  2250. if (!GetTokenInformation(hProcessToken, TokenGroups, groupInfo,
  2251. groupLength, &groupLength))
  2252. {
  2253. goto ret;
  2254. }
  2255. }
  2256. //
  2257. // We now know the groups associated with this token. We want to look to see if
  2258. // the interactive group is active in the token, and if so, we know that
  2259. // this is an interactive process.
  2260. //
  2261. // We also look for the "service" SID, and if it's present, we know we're a service.
  2262. //
  2263. // The service SID will be present iff the service is running in a
  2264. // user account (and was invoked by the service controller).
  2265. //
  2266. if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_INTERACTIVE_RID, 0, 0,
  2267. 0, 0, 0, 0, 0, &InteractiveSid))
  2268. {
  2269. goto ret;
  2270. }
  2271. if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_SERVICE_RID, 0, 0, 0,
  2272. 0, 0, 0, 0, &ServiceSid))
  2273. {
  2274. goto ret;
  2275. }
  2276. for (i = 0; i < groupInfo->GroupCount ; i += 1)
  2277. {
  2278. SID_AND_ATTRIBUTES sanda = groupInfo->Groups[i];
  2279. PSID Sid = sanda.Sid;
  2280. //
  2281. // Check to see if the group we're looking at is one of
  2282. // the 2 groups we're interested in.
  2283. // We should never see both groups.
  2284. //
  2285. if (EqualSid(Sid, InteractiveSid))
  2286. {
  2287. //
  2288. // This process has the Interactive SID in its
  2289. // token. This means that the process is running as
  2290. // an EXE.
  2291. //
  2292. fInteractiveSID = TRUE;
  2293. break;
  2294. }
  2295. else if (EqualSid(Sid, ServiceSid))
  2296. {
  2297. //
  2298. // This process has the Service SID in its
  2299. // token. This means that the process is running as
  2300. // a service running in a user account.
  2301. //
  2302. fServiceSID = TRUE;
  2303. break;
  2304. }
  2305. }
  2306. /////// Truth table ///////
  2307. //
  2308. // 1. fServiceSID && !fInteractiveSID
  2309. // This process has the Service SID in its token.
  2310. // This means that the process is running as a service running in
  2311. // a user account.
  2312. //
  2313. // 2. !fServiceSID && fInteractiveSID
  2314. // This process has the Interactive SID in its token.
  2315. // This means that the process is running as an EXE.
  2316. //
  2317. // 3. !fServiceSID && !fInteractiveSID
  2318. // Neither Interactive or Service was present in the current users token,
  2319. // This implies that the process is running as a service, most likely
  2320. // running as LocalSystem.
  2321. //
  2322. // 4. fServiceSID && fInteractiveSID
  2323. // This shouldn't happen.
  2324. //
  2325. if (fServiceSID)
  2326. {
  2327. if (fInteractiveSID)
  2328. {
  2329. AssertSz(FALSE, "IsServiceAnExe: fServiceSID && fInteractiveSID - wha?");
  2330. }
  2331. fExe = FALSE;
  2332. }
  2333. else if (fInteractiveSID)
  2334. {
  2335. fExe = TRUE;
  2336. }
  2337. else // !fServiceSID && !fInteractiveSID
  2338. {
  2339. fExe = FALSE;
  2340. }
  2341. ret:
  2342. if (InteractiveSid)
  2343. FreeSid(InteractiveSid);
  2344. if (ServiceSid)
  2345. FreeSid(ServiceSid);
  2346. if (groupInfo)
  2347. g_pMalloc->Free(groupInfo);
  2348. if (hThreadToken)
  2349. {
  2350. if (!ImpersonateLoggedOnUser(hThreadToken))
  2351. {
  2352. AssertSz(FALSE, "ImpersonateLoggedOnUser failed!");
  2353. }
  2354. CloseHandle(hThreadToken);
  2355. }
  2356. if (hProcessToken)
  2357. CloseHandle(hProcessToken);
  2358. // Avoid the overhead for future calls
  2359. s_isState = (fExe) ? IS_INTERACTIVE : IS_NOTINTERACTIVE;
  2360. return(fExe);
  2361. }
  2362. const static HELPMAP g_rgCtxVirus[] =
  2363. {
  2364. {IDC_TO_TEXT, IDH_MAIL_VIRUS_TO},
  2365. {IDC_SUBJECT_TEXT, IDH_MAIL_VIRUS_SUBJECT},
  2366. {IDOK, IDH_MAIL_VIRUS_SEND},
  2367. {IDCANCEL, IDH_MAIL_VIRUS_DONT_SEND},
  2368. {idcStatic1, IDH_NEWS_COMM_GROUPBOX},
  2369. {idcStatic2, IDH_NEWS_COMM_GROUPBOX},
  2370. {idcStatic3, IDH_NEWS_COMM_GROUPBOX},
  2371. {0, 0}
  2372. };
  2373. INT_PTR CALLBACK WarnSendMailDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  2374. {
  2375. switch (msg)
  2376. {
  2377. case WM_INITDIALOG:
  2378. {
  2379. lpMapiMessage lpMessage = (lpMapiMessage)lParam;
  2380. if (lpMessage)
  2381. {
  2382. if (lpMessage->lpszSubject)
  2383. SetDlgItemText(hwnd, IDC_SUBJECT_TEXT, lpMessage->lpszSubject);
  2384. if (lpMessage->nRecipCount)
  2385. {
  2386. TCHAR *szTo = NULL;
  2387. int cTo = MAX_PATH;
  2388. int cch = 0;
  2389. if (MemAlloc((void**)&szTo, cTo*sizeof(TCHAR)))
  2390. {
  2391. szTo[0] = (TCHAR)0;
  2392. for (ULONG i = 0; i < lpMessage->nRecipCount; i++)
  2393. {
  2394. int cLen = lstrlen(lpMessage->lpRecips[i].lpszAddress);
  2395. if ((cch + cLen + 1) > cTo)
  2396. {
  2397. cTo += cLen + MAX_PATH;
  2398. if (!MemRealloc((void **)&szTo, cTo*sizeof(TCHAR)))
  2399. break;
  2400. }
  2401. if (i > 0)
  2402. {
  2403. StrCatBuff(szTo, ";", cTo);
  2404. cch++;
  2405. }
  2406. StrCatBuff(szTo, lpMessage->lpRecips[i].lpszAddress, cTo);
  2407. cch += cLen;
  2408. }
  2409. SetDlgItemText(hwnd, IDC_TO_TEXT, szTo);
  2410. MemFree(szTo);
  2411. }
  2412. }
  2413. }
  2414. SetFocus(GetDlgItem(hwnd, IDOK));
  2415. CenterDialog(hwnd);
  2416. return(FALSE);
  2417. }
  2418. case WM_HELP:
  2419. case WM_CONTEXTMENU:
  2420. return OnContextHelp(hwnd, msg, wParam, lParam, g_rgCtxVirus);
  2421. case WM_COMMAND:
  2422. switch (LOWORD(wParam))
  2423. {
  2424. case IDOK:
  2425. // fall through...
  2426. case IDCANCEL:
  2427. EndDialog(hwnd, LOWORD(wParam));
  2428. return(TRUE);
  2429. }
  2430. break; // wm_command
  2431. } // message switch
  2432. return(FALSE);
  2433. }