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.
 
 
 
 
 
 

744 lines
25 KiB

#include "pch.hxx"
#include "note.h"
#include "header.h"
#include "envcid.h"
#include "envguid.h"
#include "bodyutil.h"
#include "oleutil.h"
#include "acctutil.h"
#include "menures.h"
#include "instance.h"
#include "inetcfg.h"
#include "ipab.h"
#include "msgprop.h"
#include "mlang.h"
#include "shlwapip.h"
#include "demand.h"
#include <ruleutil.h>
#include "instance.h"
#include "mapiutil.h"
#include <mapi.h>
LHANDLE g_lhSession = 0;
//
// FUNCTION: NewsUtil_ReFwdByMapi
//
// PURPOSE: Allows the caller to reply to the specified message via Simple
// MAPI instead of Athena Mail.
//
// PARAMETERS:
// hwnd - Handle of the window to display UI over.
// pNewsMsg - Pointer to the news message to reply/forward to
// fReply - TRUE if we should reply, FALSE to forward.
//
// RETURN VALUE:
// HRESULT.
//
HRESULT NewsUtil_ReFwdByMapi(HWND hwnd, LPMIMEMESSAGE pMsg, DWORD msgtype)
{
// Locals
HRESULT hr=S_OK;
LPMAPIFREEBUFFER pfnMAPIFreeBuffer;
LPMAPIRESOLVENAME pfnMAPIResolveName;
LPMAPISENDMAIL pfnMAPISendMail;
MapiMessage mm;
MapiFileDesc *pFileDesc=NULL;
MapiRecipDesc *pRecips=NULL;
ULONG uAttach;
ULONG cAttach=0;
HBODY *rghAttach=NULL;
LPSTR pszReply=NULL;
LPSTR pszSubject=NULL;
LPSTR pszFrom=NULL;
LPSTR pszTo=NULL;
LPSTR pszFile=NULL;
LPSTR pszFull=NULL;
LPSTR pszDisplay=NULL;
LPSTR pszAddr=NULL;
ADDRESSLIST addrList={0};
HBODY hBody;
BOOL fQP;
TCHAR szNewSubject[256];
LPWSTR pwsz=NULL;
ULONG cchRead;
LPSTREAM pBodyStream=NULL;
LPSTREAM pQuotedStream=NULL;
INT cch;
DWORD cbUnicode;
CHAR szTempPath[MAX_PATH];
LPMIMEBODY pBody=NULL;
MapiFileDesc *pCur;
// Trace
TraceCall("NewsUtil_ReFwdByMapi");
// Initialize
ZeroMemory(&mm, sizeof(mm));
// Load the MAPI DLL. If we don't succeed, then we can't continue
IF_FAILEXIT(hr = NewsUtil_LoadMAPI(hwnd));
// pfnMAPIFreeBuffer
pfnMAPIFreeBuffer = (LPMAPIFREEBUFFER)GetProcAddress(g_hlibMAPI, c_szMAPIFreeBuffer);
if (NULL == pfnMAPIFreeBuffer)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// pfnMAPIResolveName
pfnMAPIResolveName = (LPMAPIRESOLVENAME) GetProcAddress(g_hlibMAPI, c_szMAPIResolveName);
if (NULL == pfnMAPIResolveName)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// pfnMAPISendMail
pfnMAPISendMail = (LPMAPISENDMAIL) GetProcAddress(g_hlibMAPI, c_szMAPISendMail);
if (NULL == pfnMAPISendMail)
{
hr = TraceResult(E_FAIL);
goto exit;
}
// From
if (SUCCEEDED(MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_FROM), NOFLAGS, &pwsz)))
{
IF_NULLEXIT(pszFrom = PszToANSI(CP_ACP, pwsz));
SafeMemFree(pwsz);
}
// Reply-To
if (SUCCEEDED(MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_REPLYTO), NOFLAGS, &pwsz)))
{
IF_NULLEXIT(pszReply = PszToANSI(CP_ACP, pwsz));
SafeMemFree(pwsz);
}
// To
if (SUCCEEDED(MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_TO), NOFLAGS, &pwsz)))
{
IF_NULLEXIT(pszTo = PszToANSI(CP_ACP, pwsz));
SafeMemFree(pwsz);
}
// If this is a reply or forward, we need to get the normalized subject. Otherwise, we just get the regular subject.
if (MSGTYPE_REPLY == msgtype || MSGTYPE_FWD == msgtype)
{
// Normalized Subject
if (FAILED(MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_ATT_NORMSUBJ), NOFLAGS, &pwsz)))
pwsz = NULL;
}
// Subject
else if (FAILED(MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &pwsz)))
pwsz = NULL;
// Convert to ansi
if (pwsz)
{
IF_NULLEXIT(pszSubject = PszToANSI(CP_ACP, pwsz));
SafeMemFree(pwsz);
}
// Attempt to generate a reciepent list for MAPI if we're replying or CC'ing.
if (msgtype == MSGTYPE_REPLY || msgtype == MSGTYPE_CC)
{
// Figure out which address to use
if (msgtype == MSGTYPE_REPLY)
{
// If there's a reply-to field on the message, then use that
if (pszReply)
pszFull = pszReply;
else
// Otherwise, we'll use the address in the from header
pszFull = pszFrom;
}
// Who to address to
else
pszFull = pszTo;
// Bug #24587 - Use IAT_TO instead of IAT_UNKNOWN.
if (MimeOleParseRfc822Address(IAT_TO, IET_DECODED, pszFull, &addrList)==S_OK)
{
UINT i;
lpMapiRecipDesc paRecips,pCurrent;
DWORD cchSizeName = 128;
DWORD cchSizeAddress = 128;
// we arbitrarily chose 128 as typical for EIDSize and address string lengths
int cAlloc = (sizeof(MapiRecipDesc) + (sizeof(TCHAR) * cchSizeName) + 128) * addrList.cAdrs;
int cUsed = sizeof(MapiRecipDesc) * addrList.cAdrs;
LPBYTE pVal = NULL;
IF_FAILEXIT(hr = HrAlloc((LPVOID *)&paRecips, cAlloc));
pCurrent = paRecips;
pVal = (LPBYTE)pCurrent + sizeof(MapiRecipDesc) * addrList.cAdrs;
// More than one address
for (i=0; i < addrList.cAdrs ;i++)
{
int cBytes;
// free Safe Friendly Name (not used here, but was allocated)
SafeMemFree(addrList.prgAdr[i].pszFriendly);
addrList.prgAdr[i].pszFriendly = NULL;
// Save E-mail address
pszAddr = addrList.prgAdr[i].pszEmail;
addrList.prgAdr[i].pszEmail = NULL;
// Resolve Name
if ((cUsed < cAlloc) && SUCCESS_SUCCESS == pfnMAPIResolveName(g_lhSession, (ULONG_PTR) hwnd, pszAddr, MAPI_DIALOG, 0, &pRecips))
{
pRecips->ulRecipClass = MAPI_TO;
// copy pRecip
pCurrent->ulReserved = pRecips->ulReserved;
pCurrent->ulRecipClass = pRecips->ulRecipClass;
pCurrent->ulEIDSize = pRecips->ulEIDSize;
do {
if (pRecips->lpszName)
{
cBytes = (lstrlen(pRecips->lpszName)+1)*sizeof(TCHAR);
cUsed += cBytes;
if (cUsed > cAlloc)
break;
pCurrent->lpszName = (LPTSTR)pVal;
StrCpyN(pCurrent->lpszName, pRecips->lpszName, cchSizeName);
pVal += cBytes;
}
else
{
pCurrent->lpszName = NULL;
}
if (pRecips->lpszAddress)
{
cBytes = (lstrlen(pRecips->lpszAddress)+1)*sizeof(TCHAR);
cUsed += cBytes;
if (cUsed > cAlloc)
break;
pCurrent->lpszAddress = (LPTSTR)pVal;
StrCpyN(pCurrent->lpszAddress, pRecips->lpszAddress, cchSizeAddress);
pVal += cBytes;
}
else
{
pCurrent->lpszAddress = NULL;
}
if (pRecips->ulEIDSize)
{
cUsed += pRecips->ulEIDSize;
if (cUsed > cAlloc)
break;
pCurrent->lpEntryID = pVal;
CopyMemory(pCurrent->lpEntryID, pRecips->lpEntryID, (size_t)pRecips->ulEIDSize);
pVal += pRecips->ulEIDSize;
}
else
{
pCurrent->lpEntryID = NULL;
}
pCurrent++;
mm.nRecipCount++;
} while (FALSE);
// Free recips
(*pfnMAPIFreeBuffer)((LPVOID)pRecips);
pRecips = NULL;
}
SafeMemFree(pszAddr);
pszAddr = NULL;
}
mm.lpRecips = paRecips;
// Free the Address List
g_pMoleAlloc->FreeAddressList(&addrList);
}
}
// If this is a reply or forward, then create a normalized subject
if (msgtype == MSGTYPE_REPLY || msgtype == MSGTYPE_FWD)
{
// Pull in the new prefix from resource...
if (msgtype == MSGTYPE_REPLY)
{
StrCpyN(szNewSubject, c_szPrefixRE, ARRAYSIZE(szNewSubject));
}
else
{
StrCpyN(szNewSubject, c_szPrefixFW, ARRAYSIZE(szNewSubject));
}
// If we have a pszSubject
if (pszSubject)
{
// Get Length
cch = lstrlen(szNewSubject);
// Append the Subject
StrCpyN(szNewSubject + cch, pszSubject, ARRAYSIZE(szNewSubject) - cch - 1);
}
// Set the Subject
mm.lpszSubject = szNewSubject;
}
// Don't append anything
else
{
// If this is a CC, then just use the regular subject field
mm.lpszSubject = pszSubject;
}
// Set the note text.
// If this is a fwd as attachment, there won't be a body, don't use IF_FAILEXIT
if(SUCCEEDED(pMsg->GetTextBody(TXT_PLAIN, IET_UNICODE, &pBodyStream, &hBody)))
{
// Convert from unicode to CP_ACP - WARNING: HrStreamToByte allocates 10 extra bytes so I can slam in a L'\0'
IF_FAILEXIT(hr = HrStreamToByte(pBodyStream, (LPBYTE *)&pwsz, &cbUnicode));
// Store null
pwsz[cbUnicode / sizeof(WCHAR)] = L'\0';
// Convert to ANSI
IF_NULLEXIT(mm.lpszNoteText = PszToANSI(CP_ACP, pwsz));
// Release pBodyStream
SafeRelease(pBodyStream);
// Bug #24159 - We need to quote forwards as well as replies
if (DwGetOption(OPT_INCLUDEMSG) && (msgtype == MSGTYPE_REPLY || msgtype == MSGTYPE_FWD))
{
// Create a new stream
IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pBodyStream));
// Dump mm.lpszNoteText into pBodyStream
IF_FAILEXIT(hr = pBodyStream->Write(mm.lpszNoteText, lstrlen(mm.lpszNoteText), NULL));
// Commit
IF_FAILEXIT(hr = pBodyStream->Commit(STGC_DEFAULT));
// Rewind
IF_FAILEXIT(hr = HrRewindStream(pBodyStream));
// QP
fQP = HrHasEncodedBodyParts(pMsg, 1, &hBody)==S_OK;
// Quote the body text
NewsUtil_QuoteBodyText(pMsg, pBodyStream, &pQuotedStream, TRUE, fQP, pszFrom ? pszFrom : c_szEmpty);
// Free
SafeMemFree(mm.lpszNoteText);
// Dup
IF_FAILEXIT(hr = HrStreamToByte(pQuotedStream, (LPBYTE *)&mm.lpszNoteText, &cchRead));
// Null Term
*(mm.lpszNoteText + cchRead) = '\0';
}
}
// If this is a reply, then we don't include any attachments, otherwise we do.
if (msgtype != MSGTYPE_REPLY)
{
// Get Attachment Count
IF_FAILEXIT(hr = pMsg->GetAttachments(&cAttach, &rghAttach));
// Ar there attachments
if (cAttach)
{
// Get the temp file path so we have a place to store temp files.
GetTempPath(ARRAYSIZE(szTempPath), szTempPath);
// Create the MapiFileDesc array.
IF_FAILEXIT(hr = HrAlloc((LPVOID*) &pFileDesc, sizeof(MapiFileDesc) * cAttach));
// Zero It
ZeroMemory(pFileDesc, sizeof(MapiFileDesc) * cAttach);
// Set Current
pCur = pFileDesc;
// Loop
for (uAttach = 0; uAttach < cAttach; uAttach++)
{
// Get a temp file name
IF_FAILEXIT(hr = HrAlloc((LPVOID *)&(pCur->lpszPathName), sizeof(TCHAR) * MAX_PATH));
// Create temp filename
GetTempFileName(szTempPath, "NAB", 0, pCur->lpszPathName);
// Bind to the body
IF_FAILEXIT(hr = pMsg->BindToObject(rghAttach[uAttach], IID_IMimeBody, (LPVOID *)&pBody));
// Safe It
IF_FAILEXIT(hr = pBody->SaveToFile(IET_INETCSET, pCur->lpszPathName));
// Release
SafeRelease(pBody);
// Get the filename
if (SUCCEEDED(MimeOleGetBodyPropW(pMsg, rghAttach[uAttach], STR_ATT_GENFNAME, NOFLAGS, &pwsz)))
{
IF_NULLEXIT(pszFile = PszToANSI(CP_ACP, pwsz));
SafeMemFree(pwsz);
}
// Set up the MAPI attachment list
pCur->ulReserved = 0;
pCur->flFlags = 0;
pCur->nPosition = (ULONG) -1;
pCur->lpszFileName = pszFile;
pCur->lpFileType = NULL;
// Increment
pCur++;
// Don't Free It
pszFile = NULL;
}
mm.nFileCount = cAttach;
mm.lpFiles = pFileDesc;
}
}
// Finally send this off to MAPI for sending. If we're doing a CC, we try not to use UI
IF_FAILEXIT(hr = (HRESULT) pfnMAPISendMail(g_lhSession, (ULONG_PTR)hwnd, &mm, (msgtype == MSGTYPE_CC) ? 0 : MAPI_DIALOG, 0));
exit:
// If we have a file description
if (pFileDesc)
{
// Walk through the attachments
for (uAttach=0; uAttach<cAttach; uAttach++)
{
// Free It
MemFree(pFileDesc[uAttach].lpszFileName);
// If we have a file path
if (pFileDesc[uAttach].lpszPathName)
{
// Delete the file
DeleteFile(pFileDesc[uAttach].lpszPathName);
// Free It
MemFree(pFileDesc[uAttach].lpszPathName);
}
}
// Free It
MemFree(pFileDesc);
}
// Free recips
if (pRecips)
(*pfnMAPIFreeBuffer)((LPVOID)pRecips);
// Cleanup
SafeMemFree(mm.lpRecips);
SafeMemFree(pszAddr);
SafeMemFree(pszDisplay);
SafeMemFree(mm.lpszNoteText);
SafeMemFree(pwsz);
SafeMemFree(pszReply);
SafeMemFree(pszSubject);
SafeMemFree(pszFrom);
SafeMemFree(rghAttach);
SafeMemFree(pszTo);
SafeRelease(pQuotedStream);
SafeRelease(pBodyStream);
SafeRelease(pBody);
// If we logged on to MAPI, we must log off
NewsUtil_FreeMAPI();
return(hr);
}
//
// FUNCTION: NewsUtil_LoadMAPI()
//
// PURPOSE: Takes care of checking to see if Simple MAPI is available, and
// if so loads the library and logs the user on. If successful,
// then the global variable g_hlibMAPI is set to the library for
// MAPI.
//
HRESULT NewsUtil_LoadMAPI(HWND hwnd)
{
LPMAPILOGON pfnMAPILogon;
HRESULT hr = E_FAIL;
// Load mapi32 dll if we haven't already
if (!g_hlibMAPI)
{
// Check to see if Simple MAPI is available
if (1 != GetProfileInt(c_szMailIni, c_szMAPI, 0))
{
// Bug #17561 - Need to tell the user they can't send mail without
// a mail client.
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaNews),
MAKEINTRESOURCEW(idsErrNoMailInstalled), 0, MB_OK | MB_ICONSTOP);
return (E_FAIL);
}
g_hlibMAPI = (HMODULE) LoadLibrary(c_szMAPIDLL);
if (!g_hlibMAPI)
{
// Bug #17561 - Need to tell the user they can't send mail without
// a mail client.
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaNews),
MAKEINTRESOURCEW(idsErrNoMailInstalled), 0, MB_OK | MB_ICONSTOP);
return (E_FAIL);
}
}
// Get the entry point for MAPILogon and the other APIs we'll use.
pfnMAPILogon = (LPMAPILOGON) GetProcAddress(g_hlibMAPI, c_szMAPILogon);
if (!pfnMAPILogon)
{
AssertSz(pfnMAPILogon, TEXT("Couldn't find the MAPILogon() API"));
goto error;
}
// Attempt to log on.
// Bug #17558 - Can't used the FAILED() macro to check the success of this
// one, MAPI is not returning HRESULTs, just numbers.
if (SUCCESS_SUCCESS != (hr = pfnMAPILogon(NULL, NULL, NULL, MAPI_LOGON_UI, 0, &g_lhSession)))
{
// AssertSz(FALSE, TEXT("Failed call to MAPILogon()"));
goto error;
}
return (S_OK);
error:
if (g_hlibMAPI)
{
FreeLibrary(g_hlibMAPI);
g_hlibMAPI = 0;
}
g_lhSession = 0;
return (hr);
}
//
// FUNCTION: NewsUtil_FreeMAPI()
//
// PURPOSE: Frees the Simple MAPI library if it was previous library and
// also logs the user off from the current MAPI session.
//
void NewsUtil_FreeMAPI(void)
{
LPMAPILOGOFF pfnMAPILogoff;
if (!g_hlibMAPI)
return;
pfnMAPILogoff = (LPMAPILOGOFF) GetProcAddress(g_hlibMAPI, c_szMAPILogoff);
if (g_lhSession)
pfnMAPILogoff(g_lhSession, NULL, 0, 0);
g_lhSession = 0;
}
//
// FUNCTION: NewsUtil_QuoteBodyText()
//
// PURPOSE: Takes a body text stream (ASCII plain text) and copies the
// text to a separate outbound stream while prepending the
// current quote character (">") to the beginning of each line.
//
// PARAMETERS:
// pMsg - Pointer to the message being replied to. We use this
// to add the "On 1/1/96, B.L. Opie Bailey wrote..."
// pStreamIn - Pointer to the inbound body stream to quote.
// ppStreamOut - Pointer to where the new quoted stream will return.
// fInsertDesc - TRUE if we should insert the "On 1/1/96 ..." line.
// fQP - we now pass a flag to say if it's QP or not as there's no
// function on the message object
//
// RETURN VALUE:
// Returns an HRESULT signifying success or failure.
//
const DWORD c_cBufferSize = 1024;
HRESULT NewsUtil_QuoteBodyText(LPMIMEMESSAGE pMsg, LPSTREAM pStreamIn,
LPSTREAM* ppStreamOut, BOOL fInsertDesc, BOOL fQP, LPCSTR pszFrom)
{
HRESULT hr = S_OK;
ULONG cbRead;
LPTSTR pch;
TCHAR szQuoteChar;
LPSTR lpszMsgId=0;
szQuoteChar = (TCHAR)DwGetOption(OPT_NEWSINDENT);
// Validate the inbound stream.
if (!pStreamIn)
{
AssertSz(pStreamIn, TEXT("NewsUtil_QuoteBodyText - Need an inbound stream to process."));
return (E_INVALIDARG);
}
// Create our outbound stream.
if (FAILED(MimeOleCreateVirtualStream(ppStreamOut)))
{
AssertSz(FALSE, TEXT("NewsUtil_QuoteBodyText - Failed to allocate memory."));
return (E_OUTOFMEMORY);
}
// Create a buffer to read into and parse etc.
LPTSTR pszBuffer;
if (!MemAlloc((LPVOID*) &pszBuffer, c_cBufferSize * sizeof(TCHAR)))
{
(*ppStreamOut)->Release();
AssertSz(FALSE, TEXT("NewsUtil_QuoteBodyText - Failed to allocate memory."));
return (E_OUTOFMEMORY);
}
ZeroMemory(pszBuffer, c_cBufferSize * sizeof(TCHAR));
MimeOleGetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_MESSAGEID), NOFLAGS, &lpszMsgId);
if (lpszMsgId == NULL)
lpszMsgId = (LPSTR)c_szEmpty;
if (fQP)
{
// If the text has some quoted printable stuff in it, then we don't want
// to introduce hard line breaks. Instead we just prefix the stream with
// the normal desc stuff and end it with a suitable line.
// Add the quote line.
LPTSTR pszStringRes;
int ids = 0;
if (fInsertDesc)
{
pszStringRes = AthLoadString(idsReplyTextPrefix, 0, 0);
wnsprintf(pszBuffer, c_cBufferSize, pszStringRes, pszFrom, lpszMsgId);
AthFreeString(pszStringRes);
(*ppStreamOut)->Write((LPVOID) g_szCRLF2, lstrlen(g_szCRLF2), NULL);
(*ppStreamOut)->Write((LPVOID) pszBuffer, lstrlen(pszBuffer), NULL);
(*ppStreamOut)->Write((LPVOID) g_szCRLF, lstrlen(g_szCRLF), NULL);
}
while (TRUE)
{
// Read a buffer from the input and write it to the output.
hr = pStreamIn->Read((LPVOID) pszBuffer, c_cBufferSize - 2, &cbRead);
if (FAILED(hr))
goto exit;
if (cbRead == 0)
break;
(*ppStreamOut)->Write((LPVOID) pszBuffer, cbRead, NULL);
}
// Write the trailing comment.
pszStringRes = AthLoadString(idsReplyTextAppend, 0, 0);
(*ppStreamOut)->Write((LPVOID) pszStringRes, lstrlen(pszStringRes), NULL);
AthFreeString(pszStringRes);
}
else
{
if (fInsertDesc)
{
// Add the quote line.
LPTSTR pszStringRes;
int ids = 0;
pszStringRes = AthLoadString(idsReplyTextPrefix, 0, 0);
wnsprintf(pszBuffer, c_cBufferSize, pszStringRes, pszFrom, lpszMsgId);
AthFreeString(pszStringRes);
(*ppStreamOut)->Write((LPVOID) g_szCRLF2, lstrlen(g_szCRLF2), NULL);
(*ppStreamOut)->Write((LPVOID) pszBuffer, lstrlen(pszBuffer), NULL);
(*ppStreamOut)->Write((LPVOID) g_szCRLF, lstrlen(g_szCRLF), NULL);
}
// Write the first quote char to the new stream.
// Bug #26297 - Still go through this bs even if no quote char is necessary
// to make sure we get the attribution line right.
if (szQuoteChar != INDENTCHAR_NONE)
{
(*ppStreamOut)->Write((const LPVOID) &szQuoteChar,
sizeof(TCHAR), NULL);
(*ppStreamOut)->Write((const LPVOID) g_szSpace, sizeof(TCHAR), NULL);
}
// Now start the reading and parsing.
// NOTE - Right now all we're doing is adding a quote char to the beginning
// of each line. We're not trying to wrap lines or re-wrap previously
// quoted areas. - SteveSer
while (TRUE)
{
hr = pStreamIn->Read((LPVOID) pszBuffer, c_cBufferSize - 2, &cbRead);
if (FAILED(hr))
goto exit;
if (cbRead == 0)
break;
pch = pszBuffer;
// Make sure the buffer is NULL terminated
*(pch + cbRead) = 0;
// Now run through the stream. Whenever we find a line break, we
// insert a quote char after the line break.
while (*pch)
{
(*ppStreamOut)->Write((const LPVOID) pch,
(ULONG)((IsDBCSLeadByte(*pch) ? 2 * sizeof(TCHAR) : sizeof(TCHAR))),
NULL);
if (*pch == *g_szNewline)
{
// Bug #26297 - Still go through this bs even if no quote char is necessary
// to make sure we get the attribution line right.
if (szQuoteChar != INDENTCHAR_NONE)
{
(*ppStreamOut)->Write((const LPVOID) &szQuoteChar,
sizeof(TCHAR), NULL);
(*ppStreamOut)->Write((const LPVOID) g_szSpace, sizeof(TCHAR),
NULL);
}
}
pch = CharNext(pch);
// Do some checking to see if we're at the end of a buffer.
if (IsDBCSLeadByte(*(pch)) && (0 == *(pch + 1)))
{
// Here's a little special case. If we have one byte left in
// the buffer, and that byte happens to be the first byte in
// a DBCS character, we need to write that byte now, then move
// the pointer to the end of the buffer so the next character
// get's read off the next stream OK.
(*ppStreamOut)->Write((const LPVOID) pch, sizeof(TCHAR), NULL);
pch++;
}
}
}
}
exit:
if (pszBuffer)
MemFree(pszBuffer);
if (lpszMsgId != c_szEmpty)
SafeMimeOleFree(lpszMsgId);
return (hr);
}