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.

460 lines
15 KiB

  1. // =====================================================================================
  2. // m a p c o n v . c p p
  3. // conver a MAPI message to and from an RFC 822/RFC 1521 (mime) internet message
  4. // =====================================================================================
  5. #include "pch.hxx"
  6. #include "Imnapi.h"
  7. #include "Exchrep.h"
  8. #include "Mapiconv.h"
  9. #include "Error.h"
  10. HRESULT HrCopyStream (LPSTREAM lpstmIn, LPSTREAM lpstmOut, ULONG *pcb);
  11. // =====================================================================================
  12. // MAPI Message Properties that I want
  13. // =====================================================================================
  14. enum
  15. {
  16. colSenderAddrType,
  17. colSenderName,
  18. colSenderEMail,
  19. colSubject,
  20. colDeliverTime,
  21. colBody,
  22. colPriority,
  23. colLast1
  24. };
  25. SizedSPropTagArray (colLast1, sptMessageProps) =
  26. {
  27. colLast1,
  28. {
  29. PR_SENDER_ADDRTYPE,
  30. PR_SENDER_NAME,
  31. PR_SENDER_EMAIL_ADDRESS,
  32. PR_SUBJECT,
  33. PR_MESSAGE_DELIVERY_TIME,
  34. PR_BODY,
  35. PR_PRIORITY
  36. }
  37. };
  38. // =====================================================================================
  39. // MAPI Recip Props
  40. // =====================================================================================
  41. enum
  42. {
  43. colRecipAddrType,
  44. colRecipName,
  45. colRecipAddress,
  46. colRecipType,
  47. colLast2
  48. };
  49. SizedSPropTagArray (colLast2, sptRecipProps) =
  50. {
  51. colLast2,
  52. {
  53. PR_ADDRTYPE,
  54. PR_DISPLAY_NAME,
  55. PR_EMAIL_ADDRESS,
  56. PR_RECIPIENT_TYPE
  57. }
  58. };
  59. // =====================================================================================
  60. // MAPI Attachment Props
  61. // =====================================================================================
  62. enum
  63. {
  64. colAttMethod,
  65. colAttNum,
  66. colAttLongFilename,
  67. colAttLongPathname,
  68. colAttPathname,
  69. colAttTag,
  70. colAttFilename,
  71. colAttExtension,
  72. colAttSize,
  73. colLast3
  74. };
  75. SizedSPropTagArray (colLast3, sptAttProps) =
  76. {
  77. colLast3,
  78. {
  79. PR_ATTACH_METHOD,
  80. PR_ATTACH_NUM,
  81. PR_ATTACH_LONG_FILENAME,
  82. PR_ATTACH_LONG_PATHNAME,
  83. PR_ATTACH_PATHNAME,
  84. PR_ATTACH_TAG,
  85. PR_ATTACH_FILENAME,
  86. PR_ATTACH_EXTENSION,
  87. PR_ATTACH_SIZE
  88. }
  89. };
  90. // =============================================================================================
  91. // StringDup - duplicates a string
  92. // =============================================================================================
  93. LPTSTR StringDup (LPCTSTR lpcsz)
  94. {
  95. // Locals
  96. LPTSTR lpszDup;
  97. if (lpcsz == NULL)
  98. return NULL;
  99. INT nLen = lstrlen (lpcsz) + 1;
  100. lpszDup = (LPTSTR)malloc (nLen * sizeof (TCHAR));
  101. if (lpszDup)
  102. CopyMemory (lpszDup, lpcsz, nLen);
  103. return lpszDup;
  104. }
  105. // =====================================================================================
  106. // HrMapiToImsg
  107. // =====================================================================================
  108. HRESULT HrMapiToImsg (LPMESSAGE lpMessage, LPIMSG lpImsg)
  109. {
  110. // Locals
  111. HRESULT hr = S_OK;
  112. ULONG cProp, i;
  113. LPSPropValue lpMsgPropValue = NULL;
  114. LPSRowSet lpRecipRows = NULL, lpAttRows = NULL;
  115. LPMAPITABLE lptblRecip = NULL, lptblAtt = NULL;
  116. LPATTACH lpAttach = NULL;
  117. LPMESSAGE lpMsgAtt = NULL;
  118. LPSTREAM lpstmRtfComp = NULL, lpstmRtf = NULL;
  119. // Zero init
  120. ZeroMemory (lpImsg, sizeof (IMSG));
  121. // Get the propsw
  122. hr = lpMessage->GetProps ((LPSPropTagArray)&sptMessageProps, 0, &cProp, &lpMsgPropValue);
  123. if (FAILED (hr))
  124. goto exit;
  125. // Subject
  126. if (PROP_TYPE(lpMsgPropValue[colSubject].ulPropTag) != PT_ERROR)
  127. lpImsg->lpszSubject = StringDup (lpMsgPropValue[colSubject].Value.lpszA);
  128. // Body
  129. if (PROP_TYPE(lpMsgPropValue[colBody].ulPropTag) != PT_ERROR)
  130. lpImsg->lpszBody = StringDup (lpMsgPropValue[colBody].Value.lpszA);
  131. // RTF
  132. if (!FAILED (lpMessage->OpenProperty (PR_RTF_COMPRESSED, (LPIID)&IID_IStream, 0, 0, (LPUNKNOWN *)&lpstmRtfComp)))
  133. if (!FAILED (WrapCompressedRTFStream (lpstmRtfComp, 0, &lpstmRtf)))
  134. if (!FAILED (CreateStreamOnHFile (NULL, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL, &lpImsg->lpstmRtf)))
  135. HrCopyStream (lpstmRtf, lpImsg->lpstmRtf, NULL);
  136. // Delivery Time
  137. if (PROP_TYPE(lpMsgPropValue[colDeliverTime].ulPropTag) != PT_ERROR)
  138. CopyMemory (&lpImsg->ftDelivery, &lpMsgPropValue[colDeliverTime].Value.ft, sizeof (FILETIME));
  139. // Priority
  140. lpImsg->wPriority = PRI_NORMAL;
  141. if (PROP_TYPE(lpMsgPropValue[colPriority].ulPropTag) != PT_ERROR)
  142. {
  143. switch (lpMsgPropValue[colPriority].Value.l)
  144. {
  145. case PRIO_NORMAL:
  146. lpImsg->wPriority = PRI_NORMAL;
  147. break;
  148. case PRIO_URGENT:
  149. lpImsg->wPriority = PRI_HIGH;
  150. break;
  151. case PRIO_NONURGENT:
  152. default:
  153. lpImsg->wPriority = PRI_LOW;
  154. break;
  155. }
  156. }
  157. // Get the recipient table
  158. hr = lpMessage->GetRecipientTable (0, &lptblRecip);
  159. if (FAILED (hr))
  160. goto exit;
  161. // Get all the rows of the recipient table
  162. hr = HrQueryAllRows (lptblRecip, (LPSPropTagArray)&sptRecipProps, NULL, NULL, 0, &lpRecipRows);
  163. if (FAILED (hr))
  164. goto exit;
  165. // Allocate Recipient Array
  166. lpImsg->cAddress = lpRecipRows->cRows + 1;
  167. lpImsg->lpIaddr = (LPIADDRINFO)malloc (sizeof (IADDRINFO) * lpImsg->cAddress);
  168. if (lpImsg->lpIaddr == NULL)
  169. goto exit;
  170. // Originator of the message "From: "
  171. lpImsg->lpIaddr[0].dwType = IADDR_FROM;
  172. if (PROP_TYPE(lpMsgPropValue[colSenderName].ulPropTag) != PT_ERROR)
  173. {
  174. lpImsg->lpIaddr[0].lpszDisplay = StringDup (lpMsgPropValue[colSenderName].Value.lpszA);
  175. lpImsg->lpIaddr[0].lpszAddress = StringDup (lpMsgPropValue[colSenderName].Value.lpszA);
  176. }
  177. if (PROP_TYPE(lpMsgPropValue[colSenderEMail].ulPropTag) != PT_ERROR &&
  178. PROP_TYPE(lpMsgPropValue[colSenderAddrType].ulPropTag) != PT_ERROR &&
  179. lstrcmpi (lpMsgPropValue[colSenderAddrType].Value.lpszA, "SMTP") == 0)
  180. {
  181. lpImsg->lpIaddr[0].lpszAddress = StringDup (lpMsgPropValue[colSenderEMail].Value.lpszA);
  182. }
  183. // Add in the rest of the recipients
  184. for (i=0; i<lpRecipRows->cRows; i++)
  185. {
  186. assert (i+1 < lpImsg->cAddress);
  187. if (PROP_TYPE(lpRecipRows->aRow[i].lpProps[colRecipType].ulPropTag) != PT_ERROR)
  188. {
  189. switch (lpRecipRows->aRow[i].lpProps[colRecipType].Value.ul)
  190. {
  191. case MAPI_TO:
  192. lpImsg->lpIaddr[i+1].dwType = IADDR_TO;
  193. break;
  194. case MAPI_ORIG:
  195. lpImsg->lpIaddr[i+1].dwType = IADDR_FROM;
  196. break;
  197. case MAPI_CC:
  198. lpImsg->lpIaddr[i+1].dwType = IADDR_CC;
  199. break;
  200. case MAPI_BCC:
  201. lpImsg->lpIaddr[i+1].dwType = IADDR_BCC;
  202. break;
  203. default:
  204. Assert (FALSE);
  205. lpImsg->lpIaddr[i+1].dwType = IADDR_TO;
  206. break;
  207. }
  208. }
  209. else
  210. lpImsg->lpIaddr[i+1].dwType = IADDR_TO;
  211. if (PROP_TYPE(lpRecipRows->aRow[i].lpProps[colRecipName].ulPropTag) != PT_ERROR)
  212. {
  213. lpImsg->lpIaddr[i+1].lpszDisplay = StringDup (lpRecipRows->aRow[i].lpProps[colRecipName].Value.lpszA);
  214. lpImsg->lpIaddr[i+1].lpszAddress = StringDup (lpRecipRows->aRow[i].lpProps[colRecipName].Value.lpszA);
  215. }
  216. if (PROP_TYPE(lpRecipRows->aRow[i].lpProps[colRecipName].ulPropTag) != PT_ERROR &&
  217. PROP_TYPE(lpMsgPropValue[colRecipAddrType].ulPropTag) != PT_ERROR &&
  218. lstrcmpi (lpMsgPropValue[colRecipAddrType].Value.lpszA, "SMTP") == 0)
  219. {
  220. lpImsg->lpIaddr[i+1].lpszAddress = StringDup (lpRecipRows->aRow[i].lpProps[colRecipAddress].Value.lpszA);
  221. }
  222. }
  223. // Free Rows
  224. if (lpRecipRows)
  225. FreeProws (lpRecipRows);
  226. lpRecipRows = NULL;
  227. // Attachments
  228. hr = lpMessage->GetAttachmentTable (0, &lptblAtt);
  229. if (FAILED (hr))
  230. goto exit;
  231. // Get all the rows of the recipient table
  232. hr = HrQueryAllRows (lptblAtt, (LPSPropTagArray)&sptAttProps, NULL, NULL, 0, &lpAttRows);
  233. if (FAILED (hr))
  234. goto exit;
  235. // Allocate files list
  236. if (lpAttRows->cRows == 0)
  237. goto exit;
  238. // Allocate memory
  239. lpImsg->cAttach = lpAttRows->cRows;
  240. lpImsg->lpIatt = (LPIATTINFO)malloc (sizeof (IATTINFO) * lpImsg->cAttach);
  241. if (lpImsg->lpIatt == NULL)
  242. goto exit;
  243. // Zero init
  244. ZeroMemory (lpImsg->lpIatt, sizeof (IATTINFO) * lpImsg->cAttach);
  245. // Walk the rows
  246. for (i=0; i<lpAttRows->cRows; i++)
  247. {
  248. if (PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttMethod].ulPropTag) != PT_ERROR &&
  249. PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttNum].ulPropTag) != PT_ERROR)
  250. {
  251. // Basic Properties
  252. if (PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttPathname].ulPropTag) != PT_ERROR)
  253. lpImsg->lpIatt[i].lpszPathName = StringDup (lpAttRows->aRow[i].lpProps[colAttPathname].Value.lpszA);
  254. if (PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttFilename].ulPropTag) != PT_ERROR)
  255. lpImsg->lpIatt[i].lpszFileName = StringDup (lpAttRows->aRow[i].lpProps[colAttFilename].Value.lpszA);
  256. if (PROP_TYPE(lpAttRows->aRow[i].lpProps[colAttExtension].ulPropTag) != PT_ERROR)
  257. lpImsg->lpIatt[i].lpszExt = StringDup (lpAttRows->aRow[i].lpProps[colAttExtension].Value.lpszA);
  258. // Open the attachment
  259. hr = lpMessage->OpenAttach (lpAttRows->aRow[i].lpProps[colAttNum].Value.l, NULL, MAPI_BEST_ACCESS, &lpAttach);
  260. if (FAILED (hr))
  261. {
  262. lpImsg->lpIatt[i].fError = TRUE;
  263. continue;
  264. }
  265. // Handle the attachment method
  266. switch (lpAttRows->aRow[i].lpProps[colAttMethod].Value.ul)
  267. {
  268. case NO_ATTACHMENT:
  269. lpImsg->lpIatt[i].dwType = 0;
  270. lpImsg->lpIatt[i].fError = TRUE;
  271. break;
  272. case ATTACH_BY_REF_RESOLVE:
  273. case ATTACH_BY_VALUE:
  274. lpImsg->lpIatt[i].dwType = IATT_FILE;
  275. hr = lpAttach->OpenProperty (PR_ATTACH_DATA_BIN, (LPIID)&IID_IStream, 0, 0, (LPUNKNOWN *)&lpImsg->lpIatt[i].lpstmAtt);
  276. if (FAILED (hr))
  277. lpImsg->lpIatt[i].fError = TRUE;
  278. break;
  279. case ATTACH_BY_REF_ONLY:
  280. case ATTACH_BY_REFERENCE:
  281. lpImsg->lpIatt[i].dwType = IATT_FILE;
  282. hr = CreateStreamOnHFile (lpImsg->lpIatt[i].lpszPathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, &lpImsg->lpIatt[i].lpstmAtt);
  283. if (FAILED (hr))
  284. lpImsg->lpIatt[i].fError = TRUE;
  285. break;
  286. case ATTACH_EMBEDDED_MSG:
  287. lpImsg->lpIatt[i].dwType = IATT_MSG;
  288. hr = lpAttach->OpenProperty (PR_ATTACH_DATA_OBJ, (LPIID)&IID_IMessage, 0, 0, (LPUNKNOWN *)&lpMsgAtt);
  289. if (FAILED (hr) || lpMsgAtt == NULL)
  290. lpImsg->lpIatt[i].fError = TRUE;
  291. else
  292. {
  293. lpImsg->lpIatt[i].lpImsg = (LPIMSG)malloc (sizeof (IMSG));
  294. if (lpImsg->lpIatt[i].lpImsg == NULL)
  295. lpImsg->lpIatt[i].fError = TRUE;
  296. else
  297. {
  298. hr = HrMapiToImsg (lpMsgAtt, lpImsg->lpIatt[i].lpImsg);
  299. if (FAILED (hr))
  300. lpImsg->lpIatt[i].fError = TRUE;
  301. }
  302. lpMsgAtt->Release ();
  303. lpMsgAtt = NULL;
  304. }
  305. break;
  306. case ATTACH_OLE:
  307. default:
  308. lpImsg->lpIatt[i].dwType = IATT_OLE;
  309. lpImsg->lpIatt[i].fError = TRUE;
  310. break;
  311. }
  312. // Free Attachment
  313. if (lpAttach)
  314. lpAttach->Release ();
  315. lpAttach = NULL;
  316. }
  317. }
  318. exit:
  319. // Cleanup
  320. if (lpAttach)
  321. lpAttach->Release ();
  322. if (lptblAtt)
  323. lptblAtt->Release ();
  324. if (lpAttRows)
  325. FreeProws (lpAttRows);
  326. if (lpRecipRows)
  327. FreeProws (lpRecipRows);
  328. if (lpMsgPropValue)
  329. MAPIFreeBuffer (lpMsgPropValue);
  330. if (lptblRecip)
  331. lptblRecip->Release ();
  332. if (lpMsgAtt)
  333. lpMsgAtt->Release ();
  334. if (lpstmRtfComp)
  335. lpstmRtfComp->Release ();
  336. if (lpstmRtf)
  337. lpstmRtf->Release ();
  338. // Done
  339. return hr;
  340. }
  341. void AssertSzFn(LPSTR szMsg, LPSTR szFile, int nLine)
  342. {
  343. static const char rgch1[] = "File %s, line %d:";
  344. static const char rgch2[] = "Unknown file:";
  345. static const char szAssert[] = "Assert Failure";
  346. char rgch[512];
  347. char *lpsz;
  348. int ret, cch;
  349. if (szFile)
  350. wnsprintf(rgch, ARRAYSIZE(rgch),rgch1, szFile, nLine);
  351. else
  352. StrCpyN(rgch, rgch2,ARRAYSIZE(rgch));
  353. cch = lstrlen(rgch);
  354. Assert(lstrlen(szMsg)<(512-cch-3));
  355. lpsz = &rgch[cch];
  356. *lpsz++ = '\n';
  357. *lpsz++ = '\n';
  358. StrCpyN(lpsz, szMsg, (ARRAYSIZE(rgch)-cch-2));
  359. ret = MessageBox(GetActiveWindow(), rgch, szAssert, MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SYSTEMMODAL|MB_SETFOREGROUND);
  360. if (ret != IDIGNORE)
  361. DebugBreak();
  362. /* Force a hard exit w/ a GP-fault so that Dr. Watson generates a nice stack trace log. */
  363. if (ret == IDABORT)
  364. *(LPBYTE)0 = 1; // write to address 0 causes GP-fault
  365. }
  366. // =====================================================================================
  367. // HrCopyStream - caller must do the commit
  368. // =====================================================================================
  369. HRESULT HrCopyStream (LPSTREAM lpstmIn, LPSTREAM lpstmOut, ULONG *pcb)
  370. {
  371. // Locals
  372. HRESULT hr = S_OK;
  373. BYTE buf[4096];
  374. ULONG cbRead = 0, cbTotal = 0;
  375. do
  376. {
  377. hr = lpstmIn->Read (buf, sizeof (buf), &cbRead);
  378. if (FAILED (hr))
  379. goto exit;
  380. if (cbRead == 0) break;
  381. hr = lpstmOut->Write (buf, cbRead, NULL);
  382. if (FAILED (hr))
  383. goto exit;
  384. cbTotal += cbRead;
  385. }
  386. while (cbRead == sizeof (buf));
  387. exit:
  388. if (pcb)
  389. *pcb = cbTotal;
  390. return hr;
  391. }