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.

384 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. mail.cpp
  5. Abstract:
  6. Implementation of mail related utility functions
  7. Author:
  8. Eran Yariv (EranY) Feb, 2000
  9. Revision History:
  10. --*/
  11. #include <faxutil.h>
  12. #pragma warning (disable:4146) // unary minus operator applied to unsigned type, result still unsigned
  13. #include "msado15.tlh"
  14. #include "cdosys.tlh"
  15. #include <cdosysstr.h> // String constants in this file
  16. #include <cdosyserr.h> // Error constants in this file
  17. #pragma warning (default:4146) // unary minus operator applied to unsigned type, result still unsigned
  18. #define SMTP_CONN_TIMEOUT (long)10 // Time out (sec) of SMTP connection
  19. HRESULT
  20. SendMail (
  21. LPCTSTR lpctstrFrom,
  22. LPCTSTR lpctstrTo,
  23. LPCTSTR lpctstrSubject,
  24. LPCTSTR lpctstrBody,
  25. LPCTSTR lpctstrHTMLBody,
  26. LPCTSTR lpctstrAttachmentPath,
  27. LPCTSTR lpctstrAttachmentMailFileName,
  28. LPCTSTR lpctstrServer,
  29. DWORD dwPort, // = 25
  30. CDO_AUTH_TYPE AuthType, // = CDO_AUTH_ANONYMOUS
  31. LPCTSTR lpctstrUser, // = NULL
  32. LPCTSTR lpctstrPassword, // = NULL
  33. HANDLE hLoggedOnUserToken // = NULL
  34. )
  35. /*++
  36. Routine name : SendMail
  37. Routine description:
  38. Sends a mail message using SMTP over CDO2.
  39. Author:
  40. Eran Yariv (EranY), Feb, 2000
  41. Arguments:
  42. lpctstrFrom [in] - From address (mandatory)
  43. e.g: erany@microsoft.com
  44. lpctstrTo [in] - To address (mandatory)
  45. e.g: erany@microsoft.com
  46. lpctstrSubject [in] - Subject (optional)
  47. lpctstrBody [in] - Body text of message (optional).
  48. If NULL, the message will not have a body.
  49. lpctstrHTMLBody [in] - HTML Body text of message (optional).
  50. If NULL, the message will not have a HTML body.
  51. lpctstrAttachmentPath [in] - Full path to file to attach (optional)
  52. If NULL, the message will not include attachments.
  53. lpctstrAttachmentMailFileName [in] - The file name of the attachment as is will appear in the mail message.
  54. lpctstrServer [in] - SMTP server to connect to (mandatory)
  55. e.g: hai-msg-01
  56. dwPort [in] - SMTP port (optional, default = 25)
  57. AuthType [in] - Type of SMTP authentication.
  58. Valid values are CDO_AUTH_ANONYMOUS, CDO_AUTH_BASIC,
  59. and CDO_AUTH_NTLM.
  60. lpctstrUser [in] - User to authenticate
  61. In use only if AuthType is CDO_AUTH_BASIC or CDO_AUTH_NTLM.
  62. lpctstrPassword [in] - Password to authenticate
  63. In use only if AuthType is CDO_AUTH_BASIC or CDO_AUTH_NTLM.
  64. hLoggedOnUserToken [in] - Handle to alogged on user token.
  65. In use only if AuthType is CDO_AUTH_NTLM.
  66. Return Value:
  67. Standard HRESULT code
  68. --*/
  69. {
  70. DEBUG_FUNCTION_NAME(TEXT("SendMail"))
  71. Assert (lpctstrFrom && lpctstrTo && lpctstrServer);
  72. HRESULT hr = NOERROR;
  73. Assert ((CDO_AUTH_ANONYMOUS == AuthType) ||
  74. (CDO_AUTH_BASIC == AuthType) ||
  75. (CDO_AUTH_NTLM == AuthType));
  76. BOOL bImpersonated = FALSE;
  77. hr = CoInitialize(NULL);
  78. if (S_FALSE == hr)
  79. {
  80. //
  81. // Thread's COM already initialized.
  82. // This is not an error and we still have to call CoUninitialize at the end.
  83. //
  84. hr = NOERROR;
  85. }
  86. if (FAILED(hr))
  87. {
  88. DebugPrintEx(
  89. DEBUG_ERR,
  90. TEXT("CoInitialize failed. (hr: 0x%08x)"),
  91. hr);
  92. return hr;
  93. }
  94. try
  95. {
  96. //
  97. // The following code is in a seperate block so that the auto pointers dtors
  98. // get called before CoUninitialize
  99. //
  100. //
  101. // Create a new message instance (can throw exception)
  102. //
  103. IMessagePtr iMsg(__uuidof(Message));
  104. //
  105. // Create a new CDO2 configuration instance (can throw exception)
  106. IConfigurationPtr iConf(__uuidof(Configuration));
  107. //
  108. // Access configuration fields collection
  109. //
  110. FieldsPtr Flds;
  111. Flds = iConf->Fields;
  112. //
  113. // Send the message using the network. (SMTP protocol over the network)
  114. //
  115. Flds->Item[cdoSendUsingMethod]->Value = _variant_t((long)cdoSendUsingPort);
  116. //
  117. // Define SMTP server
  118. //
  119. Flds->Item[cdoSMTPServer]->Value = _variant_t(lpctstrServer);
  120. //
  121. // Define SMTP port
  122. //
  123. Flds->Item[cdoSMTPServerPort]->Value = _variant_t((long)dwPort);
  124. //
  125. // Define SMTP connection timeout (in seconds)
  126. //
  127. Flds->Item[cdoSMTPConnectionTimeout]->Value = _variant_t(SMTP_CONN_TIMEOUT);
  128. //
  129. // Make sure we don't used cached info for attachments
  130. //
  131. Flds->Item[cdoURLGetLatestVersion]->Value = _variant_t(VARIANT_TRUE);
  132. //
  133. // Choose authentication method
  134. //
  135. switch (AuthType)
  136. {
  137. case CDO_AUTH_ANONYMOUS:
  138. Flds->Item[cdoSMTPAuthenticate]->Value = _variant_t((long)cdoAnonymous);
  139. break;
  140. case CDO_AUTH_BASIC:
  141. Flds->Item[cdoSMTPAuthenticate]->Value = _variant_t((long)cdoBasic);
  142. Flds->Item[cdoSendUserName]->Value = _variant_t(lpctstrUser);
  143. Flds->Item[cdoSendPassword]->Value = _variant_t(lpctstrPassword);
  144. break;
  145. case CDO_AUTH_NTLM:
  146. //
  147. // NTLM authentication required the calling client (that's us)
  148. // to impersonate the user
  149. //
  150. Flds->Item[cdoSMTPAuthenticate]->Value = _variant_t((long)cdoNTLM);
  151. break;
  152. default:
  153. ASSERT_FALSE;
  154. }
  155. //
  156. // Update configuration from the fields
  157. //
  158. Flds->Update();
  159. //
  160. // Store configuration in the message
  161. //
  162. iMsg->Configuration = iConf;
  163. //
  164. // Set recipient
  165. //
  166. iMsg->To = lpctstrTo;
  167. //
  168. // Set sender
  169. //
  170. iMsg->From = lpctstrFrom;
  171. //
  172. // Set subject
  173. //
  174. iMsg->Subject = lpctstrSubject;
  175. //
  176. // Set message format to MIME
  177. //
  178. iMsg->MimeFormatted = _variant_t(VARIANT_TRUE);
  179. //
  180. // Set charset to Unicode (UTF-8)
  181. //
  182. iMsg->BodyPart->Charset = "utf-8";
  183. iMsg->BodyPart->ContentTransferEncoding = "base64";
  184. IBodyPartPtr iBp;
  185. //
  186. // Get message body root
  187. //
  188. iBp = iMsg;
  189. //
  190. // Set content type fo mixed to support both body and attachment
  191. //
  192. iBp->ContentMediaType = "multipart/mixed; charset=""utf-8""";
  193. if (lpctstrBody)
  194. {
  195. //
  196. // Add body text
  197. //
  198. IBodyPartPtr iBp2;
  199. _StreamPtr Stm;
  200. //
  201. // Add text body under root
  202. //
  203. iBp2 = iBp->AddBodyPart(-1);
  204. //
  205. // Use text format
  206. //
  207. iBp2->ContentMediaType = "text/plain";
  208. //
  209. // Set charset to Unicode (UTF-8)
  210. //
  211. iBp2->Charset = "utf-8";
  212. iBp2->ContentTransferEncoding = "base64";
  213. //
  214. // Get body text stream
  215. //
  216. Stm = iBp2->GetDecodedContentStream();
  217. //
  218. // Write stream text
  219. //
  220. Stm->WriteText(lpctstrBody, adWriteChar);
  221. Stm->Flush();
  222. }
  223. if (lpctstrHTMLBody)
  224. {
  225. //
  226. // Set content type to alternative to support both plain text body and HTML body
  227. // If an attachment is added afterwards, the ContentMediaType is automatically set
  228. // to mixed and the multipart/alternative is moved to new sub-BodyPart.
  229. //
  230. iBp->ContentMediaType = "multipart/alternative; charset=""utf-8""";
  231. IBodyPartPtr iBp2;
  232. _StreamPtr Stm;
  233. //
  234. // Add html body under root
  235. //
  236. iBp2 = iBp->AddBodyPart(-1);
  237. //
  238. // Use html format
  239. //
  240. iBp2->ContentMediaType = "text/html";
  241. //
  242. // Set charset to Unicode (UTF-8)
  243. //
  244. iBp2->Charset = "utf-8";
  245. iBp2->ContentTransferEncoding = "base64";
  246. //
  247. // Get body html stream
  248. //
  249. Stm = iBp2->GetDecodedContentStream();
  250. //
  251. // Write stream html
  252. //
  253. Stm->WriteText(lpctstrHTMLBody, adWriteChar);
  254. Stm->Flush();
  255. }
  256. if (lpctstrAttachmentPath)
  257. {
  258. //
  259. // Add attachment
  260. //
  261. IBodyPartPtr iBpAttachment;
  262. iBpAttachment = iMsg->AddAttachment(lpctstrAttachmentPath, TEXT(""), TEXT(""));
  263. iBpAttachment->ContentMediaType = "image/tif";
  264. if (lpctstrHTMLBody)
  265. { // The multipart/alternative section was moved to sub-bodypart and
  266. // the main ContentMediaType was moved with it so now we restore it.
  267. iBp->ContentMediaType = "multipart/mixed; charset=""utf-8""";
  268. }
  269. if (lpctstrAttachmentMailFileName)
  270. {
  271. //
  272. // User wishes to rename attachment in the mail message
  273. //
  274. FieldsPtr Flds = iBpAttachment->Fields;
  275. _bstr_t bstrContentType = iBpAttachment->ContentMediaType +
  276. TEXT("; name=\"") +
  277. lpctstrAttachmentMailFileName +
  278. TEXT("\"");
  279. Flds->Item[cdoContentType]->Value = _variant_t(bstrContentType);
  280. Flds->Update();
  281. Flds->Resync(adResyncAllValues);
  282. }
  283. }
  284. if (CDO_AUTH_NTLM == AuthType)
  285. {
  286. //
  287. // We impersonate the user in the NTLM authentication mode.
  288. // This is the last thing we do just before sending the message.
  289. //
  290. Assert (hLoggedOnUserToken);
  291. if (!ImpersonateLoggedOnUser (hLoggedOnUserToken))
  292. {
  293. hr = HRESULT_FROM_WIN32(GetLastError());
  294. DebugPrintEx(
  295. DEBUG_ERR,
  296. TEXT("ImpersonateLoggedOnUser failed. (hr: 0x%08x)"),
  297. hr);
  298. goto exit;
  299. }
  300. bImpersonated = TRUE;
  301. }
  302. //
  303. // Finally - send the message
  304. //
  305. iMsg->Send();
  306. }
  307. catch (_com_error &er)
  308. {
  309. //
  310. // Error in CDO2
  311. //
  312. hr = er.Error ();
  313. DebugPrintEx(
  314. DEBUG_ERR,
  315. TEXT("CDO2 Error 0x%08x: to:%s, subject:%s")
  316. #ifdef UNICODE
  317. TEXT(" Description:%s")
  318. #endif
  319. ,hr,
  320. lpctstrTo,
  321. lpctstrSubject
  322. #ifdef UNICODE
  323. ,(LPCTSTR)er.Description()
  324. #endif
  325. );
  326. }
  327. exit:
  328. CoUninitialize();
  329. if (bImpersonated)
  330. {
  331. if (!RevertToSelf ())
  332. {
  333. hr = HRESULT_FROM_WIN32(GetLastError());
  334. DebugPrintEx(
  335. DEBUG_ERR,
  336. TEXT("RevertToSelf failed. (hr: 0x%08x)"),
  337. hr);
  338. }
  339. }
  340. return hr;
  341. } // SendMail