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.
 
 
 
 
 
 

455 lines
14 KiB

/*
* h t t p u t i l. c p p
*
* Author: Greg Friedman
*
* Purpose: Utility functions used to implement http mail.
*
* Copyright (C) Microsoft Corp. 1998.
*/
#include "pch.hxx"
#include "httputil.h"
#include "xpcomm.h"
#include "iso8601.h"
#include "storutil.h"
#include "flagconv.h"
#include "demand.h"
//----------------------------------------------------------------------
// Http_FreeTargetList
//----------------------------------------------------------------------
void Http_FreeTargetList(LPHTTPTARGETLIST pTargets)
{
if (pTargets)
{
if (pTargets->prgTarget)
{
for (DWORD dw = 0; dw < pTargets->cTarget; dw++)
{
if (pTargets->prgTarget[dw])
MemFree(const_cast<char *>(pTargets->prgTarget[dw]));
}
MemFree(pTargets->prgTarget);
}
MemFree(pTargets);
}
}
//----------------------------------------------------------------------
// Http_NameFromUrl
//----------------------------------------------------------------------
HRESULT Http_NameFromUrl(LPCSTR pszUrl, LPSTR pszBuffer, DWORD *pdwBufferLen)
{
HRESULT hr = S_OK;
char szLocalBuf[MAX_PATH];
URL_COMPONENTS urlComponents;
DWORD dw = 0;
ZeroMemory(&urlComponents, sizeof(URL_COMPONENTS));
// use wininet to break the path out and to decode the url while
// we're at it.
urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
urlComponents.lpszUrlPath = szLocalBuf;
urlComponents.dwUrlPathLength = MAX_PATH;
if (!InternetCrackUrl(pszUrl, lstrlen(pszUrl), NOFLAGS /* ICU_DECODE */, &urlComponents))
{
hr = GetLastError();
goto exit;
}
// subtract one to start at the char before the last one. this skips
// the last char in the case of a folder that ends in '/'
dw = urlComponents.dwUrlPathLength - 1;
while (dw && ('/' != szLocalBuf[dw - 1]))
dw--;
// dw represents the count of chars that are NOT in the
// name. reverse it.
dw = urlComponents.dwUrlPathLength - dw;
if (dw >= *pdwBufferLen)
{
hr = E_OUTOFMEMORY;
goto exit;
}
CopyMemory(pszBuffer, &szLocalBuf[urlComponents.dwUrlPathLength - dw], dw + 1);
*pdwBufferLen = dw;
exit:
return hr;
}
//----------------------------------------------------------------------
// Http_AddMessageToFolder
//----------------------------------------------------------------------
HRESULT Http_AddMessageToFolder(IMessageFolder *pFolder,
LPSTR pszAcctId,
LPHTTPMEMBERINFO pmi,
MESSAGEFLAGS dwFlags,
LPSTR pszUrl,
LPMESSAGEID pidMessage)
{
HRESULT hr = S_OK;
MESSAGEINFO mi;
FILETIME ft;
DWORD dwTimeFlags = NOFLAGS;
LPSTR pszFreeFrom = NULL;
LPSTR pszFreeTo = NULL;
ADDRESSLIST addrList;
char szUrlComponent[MAX_PATH];
DWORD dwUrlComponentLen = MAX_PATH;
PROPVARIANT rDecodedSubj;
PROPVARIANT rDecodedFrom;
PROPVARIANT rDecodedTo;
LPSTR pszSubject = NULL;
if (NULL == pszUrl)
return E_INVALIDARG;
ZeroMemory(&mi, sizeof(MESSAGEINFO));
rDecodedSubj.vt = rDecodedFrom.vt = rDecodedTo.vt = VT_LPSTR;
rDecodedSubj.pszVal = rDecodedFrom.pszVal = rDecodedTo.pszVal = NULL;
// build a message info and pump the header into the store
mi.pszAcctId = pszAcctId;
// get the store to generate an id
if (FAILED(hr = pFolder->GenerateId((DWORD *)&mi.idMessage)))
goto exit;
if (NULL != pidMessage)
*pidMessage = mi.idMessage;
if (FAILED(hr = Http_NameFromUrl(pszUrl, szUrlComponent, &dwUrlComponentLen)))
goto exit;
mi.dwFlags |= dwFlags;
// if a message info was passed in, use its data
if (NULL != pmi)
{
mi.cbMessage = pmi->dwContentLength;
if (pmi->fRead)
mi.dwFlags = ARF_READ;
if (pmi->fHasAttachment)
mi.dwFlags |= ARF_HASATTACH;
if (NULL != pmi->pszSubject)
{
if (SUCCEEDED(MimeOleDecodeHeader(NULL, pmi->pszSubject, &rDecodedSubj, NULL)))
pszSubject = rDecodedSubj.pszVal;
else
pszSubject = pmi->pszSubject;
mi.pszSubject = pszSubject;
mi.pszNormalSubj = SzNormalizeSubject(pszSubject);
if (NULL == mi.pszNormalSubj)
mi.pszNormalSubj = pszSubject;
}
if (pmi->pszFrom && S_OK == MimeOleParseRfc822Address(IAT_FROM, IET_ENCODED, pmi->pszFrom, &addrList))
{
if (addrList.cAdrs > 0)
{
pszFreeFrom = addrList.prgAdr[0].pszFriendly;
addrList.prgAdr[0].pszFriendly = NULL;
// only use the parsed address if it is at least three chars long
if (pszFreeFrom && lstrlen(pszFreeFrom) >= 3)
mi.pszDisplayFrom = pszFreeFrom;
}
g_pMoleAlloc->FreeAddressList(&addrList);
}
if (NULL == mi.pszDisplayFrom && NULL != pmi->pszFrom)
{
if (SUCCEEDED(MimeOleDecodeHeader(NULL, pmi->pszFrom, &rDecodedFrom, NULL)))
mi.pszDisplayFrom = rDecodedFrom.pszVal;
else
mi.pszDisplayFrom = pmi->pszFrom;
}
if (SUCCEEDED(iso8601::toFileTime(pmi->pszDate, &ft, &dwTimeFlags)))
{
if (!(dwTimeFlags & ISO8601_ST_HOUR))
mi.dwFlags |= ARF_PARTIAL_RECVTIME;
mi.ftReceived = ft;
}
if (pmi->pszTo && S_OK == MimeOleParseRfc822Address(IAT_TO, IET_ENCODED, pmi->pszTo, &addrList))
{
if (addrList.cAdrs > 0)
{
pszFreeTo = addrList.prgAdr[0].pszFriendly;
addrList.prgAdr[0].pszFriendly = NULL;
// only use the parsed address if it is at least three chars long
if (pszFreeTo && lstrlen(pszFreeTo) >= 3)
mi.pszDisplayTo = pszFreeTo;
}
g_pMoleAlloc->FreeAddressList(&addrList);
}
if (NULL == mi.pszDisplayTo && NULL != pmi->pszTo)
{
if (SUCCEEDED(MimeOleDecodeHeader(NULL, pmi->pszTo, &rDecodedTo, NULL)))
mi.pszDisplayTo = rDecodedTo.pszVal;
else
mi.pszDisplayTo = pmi->pszTo;
}
}
mi.pszUrlComponent = szUrlComponent;
// Add it to the database
IF_FAILEXIT(hr = pFolder->InsertRecord(&mi));
// normalize the response
hr = S_OK;
exit:
SafeMimeOleFree(rDecodedSubj.pszVal);
SafeMimeOleFree(rDecodedFrom.pszVal);
SafeMimeOleFree(rDecodedTo.pszVal);
SafeMemFree(pszFreeFrom);
SafeMemFree(pszFreeTo);
return hr;
}
//----------------------------------------------------------------------
// Http_SetMessageStream
//----------------------------------------------------------------------
HRESULT Http_SetMessageStream(IMessageFolder *pFolder,
MESSAGEID idMessage,
IStream *pStream,
LPFILEADDRESS pfa,
BOOL fSetDisplayProps)
{
HRESULT hr = S_OK;
IMimeMessage *pMimeMsg = NULL;
IMimePropertySet *pPropertySet = NULL;
DWORD dwFlags = 0;
MESSAGEINFO mi = {0};
LPMESSAGEINFO pmiFree = NULL;
FILETIME ftCurrent;
PROPVARIANT rVariant;
IMimeAddressTable *pAdrTable = NULL;
ADDRESSPROPS rAddress = {0};
LPSTR pszDisplayFrom = NULL;
LPSTR pszEmailFrom = NULL;
LPSTR pszDisplayTo = NULL;
LPSTR pszEmailTo = NULL;
LPSTR pszMessageId = NULL;
LPSTR pszXref = NULL;
LPSTR pszReferences = NULL;
LPSTR pszSubject = NULL;
LPSTR pszNormalSubj = NULL;
LPSTR pszAcctId = NULL;
LPSTR pszAcctName = NULL;
LPSTR pszServer = NULL;
LPSTR pszForwardTo = NULL;
LPSTR pszMSOESRec = NULL;
// Default Sent and Received Times...
GetSystemTimeAsFileTime(&ftCurrent);
// Create a Message. We can't use the folder's OpenMessage
// method, because the folder's stream will be locked for write
// access.
IF_FAILEXIT(hr = MimeOleCreateMessage(NULL, &pMimeMsg));
IF_FAILEXIT(hr = HrRewindStream(pStream));
IF_FAILEXIT(hr = pMimeMsg->Load(pStream));
// Get the Root Property Set from the Message
IF_FAILEXIT(hr = pMimeMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pPropertySet));
// find the message in the store
IF_FAILEXIT(hr = GetMessageInfo(pFolder, idMessage, &mi));
pmiFree = &mi;
// update the fields of the message info
if (SUCCEEDED(pMimeMsg->GetFlags(&dwFlags)))
mi.dwFlags |= ConvertIMFFlagsToARF(dwFlags);
// unset the download flag
mi.dwFlags &= ~ARF_DOWNLOAD;
// Set Variant tyStore
rVariant.vt = VT_UI4;
// Priority
if (SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &rVariant)))
mi.wPriority = (WORD)rVariant.ulVal;
// Init Variant
rVariant.vt = VT_FILETIME;
if (0 == mi.ftSent.dwLowDateTime && 0 == mi.ftSent.dwHighDateTime)
{
if (SUCCEEDED(pMimeMsg->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &rVariant)))
mi.ftSent = rVariant.filetime;
else
mi.ftSent = ftCurrent;
}
if (0 == mi.ftReceived.dwLowDateTime && 0 == mi.ftReceived.dwHighDateTime)
{
if (SUCCEEDED(pMimeMsg->GetProp(PIDTOSTR(PID_ATT_RECVTIME), 0, &rVariant)))
mi.ftReceived = rVariant.filetime;
else
mi.ftReceived = ftCurrent;
}
// Get Address Table
IF_FAILEXIT(hr = pPropertySet->BindToObject(IID_IMimeAddressTable, (LPVOID *)&pAdrTable));
// Display From
if (fSetDisplayProps && NULL == mi.pszDisplayFrom)
{
pAdrTable->GetFormat(IAT_FROM, AFT_DISPLAY_FRIENDLY, &pszDisplayFrom);
mi.pszDisplayFrom = pszDisplayFrom;
}
// Email From
rAddress.dwProps = IAP_EMAIL;
if (NULL == mi.pszEmailFrom && SUCCEEDED(pAdrTable->GetSender(&rAddress)))
{
pszEmailFrom = rAddress.pszEmail;
mi.pszEmailFrom = pszEmailFrom;
}
// Display to
if (fSetDisplayProps && NULL == mi.pszDisplayTo)
{
pAdrTable->GetFormat(IAT_TO, AFT_DISPLAY_FRIENDLY, &pszDisplayTo);
mi.pszDisplayTo = pszDisplayTo;
}
// Email To
if (NULL == mi.pszEmailTo)
{
pAdrTable->GetFormat(IAT_TO, AFT_DISPLAY_EMAIL, &pszEmailTo);
mi.pszEmailTo = pszEmailTo;
}
// String properties
rVariant.vt = VT_LPSTR;
// pszMessageId
if (NULL == mi.pszMessageId && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &rVariant)))
{
pszMessageId = rVariant.pszVal;
mi.pszMessageId = pszMessageId;
}
// pszXref
if (NULL == mi.pszXref && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_XREF), NOFLAGS, &rVariant)))
{
pszXref = rVariant.pszVal;
mi.pszXref = pszXref;
}
// pszReferences
if (NULL == mi.pszReferences && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(STR_HDR_REFS), NOFLAGS, &rVariant)))
{
pszReferences = rVariant.pszVal;
mi.pszReferences = pszReferences;
}
// pszSubject
if (NULL == mi.pszSubject && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &rVariant)))
{
pszSubject = rVariant.pszVal;
mi.pszSubject = pszSubject;
}
// pszNormalSubj
if (fSetDisplayProps && NULL == mi.pszNormalSubj && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_NORMSUBJ), NOFLAGS, &rVariant)))
{
pszNormalSubj = rVariant.pszVal;
mi.pszNormalSubj = pszNormalSubj;
}
// pszAcctId
if (NULL == mi.pszAcctId && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &rVariant)))
{
pszAcctId = rVariant.pszVal;
mi.pszAcctId = pszAcctId;
}
// pszAcctName
if (NULL == mi.pszAcctName && SUCCEEDED(pPropertySet->GetProp(STR_ATT_ACCOUNTNAME, NOFLAGS, &rVariant)))
{
pszAcctName = rVariant.pszVal;
mi.pszAcctName = pszAcctName;
}
// pszServer
if (NULL == mi.pszServer && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_SERVER), NOFLAGS, &rVariant)))
{
pszServer = rVariant.pszVal;
mi.pszServer = pszServer;
}
// ForwardTo
if (NULL == mi.pszForwardTo && SUCCEEDED(pPropertySet->GetProp(PIDTOSTR(PID_ATT_FORWARDTO), NOFLAGS, &rVariant)))
{
pszForwardTo = rVariant.pszVal;
mi.pszForwardTo = pszForwardTo;
}
if (NULL == mi.pszMSOESRec && SUCCEEDED(pPropertySet->GetProp(STR_HDR_XMSOESREC, NOFLAGS, &rVariant)))
{
pszMSOESRec = rVariant.pszVal;
mi.pszMSOESRec = pszMSOESRec;
}
IF_FAILEXIT(hr = pFolder->UpdateRecord(&mi));
// if everything succeeded, commit the message to the store
IF_FAILEXIT(hr = pFolder->SetMessageStream(idMessage, pStream));
// the stream has now been used. null out the file address
if (NULL != pfa)
*pfa = NULL;
exit:
MemFree(pszDisplayFrom);
MemFree(pszEmailFrom);
MemFree(pszDisplayTo);
MemFree(pszEmailTo);
MemFree(pszMessageId);
MemFree(pszXref);
MemFree(pszReferences);
MemFree(pszSubject);
MemFree(pszNormalSubj);
MemFree(pszAcctId);
MemFree(pszAcctName);
MemFree(pszServer);
MemFree(pszForwardTo);
MemFree(pszMSOESRec);
SafeRelease(pMimeMsg);
SafeRelease(pPropertySet);
if (pmiFree)
pFolder->FreeRecord(pmiFree);
SafeRelease(pAdrTable);
return hr;
}