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