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.
 
 
 
 
 
 

866 lines
28 KiB

// ----------------------------------------------------------------------------------------------------------
// M A I L U T I L . C P P
// ----------------------------------------------------------------------------------------------------------
#include "pch.hxx"
#include "demand.h"
#include "resource.h"
#include "mimeole.h"
#include "mimeutil.h"
#include "strconst.h"
#include "url.h"
#include "mailutil.h"
#include <spoolapi.h>
#include <fonts.h>
#include "instance.h"
#include "pop3task.h"
#include <ntverp.h>
#include "msgfldr.h"
#include "storutil.h"
#include "note.h"
#include "shlwapip.h"
#include <iert.h>
#include "storecb.h"
#include "conman.h"
#include "multiusr.h"
#include "ipab.h"
#include "secutil.h"
// ----------------------------------------------------------------------------------------------------------
// Folder Dialog Info
// ----------------------------------------------------------------------------------------------------------
typedef struct FLDRDLG_tag
{
FOLDERID idFolder;
BOOL fPending;
CStoreDlgCB *pCallback;
} FLDRDLG, *PFLDRDLG;
// ----------------------------------------------------------------------------------------------------------
// Prototypes
// ----------------------------------------------------------------------------------------------------------
INT_PTR CALLBACK MailUtil_FldrDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK WebPageDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HRESULT HrDlgCreateWebPage(HWND hwndDlg);
// ----------------------------------------------------------------------------------------------------------
// DoFolderDialog
// ----------------------------------------------------------------------------------------------------------
void MailUtil_DoFolderDialog(HWND hwndParent, FOLDERID idFolder)
{
FLDRDLG fdlg;
fdlg.idFolder = idFolder;
fdlg.fPending = FALSE;
fdlg.pCallback = new CStoreDlgCB;
if (fdlg.pCallback == NULL)
// TODO: an error message might be nice
return;
DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddNewFolder), hwndParent, MailUtil_FldrDlgProc, (LPARAM)&fdlg);
fdlg.pCallback->Release();
}
// ----------------------------------------------------------------------------------------------------------
// FldrDlgProc
// ----------------------------------------------------------------------------------------------------------
INT_PTR CALLBACK MailUtil_FldrDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PFLDRDLG pfdlg;
TCHAR sz[CCHMAX_STRINGRES];
HWND hwndT;
HRESULT hr;
WORD id;
FOLDERINFO Folder;
Assert(CCHMAX_STRINGRES > CCHMAX_FOLDER_NAME);
switch(msg)
{
case WM_INITDIALOG:
pfdlg = (PFLDRDLG)lParam;
Assert(pfdlg != NULL);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pfdlg);
hwndT = GetDlgItem(hwnd, idtxtFolderName);
Assert(hwndT != NULL);
SetIntlFont(hwndT);
SendMessage(hwndT, EM_LIMITTEXT, CCHMAX_FOLDER_NAME, 0);
LoadString(g_hLocRes, idsRenameFolderTitle, sz, ARRAYSIZE(sz));
SetWindowText(hwnd, sz);
hr = g_pStore->GetFolderInfo(pfdlg->idFolder, &Folder);
if (!FAILED(hr))
{
SetWindowText(hwndT, Folder.pszName);
g_pStore->FreeRecord(&Folder);
}
pfdlg->pCallback->Initialize(hwnd);
SendMessage(hwndT, EM_SETSEL, 0, -1);
CenterDialog(hwnd);
return(TRUE);
case WM_STORE_COMPLETE:
pfdlg = (PFLDRDLG)GetDlgThisPtr(hwnd);
Assert(pfdlg->fPending);
pfdlg->fPending = FALSE;
hr = pfdlg->pCallback->GetResult();
if (hr == S_FALSE)
{
EndDialog(hwnd, IDCANCEL);
}
else if (FAILED(hr))
{
// No need to put up error dialog, CStoreDlgCB already did this on failed OnComplete
/*
AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsErrRenameFld), hr);
*/
hwndT = GetDlgItem(hwnd, idtxtFolderName);
SendMessage(hwndT, EM_SETSEL, 0, -1);
SetFocus(hwndT);
}
else
{
EndDialog(hwnd, IDOK);
}
break;
case WM_COMMAND:
pfdlg = (PFLDRDLG)GetDlgThisPtr(hwnd);
id=GET_WM_COMMAND_ID(wParam, lParam);
if (id == IDOK)
{
if (pfdlg->fPending)
break;
pfdlg->pCallback->Reset();
hwndT = GetDlgItem(hwnd, idtxtFolderName);
GetWindowText(hwndT, sz, ARRAYSIZE(sz));
hr = g_pStore->RenameFolder(pfdlg->idFolder, sz, NOFLAGS, (IStoreCallback *)pfdlg->pCallback);
if (hr == E_PENDING)
{
pfdlg->fPending = TRUE;
}
else if (FAILED(hr))
{
AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsErrRenameFld), hr);
SendMessage(hwndT, EM_SETSEL, 0, -1);
SetFocus(hwndT);
}
else
{
EndDialog(hwnd, IDOK);
}
}
else if (id==IDCANCEL)
{
if (pfdlg->fPending)
pfdlg->pCallback->Cancel();
else
EndDialog(hwnd, IDCANCEL);
}
break;
}
return FALSE;
}
//
// FUNCTION: MailUtil_OnImportAddressBook()
//
// PURPOSE: Calls the WAB migration code to handle import/export.
//
// PARAMETERS:
// <in> fImport - TRUE if we should import, FALSE to export.
//
HRESULT MailUtil_OnImportExportAddressBook(HWND hwnd, BOOL fImport)
{
OFSTRUCT of;
HFILE hfile;
TCHAR szParam[255];
LPTSTR lpParam = fImport ? _T("/import") : _T("/export");
StrCpyN(szParam, lpParam, ARRAYSIZE(szParam));
//MU_GetCurrentUserInfo(szParam+13, ARRAYSIZE(szParam) - 13, NULL, 0);
hfile = OpenFile((TCHAR *)c_szWabMigExe, &of, OF_EXIST);
if (hfile == HFILE_ERROR)
return(E_FAIL);
ShellExecute(hwnd, _T("Open"), of.szPathName, szParam, NULL, SW_SHOWNORMAL);
return(S_OK);
}
HRESULT HrSendWebPageDirect(LPWSTR pwszUrl, HWND hwnd, BOOL fModal, BOOL fMail, FOLDERID folderID,
BOOL fIncludeSig, IUnknown *pUnkPump, IMimeMessage *pMsg)
{
HRESULT hr;
LPSTREAM pstm=NULL;
HCURSOR hcur=0;
INIT_MSGSITE_STRUCT initStruct;
DWORD dwCreateFlags = OENCF_SENDIMMEDIATE|OENCF_USESTATIONERYFONT;
HCHARSET hCharset;
ENCODINGTYPE ietEncoding = IET_DECODED;
BOOL fLittleEndian;
LPSTR pszCharset = NULL;
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
if (!pMsg)
{
//We were not passed pMessage, so we need to create one.
IF_FAILEXIT(hr = HrCreateMessage(&pMsg));
}
else
{
pMsg->AddRef();
}
IF_FAILEXIT(hr = HrCreateBasedWebPage(pwszUrl, &pstm));
if (S_OK == HrIsStreamUnicode(pstm, &fLittleEndian))
{
if (SUCCEEDED(MimeOleFindCharset("utf-8", &hCharset)))
{
pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
}
ietEncoding = IET_UNICODE;
}
else if((S_OK == GetHtmlCharset(pstm, &pszCharset)) && pszCharset)
{
if (SUCCEEDED(MimeOleFindCharset(pszCharset, &hCharset)))
{
pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
}
ietEncoding = IET_INETCSET;
}
IF_FAILEXIT(hr = pMsg->SetTextBody(TXT_HTML, ietEncoding, NULL, pstm, NULL));
initStruct.dwInitType = OEMSIT_MSG;
initStruct.pMsg = pMsg;
initStruct.folderID = folderID;
if (!fIncludeSig)
dwCreateFlags |= OENCF_NOSIGNATURE;
if (fModal)
dwCreateFlags |= OENCF_MODAL;
if (!fMail)
dwCreateFlags |= OENCF_NEWSFIRST;
IF_FAILEXIT(hr = CreateAndShowNote(OENA_STATIONERY, dwCreateFlags, &initStruct, hwnd, pUnkPump));
exit:
if (hcur)
SetCursor(hcur);
ReleaseObj(pMsg);
ReleaseObj(pstm);
return hr;
}
HRESULT HrSendWebPage(HWND hwnd, BOOL fModal, BOOL fMail, FOLDERID folderID, IUnknown *pUnkPump)
{
HRESULT hr;
LPMIMEMESSAGE pMsg=0;
LPSTREAM pstm=0;
INIT_MSGSITE_STRUCT initStruct;
DWORD dwCreateFlags = OENCF_SENDIMMEDIATE;
LPSTR pszCharset;
HCHARSET hCharset;
BOOL fLittleEndian;
ENCODINGTYPE ietEncoding=IET_INETCSET;
if(DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddWebPage), hwnd, WebPageDlgProc, (LPARAM)&pstm)==IDCANCEL)
return NOERROR;
hr=HrCreateMessage(&pMsg);
if (FAILED(hr))
goto error;
// [SBAILEY]: Raid 23209: OE: File/Send Web Page sends all pages as Latin-1 even if they aren't
if (S_OK == HrIsStreamUnicode(pstm, &fLittleEndian))
{
if (SUCCEEDED(MimeOleFindCharset("utf-8", &hCharset)))
{
pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
}
ietEncoding = IET_UNICODE;
}
else if (SUCCEEDED(GetHtmlCharset(pstm, &pszCharset)))
{
if (SUCCEEDED(MimeOleFindCharset(pszCharset, &hCharset)))
{
pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
}
MemFree(pszCharset);
}
hr=pMsg->SetTextBody(TXT_HTML, ietEncoding, NULL, pstm, NULL);
if (FAILED(hr))
goto error;
if (fModal)
dwCreateFlags |= OENCF_MODAL;
if (!fMail)
dwCreateFlags |= OENCF_NEWSFIRST;
initStruct.dwInitType = OEMSIT_MSG;
initStruct.pMsg = pMsg;
initStruct.folderID = folderID;
hr = CreateAndShowNote(OENA_WEBPAGE, dwCreateFlags, &initStruct, hwnd, pUnkPump);
error:
ReleaseObj(pMsg);
ReleaseObj(pstm);
return hr;
}
static const HELPMAP g_rgCtxMapWebPage[] = {
{idTxtWebPage, 50210},
{0, 0}
};
INT_PTR CALLBACK WebPageDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
{
int iTxtLength;
HWND hwndEdit = GetDlgItem(hwnd, idTxtWebPage);
Assert(hwndEdit);
Assert(lParam!= NULL);
SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)lParam);
SendDlgItemMessage(hwnd, idTxtWebPage, EM_LIMITTEXT, MAX_PATH-1, NULL);
SetFocus(hwndEdit);
SHAutoComplete(hwndEdit, SHACF_URLALL);
CenterDialog(hwnd);
return FALSE;
}
case WM_HELP:
case WM_CONTEXTMENU:
return OnContextHelp(hwnd, msg, wParam, lParam, g_rgCtxMapWebPage);
case WM_COMMAND:
{
int id = GET_WM_COMMAND_ID(wParam, lParam);
HWND hwndEdit = GetDlgItem(hwnd, idTxtWebPage);
switch(id)
{
case IDOK:
if (FAILED(HrDlgCreateWebPage(hwnd)))
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsErrSendWebPageUrl), NULL, MB_OK);
SendMessage(hwndEdit, EM_SETSEL, 0, -1);
SetFocus(hwndEdit);
return 0;
}
// fall thro'
case IDCANCEL:
EndDialog(hwnd, id);
break;
}
}
}
return FALSE;
}
static const CHAR c_wszHTTP[] = "http://";
HRESULT HrDlgCreateWebPage(HWND hwndDlg)
{
WCHAR wszUrl[MAX_PATH+1],
wszUrlCanon[MAX_PATH + 10 + 1];
DWORD cCanon = ARRAYSIZE(wszUrlCanon);
LPSTREAM *ppstm = NULL;
HRESULT hr = E_FAIL;
HCURSOR hcur=0;
*wszUrlCanon = 0;
ppstm = (LPSTREAM *)GetWindowLongPtr(hwndDlg, DWLP_USER);
if(!GetWindowTextWrapW(GetDlgItem(hwndDlg, idTxtWebPage), wszUrl, ARRAYSIZE(wszUrl)))
goto exit;
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
IF_FAILEXIT(hr = UrlApplySchemeW(wszUrl, wszUrlCanon, &cCanon, URL_APPLY_DEFAULT|URL_APPLY_GUESSSCHEME|URL_APPLY_GUESSFILE));
// If UrlApplyScheme returns S_FALSE, then it thought that the original works just fine, so use original
IF_FAILEXIT(hr = HrCreateBasedWebPage((S_FALSE == hr) ? wszUrl : wszUrlCanon, ppstm));
exit:
if (hcur)
SetCursor(hcur);
return hr;
}
HRESULT HrSaveMessageInFolder(HWND hwnd, IMessageFolder *pfldr, LPMIMEMESSAGE pMsg,
MESSAGEFLAGS dwFlags, MESSAGEID *pNewMsgid, BOOL fSaveChanges)
{
CStoreCB *pCB;
HRESULT hr;
Assert(pfldr != NULL);
pCB = new CStoreCB;
if (pCB == NULL)
return(E_OUTOFMEMORY);
hr = pCB->Initialize(hwnd, MAKEINTRESOURCE(idsSavingToFolder), TRUE);
if (SUCCEEDED(hr))
{
hr = SaveMessageInFolder((IStoreCallback *)pCB, pfldr, pMsg, dwFlags, pNewMsgid, fSaveChanges);
if (hr == E_PENDING)
hr = pCB->Block();
pCB->Close();
}
pCB->Release();
return(hr);
}
HRESULT SaveMessageInFolder(IStoreCallback *pStoreCB, IMessageFolder *pfldr,
LPMIMEMESSAGE pMsg, MESSAGEFLAGS dwFlags, MESSAGEID *pNewMsgid, BOOL fSaveChanges)
{
// Locals
HRESULT hr=S_OK;
HRESULT hrWarnings=S_OK;
MESSAGEID msgid;
// Trace
TraceCall("HrSaveMessageInFolder");
// Invalid Args
if (pMsg == NULL || pfldr == NULL)
return TraceResult(E_INVALIDARG);
// Don't save changes, then clear the dirty bit
if (FALSE == fSaveChanges)
MimeOleClearDirtyTree(pMsg);
// Save the message
IF_FAILEXIT(hr = pMsg->Commit(0));
// Insert the Message
hr = pfldr->SaveMessage(pNewMsgid, SAVE_MESSAGE_GENID, dwFlags, 0, pMsg, pStoreCB);
exit:
// Done
return (hr == S_OK ? hrWarnings : hr);
}
HRESULT SaveMessageInFolder(IStoreCallback *pStoreCB, FOLDERID idFolder, LPMIMEMESSAGE pMsg,
MESSAGEFLAGS dwFlags, MESSAGEID *pNewMsgid)
{
// Locals
HRESULT hr;
IMessageFolder *pfldr=NULL;
// Open the Folder..
hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pfldr);
if (SUCCEEDED(hr))
{
hr = SaveMessageInFolder(pStoreCB, pfldr, pMsg, dwFlags, pNewMsgid, TRUE);
pfldr->Release();
}
return hr;
}
HRESULT HrSaveMessageInFolder(HWND hwnd, FOLDERID idFolder, LPMIMEMESSAGE pMsg, MESSAGEFLAGS dwFlags,
MESSAGEID *pNewMsgid)
{
// Locals
HRESULT hr;
IMessageFolder *pfldr=NULL;
// Open the Folder..
hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pfldr);
if (SUCCEEDED(hr))
{
hr = HrSaveMessageInFolder(hwnd, pfldr, pMsg, dwFlags, pNewMsgid, TRUE);
pfldr->Release();
}
return hr;
}
HRESULT HrSendMailToOutBox(HWND hwndOwner, LPMIMEMESSAGE pMsg, BOOL fSendImmediate, BOOL fNoUI, BOOL fMail)
{
CStoreCB *pCB;
HRESULT hr;
pCB = new CStoreCB;
if (pCB == NULL)
return(E_OUTOFMEMORY);
hr = pCB->Initialize(hwndOwner, MAKEINTRESOURCE(idsSendingToOutbox), TRUE);
if (SUCCEEDED(hr))
{
hr = SendMailToOutBox((IStoreCallback *)pCB, pMsg, fSendImmediate, fNoUI, fMail);
if (hr == E_PENDING)
hr = pCB->Block();
pCB->Close();
}
pCB->Release();
return(hr);
}
HRESULT SendMailToOutBox(IStoreCallback *pStoreCB, LPMIMEMESSAGE pMsg, BOOL fSendImmediate, BOOL fNoUI, BOOL fMail)
{
HRESULT hr;
FOLDERINFO Outbox;
const TCHAR c_szXMailerAndNewsReader[] = "Microsoft Outlook Express " VER_PRODUCTVERSION_STR;
DWORD dwSendFlags = fMail ? ARF_SUBMITTED|ARF_UNSENT : ARF_SUBMITTED|ARF_UNSENT|ARF_NEWSMSG;
HWND hwnd = 0;
BOOL fSecure = IsSecure(pMsg);
Assert(pStoreCB);
pStoreCB->GetParentWindow(0, &hwnd);
hr = g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_OUTBOX, &Outbox);
if (FAILED(hr))
return hr;
// make sure we never send mail with the X-Unsent header on it.
pMsg->DeleteBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_XUNSENT));
if (fMail)
{
// pound the X-Mailer prop always for anyone going' thro' our spooler.
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_XMAILER), NOFLAGS, c_szXMailerAndNewsReader);
}
else
{
DWORD dwLines;
TCHAR rgch[12];
HrComputeLineCount(pMsg, &dwLines);
wnsprintf(rgch, ARRAYSIZE(rgch), "%d", dwLines);
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_LINES), NOFLAGS, rgch);
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_XNEWSRDR), NOFLAGS, c_szXMailerAndNewsReader);
}
hr = SaveMessageInFolder(pStoreCB, Outbox.idFolder, pMsg, dwSendFlags, NULL);
if (FAILED(hr))
goto error;
// if immediate send is required, tell the spooler to pick up next cycle
// or start a cycle...
if (fSendImmediate)
{
Assert(g_pSpooler);
if (fMail)
g_pSpooler->StartDelivery(hwnd, NULL, FOLDERID_INVALID,
DELIVER_BACKGROUND | DELIVER_QUEUE | DELIVER_MAIL_SEND | DELIVER_NOSKIP);
else
{
PROPVARIANT var;
var.vt = VT_LPSTR;
hr = pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var);
if (FAILED(hr))
var.pszVal = NULL;
if (S_OK == g_pConMan->CanConnect(var.pszVal))
g_pSpooler->StartDelivery(hwnd, var.pszVal, FOLDERID_INVALID,
DELIVER_BACKGROUND | DELIVER_NOSKIP | DELIVER_NEWS_SEND);
else
{
// Warn the user that this message is going to live in their
// outbox for all of eternity
DoDontShowMeAgainDlg(hwnd, c_szDSPostInOutbox,
MAKEINTRESOURCE(idsPostNewsMsg),
MAKEINTRESOURCE(idsPostInOutbox),
MB_OK);
hr = S_FALSE;
}
SafeMemFree(var.pszVal);
}
}
else if (!fNoUI)
{
HWND hwnd = 0;
pStoreCB->GetParentWindow(0, &hwnd);
AssertSz(hwnd, "How did we not get an hwnd???");
// warn the user, before we close if it will be stacked in the outbox.
DoDontShowMeAgainDlg(hwnd, fMail?c_szDSSendMail:c_szDSSendNews,
MAKEINTRESOURCE(fMail?idsSendMail:idsPostNews),
MAKEINTRESOURCE(fMail?idsMailInOutbox:idsPostInOutbox),
MB_OK);
}
error:
// Cleanup
g_pStore->FreeRecord(&Outbox);
return hr;
}
HRESULT HrSetSenderInfoUtil(IMimeMessage *pMsg, IImnAccount *pAccount, LPWABAL lpWabal, BOOL fMail, CODEPAGEID cpID, BOOL fCheckConflictOnly)
{
HRESULT hr = S_OK;
// Don't set any info if no account.
if (pAccount)
{
char szEMail[CCHMAX_EMAIL_ADDRESS] = "";
char szName[CCHMAX_DISPLAY_NAME] = "";
char szOrg[CCHMAX_ORG_NAME] = "";
BOOL fUseEmailAsName = FALSE;
DWORD propID;
if (fCheckConflictOnly)
{
hr = S_OK;
propID = fMail ? AP_SMTP_DISPLAY_NAME : AP_NNTP_DISPLAY_NAME;
if (SUCCEEDED(pAccount->GetPropSz(propID, szName, ARRAYSIZE(szName))) && *szName)
{
IF_FAILEXIT(hr = HrSafeToEncodeToCPA(szName, CP_ACP, cpID));
if (MIME_S_CHARSET_CONFLICT == hr)
goto exit;
}
propID = fMail ? AP_SMTP_ORG_NAME : AP_NNTP_ORG_NAME;
if (SUCCEEDED(pAccount->GetPropSz(propID, szOrg, ARRAYSIZE(szOrg))) && *szOrg)
{
IF_FAILEXIT(hr = HrSafeToEncodeToCPA(szOrg, CP_ACP, cpID));
if (MIME_S_CHARSET_CONFLICT == hr)
goto exit;
}
}
else
{
hr = hrNoSender;
lpWabal->DeleteRecipType(MAPI_REPLYTO);
propID = fMail ? AP_SMTP_EMAIL_ADDRESS : AP_NNTP_EMAIL_ADDRESS;
if (SUCCEEDED(pAccount->GetPropSz(propID, szEMail, ARRAYSIZE(szEMail))) && *szEMail)
{
propID = fMail ? AP_SMTP_DISPLAY_NAME : AP_NNTP_DISPLAY_NAME;
// we've got enough to post
if (FAILED(pAccount->GetPropSz(propID, szName, ARRAYSIZE(szName))) && *szName)
fUseEmailAsName = TRUE;
IF_FAILEXIT(hr = lpWabal->HrAddEntryA(fUseEmailAsName?szEMail:szName, szEMail, MAPI_ORIG));
}
propID = fMail ? AP_SMTP_REPLY_EMAIL_ADDRESS : AP_NNTP_REPLY_EMAIL_ADDRESS;
if (SUCCEEDED(pAccount->GetPropSz(propID, szEMail, ARRAYSIZE(szEMail))) && *szEMail)
IF_FAILEXIT(hr = lpWabal->HrAddEntryA((*szName)?szName:szEMail, szEMail, MAPI_REPLYTO));
propID = fMail ? AP_SMTP_ORG_NAME : AP_NNTP_ORG_NAME;
if (SUCCEEDED(pAccount->GetPropSz(propID, szOrg, ARRAYSIZE(szOrg))) && *szOrg)
{
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_ORG), NOFLAGS, szOrg);
}
}
}
exit:
return hr;
}
// This function takes an existing refererences line and appends a new
// references to the end removing any references necessary.
// NOTE these SHOULD be char and not TCHAR.
HRESULT HrCreateReferences(LPWSTR pszOrigRefs, LPWSTR pszNewRef,
LPWSTR *ppszRefs)
{
UINT cch,
cchOrig,
cchNew;
// Validate the arguements
if (!pszNewRef || !*pszNewRef)
{
AssertSz(FALSE, TEXT("pszNewRef cannot be empty."));
return (E_INVALIDARG);
}
// Figure out how long the new references line must be
cchNew = lstrlenW(pszNewRef);
// It's possible not to have original references if this is the first
// reply to an article.
if (pszOrigRefs && *pszOrigRefs)
cchOrig = lstrlenW(pszOrigRefs);
else
cchOrig = 0;
cch = cchNew + cchOrig + 1; // extra is for the separator space
if (!MemAlloc((LPVOID*) ppszRefs, (cch + 1)*sizeof(WCHAR)))
return (E_OUTOFMEMORY);
// The line length should be < 1000 chars. If it is, this is simple
if (cch <= 1000)
{
if (pszOrigRefs)
wnsprintfW(*ppszRefs, cch+1, L"%s %s", pszOrigRefs, pszNewRef);
else
StrCpyNW(*ppszRefs, pszNewRef, cch+1);
}
// Since cch > 1000, we have some extra work to do.
// We need to remove some references. The Son-of-1036 recommends to leave
// the first and last three. Unless the IDs are greater than 255, we will
// be able to do at least this. Otherwise, we will dump as many ids as
// needed to get below the 1000 char limit.
// For each ID removed, the Son-of-1036 says that we must add 3 spaces in
// place of the removed ID.
else
{
UINT cchMaxWithoutNewRef, // Max length that the orig size can be
cchNewOrigSize = cchOrig; // Size of orig after deletion. Always shows final size
LPWSTR pszNew = *ppszRefs,
pszOld = pszOrigRefs;
BOOL fCopiedFirstValidID = FALSE;
*pszNew = 0;
// Make sure the new ID is not too long. If it is, discard it.
if (cchNew > 255)
{
cchNew = 0;
cchMaxWithoutNewRef = 1000;
}
else
cchMaxWithoutNewRef = 1000 - cchNew - 1; // the space between
// parse the old string looking for ids
// Son-of-1036 says that we must try to keep the first and the most recent
// three IDs. So we will copy in the first valid ID and then follow a FIFO
// algorithm until we can fit the rest of the IDs into the 1000 char limit
while (pszOld && *pszOld)
{
// Is what is left from the original string too big for the left over buffer?
if (cchNewOrigSize >= cchMaxWithoutNewRef)
{
UINT cchEntryLen = 0; // Size of particular entry ID.
// If this is the first ID, make sure we copy into the buffer as we
// get length, as well, add the additional spaces required when any
// deletion will be happening. Since we only delete directly after
// the first valid ID, add the required 3 spaces now
if (!fCopiedFirstValidID)
{
while (*pszOld && *pszOld != L' ')
{
*pszNew++ = *pszOld++;
cchEntryLen++;
}
*pszNew++ = L' ';
*pszNew++ = L' ';
*pszNew++ = L' ';
cchNewOrigSize += 3;
cchEntryLen += 3;
}
// If this in not the first ID, then just skip over it.
else
{
while (*pszOld && *pszOld != L' ')
{
pszOld++;
cchEntryLen++;
}
}
// Skip over whitespace in old references between IDs that
// we are deleting anyway.
while (*pszOld == L' ')
{
pszOld++;
cchNewOrigSize--;
}
// If we already did the first, or the current one is invalid
// we need to do some fix up with sizes. And in the case that
// we copied one that is not valid, we need to reset the pointer
// as well as reset the size.
if (fCopiedFirstValidID || (cchEntryLen > 255))
{
cchNewOrigSize -= cchEntryLen;
// Did we copy an invalid ID?
if (!fCopiedFirstValidID)
pszNew -= cchEntryLen;
}
// If we haven't copied the first one in yet and this
// ID is valid, then remember that we have at this
// point copied the first valid ID.
if (!fCopiedFirstValidID && (cchEntryLen <= 255))
fCopiedFirstValidID = TRUE;
}
else
{
// Since we now have a orig string that will fit in the max allowed,
// just rip through the rest of the orig string and copy.
while (*pszOld)
*pszNew++ = *pszOld++;
}
}
// At this point, pszNew should be pointing the the char directly after
// the last digit. If we add a new reference, then we need to add a space.
// If we don't add a new reference, then we need to null terminate the string.
if (cchNew)
{
// With this assignment, we can end up with 4 spaces in a row if we
// deleted all references after the first valid one was copied. The
// son-of-1036 only specifies minimum of 3 spaces when deleting, so
// we will be OK with that, especially since the only way to get into
// this situation is by forcing the references line into a strange state.
*pszNew++ = L' ';
pszOld = pszNewRef;
while (*pszOld)
*pszNew++ = *pszOld++;
}
// NULL terminate the string of references.
*pszNew = 0;
}
return S_OK;
}