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.

489 lines
11 KiB

  1. #define DEFINE_STRCONST
  2. #define INITGUID
  3. #define INC_OLE2
  4. #include <windows.h>
  5. #include <initguid.h>
  6. #include <mimeole.h>
  7. //#include <mimeapi.h>
  8. #include <urlmon.h>
  9. #include "main.h"
  10. #include "smtpcb.h"
  11. #define ReleaseObj(x) (x?(x)->Release : 0)
  12. typedef struct MSGDATA_tag
  13. {
  14. TCHAR rgchSubj[MAX_PATH];
  15. TCHAR rgchTo[MAX_PATH];
  16. TCHAR rgchFrom[MAX_PATH];
  17. TCHAR rgchFile[MAX_PATH];
  18. TCHAR rgchServer[MAX_PATH];
  19. TCHAR rgchBase[MAX_PATH];
  20. BOOL fRaw;
  21. BOOL fB64;
  22. } MSGDATA, *PMSGDATA;
  23. UINT g_msgSMTP;
  24. ISMTPTransport *g_pSMTP=NULL;
  25. void WaitForCompletion(UINT uiMsg, DWORD wparam);
  26. HRESULT HrParseCommandLine(LPSTR pszCmdLine, PMSGDATA pmsgData);
  27. HRESULT HrSendFile(PMSGDATA pmsgData);
  28. HRESULT HrInitSMTP(LPSTR lpszServer);
  29. HRESULT HrSendStream(LPSTREAM pstm, PMSGDATA pMsgData);
  30. HRESULT HrGetStreamSize(LPSTREAM pstm, ULONG *pcb);
  31. HRESULT HrCopyStream(LPSTREAM pstmIn, LPSTREAM pstmOut, ULONG *pcb);
  32. HRESULT HrRewindStream(LPSTREAM pstm);
  33. HRESULT HrBaseStream(LPSTREAM pstm, LPSTR lpszURL, LPSTREAM *ppstmBase);
  34. void Usage();
  35. void err(LPSTR lpsz);
  36. int CALLBACK WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPTSTR pszCmdLine, int nCmdShow)
  37. {
  38. MSGDATA msgData={0};
  39. if (FAILED(CoInitialize(NULL)))
  40. {
  41. err("OLE Init Failed");
  42. return -1;
  43. }
  44. if (FAILED(HrParseCommandLine(pszCmdLine, &msgData)))
  45. {
  46. err("Bad CmdLine");
  47. return -1;
  48. }
  49. if (FAILED(HrSendFile(&msgData)))
  50. {
  51. err("Unable to send file");
  52. return -1;
  53. }
  54. CoUninitialize();
  55. return 0;
  56. }
  57. HRESULT HrParseCommandLine(LPSTR pszCmdLine, PMSGDATA pmsgData)
  58. {
  59. LPSTR psz;
  60. BOOL fQuote=FALSE;
  61. // find first switch
  62. while(*pszCmdLine && *pszCmdLine!='/')
  63. pszCmdLine++;
  64. while (pszCmdLine && *pszCmdLine)
  65. {
  66. if (_strnicmp(pszCmdLine, "file:", 5)==0)
  67. {
  68. pszCmdLine+=5;
  69. psz = pmsgData->rgchFile;
  70. while (*pszCmdLine && (*pszCmdLine!='/' || fQuote))
  71. {
  72. if (*pszCmdLine=='"') // allow /file:"http://www.microsoft.com"
  73. fQuote = !fQuote;
  74. else
  75. *psz++ = *pszCmdLine;
  76. pszCmdLine++;
  77. }
  78. *psz =0;
  79. continue;
  80. }
  81. if (_strnicmp(pszCmdLine, "raw", 3)==0)
  82. {
  83. pmsgData->fRaw=TRUE;
  84. pszCmdLine+=3;
  85. continue;
  86. }
  87. if (_strnicmp(pszCmdLine, "B64", 3)==0)
  88. {
  89. pmsgData->fB64=TRUE;
  90. pszCmdLine+=3;
  91. continue;
  92. }
  93. if (_strnicmp(pszCmdLine, "to:", 3)==0)
  94. {
  95. pszCmdLine+=3;
  96. psz = pmsgData->rgchTo;
  97. while (*pszCmdLine && *pszCmdLine!='/')
  98. *psz++ = *pszCmdLine++;
  99. *psz =0;
  100. continue;
  101. }
  102. if (_strnicmp(pszCmdLine, "base:", 5)==0)
  103. {
  104. pszCmdLine+=5;
  105. psz = pmsgData->rgchBase;
  106. while (*pszCmdLine && (*pszCmdLine!='/' || fQuote))
  107. {
  108. if (*pszCmdLine=='"') // allow /base:"http://www.microsoft.com"
  109. fQuote = !fQuote;
  110. else
  111. *psz++ = *pszCmdLine;
  112. pszCmdLine++;
  113. }
  114. *psz =0;
  115. continue;
  116. }
  117. if (_strnicmp(pszCmdLine, "subj:", 5)==0)
  118. {
  119. pszCmdLine+=5;
  120. psz = pmsgData->rgchSubj;
  121. while (*pszCmdLine && *pszCmdLine!='/')
  122. *psz++ = *pszCmdLine++;
  123. *psz =0;
  124. continue;
  125. }
  126. if (_strnicmp(pszCmdLine, "from:", 5)==0)
  127. {
  128. pszCmdLine+=5;
  129. psz = pmsgData->rgchFrom;
  130. while (*pszCmdLine && *pszCmdLine!='/')
  131. *psz++ = *pszCmdLine++;
  132. *psz =0;
  133. continue;
  134. }
  135. if (_strnicmp(pszCmdLine, "server:", 7)==0)
  136. {
  137. pszCmdLine+=7;
  138. psz = pmsgData->rgchServer;
  139. while (*pszCmdLine && *pszCmdLine!='/')
  140. *psz++ = *pszCmdLine++;
  141. *psz =0;
  142. continue;
  143. }
  144. pszCmdLine++;
  145. }
  146. return S_OK;
  147. }
  148. HRESULT HrSendFile(PMSGDATA pmsgData)
  149. {
  150. HRESULT hr;
  151. LPMIMEMESSAGE pMsg=0;
  152. LPSTREAM pstm=0,
  153. pstmSend=0;
  154. if (*pmsgData->rgchFile==NULL || *pmsgData->rgchTo==NULL)
  155. {
  156. Usage();
  157. return E_FAIL;
  158. }
  159. /*
  160. hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER, IID_IMimeMessage, (LPVOID *)&pMsg);
  161. if (FAILED(hr))
  162. {
  163. err("Could not create IMimeMessage");
  164. goto error;
  165. }
  166. */
  167. hr = URLOpenBlockingStream(NULL, pmsgData->rgchFile, &pstm, 0, NULL);
  168. if (FAILED(hr))
  169. {
  170. err("Could not open URL");
  171. goto error;
  172. }
  173. if (pmsgData->fRaw)
  174. {
  175. pstmSend = pstm;
  176. pstm->AddRef();
  177. }
  178. else
  179. {
  180. hr = MimeOleCreateMessage(NULL, &pMsg);
  181. if (FAILED(hr))
  182. {
  183. err("Could not create IMimeMessage");
  184. goto error;
  185. }
  186. hr = pMsg->InitNew();
  187. if (FAILED(hr))
  188. goto error;
  189. if (*pmsgData->rgchSubj)
  190. MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, pmsgData->rgchSubj);
  191. MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_TO), NOFLAGS, pmsgData->rgchTo);
  192. if (pmsgData->rgchBase)
  193. {
  194. LPSTREAM pstmBase=0;
  195. if (!FAILED(hr = HrBaseStream(pstm, pmsgData->rgchBase, &pstmBase)))
  196. {
  197. pstm->Release();
  198. pstm = pstmBase;
  199. }
  200. }
  201. hr = pMsg->SetTextBody(TXT_HTML, IET_DECODED, NULL, pstm, NULL);
  202. if (FAILED(hr))
  203. goto error;
  204. if (pmsgData->fB64)
  205. {
  206. PROPVARIANT rVariant;
  207. // HTML Text body encoding
  208. rVariant.vt = VT_UI4;
  209. rVariant.ulVal = IET_BASE64;
  210. pMsg->SetOption(OID_XMIT_HTML_TEXT_ENCODING, &rVariant);
  211. }
  212. hr = pMsg->GetMessageSource(&pstmSend, TRUE);
  213. if (FAILED(hr))
  214. goto error;
  215. }
  216. hr = HrInitSMTP(pmsgData->rgchServer);
  217. if (FAILED(hr))
  218. {
  219. err("Could not connect to SMTP Server");
  220. goto error;
  221. }
  222. hr = HrSendStream(pstmSend, pmsgData);
  223. if (FAILED(hr))
  224. goto error;
  225. error:
  226. ReleaseObj(pMsg);
  227. ReleaseObj(pstm);
  228. ReleaseObj(pstmSend);
  229. return hr;
  230. }
  231. HRESULT HrInitSMTP(LPSTR lpszServer)
  232. {
  233. HRESULT hr;
  234. INETSERVER rServer={0};
  235. SMTPMESSAGE rMsg={0};
  236. g_msgSMTP = RegisterWindowMessage("SMTPTransport_Notify");
  237. if (!g_msgSMTP)
  238. {
  239. hr = E_FAIL;
  240. goto error;
  241. }
  242. // Create smtp transport
  243. hr = HrCreateSMTPTransport(&g_pSMTP);
  244. if (FAILED(hr))
  245. goto error;
  246. if (!lpszServer || !*lpszServer)
  247. lstrcpy(rServer.szServerName, "popdog"); // default to popdog
  248. else
  249. lstrcpy(rServer.szServerName, lpszServer);
  250. rServer.dwPort = 25;
  251. rServer.dwTimeout = 30;
  252. hr = g_pSMTP->Connect(&rServer, TRUE, TRUE);
  253. if (FAILED(hr))
  254. goto error;
  255. // Wait for completion
  256. WaitForCompletion(g_msgSMTP, SMTP_CONNECTED);
  257. error:
  258. return hr;
  259. }
  260. HRESULT HrSendStream(LPSTREAM pstm, PMSGDATA pMsgData)
  261. {
  262. HRESULT hr;
  263. INETADDR rAddr[2];
  264. SMTPMESSAGE rMsg={0};
  265. ULONG cb=MAX_PATH;
  266. hr = HrGetStreamSize(pstm, &rMsg.cbSize);
  267. if (FAILED(hr))
  268. goto error;
  269. rMsg.pstmMsg = pstm;
  270. rAddr[0].addrtype = ADDR_FROM;
  271. if (*pMsgData->rgchFrom==NULL) // default sender
  272. GetUserName(pMsgData->rgchFrom, &cb);
  273. lstrcpy(rAddr[0].szEmail, pMsgData->rgchFrom);
  274. rAddr[1].addrtype = ADDR_TO;
  275. lstrcpy(rAddr[1].szEmail, pMsgData->rgchTo);
  276. rMsg.rAddressList.cAddress = 2;
  277. rMsg.rAddressList.prgAddress = (LPINETADDR)&rAddr;
  278. hr = g_pSMTP->SendMessage(&rMsg);
  279. if (FAILED(hr))
  280. goto error;
  281. WaitForCompletion(g_msgSMTP, SMTP_SEND_MESSAGE);
  282. error:
  283. return hr;
  284. }
  285. void WaitForCompletion(UINT uiMsg, DWORD wparam)
  286. {
  287. MSG msg;
  288. while(GetMessage(&msg, NULL, 0, 0))
  289. {
  290. if (msg.message == uiMsg && msg.wParam == wparam || msg.wParam == IXP_DISCONNECTED)
  291. break;
  292. TranslateMessage(&msg);
  293. DispatchMessage(&msg);
  294. }
  295. }
  296. HRESULT HrGetStreamSize(LPSTREAM pstm, ULONG *pcb)
  297. {
  298. // Locals
  299. HRESULT hr=S_OK;
  300. ULARGE_INTEGER uliPos = {0,0};
  301. LARGE_INTEGER liOrigin = {0,0};
  302. // Seek
  303. hr = pstm->Seek(liOrigin, STREAM_SEEK_END, &uliPos);
  304. if (FAILED(hr))
  305. goto error;
  306. // set size
  307. *pcb = uliPos.LowPart;
  308. error:
  309. // Done
  310. return hr;
  311. }
  312. void Usage()
  313. {
  314. err("Usage:\n\r"
  315. "/TO:<recipient>\n\r"
  316. "/FILE:\"<file name or URL>\"\n\r"
  317. "[/FROM:<sender>]\n\r"
  318. "[/SUBJ:<subject>]\n\r"
  319. "[/SERVER:<SMTP server name>]\n\r"
  320. "[/BASE:<url base path>]\n\r"
  321. "[/RAW] (file points to raw rfc822 source)"
  322. "[/B64] (base64 encode)");
  323. }
  324. void err(LPSTR lpsz)
  325. {
  326. MessageBox(GetFocus(), lpsz, "SendFile", MB_OK|MB_ICONEXCLAMATION);
  327. }
  328. HRESULT HrBaseStream(LPSTREAM pstm, LPSTR lpszURL, LPSTREAM *ppstmBase)
  329. {
  330. HRESULT hr;
  331. LPSTREAM pstmBase=0;
  332. char szBase[MAX_PATH + MAX_PATH];
  333. hr = CreateStreamOnHGlobal(NULL, TRUE, &pstmBase);
  334. if (FAILED(hr))
  335. goto error;
  336. wsprintf(szBase, "<BASE HREF=\"%s\">", lpszURL);
  337. hr = pstmBase->Write(szBase, lstrlen(szBase), NULL);
  338. if (FAILED(hr))
  339. goto error;
  340. hr = HrRewindStream(pstm);
  341. if (FAILED(hr))
  342. goto error;
  343. hr = HrCopyStream(pstm, pstmBase, NULL);
  344. if (FAILED(hr))
  345. goto error;
  346. pstmBase->AddRef();
  347. *ppstmBase = pstmBase;
  348. error:
  349. ReleaseObj(pstmBase);
  350. return hr;
  351. }
  352. HRESULT HrCopyStream(LPSTREAM pstmIn, LPSTREAM pstmOut, ULONG *pcb)
  353. {
  354. // Locals
  355. HRESULT hr = S_OK;
  356. BYTE buf[4096];
  357. ULONG cbRead=0,
  358. cbTotal=0;
  359. do
  360. {
  361. hr = pstmIn->Read(buf, sizeof(buf), &cbRead);
  362. if (FAILED(hr))
  363. goto exit;
  364. if (cbRead == 0)
  365. break;
  366. hr = pstmOut->Write(buf, cbRead, NULL);
  367. if (FAILED(hr))
  368. goto exit;
  369. cbTotal += cbRead;
  370. }
  371. while (cbRead == sizeof (buf));
  372. exit:
  373. if (pcb)
  374. *pcb = cbTotal;
  375. return hr;
  376. }
  377. HRESULT HrRewindStream(LPSTREAM pstm)
  378. {
  379. LARGE_INTEGER liOrigin = {0,0};
  380. return pstm->Seek(liOrigin, STREAM_SEEK_SET, NULL);
  381. }