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.

447 lines
12 KiB

  1. #include "precomp.h"
  2. #include <stdio.h>
  3. #include <initguid.h>
  4. #include <wbemutil.h>
  5. #include <cominit.h>
  6. #include <ArrTempl.h>
  7. #include <wbemidl.h>
  8. #include <errorObj.h>
  9. #include "smtp.h"
  10. #define SMTP_PROPNAME_TO L"ToLine"
  11. #define SMTP_PROPNAME_CC L"CcLine"
  12. #define SMTP_PROPNAME_BCC L"BccLine"
  13. #define SMTP_PROPNAME_SUBJECT L"Subject"
  14. #define SMTP_PROPNAME_MESSAGE L"Message"
  15. #define SMTP_PROPNAME_SERVER L"SMTPServer"
  16. #define SMTP_PROPNAME_REPLYTO L"ReplyToLine"
  17. #define SMTP_PROPNAME_FROM L"FromLine"
  18. #define SMTP_PROPNAME_HEADERS L"HeaderFields"
  19. DWORD SMTPSend(char* szServer, char* szTo, char* szCc, char* szBcc, char* szFrom, char* szSender,
  20. char* szReplyTo, char* szSubject, char* szHeaders, char *szText);
  21. CSMTPConsumer::CSMTPConsumer(CLifeControl* pControl, IUnknown* pOuter)
  22. : CUnk(pControl, pOuter), m_XProvider(this)
  23. {
  24. }
  25. CSMTPConsumer::~CSMTPConsumer()
  26. {
  27. }
  28. // copies gazinta inta gazotta, excluding white space
  29. // no checking - better be good little pointers
  30. void StripWhitespace(const WCHAR* pGazinta, WCHAR* pGazotta)
  31. {
  32. WCHAR* pSource = (WCHAR*)pGazinta;
  33. WCHAR* pDest = pGazotta;
  34. do
  35. if (!iswspace(*pSource))
  36. *pDest++ = *pSource;
  37. while (*pSource++);
  38. }
  39. HRESULT STDMETHODCALLTYPE CSMTPConsumer::XProvider::FindConsumer(
  40. IWbemClassObject* pLogicalConsumer,
  41. IWbemUnboundObjectSink** ppConsumer)
  42. {
  43. CSMTPSink* pSink = new CSMTPSink(m_pObject->m_pControl);
  44. if (!pSink)
  45. return WBEM_E_OUT_OF_MEMORY;
  46. HRESULT hres = pSink->Initialize(pLogicalConsumer);
  47. if(FAILED(hres))
  48. {
  49. delete pSink;
  50. return hres;
  51. }
  52. return pSink->QueryInterface(IID_IWbemUnboundObjectSink,
  53. (void**)ppConsumer);
  54. }
  55. void* CSMTPConsumer::GetInterface(REFIID riid)
  56. {
  57. if(riid == IID_IWbemEventConsumerProvider)
  58. return &m_XProvider;
  59. else
  60. return NULL;
  61. }
  62. CSMTPSink::CSMTPSink(CLifeControl* pControl)
  63. : CUnk(pControl), m_XSink(this), m_bSMTPInitialized(false), m_bFakeFromLine(false), m_pErrorObj(NULL)
  64. {
  65. }
  66. HRESULT CSMTPSink::Initialize(IWbemClassObject* pLogicalConsumer)
  67. {
  68. HRESULT hres;
  69. // this is actually a pointer to a static object
  70. // if it fails, something is Very, Very Wrong.
  71. m_pErrorObj = ErrorObj::GetErrorObj();
  72. if (!m_pErrorObj)
  73. return WBEM_E_CRITICAL_ERROR;
  74. WSADATA WsaData;
  75. int error = WSAStartup (0x101, &WsaData);
  76. if (error)
  77. {
  78. ERRORTRACE((LOG_ESS, "Unable to initialize WinSock dll: %X\n", error));
  79. return WBEM_E_FAILED;
  80. }
  81. else
  82. m_bSMTPInitialized = true;
  83. // Retrieve information from the logical consumer instance
  84. // =======================================================
  85. VARIANT v;
  86. VariantInit(&v);
  87. // Get subject
  88. // ===========
  89. hres = pLogicalConsumer->Get(SMTP_PROPNAME_SUBJECT, 0, &v, NULL, NULL);
  90. if(V_VT(&v) == VT_BSTR)
  91. m_SubjectTemplate.SetTemplate(V_BSTR(&v));
  92. else
  93. m_SubjectTemplate.SetTemplate(L"");
  94. VariantClear(&v);
  95. // Get message
  96. // ===========
  97. hres = pLogicalConsumer->Get(SMTP_PROPNAME_MESSAGE, 0, &v, NULL, NULL);
  98. if(V_VT(&v) == VT_BSTR)
  99. m_MessageTemplate.SetTemplate(V_BSTR(&v));
  100. else
  101. m_MessageTemplate.SetTemplate(L"");
  102. VariantClear(&v);
  103. // flag for 'do we have any recipients at all?'
  104. bool bOneAddressee = false;
  105. // Get the To line
  106. // ===============
  107. hres = pLogicalConsumer->Get(SMTP_PROPNAME_TO, 0, &v, NULL, NULL);
  108. if ((V_VT(&v) == VT_BSTR) && (v.bstrVal != NULL))
  109. {
  110. m_To.SetTemplate(V_BSTR(&v));
  111. if (wcslen(V_BSTR(&v)) > 0)
  112. bOneAddressee = true;
  113. }
  114. else
  115. m_To.SetTemplate(L"");
  116. VariantClear(&v);
  117. // Create the fake from line for various uses
  118. // ==========================================
  119. m_wsFakeFromLine = L"WMI@";
  120. pLogicalConsumer->Get(L"__SERVER", 0, &v, NULL, NULL);
  121. m_wsFakeFromLine += V_BSTR(&v);
  122. VariantClear(&v);
  123. // Get the From line
  124. // =================
  125. hres = pLogicalConsumer->Get(SMTP_PROPNAME_FROM, 0, &v, NULL, NULL);
  126. if (SUCCEEDED(hres) && (V_VT(&v) == VT_BSTR))
  127. m_From.SetTemplate(V_BSTR(&v));
  128. else
  129. {
  130. m_From.SetTemplate(m_wsFakeFromLine);
  131. m_bFakeFromLine = true;
  132. }
  133. VariantClear(&v);
  134. // Get the ReplyTo line
  135. // =====================
  136. hres = pLogicalConsumer->Get(SMTP_PROPNAME_REPLYTO, 0, &v, NULL, NULL);
  137. if(V_VT(&v) == VT_BSTR)
  138. m_ReplyTo.SetTemplate(V_BSTR(&v));
  139. else
  140. m_ReplyTo.SetTemplate(L"");
  141. VariantClear(&v);
  142. // Get the CC line
  143. // ===============
  144. hres = pLogicalConsumer->Get(SMTP_PROPNAME_CC, 0, &v, NULL, NULL);
  145. if ((V_VT(&v) == VT_BSTR) && (v.bstrVal != NULL))
  146. {
  147. m_Cc.SetTemplate( V_BSTR(&v));
  148. if (wcslen(V_BSTR(&v)) > 0)
  149. bOneAddressee = true;
  150. }
  151. else
  152. m_Cc.SetTemplate(L"");
  153. VariantClear(&v);
  154. // Get the BCC line
  155. // ===============
  156. hres = pLogicalConsumer->Get(SMTP_PROPNAME_BCC, 0, &v, NULL, NULL);
  157. if ((V_VT(&v) == VT_BSTR) && (v.bstrVal != NULL))
  158. {
  159. m_Bcc.SetTemplate(V_BSTR(&v));
  160. if (wcslen(V_BSTR(&v)) > 0)
  161. bOneAddressee = true;
  162. }
  163. else
  164. m_Bcc.SetTemplate(L"");
  165. VariantClear(&v);
  166. // okay, at least ONE should be filled in...
  167. if (!bOneAddressee)
  168. {
  169. ERRORTRACE((LOG_ESS, "SMTP: No addressees found, no mail delivered\n"));
  170. return WBEM_E_INVALID_PARAMETER;
  171. }
  172. // Get the server
  173. // ===============
  174. hres = pLogicalConsumer->Get(SMTP_PROPNAME_SERVER, 0, &v, NULL, NULL);
  175. if(V_VT(&v) == VT_BSTR)
  176. m_wsServer = V_BSTR(&v);
  177. VariantClear(&v);
  178. // and any extra header fields
  179. hres = pLogicalConsumer->Get(SMTP_PROPNAME_HEADERS, 0, &v, NULL, NULL);
  180. if ((V_VT(&v) & VT_BSTR) && (V_VT(&v) & VT_ARRAY))
  181. {
  182. long lBound;
  183. SafeArrayGetUBound(v.parray, 1, &lBound);
  184. for (long i = 0; i <= lBound; i++)
  185. {
  186. BSTR pStr = NULL;
  187. if ( SUCCEEDED(SafeArrayGetElement(v.parray, &i, &pStr)) )
  188. {
  189. if ( pStr != NULL )
  190. {
  191. m_wsHeaders += pStr;
  192. SysFreeString( pStr );
  193. }
  194. }
  195. else
  196. {
  197. VariantClear(&v);
  198. return WBEM_E_OUT_OF_MEMORY;
  199. }
  200. if (i != lBound)
  201. m_wsHeaders += L"\r\n";
  202. }
  203. }
  204. VariantClear(&v);
  205. return WBEM_S_NO_ERROR;
  206. }
  207. CSMTPSink::~CSMTPSink()
  208. {
  209. if (m_bSMTPInitialized)
  210. {
  211. if (SOCKET_ERROR == WSACleanup())
  212. ERRORTRACE((LOG_ESS, "WSACleanup failed, 0x%X\n", WSAGetLastError()));
  213. }
  214. if (m_pErrorObj)
  215. m_pErrorObj->Release();
  216. }
  217. // allocates buffer, strips whitespace if asked
  218. // scrunches wide string down to MBCS
  219. // callers responsibility to delete return pointer
  220. // returns NULL on allocation failure
  221. // if bHammerSemiColons, the semi colons shall be replaced by commas
  222. char* CSMTPSink::PreProcessLine(WCHAR* line, bool bStripWhitespace, bool bHammerSemiColons)
  223. {
  224. char *pNewLine = NULL;
  225. WCHAR *pSource = NULL;
  226. WCHAR *pStripBuf = NULL;
  227. if (line == NULL)
  228. return NULL;
  229. if (bStripWhitespace && (pStripBuf = new WCHAR[wcslen(line) +1]))
  230. {
  231. StripWhitespace(line, pStripBuf);
  232. pSource = pStripBuf;
  233. }
  234. else
  235. pSource = line;
  236. if (pSource && (pNewLine = new char[2*wcslen(pSource) +1]))
  237. {
  238. sprintf(pNewLine, "%S", pSource);
  239. if (bHammerSemiColons)
  240. {
  241. char* pSemiColon;
  242. while (pSemiColon = strchr(pNewLine, ';'))
  243. *pSemiColon = ',';
  244. }
  245. }
  246. if (pStripBuf)
  247. delete[] pStripBuf;
  248. return pNewLine;
  249. }
  250. HRESULT STDMETHODCALLTYPE CSMTPSink::XSink::IndicateToConsumer(
  251. IWbemClassObject* pLogicalConsumer, long lNumObjects,
  252. IWbemClassObject** apObjects)
  253. {
  254. // HRESULT hres;
  255. for(long i = 0; i < lNumObjects; i++)
  256. {
  257. // TODO: Lots of duplicated code, here - fix.
  258. // VARIANT v;
  259. BSTR str;
  260. // Obtain customized versions of the subject and the message
  261. // stripping white space as we go...
  262. // =========================================================
  263. // TO
  264. str = m_pObject->m_To.Apply(apObjects[i]);
  265. if (!str)
  266. return WBEM_E_OUT_OF_MEMORY;
  267. char* szTo;
  268. szTo = m_pObject->PreProcessLine(str, true, true);
  269. SysFreeString(str);
  270. if (!szTo)
  271. return WBEM_E_OUT_OF_MEMORY;
  272. CDeleteMe<char> delTo(szTo);
  273. // CC
  274. char* szCc;
  275. str = m_pObject->m_Cc.Apply(apObjects[i]);
  276. if (!str)
  277. return WBEM_E_OUT_OF_MEMORY;
  278. szCc = m_pObject->PreProcessLine(str, true, true);
  279. SysFreeString(str);
  280. if (!szCc)
  281. return WBEM_E_OUT_OF_MEMORY;
  282. CDeleteMe<char> delCc(szCc);
  283. // BCC
  284. char* szBcc;
  285. str = m_pObject->m_Bcc.Apply(apObjects[i]);
  286. if (!str)
  287. return WBEM_E_OUT_OF_MEMORY;
  288. szBcc = m_pObject->PreProcessLine(str, true, true);
  289. SysFreeString(str);
  290. if (!szBcc)
  291. return WBEM_E_OUT_OF_MEMORY;
  292. CDeleteMe<char> delBcc(szBcc);
  293. // FROM
  294. char* szFrom;
  295. str = m_pObject->m_From.Apply(apObjects[i]);
  296. if (!str)
  297. return WBEM_E_OUT_OF_MEMORY;
  298. szFrom = m_pObject->PreProcessLine(str, false, false);
  299. SysFreeString(str);
  300. if (!szFrom)
  301. return WBEM_E_OUT_OF_MEMORY;
  302. CDeleteMe<char> delFrom(szFrom);
  303. //SENDER
  304. char* szSender;
  305. szSender = m_pObject->PreProcessLine(m_pObject->m_wsFakeFromLine, false, false);
  306. if (!szSender)
  307. return WBEM_E_OUT_OF_MEMORY;
  308. CDeleteMe<char> delSender(szSender);
  309. // Reply To
  310. char* szReplyTo;
  311. str = m_pObject->m_ReplyTo.Apply(apObjects[i]);
  312. if (!str)
  313. return WBEM_E_OUT_OF_MEMORY;
  314. szReplyTo = m_pObject->PreProcessLine(str, true, true);
  315. SysFreeString(str);
  316. if (!szReplyTo)
  317. return WBEM_E_OUT_OF_MEMORY;
  318. CDeleteMe<char> delReplyTo(szReplyTo);
  319. // SERVER
  320. char* szServer;
  321. szServer = m_pObject->PreProcessLine(m_pObject->m_wsServer, false, false);
  322. if (!szServer)
  323. return WBEM_E_OUT_OF_MEMORY;
  324. CDeleteMe<char> delServer(szServer);
  325. // SUBJECT
  326. str = m_pObject->m_SubjectTemplate.Apply(apObjects[i]);
  327. char* szSubject;
  328. szSubject = m_pObject->PreProcessLine(str, false, false);
  329. SysFreeString(str);
  330. if (!szSubject)
  331. return WBEM_E_OUT_OF_MEMORY;
  332. CDeleteMe<char> delSubject(szSubject);
  333. // MESSAGE TEXT
  334. str = m_pObject->m_MessageTemplate.Apply(apObjects[i]);
  335. char* szText;
  336. szText = m_pObject->PreProcessLine(str, false, false);
  337. SysFreeString(str);
  338. if (!szText)
  339. return WBEM_E_OUT_OF_MEMORY;
  340. CDeleteMe<char> delText(szText);
  341. // extra added header entries
  342. char* szHeaders;
  343. szHeaders = m_pObject->PreProcessLine(m_pObject->m_wsHeaders, false, false);
  344. if (!szHeaders)
  345. return WBEM_E_OUT_OF_MEMORY;
  346. CDeleteMe<char> delHeaders(szHeaders);
  347. // djinn up a reply-to line
  348. // if we haven't been given one explicitly AND we haven't faked one up,
  349. // we'll use the from line.
  350. char* szReplyToReally;
  351. if ((strlen(szReplyTo) == 0) && !m_pObject->m_bFakeFromLine)
  352. szReplyToReally = szFrom;
  353. else
  354. szReplyToReally = szReplyTo;
  355. // DO IT TO IT
  356. DWORD dwRes = SMTPSend(szServer, szTo, szCc, szBcc, szFrom, szSender, szReplyToReally, szSubject, szHeaders, szText);
  357. if(dwRes)
  358. {
  359. ERRORTRACE((LOG_ESS, "Unable to send message: 0x%X\n", dwRes));
  360. return WBEM_E_FAILED;
  361. }
  362. }
  363. return WBEM_S_NO_ERROR;
  364. }
  365. void* CSMTPSink::GetInterface(REFIID riid)
  366. {
  367. if(riid == IID_IWbemUnboundObjectSink)
  368. return &m_XSink;
  369. else
  370. return NULL;
  371. }