|
|
#include "precomp.h"
#include <stdio.h>
#include <initguid.h>
#include <wbemutil.h>
#include <cominit.h>
#include <ArrTempl.h>
#include <wbemidl.h>
#include <errorObj.h>
#include "smtp.h"
#define SMTP_PROPNAME_TO L"ToLine"
#define SMTP_PROPNAME_CC L"CcLine"
#define SMTP_PROPNAME_BCC L"BccLine"
#define SMTP_PROPNAME_SUBJECT L"Subject"
#define SMTP_PROPNAME_MESSAGE L"Message"
#define SMTP_PROPNAME_SERVER L"SMTPServer"
#define SMTP_PROPNAME_REPLYTO L"ReplyToLine"
#define SMTP_PROPNAME_FROM L"FromLine"
#define SMTP_PROPNAME_HEADERS L"HeaderFields"
DWORD SMTPSend(char* szServer, char* szTo, char* szCc, char* szBcc, char* szFrom, char* szSender, char* szReplyTo, char* szSubject, char* szHeaders, char *szText);
CSMTPConsumer::CSMTPConsumer(CLifeControl* pControl, IUnknown* pOuter) : CUnk(pControl, pOuter), m_XProvider(this) { }
CSMTPConsumer::~CSMTPConsumer() { }
// copies gazinta inta gazotta, excluding white space
// no checking - better be good little pointers
void StripWhitespace(const WCHAR* pGazinta, WCHAR* pGazotta) { WCHAR* pSource = (WCHAR*)pGazinta; WCHAR* pDest = pGazotta;
do if (!iswspace(*pSource)) *pDest++ = *pSource; while (*pSource++); }
HRESULT STDMETHODCALLTYPE CSMTPConsumer::XProvider::FindConsumer( IWbemClassObject* pLogicalConsumer, IWbemUnboundObjectSink** ppConsumer) { CSMTPSink* pSink = new CSMTPSink(m_pObject->m_pControl); if (!pSink) return WBEM_E_OUT_OF_MEMORY;
HRESULT hres = pSink->Initialize(pLogicalConsumer); if(FAILED(hres)) { delete pSink; return hres; } return pSink->QueryInterface(IID_IWbemUnboundObjectSink, (void**)ppConsumer); }
void* CSMTPConsumer::GetInterface(REFIID riid) { if(riid == IID_IWbemEventConsumerProvider) return &m_XProvider; else return NULL; }
CSMTPSink::CSMTPSink(CLifeControl* pControl) : CUnk(pControl), m_XSink(this), m_bSMTPInitialized(false), m_bFakeFromLine(false), m_pErrorObj(NULL) { }
HRESULT CSMTPSink::Initialize(IWbemClassObject* pLogicalConsumer) { HRESULT hres;
// this is actually a pointer to a static object
// if it fails, something is Very, Very Wrong.
m_pErrorObj = ErrorObj::GetErrorObj(); if (!m_pErrorObj) return WBEM_E_CRITICAL_ERROR;
WSADATA WsaData; int error = WSAStartup (0x101, &WsaData); if (error) { ERRORTRACE((LOG_ESS, "Unable to initialize WinSock dll: %X\n", error)); return WBEM_E_FAILED; } else m_bSMTPInitialized = true;
// Retrieve information from the logical consumer instance
// =======================================================
VARIANT v; VariantInit(&v);
// Get subject
// ===========
hres = pLogicalConsumer->Get(SMTP_PROPNAME_SUBJECT, 0, &v, NULL, NULL); if(V_VT(&v) == VT_BSTR) m_SubjectTemplate.SetTemplate(V_BSTR(&v)); else m_SubjectTemplate.SetTemplate(L""); VariantClear(&v);
// Get message
// ===========
hres = pLogicalConsumer->Get(SMTP_PROPNAME_MESSAGE, 0, &v, NULL, NULL);
if(V_VT(&v) == VT_BSTR) m_MessageTemplate.SetTemplate(V_BSTR(&v)); else m_MessageTemplate.SetTemplate(L""); VariantClear(&v);
// flag for 'do we have any recipients at all?'
bool bOneAddressee = false;
// Get the To line
// ===============
hres = pLogicalConsumer->Get(SMTP_PROPNAME_TO, 0, &v, NULL, NULL); if ((V_VT(&v) == VT_BSTR) && (v.bstrVal != NULL)) { m_To.SetTemplate(V_BSTR(&v)); if (wcslen(V_BSTR(&v)) > 0) bOneAddressee = true; } else m_To.SetTemplate(L""); VariantClear(&v);
// Create the fake from line for various uses
// ==========================================
m_wsFakeFromLine = L"WMI@"; pLogicalConsumer->Get(L"__SERVER", 0, &v, NULL, NULL); m_wsFakeFromLine += V_BSTR(&v);
VariantClear(&v);
// Get the From line
// =================
hres = pLogicalConsumer->Get(SMTP_PROPNAME_FROM, 0, &v, NULL, NULL); if (SUCCEEDED(hres) && (V_VT(&v) == VT_BSTR)) m_From.SetTemplate(V_BSTR(&v)); else { m_From.SetTemplate(m_wsFakeFromLine);
m_bFakeFromLine = true; } VariantClear(&v);
// Get the ReplyTo line
// =====================
hres = pLogicalConsumer->Get(SMTP_PROPNAME_REPLYTO, 0, &v, NULL, NULL); if(V_VT(&v) == VT_BSTR) m_ReplyTo.SetTemplate(V_BSTR(&v)); else m_ReplyTo.SetTemplate(L"");
VariantClear(&v);
// Get the CC line
// ===============
hres = pLogicalConsumer->Get(SMTP_PROPNAME_CC, 0, &v, NULL, NULL); if ((V_VT(&v) == VT_BSTR) && (v.bstrVal != NULL)) { m_Cc.SetTemplate( V_BSTR(&v)); if (wcslen(V_BSTR(&v)) > 0) bOneAddressee = true; } else m_Cc.SetTemplate(L"");
VariantClear(&v);
// Get the BCC line
// ===============
hres = pLogicalConsumer->Get(SMTP_PROPNAME_BCC, 0, &v, NULL, NULL); if ((V_VT(&v) == VT_BSTR) && (v.bstrVal != NULL)) { m_Bcc.SetTemplate(V_BSTR(&v)); if (wcslen(V_BSTR(&v)) > 0) bOneAddressee = true; } else m_Bcc.SetTemplate(L""); VariantClear(&v);
// okay, at least ONE should be filled in...
if (!bOneAddressee) { ERRORTRACE((LOG_ESS, "SMTP: No addressees found, no mail delivered\n")); return WBEM_E_INVALID_PARAMETER; }
// Get the server
// ===============
hres = pLogicalConsumer->Get(SMTP_PROPNAME_SERVER, 0, &v, NULL, NULL); if(V_VT(&v) == VT_BSTR) m_wsServer = V_BSTR(&v); VariantClear(&v);
// and any extra header fields
hres = pLogicalConsumer->Get(SMTP_PROPNAME_HEADERS, 0, &v, NULL, NULL); if ((V_VT(&v) & VT_BSTR) && (V_VT(&v) & VT_ARRAY)) { long lBound;
SafeArrayGetUBound(v.parray, 1, &lBound); for (long i = 0; i <= lBound; i++) { BSTR pStr = NULL; if ( SUCCEEDED(SafeArrayGetElement(v.parray, &i, &pStr)) ) { if ( pStr != NULL ) { m_wsHeaders += pStr; SysFreeString( pStr ); } } else { VariantClear(&v); return WBEM_E_OUT_OF_MEMORY; }
if (i != lBound) m_wsHeaders += L"\r\n"; } } VariantClear(&v);
return WBEM_S_NO_ERROR; }
CSMTPSink::~CSMTPSink() { if (m_bSMTPInitialized) { if (SOCKET_ERROR == WSACleanup()) ERRORTRACE((LOG_ESS, "WSACleanup failed, 0x%X\n", WSAGetLastError())); } if (m_pErrorObj) m_pErrorObj->Release(); }
// allocates buffer, strips whitespace if asked
// scrunches wide string down to MBCS
// callers responsibility to delete return pointer
// returns NULL on allocation failure
// if bHammerSemiColons, the semi colons shall be replaced by commas
char* CSMTPSink::PreProcessLine(WCHAR* line, bool bStripWhitespace, bool bHammerSemiColons) { char *pNewLine = NULL; WCHAR *pSource = NULL; WCHAR *pStripBuf = NULL;
if (line == NULL) return NULL;
if (bStripWhitespace && (pStripBuf = new WCHAR[wcslen(line) +1])) { StripWhitespace(line, pStripBuf); pSource = pStripBuf; } else pSource = line; if (pSource && (pNewLine = new char[2*wcslen(pSource) +1])) { sprintf(pNewLine, "%S", pSource); if (bHammerSemiColons) { char* pSemiColon; while (pSemiColon = strchr(pNewLine, ';')) *pSemiColon = ','; } }
if (pStripBuf) delete[] pStripBuf;
return pNewLine; }
HRESULT STDMETHODCALLTYPE CSMTPSink::XSink::IndicateToConsumer( IWbemClassObject* pLogicalConsumer, long lNumObjects, IWbemClassObject** apObjects) { // HRESULT hres;
for(long i = 0; i < lNumObjects; i++) {
// TODO: Lots of duplicated code, here - fix.
// VARIANT v;
BSTR str;
// Obtain customized versions of the subject and the message
// stripping white space as we go...
// =========================================================
// TO
str = m_pObject->m_To.Apply(apObjects[i]); if (!str) return WBEM_E_OUT_OF_MEMORY; char* szTo; szTo = m_pObject->PreProcessLine(str, true, true); SysFreeString(str); if (!szTo) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delTo(szTo); // CC
char* szCc; str = m_pObject->m_Cc.Apply(apObjects[i]); if (!str) return WBEM_E_OUT_OF_MEMORY; szCc = m_pObject->PreProcessLine(str, true, true); SysFreeString(str); if (!szCc) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delCc(szCc);
// BCC
char* szBcc; str = m_pObject->m_Bcc.Apply(apObjects[i]); if (!str) return WBEM_E_OUT_OF_MEMORY; szBcc = m_pObject->PreProcessLine(str, true, true); SysFreeString(str); if (!szBcc) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delBcc(szBcc);
// FROM
char* szFrom; str = m_pObject->m_From.Apply(apObjects[i]); if (!str) return WBEM_E_OUT_OF_MEMORY; szFrom = m_pObject->PreProcessLine(str, false, false); SysFreeString(str); if (!szFrom) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delFrom(szFrom);
//SENDER
char* szSender; szSender = m_pObject->PreProcessLine(m_pObject->m_wsFakeFromLine, false, false); if (!szSender) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delSender(szSender);
// Reply To
char* szReplyTo; str = m_pObject->m_ReplyTo.Apply(apObjects[i]); if (!str) return WBEM_E_OUT_OF_MEMORY; szReplyTo = m_pObject->PreProcessLine(str, true, true); SysFreeString(str); if (!szReplyTo) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delReplyTo(szReplyTo); // SERVER
char* szServer; szServer = m_pObject->PreProcessLine(m_pObject->m_wsServer, false, false); if (!szServer) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delServer(szServer);
// SUBJECT
str = m_pObject->m_SubjectTemplate.Apply(apObjects[i]); char* szSubject; szSubject = m_pObject->PreProcessLine(str, false, false); SysFreeString(str); if (!szSubject) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delSubject(szSubject);
// MESSAGE TEXT
str = m_pObject->m_MessageTemplate.Apply(apObjects[i]); char* szText; szText = m_pObject->PreProcessLine(str, false, false); SysFreeString(str); if (!szText) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delText(szText);
// extra added header entries
char* szHeaders; szHeaders = m_pObject->PreProcessLine(m_pObject->m_wsHeaders, false, false); if (!szHeaders) return WBEM_E_OUT_OF_MEMORY; CDeleteMe<char> delHeaders(szHeaders);
// djinn up a reply-to line
// if we haven't been given one explicitly AND we haven't faked one up,
// we'll use the from line.
char* szReplyToReally; if ((strlen(szReplyTo) == 0) && !m_pObject->m_bFakeFromLine) szReplyToReally = szFrom; else szReplyToReally = szReplyTo;
// DO IT TO IT
DWORD dwRes = SMTPSend(szServer, szTo, szCc, szBcc, szFrom, szSender, szReplyToReally, szSubject, szHeaders, szText); if(dwRes) { ERRORTRACE((LOG_ESS, "Unable to send message: 0x%X\n", dwRes)); return WBEM_E_FAILED; } }
return WBEM_S_NO_ERROR; }
void* CSMTPSink::GetInterface(REFIID riid) { if(riid == IID_IWbemUnboundObjectSink) return &m_XSink; else return NULL; }
|