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.
 
 
 
 
 
 

832 lines
27 KiB

/*
* b o d y u t i l . c p p
*
* Purpose:
* utility functions for body
*
* History
* August '96: brettm - created
*
* Copyright (C) Microsoft Corp. 1995, 1996.
*/
#include <pch.hxx>
#include "dllmain.h"
#include "olealloc.h"
#include "resource.h"
#include "htmlstr.h"
#include "strconst.h"
#include "bodyutil.h"
#include "plainstm.h"
#include "mimeutil.h"
#include "util.h"
#include "demand.h"
ASSERTDATA
/*
* t y p e d e f s
*/
enum
{
HEADER_FROM=0,
HEADER_NEWSGROUP,
HEADER_TO,
HEADER_CC,
HEADER_SENT,
HEADER_ATTACH,
HEADER_SUBJECT,
HEADER_MAX
};
/*
* m a c r o s
*/
#define WSZ_CB(str) (lstrlenW(str)*sizeof(WCHAR))
#define WSZ_CBNULL(str) ((lstrlenW(str)+1)*sizeof(WCHAR))
#define WSZ_CCH(str) lstrlenW(str)
#define WSZ_CCHNULL(str) (lstrlenW(str)+1)
/*
* c o n s t a n t s
*/
static const WCHAR c_wszHtmlDIV_Close[] = L"</DIV>\r\n",
c_wszTableTag_Close[] = L"</TABLE>\r\n",
c_wszHtml[] = L"<HTML>\r\n",
c_wszHtmlReplyAnchor[] = L"<A href=\"mailto:%s\" TITLE=\"%s\">%s</A>\r\n",
c_wszHtml_HeaderDIV[] = L"<DIV>\r\n<B>%s</B> ",
c_wszHtml_DIV_BR_DIV[] = L"<DIV><BR></DIV>\r\n",
c_wszHtml_FromDIV[] = L"<DIV STYLE=\"background:#E4E4E4; font-color:black\">\r\n<B>%s</B> ",
c_wszHtml_HeaderDIVFmt_Start[] = L"<DIV>\r\n<B>",
c_wszHtml_HeaderDIVFmt_Middle[] = L"</B> ",
c_wszHtml_HeaderDIVFmt_End[] = L"</DIV>",
c_wszHtml_HeaderDIVFmt_Plain_Start[]= L"<DIV>\r\n",
c_wszHtml_HeaderDIVFmt_Plain_Middle[]= L" ",
c_wszHtml_HeaderDIVFmt_Plain_End[] = L"</DIV>";
static const int c_cchHtml_HeaderDIVFmt_Start = ARRAYSIZE(c_wszHtml_HeaderDIVFmt_Start) - 1,
c_cchHtml_HeaderDIVFmt_Middle = ARRAYSIZE(c_wszHtml_HeaderDIVFmt_Middle) - 1,
c_cchHtml_HeaderDIVFmt_End = ARRAYSIZE(c_wszHtml_HeaderDIVFmt_End) - 1,
c_cchHtml_HeaderDIVFmt_Plain_Start = ARRAYSIZE(c_wszHtml_HeaderDIVFmt_Plain_Start) - 1,
c_cchHtml_HeaderDIVFmt_Plain_Middle = ARRAYSIZE(c_wszHtml_HeaderDIVFmt_Plain_Middle) - 1,
c_cchHtml_HeaderDIVFmt_Plain_End = ARRAYSIZE(c_wszHtml_HeaderDIVFmt_Plain_End) - 1;
// HARDCODED Western headers
static const LPWSTR c_rgwszHeaders[HEADER_MAX] = { L"From:",
L"Newsgroups:",
L"To:",
L"Cc:",
L"Sent:",
L"Attach:",
L"Subject:"};
static const int c_rgidsHeaders[HEADER_MAX] ={
idsFromField,
idsNewsgroupsField,
idsToField,
idsCcField,
idsDateField,
idsAttachField,
idsSubjectField};
/*
* g l o b a l s
*/
/*
* p r o t o t y p e s
*/
HRESULT CreatePrintHeader(IMimeMessageW *pMsg, LPWSTR pwszUser, DWORD dwFlags, LPSTREAM pstm);
HRESULT CreateMailHeader(IMimeMessageW *pMsg, DWORD dwFlags, LPSTREAM pstm);
HRESULT CreateNewsHeader(IMimeMessageW *pMsg, DWORD dwFlags, LPSTREAM pstm);
HRESULT GetHeaderLabel(ULONG uHeader, DWORD dwFlags, LPWSTR *ppwszOut);
HRESULT GetHeaderText(IMimeMessageW *pMsg, ULONG uHeader, DWORD dwFlags, LPWSTR *ppwszOut);
HRESULT CreateHTMLAddressLine(IMimeMessageW *pMsg, DWORD dwAdrTypes, LPWSTR *ppwszOut);
void DropAngles(LPWSTR pwszIn, LPWSTR *ppwszOut);
/*
* f u n c t i o n s
*/
/*
* Trident doesn't do a good job of converting tables->plaintext, so we can't use
* a table to construct the header of a re: fw: etc to get nice alignment on the
* field boundaries. We can use a table, however for printing. We need to be able to
* construct a header (in html source) in 3 flavours:
*
* HDR_PLAIN (regular text, eg: reply in plain-mode)
* HDR_HTML (regular text, with bolded fields, eg: reply in html-mode)
* HDR_TABLE (use table to get improved output, eg: printing)
*
*/
HRESULT GetHeaderTable(IMimeMessageW *pMsg, LPWSTR pwszUserName, DWORD dwHdrStyle, LPSTREAM *ppstm)
{
HRESULT hr = S_OK;
LPSTREAM pstm = NULL;
BYTE bUniMark = 0xFF;
if (pMsg==NULL || ppstm==NULL)
IF_FAILEXIT(hr = E_INVALIDARG);
IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pstm));
// Write out the BOM
IF_FAILEXIT(hr = pstm->Write(&bUniMark, sizeof(bUniMark), NULL));
bUniMark = 0xFE;
IF_FAILEXIT(hr = pstm->Write(&bUniMark, sizeof(bUniMark), NULL));
if (dwHdrStyle & HDR_TABLE)
IF_FAILEXIT(hr = CreatePrintHeader(pMsg, pwszUserName, dwHdrStyle, pstm));
else if (dwHdrStyle & HDR_NEWSSTYLE)
IF_FAILEXIT(hr = CreateNewsHeader(pMsg, dwHdrStyle, pstm));
else
IF_FAILEXIT(hr = CreateMailHeader(pMsg, dwHdrStyle, pstm));
*ppstm = pstm;
pstm = NULL;
exit:
ReleaseObj(pstm);
return hr;
}
HRESULT CreateNewsHeader(IMimeMessageW *pMsg, DWORD dwFlags, LPSTREAM pstm)
{
HRESULT hr = S_OK;
WCHAR wsz[CCHMAX_STRINGRES];
ULONG cch,
cb;
LPWSTR pwsz = NULL,
pwszFrom = NULL,
pwszMsgId = NULL,
pwszFmtMsgId = NULL,
pwszHtml;
Assert(pMsg);
Assert(pstm);
pMsg->GetAddressFormatW(IAT_FROM, AFT_DISPLAY_BOTH, &pwszFrom);
MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &pwszMsgId);
*wsz = 0;
cch = LoadStringWrapW(g_hLocRes, idsReplyTextPrefix, wsz, ARRAYSIZE(wsz));
cb = cch*sizeof(WCHAR);
// Opie assumes me these Sz function never return NULL. Only an empty buffer
if (pwszFrom)
cb += WSZ_CB(pwszFrom);
else
pwszFrom=(LPWSTR)c_szEmptyW;
if (pwszMsgId)
{
// We purposely remove < and > from the msgId so Trident will correctly
// format the msgId as a news: link and not a mailto:
DropAngles(pwszMsgId, &pwszFmtMsgId);
cb += WSZ_CB(pwszFmtMsgId);
}
else
pwszFmtMsgId=(LPWSTR)c_szEmptyW;
// Add null
cb += sizeof(WCHAR);
IF_NULLEXIT(MemAlloc((LPVOID *)&pwsz, cb));
IF_FAILEXIT(hr = pstm->Write(c_wszHtml_DivOpen, WSZ_CB(c_wszHtml_DivOpen), NULL));
// We just write out the e-mail name and news:message-id,
// trident does URL autodetection and makes the e-mail into a mailto link and the
// news: into a news link.
wnsprintfW(pwsz, cb, wsz, pwszFrom, pwszFmtMsgId);
IF_FAILEXIT(hr = EscapeStringToHTML(pwsz, &pwszHtml));
pstm->Write(pwszHtml, WSZ_CB(pwszHtml), NULL);
MemFree(pwszHtml);
IF_FAILEXIT(hr = pstm->Write(c_wszHtml_DivClose, WSZ_CB(c_wszHtml_DivClose), NULL));
exit:
if (pwszFrom != c_szEmptyW)
MemFree(pwszFrom);
MemFree(pwszMsgId);
// pwszFmtMsgId was freed when we freed lpsMsgId
MemFree(pwsz);
return hr;
}
/*
<DIV style="font: 10pt arial">
-----Original Message-----
<DIV STYLE="background:gainsboro; font-color:black">
<B>From:</B> <a href="mailto:[email protected]">Justin Ferrari</a>
</DIV>
<DIV>
<B>To:</B>
<A href="mailto:[email protected]" TITLE="[email protected]">John Tafoya</A>;
<A href="mailto:[email protected]" TITLE="[email protected]">Lauren Antonoff</A>;
<A href="mailto:[email protected]" TITLE="[email protected]">Dave Haws</A>;
<A href="mailto:[email protected]" TITLE="[email protected]">John Doe</A>
</DIV>
<DIV>
<B>Date:</B> Tuesday, September 01, 1998 10:40 AM
</DIV>
<DIV>
<B>Subject: </B>Re: A plea to save the life of the News Server combo box
</DIV>
<DIV><BR></DIV>
</DIV>
*/
HRESULT CreateMailHeader(IMimeMessageW *pMsg, DWORD dwFlags, LPSTREAM pstm)
{
ULONG uHeader,
cchFmt;
WCHAR wsz[CCHMAX_STRINGRES],
wszText[CCHMAX_STRINGRES];
LPWSTR pwsz = NULL,
pwszText = NULL,
pwszLabel = NULL,
pwszHtml = NULL;
LPCWSTR pwszFmtStart,
pwszFmtMiddle,
pwszFmtEnd;
int cchFmtStart,
cchFmtMiddle,
cchFmtEnd;
HRESULT hr = S_OK;
if (pMsg==NULL || pstm==NULL)
IF_FAILEXIT(hr = E_INVALIDARG);
// emit a table to display the username
if (LoadStringWrapW(g_hLocRes,
dwFlags & HDR_HTML ? idsReplyHeader_Html_SepBlock : idsReplyHeader_SepBlock,
wsz,
ARRAYSIZE(wsz)))
{
*wszText=0;
if (dwFlags & HDR_HARDCODED)
StrCpyNW(wszText, L"----- Original Message -----", ARRAYSIZE(wszText));
else
LoadStringWrapW(g_hLocRes, idsReplySep, wszText, ARRAYSIZE(wszText));
IF_NULLEXIT(pwsz = PszAllocW(WSZ_CCH(wszText) + WSZ_CCH(wsz) + 1));
wnsprintfW(pwsz, (WSZ_CCH(wszText) + WSZ_CCH(wsz) + 1), wsz, wszText);
pstm->Write(pwsz, WSZ_CB(pwsz), NULL);
SafeMemFree(pwsz);
}
if (dwFlags & HDR_HTML)
{
pwszFmtStart = c_wszHtml_HeaderDIVFmt_Start;
pwszFmtMiddle = c_wszHtml_HeaderDIVFmt_Middle;
pwszFmtEnd = c_wszHtml_HeaderDIVFmt_End;
cchFmtStart = c_cchHtml_HeaderDIVFmt_Start;
cchFmtMiddle = c_cchHtml_HeaderDIVFmt_Middle;
cchFmtEnd = c_cchHtml_HeaderDIVFmt_End;
}
else
{
pwszFmtStart = c_wszHtml_HeaderDIVFmt_Plain_Start;
pwszFmtMiddle = c_wszHtml_HeaderDIVFmt_Plain_Middle;
pwszFmtEnd = c_wszHtml_HeaderDIVFmt_Plain_End;
cchFmtStart = c_cchHtml_HeaderDIVFmt_Plain_Start;
cchFmtMiddle = c_cchHtml_HeaderDIVFmt_Plain_Middle;
cchFmtEnd = c_cchHtml_HeaderDIVFmt_Plain_End;
}
// write out each header row
for (uHeader=0; uHeader<HEADER_MAX; uHeader++)
{
// skip attachment header for reply and forward headers
if (uHeader == HEADER_ATTACH)
continue;
// special case address-headers in HTML-Mode
if (dwFlags & HDR_HTML)
{
switch (uHeader)
{
case HEADER_FROM:
{
if (CreateHTMLAddressLine(pMsg, IAT_FROM, &pwsz)==S_OK)
{
if (GetHeaderLabel(uHeader, dwFlags, &pwszLabel)==S_OK)
{
// pszLabel is fixed size
wnsprintfW(wsz, ARRAYSIZE(wsz), c_wszHtml_FromDIV, pwszLabel);
pstm->Write(wsz, WSZ_CB(wsz), NULL);
pstm->Write(pwsz, WSZ_CB(pwsz), NULL);
pstm->Write(c_wszHtmlDIV_Close, WSZ_CB(c_wszHtmlDIV_Close), NULL);
SafeMemFree(pwszLabel);
}
SafeMemFree(pwsz);
}
continue;
}
case HEADER_TO:
case HEADER_CC:
{
if (CreateHTMLAddressLine(pMsg, uHeader == HEADER_TO ? IAT_TO : IAT_CC, &pwsz)==S_OK)
{
if (GetHeaderLabel(uHeader, dwFlags, &pwszLabel)==S_OK)
{
wnsprintfW(wsz, ARRAYSIZE(wsz), c_wszHtml_HeaderDIV, pwszLabel); // pszLabel is fixed size
pstm->Write(wsz, WSZ_CB(wsz), NULL);
pstm->Write(pwsz, WSZ_CB(pwsz), NULL);
pstm->Write(c_wszHtmlDIV_Close, WSZ_CB(c_wszHtmlDIV_Close), NULL);
SafeMemFree(pwszLabel);
}
SafeMemFree(pwsz);
}
continue;
}
}
}
// normal headers
if (GetHeaderLabel(uHeader, dwFlags, &pwszLabel)==S_OK)
{
if (GetHeaderText(pMsg, uHeader, dwFlags, &pwszText)==S_OK)
{
if (*pwszText) // ignore empty strings
{
int cch = 0;
int cchLabel;
int cchHtml;
IF_FAILEXIT(hr = EscapeStringToHTML(pwszText, &pwszHtml));
cchLabel = WSZ_CCH(pwszLabel);
cchHtml = WSZ_CCH(pwszHtml);
// 1 for the NULL
DWORD cchSize = (cchLabel + cchHtml + cchFmtStart + cchFmtMiddle + cchFmtEnd + 1);
IF_NULLEXIT(pwsz = PszAllocW(cchSize));
// Avoid potentially dumping > 1024 into wnsprintfW
StrCpyNW(pwsz, pwszFmtStart, cchSize);
cch = cchFmtStart;
StrCpyNW(&pwsz[cch], pwszLabel, cchSize - cch);
cch += cchLabel;
StrCpyNW(&pwsz[cch], pwszFmtMiddle, cchSize - cch);
cch += cchFmtMiddle;
StrCpyNW(&pwsz[cch], pwszHtml, cchSize - cch);
cch += cchHtml;
StrCpyNW(&pwsz[cch], pwszFmtEnd, cchSize - cch);
cch += cchFmtEnd;
pstm->Write(pwsz, cch * sizeof(WCHAR), NULL);
SafeMemFree(pwsz);
SafeMemFree(pwszHtml);
}
SafeMemFree(pwszText);
}
SafeMemFree(pwszLabel);
}
}
// Close the <DIV> that wraps the whole thing in a font
pstm->Write(c_wszHtmlDIV_Close, WSZ_CB(c_wszHtmlDIV_Close), NULL);
// add a <DIV><BR></DIV> to give one line-spacing
pstm->Write(c_wszHtml_DIV_BR_DIV, WSZ_CB(c_wszHtml_DIV_BR_DIV), NULL);
exit:
MemFree(pwszHtml);
MemFree(pwszText);
MemFree(pwszLabel);
MemFree(pwsz);
return hr;
}
HRESULT CreatePrintHeader(IMimeMessageW *pMsg, LPWSTR pwszUser, DWORD dwFlags, LPSTREAM pstm)
{
ULONG uHeader;
WCHAR wsz[CCHMAX_STRINGRES];
LPWSTR pwsz = NULL,
pwszText = NULL,
pwszLabel = NULL,
pwszHtml = NULL;
HRESULT hr = S_OK;
int cch = 0;
if (pMsg==NULL || pstm==NULL)
IF_FAILEXIT(hr = E_INVALIDARG);
// if no username, use "" so wsprintf is happy
if (pwszUser == NULL)
pwszUser = (LPWSTR)c_szEmptyW;
// Emit an <HTML> tag for trident autodetector (used on the print-header)
pstm->Write(c_wszHtml, WSZ_CB(c_wszHtml), NULL);
// emit a table to display the username
if (LoadStringWrapW(g_hLocRes, idsPrintTable_UserName, wsz, ARRAYSIZE(wsz)))
{
IF_FAILEXIT(hr = EscapeStringToHTML(pwszUser, &pwszHtml));
IF_NULLEXIT(pwsz = PszAllocW(WSZ_CCH(wsz) + WSZ_CCH(pwszHtml) + 1));
wnsprintfW(pwsz, (WSZ_CCH(wsz) + WSZ_CCH(pwszHtml) + 1), wsz, pwszHtml);
pstm->Write(pwsz, WSZ_CB(pwsz), NULL);
SafeMemFree(pwsz);
SafeMemFree(pwszHtml);
}
// start the main-table
if (LoadStringWrapW(g_hLocRes, idsPrintTable_Header, wsz, ARRAYSIZE(wsz)))
{
pstm->Write(wsz, WSZ_CB(wsz), NULL);
if (LoadStringWrapW(g_hLocRes, idsPrintTable_HeaderRow, wsz, ARRAYSIZE(wsz)))
{
// write out each header row
for (uHeader=0; uHeader<HEADER_MAX; uHeader++)
{
if (GetHeaderLabel(uHeader, dwFlags, &pwszLabel)==S_OK)
{
if (GetHeaderText(pMsg, uHeader, dwFlags, &pwszText)==S_OK)
{
if (*pwszText) // ignore empty strings
{
IF_FAILEXIT(hr = EscapeStringToHTML(pwszText, &pwszHtml));
cch = lstrlenW(pwszLabel) + lstrlenW(pwszHtml) + lstrlenW(wsz) +1;
IF_NULLEXIT(pwsz = PszAllocW(cch));
wnsprintfW(pwsz, cch, wsz, pwszLabel, pwszHtml);
pstm->Write(pwsz, WSZ_CB(pwsz), NULL);
SafeMemFree(pwsz);
SafeMemFree(pwszHtml);
}
SafeMemFree(pwszText);
}
SafeMemFree(pwszLabel);
}
}
}
pstm->Write(c_wszTableTag_Close, WSZ_CB(c_wszTableTag_Close), NULL);
}
exit:
MemFree(pwsz);
MemFree(pwszHtml);
MemFree(pwszText);
MemFree(pwszLabel);
return hr;
}
HRESULT GetHeaderText(IMimeMessageW *pMsg, ULONG uHeader, DWORD dwFlags, LPWSTR *ppwszOut)
{
PROPVARIANT pv;
HBODY *rghAttach = NULL;
ULONG cAttach,
uAttach,
cchSize=0;
LPWSTR *rgpwsz = NULL,
pwszWrite = NULL,
pwszEnd = NULL;
HRESULT hr = S_OK;
Assert(pMsg);
Assert(ppwszOut);
*ppwszOut = 0;
switch (uHeader)
{
case HEADER_FROM:
pMsg->GetAddressFormatW(IAT_FROM, AFT_DISPLAY_BOTH, ppwszOut);
break;
case HEADER_NEWSGROUP:
MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_NEWSGROUPS), NOFLAGS, ppwszOut);
break;
case HEADER_TO:
pMsg->GetAddressFormatW(IAT_TO, AFT_DISPLAY_BOTH, ppwszOut);
break;
case HEADER_CC:
pMsg->GetAddressFormatW(IAT_CC, AFT_DISPLAY_BOTH, ppwszOut);
break;
case HEADER_ATTACH:
if (pMsg->GetAttachments(&cAttach, &rghAttach)==S_OK && cAttach)
{
// create cache-string list
IF_NULLEXIT(rgpwsz = (LPWSTR*)ZeroAllocate(sizeof(*rgpwsz) * cAttach));
for (uAttach=0; uAttach<cAttach; uAttach++)
{
if (MimeOleGetBodyPropW(pMsg, rghAttach[uAttach], PIDTOSTR(PID_ATT_GENFNAME), NOFLAGS, &rgpwsz[uAttach])==S_OK)
cchSize += (WSZ_CCH(rgpwsz[uAttach]) + 2); // +2 for "; "
}
IF_NULLEXIT(MemAlloc((LPVOID *)ppwszOut, cchSize * sizeof((*ppwszOut)[0])));
pwszWrite = *ppwszOut;
pwszEnd = pwszWrite + cchSize;
for (uAttach=0; uAttach<cAttach; uAttach++)
{
StrCpyNW(pwszWrite, rgpwsz[uAttach], (DWORD)(pwszEnd-pwszWrite));
pwszWrite += WSZ_CCH(rgpwsz[uAttach]);
if (uAttach != cAttach -1)
{
StrCpyNW(pwszWrite, L"; ", (DWORD)(pwszEnd-pwszWrite));
pwszWrite += 2;
}
}
}
break;
case HEADER_SENT:
pv.vt = VT_FILETIME;
if (SUCCEEDED(pMsg->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &pv)))
{
LPWSTR lpwsz = NULL;
INT cch = 0;
IF_NULLEXIT(MemAlloc((LPVOID*)&lpwsz, CCHMAX_STRINGRES * sizeof(*lpwsz)));
*lpwsz = 0;
// always force a western date if using hardcoded headers
// For the formatted date, DTM_FORCEWESTERN flag returns English date and time.
// Without DTM_FORCEWESTERN the formatted time may not be representable in ASCII.
cch = AthFileTimeToDateTimeW(&pv.filetime, lpwsz, CCHMAX_STRINGRES,
DTM_NOSECONDS|DTM_LONGDATE|(dwFlags & HDR_HARDCODED ?DTM_FORCEWESTERN:0));
*ppwszOut = lpwsz;
}
break;
case HEADER_SUBJECT:
MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, ppwszOut);
break;
default:
AssertSz(0, "Not Supported");
}
exit:
// free cached string-list
if (rgpwsz)
{
for (uAttach=0; uAttach<cAttach; uAttach++)
MemFree(rgpwsz[uAttach]);
MemFree(rgpwsz);
}
MemFree(rghAttach);
// In this case, we failed but that is ok so don't trace result.
// Just means that the field asked for is empty.
if (SUCCEEDED(hr) && (0 == *ppwszOut))
hr = E_FAIL;
return hr;
}
HRESULT GetHeaderLabel(ULONG uHeader, DWORD dwFlags, LPWSTR *ppwszOut)
{
WCHAR wsz[CCHMAX_STRINGRES];
Assert(ppwszOut);
*ppwszOut = 0;
if (dwFlags & HDR_HARDCODED)
*ppwszOut = PszDupW(c_rgwszHeaders[uHeader]);
else
{
if(LoadStringWrapW(g_hLocRes, c_rgidsHeaders[uHeader], wsz, ARRAYSIZE(wsz)))
*ppwszOut = PszDupW(wsz);
}
return *ppwszOut ? S_OK : E_FAIL;
}
HRESULT CreateHTMLAddressLine(IMimeMessageW *pMsg, DWORD dwAdrTypes, LPWSTR *ppwszOut)
{
ADDRESSLIST rAdrList = {0};
BOOL fFreeAdrList;
ULONG i;
ULONG cb=0;
LPWSTR pwsz = NULL,
pwszWrite = NULL,
pwszEnd = NULL,
pwszEmail = NULL,
pwszEmailLoop = NULL,
pwszFriendly = NULL,
*rgpwszEmail = NULL,
*rgpwszFriendly = NULL;
ULONG cAddr = 0;
HRESULT hr = S_OK;
Assert (pMsg);
// Get address table
IF_FAILEXIT(hr = pMsg->GetAddressTypes(dwAdrTypes, IAP_FRIENDLYW|IAP_EMAIL, &rAdrList));
cAddr = rAdrList.cAdrs;
// If no addresses, bail
if (cAddr == 0)
IF_FAILEXIT(hr = E_FAIL);
// Allocate array for escaped email addresses
IF_NULLEXIT(rgpwszEmail = (LPWSTR*)ZeroAllocate(sizeof(*rgpwszEmail) * cAddr));
// Allocate array for escaped displaynames
IF_NULLEXIT(rgpwszFriendly = (LPWSTR*)ZeroAllocate(sizeof(*rgpwszFriendly) * cAddr));
for (i=0; i < cAddr; i++)
{
// escape all of the names into our name array
if (rAdrList.prgAdr[i].pszEmail)
{
IF_NULLEXIT(pwszEmail = PszToUnicode(CP_ACP, rAdrList.prgAdr[i].pszEmail));
// Escape Into Array
IF_FAILEXIT(hr = EscapeStringToHTML(pwszEmail, &rgpwszEmail[i]));
// Use Email if no Friendly Name
if (NULL == (pwszFriendly = rAdrList.prgAdr[i].pszFriendlyW))
pwszFriendly = pwszEmail;
IF_FAILEXIT(hr = EscapeStringToHTML(pwszFriendly, &rgpwszFriendly[i]));
// for each address we use 2*email + display + htmlgoo + "; "
// if display == null, we use email. We skip if email==NULL (failure case)
cb += (
2*WSZ_CCH(rgpwszEmail[i]) +
WSZ_CCH(rgpwszFriendly[i]) +
WSZ_CCH(c_wszHtmlReplyAnchor) +
2
) * sizeof(WCHAR);
SafeMemFree(pwszEmail);
}
}
IF_NULLEXIT(MemAlloc((LPVOID *)&pwsz, cb));
pwszWrite = pwsz;
pwszEnd = pwszWrite + (cb/sizeof(WCHAR));
for (i=0; i < cAddr; i++)
{
if (pwszEmailLoop = rgpwszEmail[i])
{
pwszFriendly = rgpwszFriendly[i];
Assert (pwszFriendly);
wnsprintfW(pwszWrite, (DWORD)(pwszEnd-pwszWrite), c_wszHtmlReplyAnchor, pwszEmailLoop, pwszEmailLoop, pwszFriendly);
pwszWrite += WSZ_CCH(pwszWrite);
if (i != cAddr-1)
{
StrCpyNW(pwszWrite, L"; ", (DWORD)(pwszEnd-pwszWrite));
pwszWrite += 2;
}
}
}
*ppwszOut = pwsz;
pwsz = NULL; // freed by caller
exit:
if (rgpwszEmail)
{
for (i=0; i < cAddr; i++)
MemFree(rgpwszEmail[i]);
MemFree(rgpwszEmail);
}
if (rgpwszFriendly)
{
for (i=0; i < cAddr; i++)
MemFree(rgpwszFriendly[i]);
MemFree(rgpwszFriendly);
}
MemFree(pwsz);
MemFree(pwszEmail);
g_pMoleAlloc->FreeAddressList(&rAdrList);
return hr;
}
void GetRGBFromString(DWORD* pRGB, LPSTR pszColor)
{
DWORD dwShiftAmount = 0,
rgb = 0,
n;
CHAR ch;
Assert(pRGB);
Assert(lstrlen(pszColor) == lstrlen("RRGGBB"));
*pRGB = 0;
while (0 != (ch = *pszColor++))
{
if (ch >= '0' && ch <= '9')
n = ch - '0';
else if(ch >= 'A' && ch <= 'F')
n = ch - 'A' + 10;
else
{
Assert(ch >= 'a' && ch <= 'f')
n = ch - 'a' + 10;
}
rgb = (rgb << 4) + n;
}
rgb = ((rgb & 0x00ff0000) >> 16 ) | (rgb & 0x0000ff00) | ((rgb & 0x000000ff) << 16);
*pRGB = rgb;
}
void GetStringRGB(DWORD rgb, LPSTR pszColor)
{
INT i;
DWORD crTemp;
Assert(pszColor);
rgb = ((rgb & 0x00ff0000) >> 16 ) | (rgb & 0x0000ff00) | ((rgb & 0x000000ff) << 16);
for(i = 0; i < 6; i++)
{
crTemp = (rgb & (0x00f00000 >> (4*i))) >> (4*(5-i));
pszColor[i] = (CHAR)((crTemp < 10)? (crTemp+'0') : (crTemp+ 'a' - 10));
}
pszColor[6] = '\0';
}
/*
This function drops the enclosing < and > around a msg-id
RFC822: msg-id = "<" addr-spec ">"
NOTE:
The input buffer is MODIFIED and the output pointer
points to memory in pszIn!
*/
void DropAngles(LPWSTR pwszIn, LPWSTR *ppwszOut)
{
if (pwszIn)
{
WCHAR ch;
LPWSTR pwszCurrent = pwszIn;
// First character should be <, but be robust and scan for it
while ((ch = *pwszCurrent++) && (ch != L'<'));
if (ch)
// We are interested in stuff after the angle bracket
*ppwszOut = pwszCurrent;
else
// Perhaps the message-id was malformed and doesn't contain a <
*ppwszOut = pwszIn;
pwszCurrent = *ppwszOut;
// Find the close bracket and null it out
while ((ch = *pwszCurrent) && (ch != L'>'))
pwszCurrent++;
// If we found a >, overwrite it with NULL
if (ch)
*pwszCurrent = NULL;
}
}