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

#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;
}