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.
 
 
 
 
 
 

6532 lines
184 KiB

///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil.cpp
//
///////////////////////////////////////////////////////////////////////////////
#include <pch.hxx>
#include "ruleutil.h"
#include "rulesmgr.h"
#include "rulesui.h"
#include "editrule.h"
#include "spamui.h"
#include "viewsui.h"
#include "rule.h"
#include <msoeobj.h>
#include <xpcomm.h>
#include <ipab.h>
#include <pop3task.h>
#include <msgfldr.h>
#include <mimeolep.h>
#include <storecb.h>
#include <menures.h>
#include <hotlinks.h>
#include <menuutil.h>
#include <mru.h>
#include <options.h>
#include <mailutil.h>
#include <secutil.h>
#include "shlwapip.h"
#include "reutil.h"
#include <demand.h>
// Typedefs
typedef enum tagDEF_CRIT_TYPE
{
DEF_CRIT_ALLMSGS = 0,
DEF_CRIT_READ,
DEF_CRIT_DWNLDMSGS,
DEF_CRIT_IGNTHDS
} DEF_CRIT_TYPE;
typedef enum tagDEF_ACT_TYPE
{
DEF_ACT_SHOWMSGS = 0,
DEF_ACT_HIDEMSGS
} DEF_ACT_TYPE;
typedef struct tagDEFAULT_RULE
{
// The rule handle
RULEID ridRule;
// The rule name
UINT idName;
// Which type of criteria for the rule
DEF_CRIT_TYPE critType;
// Which type of actions for the rule
DEF_ACT_TYPE actType;
// The current version number for the rule
DWORD dwVersion;
} DEFAULT_RULE, * PDEFAULT_RULE;
// Constants
static const ULONG CDEF_CRIT_ITEM_MAX = 2;
static const ULONG CDEF_ACT_ITEM_MAX = 1;
static const DWORD DEFAULT_RULE_VERSION = 0x00000004;
static const DEFAULT_RULE g_defruleFilters[] =
{
{RULEID_VIEW_ALL, idsViewAllMessages, DEF_CRIT_ALLMSGS, DEF_ACT_SHOWMSGS, DEFAULT_RULE_VERSION},
{RULEID_VIEW_UNREAD, idsViewUnread, DEF_CRIT_READ, DEF_ACT_HIDEMSGS, DEFAULT_RULE_VERSION},
{RULEID_VIEW_DOWNLOADED, idsViewDownloaded, DEF_CRIT_DWNLDMSGS, DEF_ACT_SHOWMSGS, DEFAULT_RULE_VERSION},
{RULEID_VIEW_IGNORED, idsViewNoIgnored, DEF_CRIT_IGNTHDS, DEF_ACT_HIDEMSGS, DEFAULT_RULE_VERSION}
};
static const CHAR g_szOrderFilterDef[] = "FFA FFB FFC FFF";
static const ULONG RULE_FILE_VERSION = 0x00050000;
static const char c_szLeftParen[] = "(";
static const char c_szRightParen[] = ")";
static const char c_szDoubleQuote[] = "\"";
static const char c_szLogicalAnd[] = " && ";
static const char c_szLogicalOr[] = " || ";
static const char c_szFilterRead[] = "(0 != (MSGCOL_FLAGS & ARF_READ))";
static const char c_szFilterNotRead[] = "(0 == (MSGCOL_FLAGS & ARF_READ))";
static const char c_szFilterDeleted[] = "(0 != (MSGCOL_FLAGS & ARF_ENDANGERED))";
static const char c_szFilterNotDeleted[] = "(0 == (MSGCOL_FLAGS & ARF_ENDANGERED))";
static const char c_szFilterDownloaded[] = "(0 != (MSGCOL_FLAGS & ARF_HASBODY))";
static const char c_szFilterNotDownloaded[] = "(0 == (MSGCOL_FLAGS & ARF_HASBODY))";
static const char c_szFilterWatched[] = "(0 != (MSGCOL_FLAGS & ARF_WATCH))";
static const char c_szFilterIgnored[] = "(0 != (MSGCOL_FLAGS & ARF_IGNORE))";
static const char c_szFilterAttach[] = "(0 != (MSGCOL_FLAGS & ARF_HASATTACH))";
static const char c_szFilterSigned[] = "(0 != (MSGCOL_FLAGS & ARF_SIGNED))";
static const char c_szFilterEncrypt[] = "(0 != (MSGCOL_FLAGS & ARF_ENCRYPTED))";
static const char c_szFilterFlagged[] = "(0 != (MSGCOL_FLAGS & ARF_FLAGGED))";
static const char c_szFilterNotFlagged[] = "(0 == (MSGCOL_FLAGS & ARF_FLAGGED))";
static const char c_szFilterPriorityHi[] = "(MSGCOL_PRIORITY == IMSG_PRI_HIGH)";
static const char c_szFilterPriorityLo[] = "(MSGCOL_PRIORITY == IMSG_PRI_LOW)";
static const char c_szFilterReplyPost[] = "(0 != IsReplyPostVisible)";
static const char c_szFilterNotReplyPost[] = "(0 == IsReplyPostVisible)";
static const char c_szFilterShowAll[] = "(0 == 0)";
static const char c_szFilterHideAll[] = "(0 != 0)";
static const char c_szFilterHide[] = "0 == ";
static const char c_szFilterShow[] = "0 != ";
static const char c_szEmailFromAddrPrefix[] = "(MSGCOL_EMAILFROM containsi ";
static const char c_szEmailSubjectPrefix[] = "(MSGCOL_SUBJECT containsi ";
static const char c_szEmailAcctPrefix[] = "(MSGCOL_ACCOUNTID containsi ";
static const char c_szEmailFromPrefix[] = "(MSGCOL_DISPLAYFROM containsi ";
static const char c_szEmailLinesPrefix[] = "(MSGCOL_LINECOUNT > ";
static const char c_szFilterReplyChild[] = "(0 != (MSGCOL_FLAGS & ARF_HASCHILDREN))";
static const char c_szFilterReplyRoot[] = "(0 != MSGCOL_PARENT)";
static const char c_szEmailAgePrefix[] = "(MessageAgeInDays > ";
void DoMessageRulesDialog(HWND hwnd, DWORD dwFlags)
{
COERulesMgrUI * pRulesMgrUI = NULL;
if (NULL == hwnd)
{
goto exit;
}
// Create the rules UI object
pRulesMgrUI = new COERulesMgrUI;
if (NULL == pRulesMgrUI)
{
goto exit;
}
if (FAILED(pRulesMgrUI->HrInit(hwnd, dwFlags)))
{
goto exit;
}
pRulesMgrUI->HrShow();
exit:
if (NULL != pRulesMgrUI)
{
delete pRulesMgrUI;
}
return;
}
HRESULT HrDoViewsManagerDialog(HWND hwnd, DWORD dwFlags, RULEID * pridRule, BOOL * pfApplyAll)
{
HRESULT hr = S_OK;
COEViewsMgrUI * pViewsMgrUI = NULL;
if ((NULL == hwnd) || (NULL == pfApplyAll))
{
hr = E_INVALIDARG;
goto exit;
}
// Create the rules UI object
pViewsMgrUI = new COEViewsMgrUI;
if (NULL == pViewsMgrUI)
{
hr = E_OUTOFMEMORY;
goto exit;
}
hr = pViewsMgrUI->HrInit(hwnd, dwFlags, pridRule);
if (FAILED(hr))
{
goto exit;
}
hr = pViewsMgrUI->HrShow(pfApplyAll);
exit:
if (NULL != pViewsMgrUI)
{
delete pViewsMgrUI;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// HrCreateRuleFromMessage
//
// This creates a rules editor of the proper type.
//
// hwnd - The owner dialog
// dwFlags - What type of editor to bring up
// pmsginfo - The message information
// pMsgList - The owner of the message
//
// Returns: S_OK, on success
// E_OUTOFMEMORY, if can't create the Rules Manager object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT HrCreateRuleFromMessage(HWND hwnd, DWORD dwFlags, MESSAGEINFO * pmsginfo, IMimeMessage * pMessage)
{
HRESULT hr = S_OK;
CEditRuleUI * pEditRuleUI = NULL;
IOERule * pIRule = NULL;
UINT uiStrId = 0;
TCHAR szRes[CCHMAX_STRINGRES + 5];
ULONG cchRes = 0;
ULONG ulIndex = 0;
TCHAR szName[CCHMAX_STRINGRES + 5];
RULE_TYPE typeRule = RULE_TYPE_MAIL;
IOERule * pIRuleFound = NULL;
PROPVARIANT propvar = {0};
LPSTR pszEmailFrom = NULL;
ADDRESSPROPS rSender = {0};
RULEINFO infoRule = {0};
BYTE * pBlobData = NULL;
ULONG cbSize = 0;
Assert(NULL != g_pMoleAlloc);
Assert(NULL != g_pRulesMan);
// Check incoming params
if ((NULL == hwnd) || (NULL == pmsginfo))
{
hr = E_INVALIDARG;
goto exit;
}
// Create a rules editor object
pEditRuleUI = new CEditRuleUI;
if (NULL == pEditRuleUI)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Create a new rule object
hr = HrCreateRule(&pIRule);
if (FAILED(hr))
{
goto exit;
}
// Figure out the string Id
if (0 != (dwFlags & CRFMF_NEWS))
{
uiStrId = idsRuleNewsDefaultName;
typeRule = RULE_TYPE_NEWS;
}
else
{
uiStrId = idsRuleMailDefaultName;
typeRule = RULE_TYPE_MAIL;
}
// Figure out the name of the new rule ...
cchRes = LoadString(g_hLocRes, uiStrId, szRes, ARRAYSIZE(szRes));
if (0 == cchRes)
{
hr = E_FAIL;
goto exit;
}
ulIndex = 1;
wnsprintf(szName, ARRAYSIZE(szName), szRes, ulIndex);
// Make sure the name is unique
while (S_OK == g_pRulesMan->FindRule(szName, typeRule, &pIRuleFound))
{
pIRuleFound->Release();
pIRuleFound = NULL;
ulIndex++;
wnsprintf(szName, ARRAYSIZE(szName), szRes, ulIndex);
}
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_LPSTR;
propvar.pszVal = szName;
// Set the rule name
hr = pIRule->SetProp(RULE_PROP_NAME, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
if ((NULL == pmsginfo->pszEmailFrom) || (FALSE != FIsEmpty(pmsginfo->pszEmailFrom)))
{
// Get the load interface from the preview pane object
if (NULL != pMessage)
{
rSender.dwProps = IAP_EMAIL;
pMessage->GetSender(&rSender);
Assert(rSender.pszEmail && ISFLAGSET(rSender.dwProps, IAP_EMAIL));
pszEmailFrom = rSender.pszEmail;
}
}
else
{
pszEmailFrom = pmsginfo->pszEmailFrom;
}
if (NULL != pszEmailFrom)
{
// Create space to hold the email address
if (FALSE == FIsEmpty(pszEmailFrom))
{
cbSize = lstrlen(pszEmailFrom) + 3;
if (SUCCEEDED(HrAlloc((VOID **) &pBlobData, cbSize)))
{
StrCpyN((LPSTR) pBlobData, pszEmailFrom, cbSize);
pBlobData[cbSize - 2] = '\0';
pBlobData[cbSize - 1] = '\0';
}
else
{
cbSize = 0;
}
}
}
if (0 != cbSize)
{
CRIT_ITEM citemFrom;
// Set the default criteria on the rule
ZeroMemory(&citemFrom, sizeof(citemFrom));
citemFrom.type = CRIT_TYPE_FROM;
citemFrom.logic = CRIT_LOGIC_NULL;
citemFrom.dwFlags = CRIT_FLAG_DEFAULT;
citemFrom.propvar.vt = VT_BLOB;
citemFrom.propvar.blob.cbSize = cbSize;
citemFrom.propvar.blob.pBlobData = pBlobData;
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_BLOB;
propvar.blob.cbSize = sizeof(citemFrom);
propvar.blob.pBlobData = (BYTE *) &citemFrom;
hr = pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
}
// Initialize the editor object
hr = pEditRuleUI->HrInit(hwnd, ERF_NEWRULE, typeRule, pIRule, NULL);
if (FAILED(hr))
{
goto exit;
}
// Bring up the rules editor UI
hr = pEditRuleUI->HrShow();
if (FAILED(hr))
{
goto exit;
}
if (S_OK == hr)
{
// Initialize the rule info
infoRule.pIRule = pIRule;
infoRule.ridRule = RULEID_INVALID;
// Add the rule to the list of rules
hr = g_pRulesMan->SetRules(SETF_APPEND, typeRule, &infoRule, 1);
if(FAILED(hr))
{
goto exit;
}
}
exit:
SafeMemFree(pBlobData);
g_pMoleAlloc->FreeAddressProps(&rSender);
SafeRelease(pIRule);
if (NULL != pEditRuleUI)
{
delete pEditRuleUI;
}
if (S_OK == hr)
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsRuleAdded), NULL, MB_OK | MB_ICONINFORMATION);
}
else if (FAILED(hr))
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsCreateRuleError), NULL, MB_OK | MB_ICONERROR);
}
return hr;
}
HRESULT HrBlockSendersFromFolder(HWND hwnd, DWORD dwFlags, FOLDERID idFolder, LPSTR * ppszSender, ULONG cpszSender)
{
HRESULT hr = S_OK;
IMessageFolder * pFolder = NULL;
FOLDERINFO infoFolder = {0};
CProgress * pProgress = NULL;
IOERule * pIRule = NULL;
CRIT_ITEM * pCritItem = NULL;
ULONG cCritItem = 0;
ULONG ulIndex = 0;
PROPVARIANT propvar = {0};
CExecRules * pExecRules = NULL;
RULENODE rnode = {0};
IOEExecRules * pIExecRules = NULL;
CHAR rgchTmpl[CCHMAX_STRINGRES];
LPSTR pszText = NULL;
// Check incoming params
if ((NULL == hwnd) || (FOLDERID_INVALID == idFolder) || (NULL == ppszSender) || (0 == cpszSender))
{
hr = E_INVALIDARG;
goto exit;
}
// Open up the folder
hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pFolder);
if (FAILED(hr))
{
goto exit;
}
hr = g_pStore->GetFolderInfo(idFolder, &infoFolder);
if (FAILED(hr))
{
goto exit;
}
// Create the progress dialog
pProgress = new CProgress;
if (NULL == pProgress)
{
hr = E_OUTOFMEMORY;
goto exit;
}
pProgress->Init(hwnd, MAKEINTRESOURCE(idsAthena), MAKEINTRESOURCE(idsSendersApplyProgress), infoFolder.cMessages, 0, TRUE, FALSE);
// Create the Block Sender rule
hr = RuleUtil_HrCreateSendersRule(0, &pIRule);
if (FAILED(hr))
{
goto exit;
}
// Allocate space to hold all the senders
hr = HrAlloc((VOID **) &pCritItem, sizeof(*pCritItem) * cpszSender);
if (FAILED(hr))
{
goto exit;
}
// Initialize it
ZeroMemory(pCritItem, sizeof(*pCritItem) * cpszSender);
// Add in each of the criteria
for (ulIndex = 0; ulIndex < cpszSender; ulIndex++, ppszSender++)
{
if ((NULL != *ppszSender) && ('\0' != (*ppszSender)[0]))
{
pCritItem[cCritItem].type = CRIT_TYPE_SENDER;
pCritItem[cCritItem].logic = CRIT_LOGIC_OR;
pCritItem[cCritItem].dwFlags = CRIT_FLAG_DEFAULT;
pCritItem[cCritItem].propvar.vt = VT_LPSTR;
pCritItem[cCritItem].propvar.pszVal = *ppszSender;
cCritItem++;
}
}
// Do we need to do anything?
if (0 == cCritItem)
{
hr = E_FAIL;
goto exit;
}
// Set the senders into the rule
propvar.vt = VT_BLOB;
propvar.blob.cbSize = sizeof(*pCritItem) * cCritItem;
propvar.blob.pBlobData = (BYTE *) pCritItem;
hr = pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
// Create the rule executor
pExecRules = new CExecRules;
if (NULL == pExecRules)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize the rule executor
rnode.pIRule = pIRule;
hr = pExecRules->_HrInitialize(0, &rnode);
if (FAILED(hr))
{
goto exit;
}
// Get the rule executor interface
hr = pExecRules->QueryInterface(IID_IOEExecRules, (void **) &pIExecRules);
if (FAILED(hr))
{
goto exit;
}
pExecRules = NULL;
// Show dialog in 2 second
pProgress->Show(0);
hr = RuleUtil_HrApplyRulesToFolder(RULE_APPLY_SHOWUI, (FOLDER_LOCAL != infoFolder.tyFolder) ? DELETE_MESSAGE_NOTRASHCAN : 0,
pIExecRules, pFolder, pProgress->GetHwnd(), pProgress);
// Close the progress window
pProgress->Close();
if (FAILED(hr))
{
goto exit;
}
// Show confirmation dialog
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsSendersApplySuccess), NULL, MB_OK | MB_ICONINFORMATION);
hr = S_OK;
exit:
SafeMemFree(pszText);
SafeRelease(pIExecRules);
if (NULL != pExecRules)
{
delete pExecRules;
}
SafeMemFree(pCritItem);
SafeRelease(pIRule);
SafeRelease(pProgress);
g_pStore->FreeRecord(&infoFolder);
SafeRelease(pFolder);
if (FAILED(hr))
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsSendersApplyFail), NULL, MB_OK | MB_ICONERROR);
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// HrCreateRulesManager
//
// This creates a rules manager.
//
// pIUnkOuter - For aggregation, it must be NULL
// ppIUnknown - The interface the was created
//
// Returns: S_OK, on success
// E_OUTOFMEMORY, if can't create the Rules Manager object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT HrCreateRulesManager(IUnknown * pIUnkOuter, IUnknown ** ppIUnknown)
{
HRESULT hr = S_OK;
CRulesManager * pRulesManager = NULL;
IOERulesManager * pIRulesMgr = NULL;
// Check the incoming params
if (NULL == ppIUnknown)
{
hr = E_INVALIDARG;
goto exit;
}
Assert(NULL == pIUnkOuter);
// Initialize outgoing params
*ppIUnknown = NULL;
// Create the rules manager object
pRulesManager = new CRulesManager;
if (NULL == pRulesManager)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Get the rules manager interface
hr = pRulesManager->QueryInterface(IID_IOERulesManager, (void **) &pIRulesMgr);
if (FAILED(hr))
{
goto exit;
}
pRulesManager = NULL;
*ppIUnknown = static_cast<IUnknown *>(pIRulesMgr);
pIRulesMgr = NULL;
// Set the proper return value
hr = S_OK;
exit:
SafeRelease(pIRulesMgr);
if (NULL != pRulesManager)
{
delete pRulesManager;
}
return hr;
}
HRESULT RuleUtil_HrBuildEmailString(LPWSTR pwszText, ULONG cchText, LPWSTR * ppwszEmail, ULONG * pcchEmail)
{
HRESULT hr = S_OK;
WCHAR wszParseSep[16];
LPWSTR pwszAddr = NULL,
pwszTerm = NULL,
pwszWalk = NULL,
pwszStrip = NULL;
ULONG cchParse = 0;
// Check incoming params
if ((NULL == pwszText) || (NULL == ppwszEmail))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppwszEmail = NULL;
if (NULL != pcchEmail)
{
*pcchEmail = 0;
}
// Grab the terminator
cchParse = LoadStringWrapW(g_hLocRes, idsEmailParseSep, wszParseSep, ARRAYSIZE(wszParseSep));
Assert(cchParse != 0);
// The output string is at least as long as the imput string
pwszAddr = PszDupW(pwszText);
if (NULL == pwszAddr)
{
hr = E_OUTOFMEMORY;
goto exit;
}
DWORD cchSizeAddr = (lstrlenW(pwszAddr) + 1);
DWORD cchSizeWalk = cchSizeAddr;
pwszAddr[0] = L'\0';
pwszTerm = pwszText;
pwszWalk = pwszAddr;
while (NULL != pwszTerm)
{
pwszStrip = pwszWalk;
pwszTerm = StrStrW(pwszText, wszParseSep);
if (L'\0' != pwszAddr[0])
{
StrCpyNW(pwszWalk, g_wszComma, cchSizeWalk);
pwszStrip++;
}
if (NULL == pwszTerm)
{
StrCatBuffW(pwszWalk, pwszText, cchSizeWalk);
}
else
{
StrNCatW(pwszWalk, pwszText, (int)(pwszTerm - pwszText + 1));
pwszTerm += cchParse;
pwszText = pwszTerm;
}
if (0 == UlStripWhitespaceW(pwszStrip, TRUE, TRUE, NULL))
{
*pwszWalk = '\0';
}
cchSizeWalk -= lstrlenW(pwszWalk);
pwszWalk += lstrlenW(pwszWalk);
}
// Set the outgoing params
if (NULL != pcchEmail)
{
*pcchEmail = lstrlenW(pwszAddr);
}
*ppwszEmail = pwszAddr;
pwszAddr = NULL;
// Set proper return value
hr = S_OK;
exit:
SafeMemFree(pwszAddr);
return hr;
}
HRESULT RuleUtil_HrParseEmailString(LPWSTR pwszEmail, ULONG cchEmail, LPWSTR *ppwszOut, ULONG * pcchOut)
{
HRESULT hr = S_OK;
LPWSTR pwszText = NULL,
pwszTerm = NULL;
ULONG cchText = 0;
ULONG ulIndex = 0;
ULONG ulTerm = 0;
WCHAR wszSep[16];
ULONG cchSep = 0;
// Check incoming params
if ((NULL == pwszEmail) || (NULL == ppwszOut))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppwszOut = NULL;
if (NULL != pcchOut)
{
*pcchOut = 0;
}
// Make sure we know how big the input string is
if (0 == cchEmail)
{
cchEmail = (ULONG) lstrlenW(pwszEmail);
}
cchText = cchEmail;
pwszTerm = pwszEmail;
// Figure out the space needed to hold the new addresses
while (NULL != pwszTerm)
{
pwszTerm = StrStrW(pwszTerm, g_wszComma);
if (NULL != pwszTerm)
{
cchText++;
pwszTerm++;
}
}
// Grab the terminator
LoadStringWrapW(g_hLocRes, idsEmailSep, wszSep, ARRAYSIZE(wszSep));
cchSep = lstrlenW(wszSep);
// The output string is at least as long as the imput string
hr = HrAlloc((void **) &pwszText, (cchText + 1)*sizeof(*pwszText));
if (FAILED(hr))
{
goto exit;
}
pwszText[0] = L'\0';
pwszTerm = pwszEmail;
cchText++;
while (NULL != pwszTerm)
{
pwszTerm = StrStrW(pwszEmail, g_wszComma);
if (NULL != pwszTerm)
{
pwszTerm++;
StrNCatW(pwszText, pwszEmail, (int)(pwszTerm - pwszEmail));
StrCatBuffW(pwszText, wszSep, cchText);
pwszEmail = pwszTerm;
}
else
{
StrCatBuffW(pwszText, pwszEmail, cchText);
}
}
// Terminate the string
cchText = lstrlenW(pwszText);
// Set the outgoing param
*ppwszOut = pwszText;
pwszText = NULL;
if (NULL != pcchOut)
{
*pcchOut = cchText;
}
// Set proper return value
hr = S_OK;
exit:
SafeMemFree(pwszText);
return hr;
}
HRESULT RuleUtil_HrBuildTextString(LPTSTR pszIn, ULONG cchIn, LPTSTR * ppszText, ULONG * pcchText)
{
HRESULT hr = S_OK;
LPTSTR pszText = NULL;
LPTSTR pszTerm = NULL;
LPTSTR pszWalk = NULL;
LPTSTR pszStrip = NULL;
ULONG cchSpace = 0;
// Check incoming params
if ((NULL == pszIn) || (NULL == ppszText))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppszText = NULL;
if (NULL != pcchText)
{
*pcchText = 0;
}
// The output string is at least as long as the imput string
pszText = PszDupA(pszIn);
if (NULL == pszText)
{
hr = E_OUTOFMEMORY;
goto exit;
}
pszText[0] = '\0';
pszTerm = pszIn;
pszWalk = pszText;
cchSpace = lstrlen(g_szSpace);
DWORD cchSize = lstrlen(pszIn)+1;
while ('\0' != *pszTerm)
{
pszStrip = pszWalk;
pszTerm = pszIn;
while(('\0' != *pszTerm) && (FALSE == FIsSpaceA(pszTerm)))
{
pszTerm = CharNext(pszTerm);
}
if ('\0' != pszText[0])
{
StrCpyN(pszWalk, g_szSpace, cchSize);
pszStrip += cchSpace;
}
if ('\0' == *pszTerm)
{
StrCatBuff(pszWalk, pszIn, cchSize);
}
else
{
pszTerm = CharNext(pszTerm);
StrNCat(pszWalk, pszIn, (int)(pszTerm - pszIn));
pszIn = pszTerm;
}
if (0 == UlStripWhitespace(pszStrip, TRUE, TRUE, NULL))
{
*pszWalk = '\0';
}
cchSize -= lstrlen(pszWalk);
pszWalk += lstrlen(pszWalk);
}
// Set the outgoing params
if (NULL != pcchText)
{
*pcchText = lstrlen(pszText);
}
*ppszText = pszText;
pszText = NULL;
// Set proper return value
hr = S_OK;
exit:
SafeMemFree(pszText);
return hr;
}
// -------------------------------------------------------------------------------------------
// HrDlgRuleGetString
// -------------------------------------------------------------------------------------------
HRESULT RuleUtil_HrGetDlgString(HWND hwndDlg, UINT uiCtlId, LPTSTR *ppszText, ULONG * pcchText)
{
HRESULT hr = S_OK;
HWND hwndCtl = NULL;
LPTSTR pszText = NULL;
ULONG cchText = 0;
// Check the incoming params
if ((NULL == hwndDlg) || (NULL == ppszText))
{
hr = E_INVALIDARG;
goto exit;
}
Assert(FALSE != IsWindow(hwndDlg));
// Init the output params
*ppszText = NULL;
if (NULL != pcchText)
{
*pcchText = 0;
}
// Get the dialog control
hwndCtl = GetDlgItem(hwndDlg, uiCtlId);
if (NULL == hwndCtl)
{
hr = E_FAIL;
goto exit;
}
// Get text length
cchText = (ULONG) SendMessage(hwndCtl, WM_GETTEXTLENGTH, 0, 0);
hr = HrAlloc((void **) &pszText, cchText + 1);
if (FAILED(hr))
{
goto exit;
}
GetDlgItemText(hwndDlg, uiCtlId, pszText, cchText + 1);
// Set the output params
*ppszText = pszText;
pszText = NULL;
if (NULL != pcchText)
{
*pcchText = cchText;
}
// Set the proper return value
hr = S_OK;
exit:
SafeMemFree(pszText);
return hr;
}
HRESULT RuleUtil_HrGetRegValue(HKEY hkey, LPCSTR pszValueName, DWORD * pdwType, BYTE ** ppbData, ULONG * pcbData)
{
HRESULT hr = S_OK;
LONG lErr = ERROR_SUCCESS;
ULONG cbData = 0;
BYTE * pbData = NULL;
// Check incoming params
if (NULL == ppbData)
{
hr = E_FAIL;
goto exit;
}
// Figure out the space to hold the criteria order
lErr = SHQueryValueEx(hkey, pszValueName, 0, pdwType, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Allocate the space to hold the criteria order
hr = HrAlloc((void **) &pbData, cbData);
if (FAILED(hr))
{
goto exit;
}
// Get the criteria order
lErr = SHQueryValueEx(hkey, pszValueName, 0, pdwType, pbData, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Return the values
*ppbData = pbData;
pbData = NULL;
if (NULL != pcbData)
{
*pcbData = cbData;
}
exit:
SafeMemFree(pbData);
return hr;
}
// -------------------------------------------------------------------------------------------
// RuleUtil_HrGetAddressesFromWAB
// -------------------------------------------------------------------------------------------
HRESULT RuleUtil_HrGetAddressesFromWAB(HWND hwndDlg, LONG lRecipType, UINT uidsWellButton, LPWSTR *ppwszAddrs)
{
HRESULT hr = S_OK;
CWabal *pWabal = NULL,
*pWabalExpand = NULL;
LPWSTR pwszText = NULL,
pwszLoop = NULL;
BOOL fFound = FALSE,
fBadAddrs = FALSE;
ULONG cchText = 0;
ADRINFO adrInfo = {0};
// Check the incoming params
if ((NULL == hwndDlg) || (NULL == ppwszAddrs))
{
hr = E_INVALIDARG;
goto exit;
}
Assert(FALSE != IsWindow(hwndDlg));
// Create Wabal Object
hr = HrCreateWabalObject(&pWabal);
if (FAILED(hr))
{
goto exit;
}
// If we have a string then add it to the wabal object
if (NULL != *ppwszAddrs)
{
for (pwszLoop = *ppwszAddrs; L'\0' != pwszLoop[0]; pwszLoop += lstrlenW(pwszLoop) + 1)
pWabal->HrAddEntry(pwszLoop, pwszLoop, lRecipType);
}
// Let's go pick some new names
hr = pWabal->HrRulePickNames(hwndDlg, lRecipType, idsRuleAddrCaption, idsRuleAddrWell, uidsWellButton);
if (FAILED(hr))
{
goto exit;
}
// Figure out the space needed to hold the new addresses
// Create the expanded Wabal Object
hr = HrCreateWabalObject(&pWabalExpand);
if (FAILED(hr))
{
goto exit;
}
//Expand the groups to addresses...
hr = pWabal->HrExpandTo(pWabalExpand);
if (FAILED(hr))
{
goto exit;
}
SafeRelease(pWabal);
cchText = 0;
fFound = pWabalExpand->FGetFirst(&adrInfo);
while(FALSE != fFound)
{
if ((NULL != adrInfo.lpwszAddress) && (L'\0' != adrInfo.lpwszAddress[0]))
{
cchText += lstrlenW(adrInfo.lpwszAddress) + 1;
}
else
{
fBadAddrs = TRUE;
}
// Get the next address
fFound = pWabalExpand->FGetNext(&adrInfo);
}
// Add space for the terminator
cchText += 2;
// Allocate the new space
hr = HrAlloc((void **) &pwszText, cchText*sizeof(WCHAR));
if (FAILED(hr))
{
goto exit;
}
pwszText[0] = L'\0';
// Build up the new string
pwszLoop = pwszText;
DWORD cchLoop = cchText;
fFound = pWabalExpand->FGetFirst(&adrInfo);
while(FALSE != fFound)
{
if ((NULL != adrInfo.lpwszAddress) && (L'\0' != adrInfo.lpwszAddress[0]))
{
StrCpyNW(pwszLoop, adrInfo.lpwszAddress, cchLoop);
cchLoop -= (lstrlenW(adrInfo.lpwszAddress) + 1);
pwszLoop += (lstrlenW(adrInfo.lpwszAddress) + 1);
}
else
{
fBadAddrs = TRUE;
}
// Get the next address
fFound = pWabalExpand->FGetNext(&adrInfo);
}
// Terminate the string
pwszLoop[0] = L'\0';
pwszLoop[1] = L'\0';
// Set the outgoing param
if (NULL != *ppwszAddrs)
{
MemFree(*ppwszAddrs);
}
*ppwszAddrs = pwszText;
pwszText = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (FALSE != fBadAddrs)
{
AthMessageBoxW(hwndDlg, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsRulesWarnEmptyEmail), NULL, MB_ICONINFORMATION | MB_OK);
}
MemFree(pwszText);
ReleaseObj(pWabal);
ReleaseObj(pWabalExpand);
return hr;
}
// -------------------------------------------------------------------------------------------
// FPickEMailNames
// -------------------------------------------------------------------------------------------
HRESULT RuleUtil_HrPickEMailNames(HWND hwndDlg, LONG lRecipType, UINT uidsWellButton, LPWSTR *ppwszAddrs)
{
HRESULT hr = S_OK;
CWabal *pWabal = NULL,
*pWabalExpand = NULL;
LPWSTR pwszText = NULL,
pwszNames = NULL,
pwszLoop = NULL,
pwszTerm = NULL;
ULONG cchText = 0,
cchSep = 0;
BOOL fFound = FALSE,
fAddSep = FALSE,
fBadAddrs = FALSE;
ADRINFO adrInfo;
// Check the incoming params
if ((NULL == hwndDlg) || (NULL == ppwszAddrs))
{
hr = E_INVALIDARG;
goto exit;
}
Assert(FALSE != IsWindow(hwndDlg));
// Create Wabal Object
hr = HrCreateWabalObject(&pWabal);
if (FAILED(hr))
{
goto exit;
}
// If we have a string then add it to the wabal object
if ((NULL != *ppwszAddrs) && (L'\0' != **ppwszAddrs))
{
pwszNames = PszDupW(*ppwszAddrs);
pwszTerm = pwszNames;
for (pwszLoop = pwszNames; NULL != pwszTerm; pwszLoop += lstrlenW(pwszLoop) + 1)
{
// Terminate the address
pwszTerm = StrStrW(pwszLoop, g_wszComma);
if (NULL != pwszTerm)
{
*pwszTerm = L'\0';
}
pWabal->HrAddEntry(pwszLoop, pwszLoop, lRecipType);
}
SafeMemFree(pwszNames);
}
// Let's go pick some new names
hr = pWabal->HrRulePickNames(hwndDlg, lRecipType, idsRuleAddrCaption, idsRuleAddrWell, uidsWellButton);
if (FAILED(hr))
{
goto exit;
}
// Figure out the space needed to hold the new addresses
// Create the expanded Wabal Object
hr = HrCreateWabalObject(&pWabalExpand);
if (FAILED(hr))
{
goto exit;
}
//Expand the groups to addresses...
hr = pWabal->HrExpandTo(pWabalExpand);
if (FAILED(hr))
{
goto exit;
}
SafeRelease(pWabal);
// Load the email seperator
cchSep = lstrlenW(g_wszComma);
cchText = 0;
fFound = pWabalExpand->FGetFirst(&adrInfo);
while(FALSE != fFound)
{
if (NULL != adrInfo.lpwszAddress)
{
cchText += lstrlenW(adrInfo.lpwszAddress) + cchSep;
}
else
{
fBadAddrs = TRUE;
}
// Get the next address
fFound = pWabalExpand->FGetNext(&adrInfo);
}
// Allocate the new space
hr = HrAlloc((void **) &pwszText, (cchText + 1)*sizeof(*pwszText));
if (FAILED(hr))
{
goto exit;
}
pwszText[0] = L'\0';
// Build up the new string
DWORD cchBufSize = cchText+1;
cchText = 0;
fFound = pWabalExpand->FGetFirst(&adrInfo);
while(FALSE != fFound)
{
if (NULL != adrInfo.lpwszAddress)
{
if (FALSE == fAddSep)
{
fAddSep = TRUE;
}
else
{
StrCatBuffW(pwszText, g_wszComma, cchBufSize);
cchText += cchSep;
}
StrCatBuffW(pwszText, adrInfo.lpwszAddress, cchBufSize);
cchText += lstrlenW(adrInfo.lpwszAddress);
}
else
{
fBadAddrs = TRUE;
}
// Get the next address
fFound = pWabalExpand->FGetNext(&adrInfo);
}
// Set the outgoing param
if (NULL != *ppwszAddrs)
{
MemFree(*ppwszAddrs);
}
*ppwszAddrs = pwszText;
pwszText = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (FALSE != fBadAddrs)
{
AthMessageBoxW(hwndDlg, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsRulesWarnEmptyEmail), NULL, MB_ICONINFORMATION | MB_OK);
}
SafeMemFree(pwszText);
SafeRelease(pWabal);
SafeRelease(pWabalExpand);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil_FEnDisDialogItem
//
// This enables or disables a control in a dialog.
// The real special thing this function does is make sure
// the focus of the dialog isn't stuck in a disabled control
//
// Returns: TRUE, if the enabled state was changed
// FALSE, otherwise
//
///////////////////////////////////////////////////////////////////////////////
BOOL RuleUtil_FEnDisDialogItem(HWND hwndDlg, UINT idcItem, BOOL fEnable)
{
BOOL fRet = FALSE;
HWND hwndFocus = NULL;
HWND hwndItem = NULL;
// check params
if (NULL == hwndDlg)
{
fRet = FALSE;
goto exit;
}
hwndItem = GetDlgItem(hwndDlg, idcItem);
// Make sure we aren't disabling the window with the focus
if ((FALSE == fEnable) && (hwndItem == GetFocus()))
{
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) 0, (LPARAM) LOWORD(FALSE));
}
// Enable or disable the window
EnableWindow(hwndItem, fEnable);
exit:
return fRet;
}
///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil_AppendRichEditText
//
// This sets a string into a richedit control with the proper style.
//
// Returns: S_OK, if the string was set
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RuleUtil_AppendRichEditText(HWND hwndRedit, ULONG ulStart, LPCWSTR pwszText, CHARFORMAT *pchfmt)
{
CHARFORMAT chFmtDef = {0};
HRESULT hr = S_OK;
ULONG cchText = 0;
CHARRANGE chrg = {0};
// check params
Assert(hwndRedit);
Assert(pwszText);
// Set the string into the richedit control
chrg.cpMin = ulStart;
chrg.cpMax = ulStart;
RichEditExSetSel(hwndRedit, &chrg);
// Figure out the string length
cchText = lstrlenW(pwszText);
SetRichEditText(hwndRedit, (LPWSTR)pwszText, TRUE, NULL, TRUE);
chrg.cpMax = ulStart + cchText;
RichEditExSetSel(hwndRedit, &chrg);
// If we have a style to set on the string let's do it
if (pchfmt)
{
SendMessage(hwndRedit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM)pchfmt);
// Reset default settings for CHARFORMAT
chrg.cpMin = ulStart + cchText;
RichEditExSetSel(hwndRedit, &chrg);
chFmtDef.cbSize = sizeof(chFmtDef);
chFmtDef.dwMask = CFM_BOLD | CFM_UNDERLINE | CFM_COLOR;
chFmtDef.dwEffects = CFE_AUTOCOLOR;
SendMessage(hwndRedit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM)&chFmtDef);
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil_HrShowLinkedString
//
// This writes a format string into a richedit control
//
// Returns: S_OK, if it was successfully written
// E_FAIL, otherwise
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RuleUtil_HrShowLinkedString(HWND hwndEdit, BOOL fError, BOOL fReadOnly,
LPWSTR pwszFmt, LPCWSTR pwszData, ULONG ulStart,
ULONG * pulStartLink, ULONG * pulEndLink, ULONG * pulEnd)
{
HRESULT hr = S_OK;
CHARFORMAT chfmt = {0};
COLORREF clr = 0;
LPWSTR pwszMark = NULL;
ULONG ulStartLink = 0;
ULONG ulEndLink = 0;
if ((NULL == hwndEdit) || (NULL == pwszFmt) || (L'\0' == *pwszFmt))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing param
if (pulStartLink)
{
*pulStartLink = 0;
}
if (pulEndLink)
{
*pulEndLink = 0;
}
if (pulEnd)
{
*pulEnd = 0;
}
// Find the underline mark
pwszMark = StrStrW(pwszFmt, c_wszRuleMarkStart);
if (NULL != pwszMark)
{
*pwszMark = L'\0';
}
// Write out the normal string
RuleUtil_AppendRichEditText(hwndEdit, ulStart, pwszFmt, NULL);
ulStart += lstrlenW(pwszFmt);
// If we didn't have anything to underline
// then we're done.
if (NULL == pwszMark)
{
// Save off the new end
if (NULL != pulEnd)
{
*pulEnd = ulStart;
}
// Return
hr = S_OK;
goto exit;
}
// Skip over the mark
pwszFmt = pwszMark + lstrlenW(c_wszRuleMarkStart);
// Find the mark end
pwszMark = StrStrW(pwszFmt, c_wszRuleMarkEnd);
if (NULL == pwszMark)
{
hr = E_FAIL;
goto exit;
}
// If we don't have some data then
// just underline the original string
if (NULL == pwszData)
{
*pwszMark = L'\0';
pwszData = pwszFmt;
}
// Save off the character positions
ulStartLink = ulStart;
ulEndLink = ulStart + lstrlenW(pwszData);
// If readonly, then don't add links
if (fReadOnly)
RuleUtil_AppendRichEditText(hwndEdit, ulStart, pwszData, NULL);
else
{
if (fError)
clr = RGB(255, 0, 0);
else
LookupLinkColors(&clr, NULL);
// Which color should we use for underlining
chfmt.crTextColor = clr;
chfmt.cbSize = sizeof(chfmt);
chfmt.dwMask = CFM_UNDERLINE | CFM_COLOR;
chfmt.dwEffects = CFE_UNDERLINE;
RuleUtil_AppendRichEditText(hwndEdit, ulStart, pwszData, &chfmt);
}
// Write out the linked string
ulStart = ulEndLink;
// Move to the next part of the string
pwszFmt = pwszMark + lstrlenW(c_wszRuleMarkEnd);
// If we have more of the string to write out
if (L'\0' != *pwszFmt)
{
// Write out the rest of the string string
RuleUtil_AppendRichEditText(hwndEdit, ulStart, pwszFmt, NULL);
ulStart += lstrlenW(pwszFmt);
}
// Set the outgoing param
if (pulStartLink)
{
*pulStartLink = ulStartLink;
}
if (pulEndLink)
{
*pulEndLink = ulEndLink;
}
if (pulEnd)
{
*pulEnd = ulStart;
}
// Set the return value
hr = S_OK;
exit:
return hr;
}
HRESULT RuleUtil_HrDupCriteriaItem(CRIT_ITEM * pItemIn, ULONG cItemIn, CRIT_ITEM ** ppItemOut)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
CRIT_ITEM * pItem = NULL;
// Check incoming params
if ((NULL == pItemIn) || (NULL == ppItemOut) || (0 == cItemIn))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing param
*ppItemOut = NULL;
// Allocate the initial list of criteria
hr = HrAlloc((void **) &pItem, cItemIn * sizeof(*pItem));
if (FAILED(hr))
{
goto exit;
}
// Initialize the entire new criteria list
ZeroMemory(pItem, cItemIn * sizeof(*pItem));
// Walk over the list of criteria and set up the propvar for each one
for (ulIndex = 0; ulIndex < cItemIn; ulIndex++)
{
// Copy over the criteria info
pItem[ulIndex].type = pItemIn[ulIndex].type;
pItem[ulIndex].dwFlags = pItemIn[ulIndex].dwFlags;
pItem[ulIndex].logic = pItemIn[ulIndex].logic;
// Copy over the propvar
hr = PropVariantCopy(&(pItem[ulIndex].propvar), &(pItemIn[ulIndex].propvar));
if (FAILED(hr))
{
goto exit;
}
}
// Set the outgoing param
*ppItemOut = pItem;
pItem = NULL;
// Set proper return value
hr = S_OK;
exit:
if (NULL != pItem)
{
RuleUtil_HrFreeCriteriaItem(pItem, cItemIn);
MemFree(pItem);
}
return hr;
}
HRESULT RuleUtil_HrFreeCriteriaItem(CRIT_ITEM * pItem, ULONG cItem)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
// Check incoming params
if ((NULL == pItem) || (0 == cItem))
{
hr = E_INVALIDARG;
goto exit;
}
// Walk over the list of criteria and free each one
for (ulIndex = 0; ulIndex < cItem; ulIndex++)
{
PropVariantClear(&(pItem[ulIndex].propvar));
}
// Set proper return value
hr = S_OK;
exit:
return hr;
}
HRESULT RuleUtil_HrDupActionsItem(ACT_ITEM * pItemIn, ULONG cItemIn, ACT_ITEM ** ppItemOut)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
ACT_ITEM * pItem = NULL;
// Check incoming params
if ((NULL == pItemIn) || (NULL == ppItemOut) || (0 == cItemIn))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing param
*ppItemOut = NULL;
// Allocate the initial list of actions
hr = HrAlloc((void **) &pItem, cItemIn * sizeof(*pItem));
if (FAILED(hr))
{
goto exit;
}
// Initialize the entire new actions list
ZeroMemory(pItem, cItemIn * sizeof(*pItem));
// Walk over the list of actions and set up the propvar for each one
for (ulIndex = 0; ulIndex < cItemIn; ulIndex++)
{
// Copy over the actions info
pItem[ulIndex].type = pItemIn[ulIndex].type;
pItem[ulIndex].dwFlags = pItemIn[ulIndex].dwFlags;
// Copy over the propvar
hr = PropVariantCopy(&(pItem[ulIndex].propvar), &(pItemIn[ulIndex].propvar));
if (FAILED(hr))
{
goto exit;
}
}
// Set the outgoing param
*ppItemOut = pItem;
pItem = NULL;
// Set proper return value
hr = S_OK;
exit:
SafeMemFree(pItem);
return hr;
}
HRESULT RuleUtil_HrFreeActionsItem(ACT_ITEM * pItem, ULONG cItem)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
// Check incoming params
if ((NULL == pItem) || (0 == cItem))
{
hr = E_INVALIDARG;
goto exit;
}
// Walk over the list of criteria and free each one
for (ulIndex = 0; ulIndex < cItem; ulIndex++)
{
PropVariantClear(&(pItem[ulIndex].propvar));
}
// Set proper return value
hr = S_OK;
exit:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil_HrAddBlockSender
//
// This adds the address/domain name to the list of senders we will block
//
// hwndOwner - the window the owns this UI
// pszAddr - the address/domain name to add
// dwFlags - modifiers on how to add the address/domain name
//
// Returns: S_OK, if the address/domain name was added
// S_FALSE, if the address/domain name was already in the list
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RuleUtil_HrAddBlockSender(RULE_TYPE type, LPCSTR pszAddr)
{
HRESULT hr = S_OK;
IOERule * pIRuleOrig = NULL;
IOERule * pIRule = NULL;
PROPVARIANT propvar = {0};
ACT_ITEM aitem;
CRIT_ITEM * pcitem = NULL;
ULONG ccitem = 0;
ULONG ulIndex = 0;
BOOL fFound = FALSE;
LPSTR pszAddrNew = NULL;
RULEINFO infoRule = {0};
// Check incoming params
if ((NULL == pszAddr) || ('\0' == pszAddr[0]))
{
hr = E_INVALIDARG;
goto exit;
}
// Get the block sender rule from the rules manager
Assert(NULL != g_pRulesMan);
hr = g_pRulesMan->GetRule(RULEID_SENDERS, type, 0, &pIRuleOrig);
if (FAILED(hr))
{
// Create the new rule
hr = RuleUtil_HrCreateSendersRule(0, &pIRule);
if (FAILED(hr))
{
goto exit;
}
}
// If the block sender rule exist
else
{
// Clone it so we can make a change
hr = pIRuleOrig->Clone(&pIRule);
if (FAILED(hr))
{
goto exit;
}
SafeRelease(pIRuleOrig);
}
// Get the criteria list from the rules object
hr = pIRule->GetProp(RULE_PROP_CRITERIA, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
Assert(VT_BLOB == propvar.vt);
ccitem = propvar.blob.cbSize / sizeof(CRIT_ITEM);
pcitem = (CRIT_ITEM *) propvar.blob.pBlobData;
ZeroMemory(&propvar, sizeof(propvar));
// Search for the address/domain name in the criteria list
if (NULL != pcitem)
{
for (ulIndex = 0; ulIndex < ccitem; ulIndex++)
{
Assert(CRIT_TYPE_SENDER == pcitem[ulIndex].type)
Assert(CRIT_LOGIC_OR == pcitem[ulIndex].logic)
if ((VT_LPSTR != pcitem[ulIndex].propvar.vt) || (NULL == pcitem[ulIndex].propvar.pszVal))
{
continue;
}
if (0 == lstrcmpi(pszAddr, pcitem[ulIndex].propvar.pszVal))
{
fFound = TRUE;
break;
}
}
}
// Did we find it?
if (FALSE != fFound)
{
hr = S_FALSE;
goto exit;
}
// Allocate space to hold the new criteria
hr = HrRealloc((void **) &pcitem, (ccitem + 1) * sizeof(CRIT_ITEM));
if (FAILED(hr))
{
goto exit;
}
// Copy over the name
pszAddrNew = PszDupA(pszAddr);
if (NULL == pszAddrNew)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Add in to the end of the criteria list
pcitem[ccitem].type = CRIT_TYPE_SENDER;
pcitem[ccitem].dwFlags = CRIT_FLAG_DEFAULT;
pcitem[ccitem].logic = CRIT_LOGIC_OR;
pcitem[ccitem].propvar.vt = VT_LPSTR;
pcitem[ccitem].propvar.pszVal = pszAddrNew;
pszAddrNew = NULL;
ccitem++;
// Set the criteria back into the rule
PropVariantClear(&propvar);
propvar.vt = VT_BLOB;
propvar.blob.cbSize = ccitem * sizeof(CRIT_ITEM);
propvar.blob.pBlobData = (BYTE *) pcitem;
hr = pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar);
ZeroMemory(&propvar, sizeof(propvar));
if (FAILED(hr))
{
goto exit;
}
// Initialize the rule info
infoRule.ridRule = RULEID_SENDERS;
infoRule.pIRule = pIRule;
// Set the rule back into the rules manager
hr = g_pRulesMan->SetRules(SETF_SENDER, type, &infoRule, 1);
if (FAILED(hr))
{
goto exit;
}
// Set the proper return value
hr = S_OK;
exit:
SafeMemFree(pszAddrNew);
RuleUtil_HrFreeCriteriaItem(pcitem, ccitem);
SafeMemFree(pcitem);
PropVariantClear(&propvar);
SafeRelease(pIRule);
SafeRelease(pIRuleOrig);
return hr;
}
HRESULT RuleUtil_HrMergeActions(ACT_ITEM * pActionsOrig, ULONG cActionsOrig,
ACT_ITEM * pActionsNew, ULONG cActionsNew,
ACT_ITEM ** ppActionsDest, ULONG * pcActionsDest)
{
HRESULT hr = S_OK;
ACT_ITEM * pActions = NULL;
ULONG cActions = 0;
ULONG ulIndex = 0;
ULONG ulAction = 0;
ULONG cActionsAdded = 0;
ULONG ulAdd = 0;
// Verify incoming params
if (((NULL == pActionsOrig) && (0 != cActionsOrig)) || (NULL == pActionsNew) || (0 == cActionsNew) ||
(NULL == ppActionsDest) || (NULL == pcActionsDest))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing params
*ppActionsDest = NULL;
*pcActionsDest = 0;
// Allocate the maximum space to hold the destination actions
hr = HrAlloc((VOID **) &pActions, (cActionsOrig + cActionsNew) * sizeof(*pActions));
if (FAILED(hr))
{
goto exit;
}
// Initialize the destination actions list
ZeroMemory(pActions, (cActionsOrig + cActionsNew) * sizeof(*pActions));
// Copy over the original list to the destination actions list
for (ulIndex = 0; ulIndex < cActionsOrig; ulIndex++)
{
// Copy over the actions info
pActions[ulIndex].type = pActionsOrig[ulIndex].type;
pActions[ulIndex].dwFlags = pActionsOrig[ulIndex].dwFlags;
// Copy over the propvar
hr = PropVariantCopy(&(pActions[ulIndex].propvar), &(pActionsOrig[ulIndex].propvar));
if (FAILED(hr))
{
goto exit;
}
}
// For each item in the new actions list
cActionsAdded = cActionsOrig;
for (ulIndex = 0; ulIndex < cActionsNew; ulIndex++)
{
// if it's a copy, fwd or reply
if ((ACT_TYPE_COPY == pActionsNew->type) ||
(ACT_TYPE_FWD == pActionsNew->type) ||
(ACT_TYPE_REPLY == pActionsNew->type))
{
// Append it to the list
ulAdd = cActionsAdded;
}
else
{
// Find the item in the new list
for (ulAction = 0; ulAction < cActionsAdded; ulAction++)
{
// If we have a match, the replace it
if (pActionsNew[ulIndex].type == pActions[ulAction].type)
{
break;
}
// else, if we have some type of move operation
// then replace it
else if (((ACT_TYPE_MOVE == pActionsNew[ulIndex].type) ||
(ACT_TYPE_DELETE == pActionsNew[ulIndex].type) ||
(ACT_TYPE_JUNKMAIL == pActionsNew[ulIndex].type)) &&
((ACT_TYPE_MOVE == pActions[ulAction].type) ||
(ACT_TYPE_DELETE == pActions[ulAction].type) ||
(ACT_TYPE_JUNKMAIL == pActions[ulAction].type)))
{
break;
}
}
// Did we find anything
if (ulAction >= cActionsAdded)
{
ulAdd = cActionsAdded;
}
else
{
ulAdd = ulAction;
}
}
// Replace the item
pActions[ulAdd].type = pActionsNew[ulIndex].type;
pActions[ulAdd].dwFlags = pActionsNew[ulIndex].dwFlags;
// Clear out the old propvar
PropVariantClear(&(pActions[ulAdd].propvar));
// Copy over the propvar
hr = PropVariantCopy(&(pActions[ulAdd].propvar), &(pActionsNew[ulIndex].propvar));
if (FAILED(hr))
{
goto exit;
}
// If we added something
if (ulAdd == cActionsAdded)
{
cActionsAdded++;
}
}
// Set the outgoing params
*ppActionsDest = pActions;
pActions = NULL;
*pcActionsDest = cActionsAdded;
// Set the return value
hr = S_OK;
exit:
return hr;
}
HRESULT RuleUtil_HrGetOldFormatString(HKEY hkeyRoot, LPCSTR pszValue, LPCSTR pszSep, LPSTR * ppszString, ULONG * pcchString)
{
HRESULT hr = S_OK;
DWORD dwType = 0;
LPSTR pszData = NULL;
ULONG cbData = 0;
LPSTR pszWalk = NULL;
ULONG ulIndex = 0;
LPSTR pszTerm = NULL;
ULONG cchLen = 0;
ULONG cchString = 0;
LPSTR pszString = NULL;
LPSTR pszOld = NULL;
// Check incoming params
if ((NULL == hkeyRoot) || (NULL == pszValue) || (NULL == pszSep) || (NULL == ppszString))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing params
*ppszString = NULL;
if (NULL != pcchString)
{
*pcchString = 0;
}
// Get the old value from the registry
hr = RuleUtil_HrGetRegValue(hkeyRoot, pszValue, &dwType, (BYTE **) &pszData, &cbData);
if (FAILED(hr))
{
goto exit;
}
// Figure out the number of bytes needed
pszWalk = pszData;
cchString = 0;
for (ulIndex = 0; ulIndex < cbData; ulIndex += cchLen, pszWalk += cchLen)
{
// Search for terminator
pszTerm = StrStr(pszWalk, pszSep);
// If we have a terminator
if (NULL != pszTerm)
{
cchLen = (ULONG)(pszTerm - pszWalk + 1);
}
else
{
cchLen = lstrlen(pszWalk) + 1;
}
// If this isn't a null string
if (1 != cchLen)
{
// Add the number of characters
cchString += cchLen;
}
}
// Add in space to hold the terminator
cchString += 2;
// Allocate space to hold the final string
hr = HrAlloc((VOID **) &pszString, cchString * sizeof(*pszString));
if (FAILED(hr))
{
goto exit;
}
// Copy over each string
pszWalk = pszString;
pszOld = pszData;
for (ulIndex = 0; ulIndex < cbData; ulIndex += cchLen, pszOld += cchLen)
{
// Search for terminator
pszTerm = StrStr(pszOld, pszSep);
// If we have a terminator
if (NULL != pszTerm)
{
cchLen = (ULONG)(pszTerm - pszOld + 1);
}
else
{
cchLen = lstrlen(pszOld) + 1;
}
// If this isn't a null string
if (1 != cchLen)
{
// Copy over the string
StrCpyN(pszWalk, pszOld, cchLen);
// Move to the next string
pszWalk += lstrlen(pszWalk) + 1;
}
}
// Terminate the string
pszWalk[0] = '\0';
pszWalk[1] = '\0';
// Set the outgoing params
*ppszString = pszString;
pszString = NULL;
if (NULL != pcchString)
{
*pcchString = cchString;
}
// Set the return value
hr = S_OK;
exit:
SafeMemFree(pszString);
SafeMemFree(pszData);
return hr;
}
// ------------------------------------------------------------------------------------
// _FIsLoopingAddress
// ------------------------------------------------------------------------------------
BOOL _FIsLoopingAddress(LPCSTR pszAddressTo)
{
// Locals
HRESULT hr=S_OK;
LPSTR pszAddress=NULL;
CHAR szFrom[CCHMAX_EMAIL_ADDRESS];
BOOL fResult=FALSE;
IImnEnumAccounts *pEnum=NULL;
IImnAccount *pAccount=NULL;
// Check State
Assert(pszAddressTo);
// Enumerate the user's SMTP and POP3 Accounts
CHECKHR(hr = g_pAcctMan->Enumerate(SRV_POP3 | SRV_SMTP, &pEnum));
// Duplicate the To Address
CHECKALLOC(pszAddress = PszDupA(pszAddressTo));
// Make it lower case
CharLower(pszAddress);
// Enumerate
while(SUCCEEDED(pEnum->GetNext(&pAccount)))
{
// Get Email Address
if (SUCCEEDED(pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szFrom, ARRAYSIZE(szFrom))))
{
// Lower it
CharLower(szFrom);
// Is this to myself
if (StrStr(pszAddress, szFrom) || StrStr(szFrom, pszAddress))
{
fResult = TRUE;
goto exit;
}
}
// Done
SafeRelease(pAccount);
}
exit:
// Cleanup
SafeRelease(pEnum);
SafeRelease(pAccount);
SafeMemFree(pszAddress);
// Done
return fResult;
}
// ------------------------------------------------------------------------------------
// _HrAutoForwardMessage
// ------------------------------------------------------------------------------------
HRESULT _HrAutoForwardMessage(HWND hwndUI, LPCSTR pszForwardTo, LPCSTR pszAcctId, IStream *pstmMsg, BOOL *pfLoop)
{
// Locals
HRESULT hr=S_OK;
IMimeMessage *pMessage=NULL;
PROPVARIANT rUserData;
IMimeAddressTable *pAddrTable=NULL;
CHAR szDisplayName[CCHMAX_DISPLAY_NAME];
CHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS];
HTMLOPT rHtmlOpt;
PLAINOPT rPlainOpt;
BOOL fHTML;
IImnAccount *pAccount=NULL;
PROPVARIANT rOption;
CHAR szId[CCHMAX_ACCOUNT_NAME];
BOOL fUseDefaultAcct = FALSE;
BOOL fSendImmediate = FALSE;
// check Params
Assert(pstmMsg && pszForwardTo && pfLoop);
// Init
*pfLoop = FALSE;
// Is the new recipient the same as my current email address
if (NULL == pszForwardTo || _FIsLoopingAddress(pszForwardTo))
{
*pfLoop = TRUE;
return TrapError(E_FAIL);
}
// Open the Account
hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAcctId, &pAccount);
// If we couldn't find the account, then just use the default
if (FAILED(hr))
{
CHECKHR(hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount));
fUseDefaultAcct = TRUE;
}
// Create a Message
CHECKHR(hr = HrCreateMessage(&pMessage));
// Lets rewind pstmReplyWith
CHECKHR(hr = HrRewindStream(pstmMsg));
// Load String into my message object
CHECKHR(hr = pMessage->Load(pstmMsg));
// Get the wabal
CHECKHR(hr = pMessage->GetAddressTable(&pAddrTable));
// Remove all of the recipients...
CHECKHR(hr = pAddrTable->DeleteTypes(IAT_ALL));
// Get Originator Display Name
CHECKHR(hr = pAccount->GetPropSz(AP_SMTP_DISPLAY_NAME, szDisplayName, ARRAYSIZE(szDisplayName)));
// Get Originator Email Name
CHECKHR(hr = pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, ARRAYSIZE(szEmailAddress)));
// Add Sender...
CHECKHR(hr = pAddrTable->Append(IAT_FROM, IET_DECODED, szDisplayName, szEmailAddress, NULL));
// Add Recipient
CHECKHR(hr = pAddrTable->AppendRfc822(IAT_TO, IET_DECODED, pszForwardTo));
// Save the AccountID
rUserData.vt = VT_LPSTR;
if (FALSE == fUseDefaultAcct)
{
rUserData.pszVal = (LPSTR) pszAcctId;
}
else
{
if (SUCCEEDED(pAccount->GetPropSz(AP_ACCOUNT_ID, szId, sizeof(szId))))
{
rUserData.pszVal = szId;
}
else
{
rUserData.pszVal = (LPSTR) pszAcctId;
}
}
pMessage->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), 0, &rUserData);
// Save the Account
CHECKHR(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szId, sizeof(szId)))
rUserData.pszVal = szId;
pMessage->SetProp(STR_ATT_ACCOUNTNAME, 0, &rUserData);
// Raid-33842: Set the date
CHECKHR(hr = HrSetSentTimeProp(pMessage, NULL));
// Get Mail Options
GetDefaultOptInfo(&rHtmlOpt, &rPlainOpt, &fHTML, FMT_MAIL);
// Store the options on the messaage
CHECKHR(hr = HrSetMailOptionsOnMessage(pMessage, &rHtmlOpt, &rPlainOpt, NULL, fHTML));
// Raid-63259: MIMEOLE - Creating message ID causes autodialer to fire
// Raid-50793: Athena: Should be setting message-ID's in email
#if 0
rOption.vt = VT_BOOL;
rOption.boolVal = TRUE;
pMessage->SetOption(OID_GENERATE_MESSAGE_ID, &rOption);
#endif
// Should we send it immediately?
fSendImmediate = DwGetOption(OPT_SENDIMMEDIATE);
// Send the message
CHECKHR(hr = HrSendMailToOutBox(hwndUI, pMessage, fSendImmediate, TRUE));
exit:
// Cleanup
SafeRelease(pMessage);
SafeRelease(pAddrTable);
SafeRelease(pAccount);
// done
return hr;
}
// ------------------------------------------------------------------------------------
// _HrAutoReplyMessage
// ------------------------------------------------------------------------------------
HRESULT _HrAutoReplyMessage(HWND hwndUI, DWORD dwType, LPCSTR pszFilename, IStream * pstmFile,
LPCSTR pszAcctId, IMimeMessage *pMsgIn, BOOL *pfLoop)
{
// Locals
HRESULT hr=S_OK;
CHAR szRe[20];
IMimeMessage *pMsgOut=NULL;
LPSTR pszNewSubj=NULL,
pszCurSubj=NULL,
pszNormal;
IMimeAddressTable *pTable=NULL;
ADDRESSPROPS rSender;
HBODY hBody;
CHAR szDisplayName[CCHMAX_DISPLAY_NAME];
CHAR szEmailAddress[CCHMAX_EMAIL_ADDRESS];
PROPVARIANT rUserData;
HTMLOPT rHtmlOpt;
PLAINOPT rPlainOpt;
BOOL fHTML;
IImnAccount *pAccount=NULL;
PROPVARIANT rOption;
CHAR szId[CCHMAX_ACCOUNT_NAME];
BOOL fUseDefaultAcct = FALSE;
BOOL fSendImmediate = FALSE;
// Problems
// PMsgIn can be NULL in here (Access Dineied for S/MIME messages.
// shoul return immediatelly
if(!pMsgIn)
return(hr);
Assert(pszFilename && pstmFile && pMsgIn && pfLoop);
// Init
*pfLoop = FALSE;
// Init
ZeroMemory(&rSender, sizeof(ADDRESSPROPS));
// Open the Account
hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAcctId, &pAccount);
// If we couldn't find the account, then just use the default
if (FAILED(hr))
{
CHECKHR(hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount));
fUseDefaultAcct = TRUE;
}
// Create a Message
CHECKHR(hr = HrCreateMessage(&pMsgOut));
// Lets rewind pstmFile
CHECKHR(hr = HrRewindStream(pstmFile));
// RW_HTML
switch (dwType)
{
case RFT_HTML:
// Use the stream as the message body
CHECKHR(hr = pMsgOut->SetTextBody(TXT_HTML, IET_DECODED, NULL, pstmFile, NULL));
break;
case RFT_TEXT:
// Use the stream as the message body
CHECKHR(hr = pMsgOut->SetTextBody(TXT_PLAIN, IET_DECODED, NULL, pstmFile, NULL));
break;
case RFT_MESSAGE:
// Use the stream as a message attachment
CHECKHR(hr = pMsgOut->AttachObject(IID_IStream, pstmFile, &hBody));
// Note that the attachment is a message
MimeOleSetBodyPropA(pMsgOut, hBody, PIDTOSTR(PID_HDR_CNTTYPE), NOFLAGS, STR_MIME_MSG_RFC822);
break;
case RFT_FILE:
// Attach File
CHECKHR(hr = pMsgOut->AttachFile(pszFilename, pstmFile, NULL));
break;
default:
Assert(FALSE);
hr = E_FAIL;
goto exit;
break;
}
// Get Re:
AthLoadString(idsPrefixReply, szRe, ARRAYSIZE(szRe));
// Get the normalized subject
if (SUCCEEDED(MimeOleGetBodyPropA(pMsgIn, HBODY_ROOT, STR_ATT_NORMSUBJ, NOFLAGS, &pszCurSubj)))
pszNormal = pszCurSubj;
// Fixup if null...
pszNormal = pszNormal ? pszNormal : (LPTSTR)c_szEmpty;
// Allocate the subject...
DWORD cchSize = (lstrlen(szRe) + lstrlen(pszNormal) + 5);
CHECKALLOC(pszNewSubj = PszAllocA(cchSize));
// Build the subject
wnsprintf(pszNewSubj, cchSize, "%s%s", szRe, pszNormal);
// Set the subject
CHECKHR(hr = MimeOleSetBodyPropA(pMsgOut, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, pszNewSubj));
// Get the message Wabal
rSender.dwProps = IAP_EMAIL | IAP_FRIENDLY;
CHECKHR(hr = pMsgIn->GetSender(&rSender));
Assert(rSender.pszEmail && ISFLAGSET(rSender.dwProps, IAP_EMAIL));
// Is the new recipient the same as my current email address
if (_FIsLoopingAddress(rSender.pszEmail))
{
*pfLoop = TRUE;
hr = TrapError(E_FAIL);
goto exit;
}
// Add to recipient list of autgen message
CHECKHR(hr = pMsgOut->GetAddressTable(&pTable));
// Modify rSender Address Type
rSender.dwAdrType = IAT_TO;
FLAGSET(rSender.dwProps, IAP_ADRTYPE);
// Append Sender as the recipient
CHECKHR(hr = pTable->Insert(&rSender, NULL));
// Get Originator Display Name
CHECKHR(hr = pAccount->GetPropSz(AP_SMTP_DISPLAY_NAME, szDisplayName, ARRAYSIZE(szDisplayName)));
// Get Originator Email Name
CHECKHR(hr = pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmailAddress, ARRAYSIZE(szEmailAddress)));
// Append Sender
CHECKHR(hr = pTable->Append(IAT_FROM, IET_DECODED, szDisplayName, szEmailAddress, NULL));
// Save the AccountID
rUserData.vt = VT_LPSTR;
if (FALSE == fUseDefaultAcct)
{
rUserData.pszVal = (LPSTR) pszAcctId;
}
else
{
if (SUCCEEDED(pAccount->GetPropSz(AP_ACCOUNT_ID, szId, sizeof(szId))))
{
rUserData.pszVal = szId;
}
else
{
rUserData.pszVal = (LPSTR) pszAcctId;
}
}
pMsgOut->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), 0, &rUserData);
// Save the Account
CHECKHR(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szId, sizeof(szId)))
rUserData.pszVal = szId;
pMsgOut->SetProp(STR_ATT_ACCOUNTNAME, 0, &rUserData);
// Raid-33842: Set the date
CHECKHR(hr = HrSetSentTimeProp(pMsgOut, NULL));
// Get Mail Options
GetDefaultOptInfo(&rHtmlOpt, &rPlainOpt, &fHTML, FMT_MAIL);
// Store the options on the messaage
CHECKHR(hr = HrSetMailOptionsOnMessage(pMsgOut, &rHtmlOpt, &rPlainOpt, NULL, fHTML));
// Raid-63259: MIMEOLE - Creating message ID causes autodialer to fire
// Raid-50793: Athena: Should be setting message-ID's in email
#if 0
rOption.vt = VT_BOOL;
rOption.boolVal = TRUE;
pMsgOut->SetOption(OID_GENERATE_MESSAGE_ID, &rOption);
#endif
// Should we send it immediately?
fSendImmediate = DwGetOption(OPT_SENDIMMEDIATE);
// Send the message
CHECKHR(hr = HrSendMailToOutBox(hwndUI, pMsgOut, fSendImmediate, TRUE));
exit:
// Cleanup
SafeRelease(pTable);
SafeMemFree(pszCurSubj);
SafeMemFree(pszNewSubj);
SafeRelease(pMsgOut);
SafeRelease(pAccount);
g_pMoleAlloc->FreeAddressProps(&rSender);
// Done
return hr;
}
HRESULT _HrRecurseSetFilter(FOLDERINFO * pfldinfo, BOOL fSubFolders, DWORD cIndent, DWORD_PTR dwCookie)
{
RULEID ridRule = RULEID_INVALID;
IMessageFolder * pFolder = NULL;
FOLDERUSERDATA UserData = {0};
ridRule = (RULEID) dwCookie;
if (RULEID_INVALID == ridRule)
{
goto exit;
}
// If not hidden
if ((0 != (pfldinfo->dwFlags & FOLDER_HIDDEN)) || (FOLDERID_ROOT == pfldinfo->idFolder))
{
goto exit;
}
// Not Subscribed
if (0 == (pfldinfo->dwFlags & FOLDER_SUBSCRIBED))
{
goto exit;
}
// Server node
if (0 != (pfldinfo->dwFlags & FOLDER_SERVER))
{
goto exit;
}
if (FAILED(g_pStore->OpenFolder(pfldinfo->idFolder, NULL, OPEN_FOLDER_NOCREATE, &pFolder)))
{
goto exit;
}
if ((FOLDER_LOCAL == pfldinfo->tyFolder) && (RULEID_VIEW_DOWNLOADED == ridRule))
{
ridRule = RULEID_VIEW_ALL;
}
// Create the struct to insert
if (FAILED(pFolder->GetUserData(&UserData, sizeof(FOLDERUSERDATA))))
{
goto exit;
}
UserData.ridFilter = ridRule;
UserData.dwFilterVersion = 0xFFFFFFFF;
if (FAILED(pFolder->SetUserData(&UserData, sizeof(FOLDERUSERDATA))))
{
goto exit;
}
exit:
SafeRelease(pFolder);
return S_OK;
}
HRESULT RuleUtil_HrApplyRulesToFolder(DWORD dwFlags, DWORD dwDeleteFlags,
IOEExecRules * pIExecRules, IMessageFolder * pFolder, HWND hwndUI, CProgress * pProgress)
{
HRESULT hr = S_OK;
HCURSOR hcursor = NULL;
FOLDERID idFolder = FOLDERID_ROOT;
HLOCK hLockNotify = NULL;
HROWSET hRowset = NULL;
MESSAGEINFO Message = {0};
IMimeMessage * pIMMsg = NULL;
IMimePropertySet * pIMPropSet = NULL;
ACT_ITEM * pActions = NULL;
ULONG cActions = 0;
DWORD dwExecFlags = 0;
// Wait Cursor
if (NULL == pProgress)
{
hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
}
// Check incoming params
if ((NULL == pIExecRules) || (NULL == pFolder))
{
hr = E_INVALIDARG;
goto exit;
}
// Get the Folder Id
hr = pFolder->GetFolderId(&idFolder);
if (FAILED(hr))
{
goto exit;
}
// We handle partial messages for News
if (FOLDER_NEWS != GetFolderType(idFolder))
{
dwExecFlags |= ERF_SKIPPARTIALS;
}
// This forces all notifications to be queued (this is good since you do segmented deletes)
pFolder->LockNotify(0, &hLockNotify);
// Create a Rowset
hr = pFolder->CreateRowset(IINDEX_PRIMARY, NOFLAGS, &hRowset);
if (FAILED(hr))
{
goto exit;
}
// Loop
while (S_OK == pFolder->QueryRowset(hRowset, 1, (LPVOID *)&Message, NULL))
{
// Do we need to only handle partial messages?
if ((0 == (dwFlags & RULE_APPLY_PARTIALS)) || (MESSAGE_COMBINED == Message.dwPartial))
{
// Open the message object if it's available
if (Message.faStream)
{
if (SUCCEEDED(pFolder->OpenMessage(Message.idMessage, 0, &pIMMsg, NOSTORECALLBACK)))
{
pIMMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pIMPropSet);
}
}
// Get the Actions for this rule
hr = pIExecRules->ExecuteRules(dwExecFlags, Message.pszAcctId, &Message, pFolder, pIMPropSet,
pIMMsg, Message.cbMessage, &pActions, &cActions);
// Free up the stuff we're not using anymore
SafeRelease(pIMPropSet);
// Did we find anything?
if (S_OK == hr)
{
// Apply this action
SideAssert(SUCCEEDED(RuleUtil_HrApplyActions(hwndUI, pIExecRules, &Message,
pFolder, pIMMsg, dwDeleteFlags, pActions, cActions, NULL, NULL)));
// Free up the actions
RuleUtil_HrFreeActionsItem(pActions, cActions);
SafeMemFree(pActions);
}
SafeRelease(pIMMsg);
}
pFolder->FreeRecord(&Message);
// Update progress
if (NULL != pProgress)
{
if (S_OK != pProgress->HrUpdate(1))
{
hr = S_FALSE;
goto exit;
}
}
}
hr = S_OK;
exit:
RuleUtil_HrFreeActionsItem(pActions, cActions);
SafeMemFree(pActions);
SafeRelease(pIMPropSet);
SafeRelease(pIMMsg);
pFolder->FreeRecord(&Message);
pFolder->CloseRowset(&hRowset);
if (NULL != hLockNotify)
{
pFolder->UnlockNotify(&hLockNotify);
}
if (NULL == pProgress)
{
SetCursor(hcursor);
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil_HrImportRules
//
// This imports the rules from a file
//
// Returns: NONE
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RuleUtil_HrImportRules(HWND hwnd)
{
HRESULT hr = S_OK;
OPENFILENAME ofn;
CHAR szFilename[MAX_PATH] = _T("");
CHAR szFilter[MAX_PATH] = _T("");
CHAR szDefExt[20] = _T("");
IStream * pIStm = NULL;
CLSID clsid = {0};
ULONG cbRead = 0;
ULONG cRules = 0;
RULEINFO * pinfoRule = NULL;
CProgress * pProgress = NULL;
ULONG ulIndex = 0;
IOERule * pIRule = NULL;
IPersistStream * pIPStm = NULL;
DWORD dwData = 0;
RULE_TYPE type;
// Load Res Strings
LoadStringReplaceSpecial(idsRulesFilter, szFilter, sizeof(szFilter));
AthLoadString(idsDefRulesExt, szDefExt, sizeof(szDefExt));
// Setup Save file struct
ZeroMemory (&ofn, sizeof (ofn));
ofn.lStructSize = sizeof (ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szFilter;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFilename;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = szDefExt;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
hr = HrAthGetFileName(&ofn, TRUE);
if (S_OK != hr)
{
goto exit;
}
hr = CreateStreamOnHFile(szFilename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, &pIStm);
if (FAILED(hr))
{
goto exit;
}
// MAke sure we have a file using our Rules Manager
hr = pIStm->Read(&clsid, sizeof(clsid), &cbRead);
if (FAILED(hr))
{
goto exit;
}
Assert(cbRead == sizeof(clsid));
if (clsid != CLSID_OERulesManager)
{
Assert("Ahhhhh This is a bogus file!!!!!");
hr = E_FAIL;
goto exit;
}
// Read in the version of the rules file format
hr = pIStm->Read(&dwData, sizeof(dwData), &cbRead);
if (FAILED(hr))
{
goto exit;
}
Assert(cbRead == sizeof(dwData));
// Check the file format version
if (dwData != RULE_FILE_VERSION)
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsRulesErrBadFileFormat), NULL, MB_ICONINFORMATION | MB_OK);
hr = E_FAIL;
goto exit;
}
// Get the count of rules in the file
hr = pIStm->Read(&cRules, sizeof(cRules), &cbRead);
if (FAILED(hr))
{
goto exit;
}
Assert(cbRead == sizeof(cRules));
// Allocate space to hold all of the rules
hr = HrAlloc((void **) &pinfoRule, cRules * sizeof(*pinfoRule));
if (FAILED(hr))
{
goto exit;
}
// Initialize it to a known value
ZeroMemory(pinfoRule, cRules * sizeof(*pinfoRule));
// Get the type of rules in the file
hr = pIStm->Read(&dwData, sizeof(dwData), &cbRead);
if (FAILED(hr))
{
goto exit;
}
Assert(cbRead == sizeof(dwData));
type = (RULE_TYPE) dwData;
// Set up the progress dialog
pProgress = new CProgress;
if (NULL == pProgress)
{
hr = E_OUTOFMEMORY;
goto exit;
}
pProgress->Init(hwnd, MAKEINTRESOURCE(idsAthena),
MAKEINTRESOURCE(idsApplyingRules), cRules, 0, TRUE, FALSE);
// Show progress in 2 second
pProgress->Show(0);
for (ulIndex = 0; ulIndex < cRules; ulIndex++)
{
SafeRelease(pIRule);
// Create a new rule
hr = HrCreateRule(&pIRule);
if (FAILED(hr))
{
continue;
}
SafeRelease(pIPStm);
// Get the persistance interface from the rule
hr = pIRule->QueryInterface(IID_IPersistStream, (void **) &pIPStm);
if (FAILED(hr))
{
continue;
}
// Load in the rule from the file
hr = pIPStm->Load(pIStm);
if (FAILED(hr))
{
continue;
}
// Add the rule to the list
pinfoRule[ulIndex].ridRule = RULEID_INVALID;
pinfoRule[ulIndex].pIRule = pIRule;
pIRule = NULL;
// Bump up the progress dialog
hr = pProgress->HrUpdate(1);
if (S_OK != hr)
{
break;
}
}
// Add the rules to the rules manager
Assert(NULL != g_pRulesMan);
hr = g_pRulesMan->SetRules(SETF_APPEND, type, pinfoRule, cRules);
if (FAILED(hr))
{
goto exit;
}
hr = S_OK;
exit:
SafeRelease(pIRule);
SafeRelease(pProgress);
SafeRelease(pIPStm);
if (NULL != pinfoRule)
{
for (ulIndex = 0; ulIndex < cRules; ulIndex++)
{
SafeRelease(pinfoRule[ulIndex].pIRule);
}
MemFree(pinfoRule);
}
SafeRelease(pIStm);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil_HrExportRules
//
// This exports the rules into a file
//
// Returns: NONE
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RuleUtil_HrExportRules(HWND hwnd)
{
HRESULT hr = S_OK;
OPENFILENAME ofn;
CHAR szFilename[MAX_PATH] = _T("");
CHAR szFilter[MAX_PATH] = _T("");
CHAR szDefExt[20] = _T("");
IStream * pIStm = NULL;
ULONG cbWritten = 0;
IOEEnumRules * pIEnumRules = NULL;
ULONG cpIRule = 0;
IPersistStream * pIPStm = NULL;
CProgress * pProgress = NULL;
ULONG ulIndex = 0;
IOERule * pIRule = NULL;
LARGE_INTEGER liSeek = {0};
DWORD dwData = 0;
// Load Res Strings
LoadStringReplaceSpecial(idsRulesFilter, szFilter, sizeof(szFilter));
AthLoadString(idsDefRulesExt, szDefExt, sizeof(szDefExt));
AthLoadString(idsRulesDefFile, szFilename, sizeof(szFilename));
// Setup Save file struct
ZeroMemory (&ofn, sizeof (ofn));
ofn.lStructSize = sizeof (ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szFilter;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFilename;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = szDefExt;
ofn.Flags = OFN_NOCHANGEDIR | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
hr = HrAthGetFileName(&ofn, FALSE);
if (S_OK != hr)
{
goto exit;
}
hr = CreateStreamOnHFile(szFilename, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL, &pIStm);
if (FAILED(hr))
{
goto exit;
}
// Write out the class id for the Rules Manager
hr = pIStm->Write(&CLSID_OERulesManager, sizeof(CLSID_OERulesManager), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(CLSID_OERulesManager));
// Write out the version of the rules format
dwData = RULE_FILE_VERSION;
hr = pIStm->Write(&dwData, sizeof(dwData), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(dwData));
// Get the list of rules
Assert(NULL != g_pRulesMan);
hr = g_pRulesMan->EnumRules(ENUMF_EDIT, RULE_TYPE_MAIL, &pIEnumRules);
if (FAILED(hr))
{
goto exit;
}
// Figure out the total number of rules
cpIRule = 0;
while (S_OK == pIEnumRules->Next(1, &pIRule, NULL))
{
cpIRule++;
SafeRelease(pIRule);
}
hr = pIEnumRules->Reset();
if (FAILED(hr))
{
goto exit;
}
// Write out the number of rules going to be exported
hr = pIStm->Write(&cpIRule, sizeof(cpIRule), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(cpIRule));
// Write out the type of rules going to be exported
dwData = RULE_TYPE_MAIL;
hr = pIStm->Write(&dwData, sizeof(dwData), &cbWritten);
if (FAILED(hr))
{
goto exit;
}
Assert(cbWritten == sizeof(dwData));
// Set up the progress dialog
pProgress = new CProgress;
if (NULL == pProgress)
{
hr = E_OUTOFMEMORY;
goto exit;
}
pProgress->Init(hwnd, MAKEINTRESOURCE(idsAthena),
MAKEINTRESOURCE(idsApplyingRules), cpIRule, 0, TRUE, FALSE);
// Show progress in 2 seconds
pProgress->Show(0);
for (ulIndex = 0; ulIndex < cpIRule; ulIndex++)
{
// Get the next rule
SafeRelease(pIRule);
hr = pIEnumRules->Next(1, &pIRule, NULL);
if (FAILED(hr))
{
continue;
}
Assert(S_OK == hr);
SafeRelease(pIPStm);
if (FAILED(pIRule->QueryInterface(IID_IPersistStream, (void **) &pIPStm)))
{
continue;
}
if (FAILED(pIPStm->Save(pIStm, FALSE)))
{
continue;
}
// Update progress
if (S_OK != pProgress->HrUpdate(1))
{
// Change the rule count to the proper total
liSeek.QuadPart = sizeof(CLSID_OERulesManager);
if (SUCCEEDED(pIStm->Seek(liSeek, STREAM_SEEK_SET, NULL)))
{
ulIndex++;
SideAssert(SUCCEEDED(pIStm->Write(&ulIndex, sizeof(ulIndex), &cbWritten)));
Assert(cbWritten == sizeof(ulIndex));
}
break;
}
}
hr = S_OK;
exit:
SafeRelease(pIPStm);
SafeRelease(pIRule);
SafeRelease(pProgress);
SafeRelease(pIEnumRules);
SafeRelease(pIStm);
return hr;
}
typedef struct _tagFOLDERIDMAP
{
FOLDERID dwFldIdOld;
FOLDERID dwFldIdNew;
} FOLDERIDMAP, * PFOLDERIDMAP;
HRESULT RuleUtil_HrMapFldId(DWORD dwFlags, BYTE * pbFldIdMap, FOLDERID fldidOld, FOLDERID * pfldidNew)
{
HRESULT hr = S_OK;
ULONG cmpfldid = 0;
FOLDERIDMAP * pmpfldid;
ULONG ulIndex = 0;
// Verify incoming params
if ((NULL == pbFldIdMap) || (FOLDERID_INVALID == fldidOld) || (NULL == pfldidNew))
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the outgoing param
*pfldidNew = FOLDERID_INVALID;
cmpfldid = *((DWORD *) pbFldIdMap);
if (0 == cmpfldid)
{
goto exit;
}
pmpfldid = (FOLDERIDMAP *) (pbFldIdMap + sizeof(cmpfldid));
for (ulIndex = 0; ulIndex < cmpfldid; ulIndex++)
{
if (fldidOld == pmpfldid[ulIndex].dwFldIdOld)
{
*pfldidNew = pmpfldid[ulIndex].dwFldIdNew;
break;
}
}
// Set the return value
hr = (FOLDERID_INVALID != *pfldidNew) ? S_OK : S_FALSE;
exit:
return hr;
}
HRESULT RuleUtil_HrGetUserData(DWORD dwFlags, LPSTR * ppszFirstName, LPSTR * ppszLastName, LPSTR * ppszCompanyName)
{
HRESULT hr = S_OK;
LPWAB pWab = NULL;
LPWABOBJECT pWabObj = NULL;
SBinary sbEID = {0};
IAddrBook * pIAddrBook = NULL;
ULONG ulObjType = 0;
IMailUser * pIMailUser = NULL;
SizedSPropTagArray(3, ptaDefMailUser) = {3, {PR_GIVEN_NAME_A, PR_SURNAME_A, PR_COMPANY_NAME_A}};
ULONG cProps = 0;
LPSPropValue pProps = NULL;
LPSPropValue pPropsWalk = NULL;
if ((NULL == ppszFirstName) || (NULL == ppszLastName) || (NULL == ppszCompanyName))
{
hr = E_INVALIDARG;
goto exit;
}
*ppszFirstName = NULL;
*ppszLastName = NULL;
*ppszCompanyName = NULL;
// Get Wab object
hr = HrCreateWabObject(&pWab);
if (FAILED(hr))
{
goto exit;
}
hr = pWab->HrGetWabObject(&pWabObj);
if (FAILED(hr))
{
goto exit;
}
hr = pWab->HrGetAdrBook(&pIAddrBook);
if (FAILED(hr))
{
goto exit;
}
// Do we already have a concept of me?
hr = pWabObj->GetMe(pIAddrBook, AB_NO_DIALOG | WABOBJECT_ME_NOCREATE, NULL, &sbEID, NULL);
if (FAILED(hr))
{
goto exit;
}
// Open the entry
hr = pIAddrBook->OpenEntry(sbEID.cb, (ENTRYID *)(sbEID.lpb), NULL, 0, &ulObjType, (IUnknown **) &pIMailUser);
if (FAILED(hr))
{
goto exit;
}
// Get the relevant info
hr = pIMailUser->GetProps((LPSPropTagArray) &ptaDefMailUser, 0, &cProps, &pProps);
if (FAILED(hr))
{
goto exit;
}
pPropsWalk = pProps;
// Grab the first name if it exists
if ((PR_GIVEN_NAME_A == pPropsWalk->ulPropTag) && (NULL != pPropsWalk->Value.lpszA))
{
*ppszFirstName = PszDupA(pPropsWalk->Value.lpszA);
}
pPropsWalk++;
// Grab the last name if it exists
if ((PR_SURNAME_A == pPropsWalk->ulPropTag) && (NULL != pPropsWalk->Value.lpszA))
{
*ppszLastName = PszDupA(pPropsWalk->Value.lpszA);
}
pPropsWalk++;
// Grab the company name if it exists
if ((PR_COMPANY_NAME_A == pPropsWalk->ulPropTag) && (NULL != pPropsWalk->Value.lpszA))
{
*ppszCompanyName = PszDupA(pPropsWalk->Value.lpszA);
}
hr = S_OK;
exit:
SafeRelease(pIMailUser);
if (NULL != pWabObj)
{
if (NULL != pProps)
{
pWabObj->FreeBuffer(pProps);
}
if (NULL != sbEID.lpb)
{
pWabObj->FreeBuffer(sbEID.lpb);
}
}
SafeRelease(pWab);
return hr;
}
HRESULT _HrMarkThreadAsWatched(MESSAGEID idMessage, IMessageFolder * pFolder, ADJUSTFLAGS * pflgWatch)
{
HRESULT hr = S_OK;
MESSAGEINFO infoMessage = {0};
// Check incoming param
if ((MESSAGEID_INVALID == idMessage) || (NULL == pFolder) || (NULL == pflgWatch))
{
hr = E_INVALIDARG;
goto exit;
}
// Get the message info
hr = GetMessageInfo(pFolder, idMessage, &infoMessage);
if (FAILED(hr))
{
goto exit;
}
// Add Flags
FLAGSET(infoMessage.dwFlags, pflgWatch->dwAdd);
// ClearFlags
FLAGCLEAR(infoMessage.dwFlags, pflgWatch->dwRemove);
// Update the Message
IF_FAILEXIT(hr = pFolder->UpdateRecord(&infoMessage));
// Set the return value
hr = S_OK;
exit:
pFolder->FreeRecord(&infoMessage);
return hr;
}
HRESULT RuleUtil_HrApplyActions(HWND hwndUI, IOEExecRules * pIExecRules, MESSAGEINFO * pMsgInfo,
IMessageFolder * pFolder, IMimeMessage * pIMMsg, DWORD dwDeleteFlags,
ACT_ITEM * pActions, ULONG cActions, ULONG * pcInfiniteLoops, BOOL *pfDeleteOffServer)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
FOLDERID idFolder = 0;
ACT_ITEM * pActionsList = NULL;
IMessageFolder * pFolderNew = NULL;
MESSAGEIDLIST List = {0};
ADJUSTFLAGS Flags = {0};
DWORD dwType = RFT_HTML;
IStream * pIStm = NULL;
LPSTR pszExt = NULL;
BOOL fLoop = FALSE;
DWORD dwFlag = 0;
FOLDERID idFolderJunkMail = FOLDERID_INVALID;
RULEFOLDERDATA * prfdData = NULL;
BOOL fSetFlags = FALSE;
DWORD dwFlagRemove = 0;
BOOL fDoWatch = FALSE;
ADJUSTFLAGS WatchFlags = {0};
// Check incoming params
if ((NULL == pIExecRules) || (NULL == pMsgInfo) || (NULL == pActions) || (NULL == pFolder))
{
hr = E_INVALIDARG;
goto exit;
}
// Init
if (pfDeleteOffServer)
*pfDeleteOffServer = FALSE;
// Initialize the list
List.cMsgs = 1;
List.prgidMsg = &(pMsgInfo->idMessage);
// Get the folder id of the message
hr = pFolder->GetFolderId(&idFolder);
if (FAILED(hr))
{
goto exit;
}
// Do all modification operations first
for (pActionsList = pActions, ulIndex = 0; ulIndex < cActions; ulIndex++, pActionsList++)
{
switch(pActionsList->type)
{
case ACT_TYPE_HIGHLIGHT:
Assert(pActionsList->propvar.vt == VT_UI4);
// Is there something to do?
if (pMsgInfo->wHighlight != (WORD) (pActionsList->propvar.ulVal))
{
pMsgInfo->wHighlight = (WORD) (pActionsList->propvar.ulVal);
pFolder->UpdateRecord(pMsgInfo);
}
break;
case ACT_TYPE_WATCH:
Assert(pActionsList->propvar.vt == VT_UI4);
// Is there something to do?
if (ACT_DATA_WATCHTHREAD == pActions[ulIndex].propvar.ulVal)
{
dwFlag = ARF_WATCH;
dwFlagRemove = ARF_IGNORE;
}
else
{
Assert(ACT_DATA_IGNORETHREAD == pActions[ulIndex].propvar.ulVal);
dwFlag = ARF_IGNORE;
dwFlagRemove = ARF_WATCH;
}
// Is there something to do?
if (0 == (pMsgInfo->dwFlags & dwFlag))
{
// Init flags
WatchFlags.dwAdd |= dwFlag;
WatchFlags.dwRemove |= dwFlagRemove;
// Mark as watched/ignored
fDoWatch = TRUE;
}
break;
case ACT_TYPE_FLAG:
Assert(pActionsList->propvar.vt == VT_EMPTY);
// Is there something to do?
if (0 == (pMsgInfo->dwFlags & ARF_FLAGGED))
{
// Init flags
Flags.dwAdd |= ARF_FLAGGED;
// Flag the message
fSetFlags = TRUE;
}
break;
case ACT_TYPE_READ:
Assert(pActionsList->propvar.vt == VT_EMPTY);
// Is there something to do?
if (0 == (pMsgInfo->dwFlags & ARF_READ))
{
// Init flags
Flags.dwAdd |= ARF_READ;
Flags.dwRemove = 0;
// Mark as read
fSetFlags = TRUE;
}
break;
case ACT_TYPE_MARKDOWNLOAD:
Assert(pActionsList->propvar.vt == VT_EMPTY);
// Is there something to do?
if (0 == (pMsgInfo->dwFlags & ARF_DOWNLOAD))
{
// Init flags
Flags.dwAdd |= ARF_DOWNLOAD;
Flags.dwRemove = 0;
// Mark as downloaded
fSetFlags = TRUE;
}
break;
case ACT_TYPE_FWD:
Assert(VT_LPSTR == pActionsList->propvar.vt);
SafeRelease(pIStm);
// Check message secure or not
if(NULL != pIMMsg)
{
pIMMsg->GetFlags(&dwFlag);
// Get the message source
if (!(IMF_SECURE & dwFlag) &&
(SUCCEEDED(pIMMsg->GetMessageSource(&pIStm, 0))))
{
// Auto Forward
fLoop = FALSE;
if ((FAILED(_HrAutoForwardMessage(hwndUI, pActionsList->propvar.pszVal,
pMsgInfo->pszAcctId, pIStm, &fLoop))) && (FALSE != fLoop))
{
if (NULL != pcInfiniteLoops)
{
(*pcInfiniteLoops)++;
}
}
else
{
// Is there something to do?
if (0 == (pMsgInfo->dwFlags & ARF_FORWARDED))
{
// Init flags
Flags.dwAdd |= ARF_FORWARDED;
Flags.dwRemove = 0;
// Mark as forwarded
fSetFlags = TRUE;
}
}
}
}
break;
case ACT_TYPE_REPLY:
Assert(VT_LPSTR == pActionsList->propvar.vt);
// Auto Reply
fLoop = FALSE;
SafeRelease(pIStm);
if (SUCCEEDED(pIExecRules->GetRuleFile(pActionsList->propvar.pszVal, &pIStm, &dwType)))
{
if ((FAILED(_HrAutoReplyMessage(hwndUI, dwType, pActionsList->propvar.pszVal, pIStm,
pMsgInfo->pszAcctId, pIMMsg, &fLoop))) && (FALSE != fLoop))
{
if (NULL != pcInfiniteLoops)
{
(*pcInfiniteLoops)++;
}
}
else
{
// Is there something to do?
if (0 == (pMsgInfo->dwFlags & ARF_REPLIED))
{
// Init flags
Flags.dwAdd |= ARF_REPLIED;
Flags.dwRemove = 0;
// Mark as replied
fSetFlags = TRUE;
}
}
}
break;
}
}
// Should we set the flags?
if (FALSE != fSetFlags)
{
SetMessageFlagsProgress(hwndUI, pFolder, &Flags, &List);
}
// Should we watch the message?
if (FALSE != fDoWatch)
{
_HrMarkThreadAsWatched(pMsgInfo->idMessage, pFolder, &WatchFlags);
}
// Do all non-modification operations next
for (pActionsList = pActions, ulIndex = 0; ulIndex < cActions; ulIndex++, pActionsList++)
{
switch(pActionsList->type)
{
case ACT_TYPE_COPY:
case ACT_TYPE_MOVE:
Assert(VT_BLOB == pActionsList->propvar.vt);
if (0 == pActionsList->propvar.blob.cbSize)
{
hr = S_FALSE;
goto exit;
}
// Make life simpler
prfdData = (RULEFOLDERDATA *) (pActionsList->propvar.blob.pBlobData);
// Validate the rule folder data
if (S_OK != RuleUtil_HrValidateRuleFolderData(prfdData))
{
hr = S_FALSE;
goto exit;
}
// Is there something to do?
if (idFolder != prfdData->idFolder)
{
hr = pIExecRules->GetRuleFolder(prfdData->idFolder, (DWORD_PTR *) (&pFolderNew));
if (FAILED(hr))
{
goto exit;
}
// Move/copy the messages
CopyMessagesProgress(hwndUI, pFolder, pFolderNew,
(pActionsList->type != ACT_TYPE_COPY) ? COPY_MESSAGE_MOVE : NOFLAGS,
&List, NULL);
}
break;
case ACT_TYPE_NOTIFYMSG:
// Nothing to do for now
break;
case ACT_TYPE_NOTIFYSND:
Assert(VT_LPSTR == pActionsList->propvar.vt);
hr = pIExecRules->AddSoundFile(ASF_PLAYIFNEW, pActionsList->propvar.pszVal);
if (FAILED(hr))
{
goto exit;
}
break;
case ACT_TYPE_DELETE:
Assert(pActionsList->propvar.vt == VT_EMPTY);
DeleteMessagesProgress(hwndUI, pFolder, dwDeleteFlags | DELETE_MESSAGE_NOPROMPT, &List);
break;
case ACT_TYPE_JUNKMAIL:
Assert(pActionsList->propvar.vt == VT_EMPTY);
// Get the Junk Mail folder id, if we don't already have it
if (FOLDERID_INVALID == idFolderJunkMail)
{
FOLDERINFO Folder;
hr = g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_JUNK, &Folder);
if (FAILED(hr))
{
goto exit;;
}
idFolderJunkMail = Folder.idFolder;
g_pStore->FreeRecord(&Folder);
}
hr = pIExecRules->GetRuleFolder(idFolderJunkMail, (DWORD_PTR *) (&pFolderNew));
if (FAILED(hr))
{
goto exit;
}
// Move the messages
CopyMessagesProgress(hwndUI, pFolder, pFolderNew, COPY_MESSAGE_MOVE, &List, NULL);
break;
case ACT_TYPE_DELETESERVER:
if (pfDeleteOffServer)
*pfDeleteOffServer = TRUE;
break;
case ACT_TYPE_DONTDOWNLOAD:
// Nothing to do for now
break;
case ACT_TYPE_STOP:
// Nothing to do for now
break;
}
}
// Set the proper return value
hr = S_OK;
exit:
SafeRelease(pIStm);
return hr;
}
HRESULT RuleUtil_HrCreateSendersRule(DWORD dwFlags, IOERule ** ppIRule)
{
HRESULT hr = S_OK;
IOERule * pIRule = NULL;
PROPVARIANT propvar = {0};
TCHAR szRes[CCHMAX_STRINGRES];
ACT_ITEM aitem;
// Check incoming params
if (NULL == ppIRule)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize the list
*ppIRule = NULL;
// Create the new rule
hr = HrCreateRule(&pIRule);
if (FAILED(hr))
{
goto exit;
}
// Get the name
if (0 != LoadString(g_hLocRes, idsBlockSender, szRes, ARRAYSIZE(szRes)))
{
propvar.vt = VT_LPSTR;
propvar.pszVal = szRes;
// Set the name
hr = pIRule->SetProp(RULE_PROP_NAME, 0, &propvar);
ZeroMemory(&propvar, sizeof(propvar));
if (FAILED(hr))
{
goto exit;
}
}
// Set the normal action
ZeroMemory(&aitem, sizeof(aitem));
aitem.type = ACT_TYPE_DELETE;
aitem.dwFlags = ACT_FLAG_DEFAULT;
PropVariantClear(&propvar);
propvar.vt = VT_BLOB;
propvar.blob.cbSize = sizeof(ACT_ITEM);
propvar.blob.pBlobData = (BYTE *) &aitem;
hr = pIRule->SetProp(RULE_PROP_ACTIONS, 0, &propvar);
ZeroMemory(&propvar, sizeof(propvar));
if (FAILED(hr))
{
goto exit;
}
// Set the outgoing param
*ppIRule = pIRule;
pIRule = NULL;
// Set the proper return value
hr = S_OK;
exit:
SafeRelease(pIRule);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// _HrLoadSender
//
// This creates the sender rule
//
//
// Returns: S_OK, if it was rules were successfully created
// S_FALSE, if the rules were already created
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RuleUtil_HrLoadSender(LPCSTR pszRegPath, DWORD dwFlags, IOERule ** ppIRule)
{
HRESULT hr = S_OK;
HKEY hkeyRoot = NULL;
LONG lErr = ERROR_SUCCESS;
DWORD dwData = 0;
ULONG cbData = 0;
TCHAR szRes[CCHMAX_STRINGRES];
IOERule * pIRule = NULL;
Assert(NULL != pszRegPath);
Assert(NULL != ppIRule);
// Let's get access to the sender root key
lErr = AthUserOpenKey(pszRegPath, KEY_ALL_ACCESS, &hkeyRoot);
if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
{
hr = E_FAIL;
goto exit;
}
// If we don't have it saved, then we're done
if (ERROR_FILE_NOT_FOUND == lErr)
{
hr = S_FALSE;
goto exit;
}
// Make sure we have a name
cbData = sizeof(dwData);
lErr = RegQueryValueEx(hkeyRoot, c_szRuleName, 0, NULL, NULL, &cbData);
if ((ERROR_SUCCESS != lErr) && (ERROR_FILE_NOT_FOUND != lErr))
{
hr = E_FAIL;
goto exit;
}
// Do we have to set the name?
if (ERROR_FILE_NOT_FOUND == lErr)
{
// Get the name
if (0 == LoadString(g_hLocRes, idsBlockSender, szRes, ARRAYSIZE(szRes)))
{
hr = E_FAIL;
goto exit;
}
// Set the name
lErr = RegSetValueEx(hkeyRoot, c_szRuleName, 0, REG_SZ, (BYTE *) szRes, lstrlen(szRes) + 1);
if (ERROR_SUCCESS != lErr)
{
hr = E_FAIL;
goto exit;
}
}
// Create the rule
hr = HrCreateRule(&pIRule);
if (FAILED(hr))
{
goto exit;
}
// Load in the rule
hr = pIRule->LoadReg(pszRegPath);
if (FAILED(hr))
{
goto exit;
}
// Set the outgoing param
*ppIRule = pIRule;
pIRule = NULL;
// Set the return value
hr = S_OK;
exit:
SafeRelease(pIRule);
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil_FMatchSender
//
// This match the sender to the message
//
//
// Returns: S_OK, if it was in the sender of the message
// S_FALSE, if it was not the sender of the message
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RuleUtil_HrMatchSender(LPCSTR pszSender, MESSAGEINFO * pMsgInfo,
IMimeMessage * pIMMsg, IMimePropertySet * pIMPropSet)
{
HRESULT hr = S_OK;
LPSTR pszAddr = NULL;
ADDRESSPROPS rSender = {0};
IMimeAddressTable * pIAddrTable = NULL;
BOOL fMatch = FALSE;
ULONG cchVal = 0;
ULONG cchEmail = 0;
CHAR chTest = 0;
// Do we have good values
if ((NULL == pszSender) || ((NULL == pMsgInfo) && (NULL == pIMMsg) && (NULL == pIMPropSet)))
{
hr = E_INVALIDARG;
goto exit;
}
// Check to make sure that there's something to match
if ('\0' == pszSender[0])
{
hr = S_FALSE;
goto exit;
}
// Get the address
if ((NULL != pMsgInfo) && (NULL != pMsgInfo->pszEmailFrom))
{
pszAddr = pMsgInfo->pszEmailFrom;
}
else if (NULL != pIMMsg)
{
rSender.dwProps = IAP_EMAIL;
if (SUCCEEDED(pIMMsg->GetSender(&rSender)))
{
pszAddr = rSender.pszEmail;
}
}
else if ((NULL != pIMPropSet) && (SUCCEEDED(pIMPropSet->BindToObject(IID_IMimeAddressTable, (LPVOID *)&pIAddrTable))))
{
rSender.dwProps = IAP_EMAIL;
if (SUCCEEDED(pIAddrTable->GetSender(&rSender)))
{
pszAddr = rSender.pszEmail;
}
pIAddrTable->Release();
}
// Did we find anything?
if (NULL == pszAddr)
{
hr = S_FALSE;
goto exit;
}
// Check to see if it is an address
if (NULL != StrStrI(pszSender, "@"))
{
fMatch = (0 == lstrcmpi(pszSender, pszAddr));
}
else
{
cchVal = lstrlen(pszSender);
cchEmail = lstrlen(pszAddr);
if (cchVal <= cchEmail)
{
fMatch = (0 == lstrcmpi(pszSender, pszAddr + (cchEmail - cchVal)));
if ((FALSE != fMatch) && (cchVal != cchEmail))
{
chTest = *(pszAddr + (cchEmail - cchVal - 1));
if (('@' != chTest) && ('.' != chTest))
{
fMatch = FALSE;
}
}
}
}
// Set the proper return value
hr = (FALSE != fMatch) ? S_OK : S_FALSE;
exit:
g_pMoleAlloc->FreeAddressProps(&rSender);
return hr;
}
HRESULT RuleUtil_HrValidateRuleFolderData(RULEFOLDERDATA * prfdData)
{
HRESULT hr = S_OK;
STOREUSERDATA UserData = {0};
// Check incoming params
if (NULL == prfdData)
{
hr = E_INVALIDARG;
goto exit;
}
// Get the timestamp for the store
hr = g_pStore->GetUserData(&UserData, sizeof(STOREUSERDATA));
if (FAILED(hr))
{
goto exit;
}
// Is the stamp correct
if ((UserData.ftCreated.dwLowDateTime != prfdData->ftStamp.dwLowDateTime) ||
(UserData.ftCreated.dwHighDateTime != prfdData->ftStamp.dwHighDateTime))
{
hr = S_FALSE;
goto exit;
}
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// _HrSetDefaultCriteria
//
// This creates a default rule in the specified location
//
//
// Returns: S_OK, if it was rules were successfully created
// S_FALSE, if the rules were already created
//
///////////////////////////////////////////////////////////////////////////////
HRESULT _HrSetDefaultCriteria(IOERule * pIRule, const DEFAULT_RULE * pdefRule)
{
HRESULT hr = S_OK;
PROPVARIANT propvar = {0};
CRIT_ITEM rgCritItem[CDEF_CRIT_ITEM_MAX];
ULONG cCritItem = 0;
Assert(NULL != pIRule);
Assert(NULL != pdefRule);
// Initialize the criteria
ZeroMemory(rgCritItem, sizeof(*rgCritItem) * CDEF_CRIT_ITEM_MAX);
// Set the criteria
switch (pdefRule->critType)
{
case DEF_CRIT_ALLMSGS:
cCritItem = 1;
rgCritItem[0].type = CRIT_TYPE_ALL;
rgCritItem[0].dwFlags = CRIT_FLAG_DEFAULT;
rgCritItem[0].propvar.vt = VT_EMPTY;
rgCritItem[0].logic = CRIT_LOGIC_NULL;
break;
case DEF_CRIT_READ:
cCritItem = 1;
rgCritItem[0].type = CRIT_TYPE_READ;
rgCritItem[0].dwFlags = CRIT_FLAG_DEFAULT;
rgCritItem[0].propvar.vt = VT_EMPTY;
rgCritItem[0].logic = CRIT_LOGIC_NULL;
break;
case DEF_CRIT_DWNLDMSGS:
cCritItem = 1;
rgCritItem[0].type = CRIT_TYPE_DOWNLOADED;
rgCritItem[0].dwFlags = CRIT_FLAG_DEFAULT;
rgCritItem[0].propvar.vt = VT_EMPTY;
rgCritItem[0].logic = CRIT_LOGIC_NULL;
break;
case DEF_CRIT_IGNTHDS:
cCritItem = 2;
rgCritItem[0].type = CRIT_TYPE_THREADSTATE;
rgCritItem[0].dwFlags = CRIT_FLAG_DEFAULT;
rgCritItem[0].propvar.vt = VT_UI4;
rgCritItem[0].propvar.ulVal = CRIT_DATA_IGNORETHREAD;
rgCritItem[0].logic = CRIT_LOGIC_OR;
rgCritItem[1].type = CRIT_TYPE_READ;
rgCritItem[1].dwFlags = CRIT_FLAG_DEFAULT;
rgCritItem[1].propvar.vt = VT_EMPTY;
rgCritItem[1].logic = CRIT_LOGIC_NULL;
break;
default:
hr = E_INVALIDARG;
goto exit;
}
// Set the rule criteria
propvar.vt = VT_BLOB;
propvar.blob.cbSize = cCritItem * sizeof(CRIT_ITEM);
propvar.blob.pBlobData = (BYTE *) rgCritItem;
hr = pIRule->SetProp(RULE_PROP_CRITERIA, 0, &propvar);
ZeroMemory(&propvar, sizeof(propvar));
if (FAILED(hr))
{
goto exit;
}
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// _HrSetDefaultActions
//
// This creates a default rule in the specified location
//
//
// Returns: S_OK, if it was rules were successfully created
// S_FALSE, if the rules were already created
//
///////////////////////////////////////////////////////////////////////////////
HRESULT _HrSetDefaultActions(IOERule * pIRule, const DEFAULT_RULE * pdefRule)
{
HRESULT hr = S_OK;
PROPVARIANT propvar = {0};
ACT_ITEM rgActItem[CDEF_ACT_ITEM_MAX];
ULONG cActItem = 0;
Assert(NULL != pIRule);
Assert(NULL != pdefRule);
// Initialize the actions
ZeroMemory(rgActItem, sizeof(*rgActItem) * CDEF_ACT_ITEM_MAX);
// Set the actions
switch (pdefRule->actType)
{
case DEF_ACT_SHOWMSGS:
cActItem = 1;
rgActItem[0].type = ACT_TYPE_SHOW;
rgActItem[0].dwFlags = ACT_FLAG_DEFAULT;
rgActItem[0].propvar.vt = VT_UI4;
rgActItem[0].propvar.ulVal = ACT_DATA_SHOW;
break;
case DEF_ACT_HIDEMSGS:
cActItem = 1;
rgActItem[0].type = ACT_TYPE_SHOW;
rgActItem[0].dwFlags = ACT_FLAG_DEFAULT;
rgActItem[0].propvar.vt = VT_UI4;
rgActItem[0].propvar.ulVal = ACT_DATA_HIDE;
break;
default:
hr = E_INVALIDARG;
goto exit;
}
// Set the rule actions
propvar.vt = VT_BLOB;
propvar.blob.cbSize = cActItem * sizeof(ACT_ITEM);
propvar.blob.pBlobData = (BYTE *) rgActItem;
hr = pIRule->SetProp(RULE_PROP_ACTIONS, 0, &propvar);
ZeroMemory(&propvar, sizeof(propvar));
if (FAILED(hr))
{
goto exit;
}
// Set the proper return value
hr = S_OK;
exit:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// _HrUpdateDefaultRule
//
// This creates a default rule in the specified location
//
//
// Returns: S_OK, if it was rules were successfully created
// S_FALSE, if the rules were already created
//
///////////////////////////////////////////////////////////////////////////////
HRESULT _HrUpdateDefaultRule(LPCSTR pszRegPath, const DEFAULT_RULE * pdefRule)
{
HRESULT hr = S_OK;
IOERule * pIRule = NULL;
TCHAR szFullPath[CCHMAX_STRINGRES];
TCHAR szName[CCHMAX_STRINGRES];
PROPVARIANT propvar = {0};
Assert(NULL != pszRegPath);
Assert(NULL != pdefRule);
// Whip up a rule
hr = HrCreateRule(&pIRule);
if (FAILED(hr))
{
goto exit;
}
// Build up the rule path
if(lstrlen(pszRegPath) >= sizeof(szFullPath) / sizeof(szFullPath[0]))
{
hr = E_FAIL;
goto exit;
}
StrCpyN(szFullPath, pszRegPath, ARRAYSIZE(szFullPath));
StrCatBuff(szFullPath, g_szBackSlash, ARRAYSIZE(szFullPath));
wnsprintf(szFullPath + lstrlen(szFullPath), (ARRAYSIZE(szFullPath) - lstrlen(szFullPath)), "%03X", pdefRule->ridRule);
// Do we need to do anything?
hr = pIRule->LoadReg(szFullPath);
if (SUCCEEDED(hr))
{
// Get the version from the rule
hr = pIRule->GetProp(RULE_PROP_VERSION, 0, &propvar);
if (SUCCEEDED(hr))
{
Assert(VT_UI4 == propvar.vt);
// Is the rule too old?
if (pdefRule->dwVersion <= propvar.ulVal)
{
//Bug# 67782
//We reload the name of the string every time in case, a localized version of OE is installed.
if (SUCCEEDED(hr = RuleUtil_SetName(pIRule, pdefRule->idName)))
{
if (SUCCEEDED(pIRule->SaveReg(szFullPath, TRUE)))
hr = S_FALSE;
}
goto exit;
}
}
}
//Bug# 67782
//We reload the name of the string every time in case, a localized version of OE is installed.
hr = RuleUtil_SetName(pIRule, pdefRule->idName);
if (FAILED(hr))
{
goto exit;
}
// Set the rule version
propvar.vt = VT_UI4;
propvar.ulVal = pdefRule->dwVersion - 1;
hr = pIRule->SetProp(RULE_PROP_VERSION, 0, &propvar);
ZeroMemory(&propvar, sizeof(propvar));
if (FAILED(hr))
{
goto exit;
}
// Set the rule criteria
hr = _HrSetDefaultCriteria(pIRule, pdefRule);
if (FAILED(hr))
{
goto exit;
}
// Set the rule actions
hr = _HrSetDefaultActions(pIRule, pdefRule);
if (FAILED(hr))
{
goto exit;
}
// Save the rule
hr = pIRule->SaveReg(szFullPath, TRUE);
if (FAILED(hr))
{
goto exit;
}
// Set the proper return value
hr = S_OK;
exit:
SafeRelease(pIRule);
return hr;
}
HRESULT RuleUtil_SetName(IOERule *pIRule, int idRes)
{
HRESULT hr = S_OK;
TCHAR szName[CCHMAX_STRINGRES];
PROPVARIANT propvar = {0};
if (0 == AthLoadString(idRes, szName, ARRAYSIZE(szName)))
{
hr = E_FAIL;
goto exit;
}
// Set the rule name
ZeroMemory(&propvar, sizeof(propvar));
propvar.vt = VT_LPSTR;
propvar.pszVal = szName;
hr = pIRule->SetProp(RULE_PROP_NAME, 0, &propvar);
exit:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RuleUtil_HrUpdateDefaultRules
//
// This updates the default rules for the specified rule type
// when the version in the registry is older than the current
// version
//
// Returns: S_OK, if it was rules were successfully updated
// S_FALSE, if the rules were already at the correct version
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RuleUtil_HrUpdateDefaultRules(RULE_TYPE typeRule)
{
HRESULT hr = S_OK;
LPCSTR pszSubKey = NULL;
LONG lErr = ERROR_SUCCESS;
HKEY hkeyRoot = NULL;
DWORD dwData = 0;
ULONG cbData = 0;
const DEFAULT_RULE * pdefrule = NULL;
ULONG cpdefrule = 0;
LPCSTR pszOrderDef = NULL;
ULONG ulIndex = 0;
// If we're already loaded then
// there's nothing to do
switch(typeRule)
{
case RULE_TYPE_FILTER:
pszSubKey = c_szRulesFilter;
pdefrule = g_defruleFilters;
cpdefrule = ARRAYSIZE(g_defruleFilters);
pszOrderDef = g_szOrderFilterDef;
break;
default:
// Nothing to do..
hr = S_FALSE;
goto exit;
}
// Check to see if the Rule node already exists
lErr = AthUserOpenKey(pszSubKey, KEY_ALL_ACCESS, &hkeyRoot);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
// Check the current version
cbData = sizeof(dwData);
lErr = RegQueryValueEx(hkeyRoot, c_szRulesVersion, NULL, NULL, (BYTE *) &dwData, &cbData);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
Assert(RULESMGR_VERSION == dwData);
// Update out the default rules
for (ulIndex = 0; ulIndex < cpdefrule; ulIndex++, pdefrule++)
{
hr = _HrUpdateDefaultRule(pszSubKey, pdefrule);
if (FAILED(hr))
{
goto exit;
}
}
// Write out the default order
if (NULL != pszOrderDef)
{
// If the order already exists, then leave it alone
lErr = RegQueryValueEx(hkeyRoot, c_szRulesOrder, NULL, NULL, NULL, &cbData);
if (ERROR_SUCCESS != lErr)
{
lErr = RegSetValueEx(hkeyRoot, c_szRulesOrder, 0,
REG_SZ, (CONST BYTE *) pszOrderDef, lstrlen(pszOrderDef) + 1);
if (ERROR_SUCCESS != lErr)
{
hr = HRESULT_FROM_WIN32(lErr);
goto exit;
}
}
}
// Set the proper return value
hr = S_OK;
exit:
if (NULL != hkeyRoot)
{
RegCloseKey(hkeyRoot);
}
return hr;
}
//--------------------------------------------------------------------------
// RuleUtil_HrGetFilterVersion
//--------------------------------------------------------------------------
HRESULT RuleUtil_HrGetFilterVersion(RULEID ridFilter, DWORD * pdwVersion)
{
HRESULT hr = S_OK;
IOERule * pIRule = NULL;
PROPVARIANT propvar = {0};
TraceCall("_GetFilterVersion");
Assert(NULL != pdwVersion);
// Is there something to do
if (RULEID_INVALID == ridFilter)
{
hr = E_FAIL;
goto exit;
}
// Initialize the outgoing param
*pdwVersion = 0;
// Get the rule from the rules manager
Assert(NULL != g_pRulesMan);
hr = g_pRulesMan->GetRule(ridFilter, RULE_TYPE_FILTER, 0, &pIRule);
if (FAILED(hr))
{
goto exit;
}
// Get the version from the rule
hr = pIRule->GetProp(RULE_PROP_VERSION, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
// Set the outgoing param
Assert(VT_UI4 == propvar.vt);
*pdwVersion = propvar.ulVal;
// Set the proper return value
hr = S_OK;
exit:
PropVariantClear(&propvar);
SafeRelease(pIRule);
return hr;
}
//--------------------------------------------------------------------------
// _HrWriteClause
//--------------------------------------------------------------------------
HRESULT _HrWriteClause(IStream * pStm, ULONG cClauses, BOOL fAnd, LPCSTR pszClause)
{
HRESULT hr = S_OK;
LPCSTR pszLogic = NULL;
// Do we have something to write
if (NULL != pszClause)
{
// Add the proper logical operation
if (cClauses > 0)
{
if (FALSE != fAnd)
{
pszLogic = c_szLogicalAnd;
}
else
{
pszLogic = c_szLogicalOr;
}
// Write Logical And
IF_FAILEXIT(hr = pStm->Write(pszLogic, lstrlen(pszLogic), NULL));
}
// Write out the clause
IF_FAILEXIT(hr = pStm->Write(pszClause, lstrlen(pszClause), NULL));
hr = S_OK;
}
else
{
hr = S_FALSE;
}
exit:
return hr;
}
//--------------------------------------------------------------------------
// _HrWriteFromClause
//--------------------------------------------------------------------------
HRESULT _HrWriteFromClause(IStream * pStream, ULONG cClauses, BOOL fAnd, DWORD dwFlags, LPCSTR pszText, ULONG * pcClausesNew)
{
HRESULT hr = S_OK;
ULONG cClausesOld = 0;
LPCSTR pszLogic = NULL;
LPCTSTR pszContains = NULL;
Assert(pStream && pszText && pcClausesNew);
// Add the proper logical operation
if (cClauses > 0)
{
if (FALSE != fAnd)
{
pszLogic = c_szLogicalAnd;
}
else
{
pszLogic = c_szLogicalOr;
}
// Write Logical And
IF_FAILEXIT(hr = pStream->Write(pszLogic, lstrlen(pszLogic), NULL));
}
// Figure out the logical operation
if (0 != (dwFlags & CRIT_FLAG_MULTIPLEAND))
{
pszLogic = c_szLogicalAnd;
}
else
{
pszLogic = c_szLogicalOr;
}
// Write the proper comparison op
if (0 == (dwFlags & CRIT_FLAG_INVERT))
{
pszContains = c_szFilterShow;
}
else
{
pszContains = c_szFilterHide;
}
// Write the left parenthesis
IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
// Write Logical And
IF_FAILEXIT(hr = pStream->Write(pszContains, lstrlen(pszContains), NULL));
// Write the left parenthesis
IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
// Add each of the addresses to the stream
cClausesOld = cClauses;
for (; '\0' != pszText[0]; pszText += lstrlen(pszText) + 1)
{
if ((cClauses - cClausesOld) > 0)
{
// Write Logical And
IF_FAILEXIT(hr = pStream->Write(pszLogic, lstrlen(pszLogic), NULL));
}
// Open the criteria
IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
// Write (MSGCOL_EMAILFROM containsi
IF_FAILEXIT(hr = pStream->Write(c_szEmailFromAddrPrefix, lstrlen(c_szEmailFromAddrPrefix), NULL));
// Write a Quote
IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
// Write a Email Address
IF_FAILEXIT(hr = pStream->Write(pszText, lstrlen(pszText), NULL));
// Write a Quote
IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
// Close the MSGCOL_EMAILFROM
IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
// Write Logical Or
IF_FAILEXIT(hr = pStream->Write(c_szLogicalOr, lstrlen(c_szLogicalOr), NULL));
// Write (MSGCOL_DISPLAYFROM containsi
IF_FAILEXIT(hr = pStream->Write(c_szEmailFromPrefix, lstrlen(c_szEmailFromPrefix), NULL));
// Write a Quote
IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
// Write a Email Address
IF_FAILEXIT(hr = pStream->Write(pszText, lstrlen(pszText), NULL));
// Write a Quote
IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
// Close the MSGCOL_DISPLAYFROM
IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
// Close the criteria
IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
cClauses++;
}
// Write the right parenthesis
IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
// Write the right parenthesis
IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
// Set the outgoing param
*pcClausesNew = cClauses - cClausesOld;
// Set the return value
hr = S_OK;
exit:
return hr;
}
//--------------------------------------------------------------------------
// _HrWriteTextClause
//--------------------------------------------------------------------------
HRESULT _HrWriteTextClause(IStream * pStream, ULONG cClauses, BOOL fAnd, DWORD dwFlags, LPCSTR pszHeader, LPCSTR pszText, ULONG * pcClausesNew)
{
HRESULT hr = S_OK;
ULONG cClausesOld = 0;
LPCSTR pszLogic = NULL;
LPCTSTR pszContains = NULL;
Assert(pStream && pszText && pcClausesNew);
// Add the proper logical operation
if (cClauses > 0)
{
if (FALSE != fAnd)
{
pszLogic = c_szLogicalAnd;
}
else
{
pszLogic = c_szLogicalOr;
}
// Write Logical And
IF_FAILEXIT(hr = pStream->Write(pszLogic, lstrlen(pszLogic), NULL));
}
// Figure out the logical operation
if (0 != (dwFlags & CRIT_FLAG_MULTIPLEAND))
{
pszLogic = c_szLogicalAnd;
}
else
{
pszLogic = c_szLogicalOr;
}
// Write the proper comparison op
if (0 == (dwFlags & CRIT_FLAG_INVERT))
{
pszContains = c_szFilterShow;
}
else
{
pszContains = c_szFilterHide;
}
// Write the left parenthesis
IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
// Write Logical And
IF_FAILEXIT(hr = pStream->Write(pszContains, lstrlen(pszContains), NULL));
// Write the left parenthesis
IF_FAILEXIT(hr = pStream->Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL));
// Add each of the words to the stream
cClausesOld = cClauses;
for (; '\0' != pszText[0]; pszText += lstrlen(pszText) + 1)
{
if ((cClauses - cClausesOld) > 0)
{
// Write Logical And
IF_FAILEXIT(hr = pStream->Write(pszLogic, lstrlen(pszLogic), NULL));
}
// Write (MSGCOL_EMAILFROM containsi
IF_FAILEXIT(hr = pStream->Write(pszHeader, lstrlen(pszHeader), NULL));
// Write a Quote
IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
// Write a Email Address
IF_FAILEXIT(hr = pStream->Write(pszText, lstrlen(pszText), NULL));
// Write a Quote
IF_FAILEXIT(hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL));
// Write Left Paren
IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
cClauses++;
}
// Write the right parenthesis
IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
// Write the right parenthesis
IF_FAILEXIT(hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL));
// Set the outgoing param
*pcClausesNew = cClauses - cClausesOld;
// Set the return value
hr = S_OK;
exit:
return hr;
}
//--------------------------------------------------------------------------
// _HrWriteAccountClause
//--------------------------------------------------------------------------
HRESULT _HrWriteAccountClause(IStream * pStream, ULONG cClauses, BOOL fAnd, LPCSTR pszAcctId, ULONG * pcClausesNew)
{
HRESULT hr = S_OK;
Assert(pStream && pszAcctId && pcClausesNew);
// Write the header
hr = _HrWriteClause(pStream, cClauses, fAnd, c_szEmailAcctPrefix);
if (FAILED(hr))
{
goto exit;
}
// Write a Quote
hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL);
if (FAILED(hr))
{
goto exit;
}
// Write the account ID
hr = pStream->Write(pszAcctId, lstrlen(pszAcctId), NULL);
if (FAILED(hr))
{
goto exit;
}
// Write a Quote
hr = pStream->Write(c_szDoubleQuote, lstrlen(c_szDoubleQuote), NULL);
if (FAILED(hr))
{
goto exit;
}
// Close the criteria query
hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL);
if (FAILED(hr))
{
goto exit;
}
// Set the outgoing param
*pcClausesNew = 1;
// Set the return value
hr = S_OK;
exit:
return hr;
}
//--------------------------------------------------------------------------
// _HrWriteUlongClause
//--------------------------------------------------------------------------
HRESULT _HrWriteUlongClause(IStream * pStream, ULONG cClauses, BOOL fAnd, LPCSTR pszHeader, ULONG ulVal, ULONG * pcClausesNew)
{
HRESULT hr = S_OK;
CHAR rgchBuff[10];
Assert(pStream && pszHeader && pcClausesNew);
// Write the header
hr = _HrWriteClause(pStream, cClauses, fAnd, pszHeader);
if (FAILED(hr))
{
goto exit;
}
// Convert the number to a string
rgchBuff[0] = '\0';
wnsprintf(rgchBuff, ARRAYSIZE(rgchBuff), "%d", ulVal);
// Write the account ID
hr = pStream->Write(rgchBuff, lstrlen(rgchBuff), NULL);
if (FAILED(hr))
{
goto exit;
}
// Close the criteria query
hr = pStream->Write(c_szRightParen, lstrlen(c_szRightParen), NULL);
if (FAILED(hr))
{
goto exit;
}
// Set the outgoing param
*pcClausesNew = 1;
// Set the return value
hr = S_OK;
exit:
return hr;
}
//--------------------------------------------------------------------------
// _HrWriteClauseFromCriteria
//--------------------------------------------------------------------------
HRESULT _HrWriteClauseFromCriteria(CRIT_ITEM *pCritItem, ULONG cClauses, BOOL fAnd, BOOL fShow, IStream *pStm, ULONG * pcClausesNew)
{
// Locals
HRESULT hr = S_OK;
LPCSTR pszClause = NULL;
ULONG cClausesNew = 0;
// Trace
TraceCall("WriteClauseFromCriteria");
// Invalid Args
Assert(pCritItem && pStm && pcClausesNew);
// Do we have something to do?
switch(pCritItem->type)
{
case CRIT_TYPE_SUBJECT:
Assert(VT_BLOB == pCritItem->propvar.vt);
hr = _HrWriteTextClause(pStm, cClauses, fAnd, pCritItem->dwFlags,
c_szEmailSubjectPrefix, (LPTSTR) (pCritItem->propvar.blob.pBlobData), &cClausesNew);
if (FAILED(hr))
{
goto exit;
}
break;
case CRIT_TYPE_ACCOUNT:
Assert(VT_LPSTR == pCritItem->propvar.vt);
hr = _HrWriteAccountClause(pStm, cClauses, fAnd, pCritItem->propvar.pszVal, &cClausesNew);
if (FAILED(hr))
{
goto exit;
}
break;
case CRIT_TYPE_FROM:
Assert(VT_BLOB == pCritItem->propvar.vt);
hr = _HrWriteFromClause(pStm, cClauses, fAnd, pCritItem->dwFlags,
(LPTSTR) (pCritItem->propvar.blob.pBlobData), &cClausesNew);
if (FAILED(hr))
{
goto exit;
}
break;
case CRIT_TYPE_PRIORITY:
Assert(VT_UI4 == pCritItem->propvar.vt);
switch (pCritItem->propvar.ulVal)
{
case CRIT_DATA_HIPRI:
pszClause = c_szFilterPriorityHi;
break;
case CRIT_DATA_LOPRI:
pszClause = c_szFilterPriorityLo;
break;
}
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
cClausesNew = 1;
break;
case CRIT_TYPE_ATTACH:
Assert(VT_EMPTY == pCritItem->propvar.vt);
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, c_szFilterAttach));
cClausesNew = 1;
break;
case CRIT_TYPE_READ:
Assert(VT_EMPTY == pCritItem->propvar.vt);
if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
{
pszClause = c_szFilterNotRead;
}
else
{
pszClause = c_szFilterRead;
}
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
cClausesNew = 1;
break;
case CRIT_TYPE_DOWNLOADED:
Assert(VT_EMPTY == pCritItem->propvar.vt);
if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
{
pszClause = c_szFilterNotDownloaded;
}
else
{
pszClause = c_szFilterDownloaded;
}
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
cClausesNew = 1;
break;
case CRIT_TYPE_DELETED:
Assert(VT_EMPTY == pCritItem->propvar.vt);
if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
{
pszClause = c_szFilterNotDeleted;
}
else
{
pszClause = c_szFilterDeleted;
}
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
cClausesNew = 1;
break;
case CRIT_TYPE_FLAGGED:
Assert(VT_EMPTY == pCritItem->propvar.vt);
if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
{
pszClause = c_szFilterNotFlagged;
}
else
{
pszClause = c_szFilterFlagged;
}
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
cClausesNew = 1;
break;
case CRIT_TYPE_THREADSTATE:
Assert(VT_UI4 == pCritItem->propvar.vt);
switch (pCritItem->propvar.ulVal)
{
case CRIT_DATA_IGNORETHREAD:
pszClause = c_szFilterIgnored;
break;
case CRIT_DATA_WATCHTHREAD:
pszClause = c_szFilterWatched;
break;
}
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
cClausesNew = 1;
break;
case CRIT_TYPE_LINES:
Assert(VT_UI4 == pCritItem->propvar.vt);
hr = _HrWriteUlongClause(pStm, cClauses, fAnd, c_szEmailLinesPrefix, pCritItem->propvar.ulVal, &cClausesNew);
if (FAILED(hr))
{
goto exit;
}
break;
case CRIT_TYPE_AGE:
Assert(VT_UI4 == pCritItem->propvar.vt);
hr = _HrWriteUlongClause(pStm, cClauses, fAnd, c_szEmailAgePrefix, pCritItem->propvar.ulVal, &cClausesNew);
if (FAILED(hr))
{
goto exit;
}
break;
case CRIT_TYPE_SECURE:
Assert(VT_UI4 == pCritItem->propvar.vt);
switch (pCritItem->propvar.ulVal)
{
case CRIT_DATA_ENCRYPTSECURE:
pszClause = c_szFilterEncrypt;
break;
case CRIT_DATA_SIGNEDSECURE:
pszClause = c_szFilterSigned;
break;
}
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
cClausesNew = 1;
break;
case CRIT_TYPE_REPLIES:
Assert(VT_EMPTY == pCritItem->propvar.vt);
if (0 != (pCritItem->dwFlags & CRIT_FLAG_INVERT))
{
pszClause = c_szFilterNotReplyPost;
}
else
{
pszClause = c_szFilterReplyPost;
}
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, pszClause));
cClausesNew = 1;
break;
case CRIT_TYPE_ALL:
Assert(VT_EMPTY == pCritItem->propvar.vt);
if (FALSE == fShow)
{
IF_FAILEXIT(hr = _HrWriteClause(pStm, cClauses, fAnd, c_szFilterShowAll));
cClausesNew = 1;
}
break;
}
// Set the outgoing param
*pcClausesNew = cClausesNew;
exit:
// Done
return(hr);
}
//--------------------------------------------------------------------------
// _HrBuildQueryFromFilter
//--------------------------------------------------------------------------
HRESULT _HrBuildQueryFromFilter(CRIT_ITEM * pCritList, ULONG cCritList, BOOL fShow,
LPSTR * ppszQuery, ULONG * pcchQuery,
ULONG * pcClauses)
{
HRESULT hr = S_OK;
BOOL fAnd = FALSE;
CByteStream stmQuery;
DWORD cClauses = 0;
ULONG ulIndex = 0;
LPSTR pszQuery = NULL;
ULONG cchQuery = 0;
BOOL fUnread = FALSE;
ULONG cClausesNew = 0;
Assert((NULL != ppszQuery) && (NULL != pcchQuery) && (NULL != pcClauses));
// Initialize all outgoing params
*ppszQuery = NULL;
*pcchQuery = 0;
*pcClauses = 0;
// Figure out the logic op
if (1 < cCritList)
{
fAnd = (CRIT_LOGIC_AND == pCritList->logic);
}
// Start the query string
hr = stmQuery.Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL);
if (FAILED(hr))
{
goto exit;
}
// Write out the proper action
if (FALSE == fShow)
{
// End the query string
IF_FAILEXIT(hr = stmQuery.Write(c_szFilterHide, lstrlen(c_szFilterHide), NULL));
}
else
{
// End the query string
IF_FAILEXIT(hr = stmQuery.Write(c_szFilterShow, lstrlen(c_szFilterShow), NULL));
}
// Start the criteria string
hr = stmQuery.Write(c_szLeftParen, lstrlen(c_szLeftParen), NULL);
if (FAILED(hr))
{
goto exit;
}
// For each of the criteria
for (ulIndex = 0; ulIndex < cCritList; ulIndex++)
{
// Write out the clause
hr = _HrWriteClauseFromCriteria(pCritList + ulIndex, cClauses, fAnd, fShow, &stmQuery, &cClausesNew);
if (FAILED(hr))
{
goto exit;
}
// If we did something
if (S_OK == hr)
{
cClauses += cClausesNew;
}
}
// Clauses
if (cClauses > 0)
{
// End the criteria string
hr = stmQuery.Write(c_szRightParen, lstrlen(c_szRightParen), NULL);
if (FAILED(hr))
{
goto exit;
}
// End the query string
hr = stmQuery.Write(c_szRightParen, lstrlen(c_szRightParen), NULL);
if (FAILED(hr))
{
goto exit;
}
// Return the Query
IF_FAILEXIT(hr = stmQuery.HrAcquireStringA(&cchQuery, &pszQuery, ACQ_DISPLACE));
}
// Set the outgoing param
*ppszQuery = pszQuery;
*pcchQuery = cchQuery;
*pcClauses = cClauses;
// Set the return value
hr = S_OK;
exit:
// Cleanup
// Done
return(hr);
}
//--------------------------------------------------------------------------
// RuleUtil_HrBuildQuerysFromFilter
//--------------------------------------------------------------------------
HRESULT RuleUtil_HrBuildQuerysFromFilter(RULEID ridFilter,
QUERYINFO * pqinfoFilter)
{
HRESULT hr = S_OK;
IOERule * pIRule = NULL;
PROPVARIANT propvar = {0};
CRIT_ITEM * pCritList = NULL;
ULONG cCritList = 0;
ACT_ITEM * pActList = NULL;
ULONG cActList = 0;
DWORD cClauses = 0;
LPSTR pszQuery = NULL;
ULONG cchQuery = 0;
// Initialize
ZeroMemory(pqinfoFilter, sizeof(pqinfoFilter));
// Get the rule
hr = g_pRulesMan->GetRule(ridFilter, RULE_TYPE_FILTER, 0, &pIRule);
if (FAILED(hr))
{
goto exit;
}
Assert(NULL != pIRule);
// Get criteria from filter
hr = pIRule->GetProp(RULE_PROP_CRITERIA, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
Assert(VT_BLOB == propvar.vt);
// Save off the criteria list
pCritList = (CRIT_ITEM *) propvar.blob.pBlobData;
cCritList = propvar.blob.cbSize / sizeof(CRIT_ITEM);
Assert(cCritList * sizeof(CRIT_ITEM) == propvar.blob.cbSize);
ZeroMemory(&propvar, sizeof(propvar));
// Get actions from filter
hr = pIRule->GetProp(RULE_PROP_ACTIONS, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
Assert(VT_BLOB == propvar.vt);
// Save off the actions list
pActList = (ACT_ITEM *) propvar.blob.pBlobData;
cActList = propvar.blob.cbSize / sizeof(ACT_ITEM);
Assert(cActList * sizeof(ACT_ITEM) == propvar.blob.cbSize);
ZeroMemory(&propvar, sizeof(propvar));
// Write out the proper action
Assert(1 == cActList);
Assert(ACT_TYPE_SHOW == pActList->type);
Assert(VT_UI4 == pActList->propvar.vt);
// Get the query string
hr = _HrBuildQueryFromFilter(pCritList, cCritList, (ACT_DATA_SHOW == pActList->propvar.ulVal),
&pszQuery, &cchQuery, &cClauses);
if (FAILED(hr))
{
goto exit;
}
// Set the outgoing param
pqinfoFilter->pszQuery = pszQuery;
pszQuery = NULL;
pqinfoFilter->cchQuery = cchQuery;
// Set the return value
hr = S_OK;
exit:
// Cleanup
if (NULL != pActList)
{
RuleUtil_HrFreeActionsItem(pActList, cActList);
MemFree(pActList);
}
if (NULL != pCritList)
{
RuleUtil_HrFreeCriteriaItem(pCritList, cCritList);
MemFree(pCritList);
}
SafeRelease(pIRule);
SafeMemFree(pszQuery);
// Done
return(hr);
}
typedef struct tagVIEWMENUMAP
{
RULEID ridFilter;
DWORD dwMenuID;
} VIEWMENUMAP, * PVIEWMENUMAP;
static const VIEWMENUMAP g_vmmDefault[] =
{
{RULEID_VIEW_ALL, ID_VIEW_ALL},
{RULEID_VIEW_UNREAD, ID_VIEW_UNREAD},
{RULEID_VIEW_DOWNLOADED, ID_VIEW_DOWNLOADED},
{RULEID_VIEW_IGNORED, ID_VIEW_IGNORED}
};
static const int g_cvmmDefault = sizeof(g_vmmDefault) / sizeof(g_vmmDefault[0]);
static const int VMM_ALL = 0;
static const int VMM_UNREAD = 1;
static const int VMM_DOWNLOADED = 2;
static const int VMM_IGNORED = 3;
///////////////////////////////////////////////////////////////////////////////
//
// HrCustomizeCurrentView
//
// This creates a rules editor of the proper type.
//
// hwnd - The owner dialog
// dwFlags - What type of editor to bring up
// ridFilter - The current filter to customize
//
// Returns: S_OK, on success
// E_OUTOFMEMORY, if can't create the Rules Manager object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT HrCustomizeCurrentView(HWND hwnd, DWORD dwFlags, RULEID * pridFilter)
{
HRESULT hr = S_OK;
CEditRuleUI * pEditRuleUI = NULL;
IOERule * pIFilter = NULL;
IOERule * pIFilterNew = NULL;
TCHAR szRes[CCHMAX_STRINGRES + 5];
ULONG cchRes = 0;
LPSTR pszName = NULL;
PROPVARIANT propvar = {0};
RULEINFO infoRule = {0};
DWORD dwFlagsSet = 0;
// Check incoming params
if ((NULL == hwnd) || (NULL == pridFilter) || (RULEID_INVALID == *pridFilter))
{
hr = E_INVALIDARG;
goto exit;
}
// Create a rule editor object
pEditRuleUI = new CEditRuleUI;
if (NULL == pEditRuleUI)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Get the filter
hr = g_pRulesMan->GetRule(*pridFilter, RULE_TYPE_FILTER, 0, &pIFilter);
if (FAILED(hr))
{
goto exit;
}
// Clone the rule
hr = pIFilter->Clone(&pIFilterNew);
if (FAILED(hr))
{
goto exit;
}
// Is this filter a read only filter?
if (FALSE != FIsFilterReadOnly(*pridFilter))
{
// Get the name from the source rule
hr = pIFilterNew->GetProp(RULE_PROP_NAME, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
// Get the string template to display
cchRes = LoadString(g_hLocRes, idsRulesCopyName, szRes, ARRAYSIZE(szRes));
if (0 == cchRes)
{
goto exit;
}
// Allocate space to hold the final display string
DWORD cchSize = (cchRes + lstrlen(propvar.pszVal) + 1);
hr = HrAlloc((void ** ) &pszName, cchSize);
if (FAILED(hr))
{
goto exit;
}
// Build up the string and set it
wnsprintf(pszName, cchSize, szRes, propvar.pszVal);
PropVariantClear(&propvar);
propvar.vt = VT_LPSTR;
propvar.pszVal = pszName;
pszName = NULL;
// Set the name into the new rule
Assert(VT_LPSTR == propvar.vt);
Assert(NULL != propvar.pszVal);
hr = pIFilterNew->SetProp(RULE_PROP_NAME, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
// Clear the version of the new rule
PropVariantClear(&propvar);
propvar.vt = VT_UI4;
propvar.ulVal = 0;
hr = pIFilterNew->SetProp(RULE_PROP_VERSION, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
// Set the rule id to invalid
*pridFilter = RULEID_INVALID;
// Note that we want to append the rule
dwFlagsSet = SETF_APPEND;
}
else
{
dwFlagsSet = SETF_REPLACE;
}
// Initialize the rule editor object
hr = pEditRuleUI->HrInit(hwnd, ERF_CUSTOMIZEVIEW, RULE_TYPE_FILTER, pIFilterNew, NULL);
if (FAILED(hr))
{
goto exit;
}
// Bring up the rules editor UI
hr = pEditRuleUI->HrShow();
if (FAILED(hr))
{
goto exit;
}
// Did anything change
if (S_OK == hr)
{
// Initialize the rule info
infoRule.pIRule = pIFilterNew;
infoRule.ridRule = *pridFilter;
// Add the rule to the list of rules
hr = g_pRulesMan->SetRules(dwFlagsSet, RULE_TYPE_FILTER, &infoRule, 1);
if(FAILED(hr))
{
goto exit;
}
*pridFilter = infoRule.ridRule;
}
exit:
PropVariantClear(&propvar);
SafeMemFree(pszName);
SafeRelease(pIFilterNew);
SafeRelease(pIFilter);
if (NULL != pEditRuleUI)
{
delete pEditRuleUI;
}
return hr;
}
CViewMenu::~CViewMenu()
{
if (NULL != m_pmruList)
{
delete m_pmruList;
}
}
ULONG CViewMenu::AddRef(VOID)
{
return ++m_cRef;
}
ULONG CViewMenu::Release(VOID)
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
HRESULT CViewMenu::HrInit(DWORD dwFlags)
{
HRESULT hr = S_OK;
m_dwFlags = dwFlags;
// Create the MRU list
m_pmruList = new CMRUList;
if (NULL == m_pmruList)
{
hr = E_OUTOFMEMORY;
goto exit;
}
m_pmruList->CreateList(5, 0, c_szRulesFilterMRU);
// Make sure the MRU list is up to date
SideAssert(FALSE != _FValiadateMRUList());
m_dwState |= STATE_INIT;
hr = S_OK;
exit:
return hr;
}
HRESULT CViewMenu::HrReplaceMenu(DWORD dwFlags, HMENU hmenu)
{
HRESULT hr = S_OK;
HMENU hmenuView = NULL;
MENUITEMINFO mii = {0};
// Load in the real view menu
hmenuView = LoadPopupMenu(IDR_VIEW_POPUP);
if (NULL == hmenuView)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Add in the default views
_AddDefaultViews(hmenuView);
// Set the real view menu in
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU;
mii.hSubMenu = hmenuView;
SetMenuItemInfo(hmenu, ID_POPUP_FILTER, FALSE, &mii);
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
hr = S_OK;
exit:
return hr;
}
HRESULT CViewMenu::UpdateViewMenu(DWORD dwFlags, HMENU hmenuView, IMessageList * pMsgList)
{
HRESULT hr = S_OK;
IOEMessageList * pIMsgList = NULL;
ULONGLONG ullFolder = 0;
FOLDERID idFolder = FOLDERID_INVALID;
FOLDERINFO infoFolder = {0};
MENUITEMINFO mii = {0};
BOOL fDeletedExists = FALSE;
BOOL fDownloadedExists = FALSE;
BOOL fRepliesExists = FALSE;
CHAR szName[CCHMAX_STRINGRES];
// Check incoming params
if (NULL == pMsgList)
{
hr = E_INVALIDARG;
goto exit;
}
// Have we been initialized yet?
if (0 == (m_dwState & STATE_INIT))
{
hr = E_UNEXPECTED;
goto exit;
}
// If we don't have a menu, we got problems
if ((NULL == hmenuView) || (FALSE == IsMenu(hmenuView)))
{
hr = E_FAIL;
goto exit;
}
// Get the folder type from the list
// Get the OE message list interface
if (FAILED(pMsgList->QueryInterface(IID_IOEMessageList, (VOID **) &pIMsgList)))
{
hr = E_FAIL;
goto exit;
}
// Get the folder id from the list
hr = pIMsgList->get_Folder(&ullFolder);
if (FAILED(hr))
{
goto exit;
}
idFolder = (FOLDERID) ullFolder;
// Get the folder info from the folder id
Assert(NULL != g_pStore);
hr = g_pStore->GetFolderInfo(idFolder, &infoFolder);
if (FAILED(hr))
{
goto exit;
}
// Figure out if we're supposed to remove/add IMAP specific menus
// Initialize the menu info for searching
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_DATA;
// Does the ID_SHOW_DELETED menu item exist?
if (FALSE != GetMenuItemInfo(hmenuView, ID_SHOW_DELETED, FALSE, &mii))
{
fDeletedExists = TRUE;
}
// Does the ID_SHOW_REPLIES menu item exist?
if (FALSE != GetMenuItemInfo(hmenuView, ID_SHOW_REPLIES, FALSE, &mii))
{
fRepliesExists = TRUE;
}
// Does the ID_VIEW_DOWNLOADED menu item exist?
if (FALSE != GetMenuItemInfo(hmenuView, ID_VIEW_DOWNLOADED, FALSE, &mii))
{
fDownloadedExists = TRUE;
}
// If the folder is not a LOCAL folder or it is a find folder and
// the menu item item does not exist
if (((FOLDER_LOCAL != infoFolder.tyFolder) || (0 != (m_dwFlags & VMF_FINDER)))&& (FALSE == fDownloadedExists))
{
// Insert the downloaded menu after the replies menu
hr = _HrInsertViewMenu(hmenuView, g_vmmDefault[VMM_DOWNLOADED].ridFilter,
g_vmmDefault[VMM_DOWNLOADED].dwMenuID, ID_VIEW_IGNORED);
if (FAILED(hr))
{
goto exit;
}
}
// else if the folder is a LOCAL folder and not a find folder and
// the menu item does exist
else if ((FOLDER_LOCAL == infoFolder.tyFolder) && (0 == (m_dwFlags & VMF_FINDER)) && (FALSE != fDownloadedExists))
{
// Remove the Deleted Items menu
RemoveMenu(hmenuView, ID_VIEW_DOWNLOADED, MF_BYCOMMAND);
}
// If the folder is an NNTP folder and
// the menu item item does not exist
if ((FOLDER_NEWS == infoFolder.tyFolder) && (FALSE == fRepliesExists))
{
// Get the name of the deleted item string
AthLoadString(idsViewReplies, szName, sizeof(szName));
// Initialize the menu info
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.wID = ID_SHOW_REPLIES;
mii.dwTypeData = szName;
mii.cch = lstrlen(szName);
// Insert the menu item
if (FALSE == InsertMenuItem(hmenuView, ID_THREAD_MESSAGES, FALSE, &mii))
{
hr = E_FAIL;
goto exit;
}
}
// else if the folder is not an NNTP folder and
// the menu item does exist
else if ((FOLDER_NEWS != infoFolder.tyFolder) && (FALSE != fRepliesExists))
{
// Remove the Deleted Items menu
RemoveMenu(hmenuView, ID_SHOW_REPLIES, MF_BYCOMMAND);
}
// If the folder is an IMAP folder or a find folder and
// the menu item item does not exist
if (((FOLDER_IMAP == infoFolder.tyFolder) || (0 != (m_dwFlags & VMF_FINDER))) && (FALSE == fDeletedExists))
{
// Get the name of the deleted item string
AthLoadString(idsShowDeleted, szName, sizeof(szName));
// Initialize the menu info
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.wID = ID_SHOW_DELETED;
mii.dwTypeData = szName;
mii.cch = lstrlen(szName);
// Insert the menu item
if (FALSE == InsertMenuItem(hmenuView, ID_THREAD_MESSAGES, FALSE, &mii))
{
hr = E_FAIL;
goto exit;
}
}
// else if the folder is not an IMAP folder and not a Find folder and
// the menu item does exist
else if ((FOLDER_IMAP != infoFolder.tyFolder) && (0 == (m_dwFlags & VMF_FINDER)) && (FALSE != fDeletedExists))
{
// Remove the Deleted Items menu
RemoveMenu(hmenuView, ID_SHOW_DELETED, MF_BYCOMMAND);
}
// if we're dirty
if (0 != (m_dwState & STATE_DIRTY))
{
// Load in the MRU filter list
hr = _HrReloadMRUViewMenu(hmenuView);
if (FAILED(hr))
{
goto exit;
}
// Note that we've reloaded ourselves
m_dwState &= ~STATE_DIRTY;
}
// See if we need to add the extra view menu
hr = _HrAddExtraViewMenu(hmenuView, pIMsgList);
if (FAILED(hr))
{
goto exit;
}
// Set the return value
hr = S_OK;
exit:
g_pStore->FreeRecord(&infoFolder);
SafeRelease(pIMsgList);
return hr;
}
HRESULT CViewMenu::QueryStatus(IMessageList * pMsgList, OLECMD * prgCmds)
{
HRESULT hr = S_OK;
IOEMessageList * pIMsgList = NULL;
BOOL fThreading = FALSE;
BOOL fShowDeleted = FALSE;
BOOL fShowReplies = FALSE;
MENUITEMINFO mii = {0};
CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
ULONGLONG ullFilter = 0;
RULEID ridFilter = RULEID_INVALID;
RULEID ridFilterTag = RULEID_INVALID;
// Check incoming params
if ((NULL == pMsgList) || (NULL == prgCmds))
{
hr = E_INVALIDARG;
goto exit;
}
// Get the OE message list interface
if (FAILED(pMsgList->QueryInterface(IID_IOEMessageList, (VOID **) &pIMsgList)))
{
hr = E_FAIL;
goto exit;
}
// Get the current filter on the message list
pIMsgList->get_FilterMessages(&ullFilter);
ridFilter = (RULEID) ullFilter;
// Set the flags on the correct menu item
switch(prgCmds->cmdID)
{
case ID_VIEW_ALL:
// These menu item are always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
// If this filter is turned on, make sure the item is checked
if (g_vmmDefault[VMM_ALL].ridFilter == ridFilter)
{
prgCmds->cmdf |= OLECMDF_NINCHED;
}
break;
case ID_VIEW_UNREAD:
// These menu item are always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
// If this filter is turned on, make sure the item is checked
if (g_vmmDefault[VMM_UNREAD].ridFilter == ridFilter)
{
prgCmds->cmdf |= OLECMDF_NINCHED;
}
break;
case ID_VIEW_DOWNLOADED:
// These menu item are always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
// If this filter is turned on, make sure the item is checked
if (g_vmmDefault[VMM_DOWNLOADED].ridFilter == ridFilter)
{
prgCmds->cmdf |= OLECMDF_NINCHED;
}
break;
case ID_VIEW_IGNORED:
// These menu item are always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
// If this filter is turned on, make sure the item is checked
if (g_vmmDefault[VMM_IGNORED].ridFilter == ridFilter)
{
prgCmds->cmdf |= OLECMDF_NINCHED;
}
break;
case ID_VIEW_CURRENT:
// These menu item are always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
// If this filter is turned on, make sure the item is checked
if (m_ridCurrent == ridFilter)
{
prgCmds->cmdf |= OLECMDF_NINCHED;
}
break;
case ID_VIEW_RECENT_0:
case ID_VIEW_RECENT_1:
case ID_VIEW_RECENT_2:
case ID_VIEW_RECENT_3:
case ID_VIEW_RECENT_4:
// These menu item are always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
if (NULL != m_pmruList)
{
if (-1 == m_pmruList->EnumList(prgCmds->cmdID - ID_VIEW_RECENT_0, rgchFilterTag, ARRAYSIZE(rgchFilterTag)))
{
break;
}
if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilterTag))
{
break;
}
// If this filter is turned on, make sure the item is checked
if (ridFilterTag == ridFilter)
{
prgCmds->cmdf |= OLECMDF_NINCHED;
}
}
break;
case ID_VIEW_APPLY:
case ID_VIEW_CUSTOMIZE:
case ID_VIEW_MANAGER:
// If we have a Rules Manager,
// then we are enabled
if (NULL != g_pRulesMan)
{
prgCmds->cmdf |= OLECMDF_ENABLED;
}
break;
case ID_SHOW_REPLIES:
// These menu item are always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
// Check to see if show replies is turned on
if (SUCCEEDED(pIMsgList->get_ShowReplies(&fShowReplies)))
{
// If replies is turned on, make sure the item is checked
if (FALSE != fShowReplies)
{
prgCmds->cmdf |= OLECMDF_LATCHED;
}
}
break;
case ID_SHOW_DELETED:
// These menu item are always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
// Check to see if show deleted is turned on
if (SUCCEEDED(pIMsgList->get_ShowDeleted(&fShowDeleted)))
{
// If threading is turned on, make sure the item is checked
if (FALSE != fShowDeleted)
{
prgCmds->cmdf |= OLECMDF_LATCHED;
}
}
break;
case ID_THREAD_MESSAGES:
// This menu item is always enabled
prgCmds->cmdf |= OLECMDF_ENABLED;
// Check to see if threading is turned on
if (SUCCEEDED(pIMsgList->get_GroupMessages(&fThreading)))
{
// If threading is turned on, make sure the item is checked
if (FALSE != fThreading)
{
prgCmds->cmdf |= OLECMDF_LATCHED;
}
}
break;
}
// Set the proper return value
hr = S_OK;
exit:
SafeRelease(pIMsgList);
return hr;
}
HRESULT CViewMenu::Exec(HWND hwndUI, DWORD nCmdID, IMessageList * pMsgList, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
{
HRESULT hr = S_OK;
IOEMessageList * pIMsgList = NULL;
BOOL fThreading = FALSE;
BOOL fShowDeleted = FALSE;
BOOL fShowReplies = FALSE;
MENUITEMINFO mii = {0};
ULONGLONG ullFilter = 0;
RULEID ridFilter = RULEID_INVALID;
TCHAR rgchFilterTag[CCH_FILTERTAG_MAX];
RULEID ridFilterTag = RULEID_INVALID;
FOLDERID idFolder = FOLDERID_INVALID;
ULONGLONG ullFolder = 0;
FOLDERTYPE typeFolder = FOLDER_INVALID;
DWORD dwFlags = 0;
BOOL fApplyAll = FALSE;
// Check incoming params
if (NULL == pMsgList)
{
hr = E_INVALIDARG;
goto exit;
}
// Get the OE message list interface
hr = pMsgList->QueryInterface(IID_IOEMessageList, (VOID **) &pIMsgList);
if (FAILED(hr))
{
goto exit;
}
// Get the current filter on the message list
hr = pIMsgList->get_FilterMessages(&ullFilter);
if (FAILED(hr))
{
goto exit;
}
ridFilter = (RULEID) ullFilter;
// Execute the actions for the correct menu item
switch(nCmdID)
{
case ID_VIEW_ALL:
// If this filter is turned on, make sure the item is checked
if (g_vmmDefault[VMM_ALL].ridFilter != ridFilter)
{
// Set the new filter on the item
hr = pIMsgList->put_FilterMessages((ULONGLONG) g_vmmDefault[VMM_ALL].ridFilter);
if (FAILED(hr))
{
goto exit;
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
break;
case ID_VIEW_UNREAD:
// If this filter is turned on, make sure the item is checked
if (g_vmmDefault[VMM_UNREAD].ridFilter != ridFilter)
{
// Set the new filter on the item
hr = pIMsgList->put_FilterMessages((ULONGLONG) g_vmmDefault[VMM_UNREAD].ridFilter);
if (FAILED(hr))
{
goto exit;
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
break;
case ID_VIEW_DOWNLOADED:
// If this filter is turned on, make sure the item is checked
if (g_vmmDefault[VMM_DOWNLOADED].ridFilter != ridFilter)
{
// Set the new filter on the item
hr = pIMsgList->put_FilterMessages((ULONGLONG) g_vmmDefault[VMM_DOWNLOADED].ridFilter);
if (FAILED(hr))
{
goto exit;
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
break;
case ID_VIEW_IGNORED:
// If this filter is turned on, make sure the item is checked
if (g_vmmDefault[VMM_IGNORED].ridFilter != ridFilter)
{
// Set the new filter on the item
hr = pIMsgList->put_FilterMessages((ULONGLONG) g_vmmDefault[VMM_IGNORED].ridFilter);
if (FAILED(hr))
{
goto exit;
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
break;
case ID_VIEW_CURRENT:
// Make sure we add the filter to the MRU list
_AddViewToMRU(m_ridCurrent);
// If this filter is turned on, make sure the item is checked
if (m_ridCurrent != ridFilter)
{
// Set the new filter on the item
hr = pIMsgList->put_FilterMessages((ULONGLONG) m_ridCurrent);
if (FAILED(hr))
{
goto exit;
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
break;
case ID_VIEW_RECENT_0:
case ID_VIEW_RECENT_1:
case ID_VIEW_RECENT_2:
case ID_VIEW_RECENT_3:
case ID_VIEW_RECENT_4:
if (NULL != m_pmruList)
{
if (-1 == m_pmruList->EnumList(nCmdID - ID_VIEW_RECENT_0, rgchFilterTag, ARRAYSIZE(rgchFilterTag)))
{
break;
}
if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilterTag))
{
break;
}
// Make sure we add the filter to the MRU list
_AddViewToMRU(ridFilterTag);
// If this filter is turned on, make sure the item is checked
if (ridFilterTag != ridFilter)
{
// Set the new filter on the item
hr = pIMsgList->put_FilterMessages((ULONGLONG) ridFilterTag);
if (FAILED(hr))
{
goto exit;
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
}
break;
case ID_VIEW_APPLY:
if ((NULL != pvaIn) && (VT_I4 == pvaIn->vt))
{
// Make sure we add the filter to the MRU list
_AddViewToMRU((RULEID) IntToPtr(pvaIn->lVal));
// If threading is turned on, make sure the item is checked
if (ridFilter != (RULEID) IntToPtr(pvaIn->lVal))
{
// Set the new filter on the item
hr = pIMsgList->put_FilterMessages((long) pvaIn->lVal);
if (FAILED(hr))
{
goto exit;
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
}
break;
case ID_VIEW_CUSTOMIZE:
hr = HrCustomizeCurrentView(hwndUI, 0, &ridFilter);
if (FAILED(hr))
{
goto exit;
}
// If the views list changed, then apply the filter to the list
if (S_OK == hr)
{
// Make sure we add the filter to the MRU list
_AddViewToMRU(ridFilter);
// Get the current threading state
hr = pIMsgList->put_FilterMessages((ULONGLONG) ridFilter);
if (FAILED(hr))
{
goto exit;
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
break;
case ID_VIEW_MANAGER:
if (0 == (m_dwFlags & VMF_FINDER))
{
// Get the current folder id
hr = pIMsgList->get_Folder(&ullFolder);
if (FAILED(hr))
{
goto exit;
}
idFolder = (FOLDERID) ullFolder;
// Get the folder info for this folder
typeFolder = GetFolderType(idFolder);
if (FOLDER_LOCAL == typeFolder)
{
dwFlags = VRDF_POP3;
}
else if (FOLDER_NEWS == typeFolder)
{
dwFlags = VRDF_NNTP;
}
else if (FOLDER_IMAP == typeFolder)
{
dwFlags = VRDF_IMAP;
}
else if (FOLDER_HTTPMAIL == typeFolder)
{
dwFlags = VRDF_HTTPMAIL;
}
}
hr = HrDoViewsManagerDialog(hwndUI, dwFlags, &ridFilter, &fApplyAll);
if (FAILED(hr))
{
goto exit;
}
// If the views list changed, then apply the filter to the list
if (S_OK == hr)
{
// Make sure the MRU list is up to date
SideAssert(FALSE != _FValiadateMRUList());
// Make sure we add the filter to the MRU list
_AddViewToMRU(ridFilter);
// Get the current threading state
hr = pIMsgList->put_FilterMessages((ULONGLONG) ridFilter);
if (FAILED(hr))
{
goto exit;
}
if (FALSE != fApplyAll)
{
// Set the global view
SetDwOption(OPT_VIEW_GLOBAL, PtrToUlong(ridFilter), NULL, 0);
// Set the new view on all the subscribed folders
hr = RecurseFolderHierarchy(FOLDERID_ROOT, RECURSE_SUBFOLDERS | RECURSE_INCLUDECURRENT,
0, (DWORD_PTR) ridFilter, _HrRecurseSetFilter);
if (FAILED(hr))
{
goto exit;
}
}
// Mark the menu as dirty
m_dwState |= STATE_DIRTY;
}
break;
case ID_SHOW_REPLIES:
// Get the current deleted state
hr = pIMsgList->get_ShowReplies(&fShowReplies);
if (FAILED(hr))
{
goto exit;
}
// Switch it to the opposite state
fShowReplies = !fShowReplies;
// Set the current deleted state
hr = pIMsgList->put_ShowReplies(fShowReplies);
if (FAILED(hr))
{
goto exit;
}
break;
case ID_SHOW_DELETED:
// Get the current deleted state
hr = pIMsgList->get_ShowDeleted(&fShowDeleted);
if (FAILED(hr))
{
goto exit;
}
// Switch it to the opposite state
fShowDeleted = !fShowDeleted;
// Set the current deleted state
hr = pIMsgList->put_ShowDeleted(fShowDeleted);
if (FAILED(hr))
{
goto exit;
}
break;
case ID_THREAD_MESSAGES:
// Get the current threading state
hr = pIMsgList->get_GroupMessages(&fThreading);
if (FAILED(hr))
{
goto exit;
}
// Switch it to the opposite state
fThreading = !fThreading;
// Set the current threading state
hr = pIMsgList->put_GroupMessages(fThreading);
if (FAILED(hr))
{
goto exit;
}
break;
}
// Set the proper return value
hr = S_OK;
exit:
SafeRelease(pIMsgList);
return hr;
}
VOID CViewMenu::_AddDefaultViews(HMENU hmenu)
{
HRESULT hr = S_OK;
ULONG ulIndex = 0;
PROPVARIANT propvar = {0};
IOERule * pIFilter = NULL;
MENUITEMINFO mii = {0};
ULONG ulMenu = 0;
Assert(NULL != hmenu);
// If we don't have a rules manager then fail
if (NULL == g_pRulesMan)
{
goto exit;
}
// Initialize the menu info
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
// Add each one of the default views
for (ulIndex = 0; ulIndex < g_cvmmDefault; ulIndex++)
{
// Get the view from the rules manager
if (FAILED(g_pRulesMan->GetRule(g_vmmDefault[ulIndex].ridFilter, RULE_TYPE_FILTER, 0, &pIFilter)))
{
continue;
}
// Get the name from the rule
ZeroMemory(&propvar, sizeof(propvar));
if ((SUCCEEDED(pIFilter->GetProp(RULE_PROP_NAME, 0, &propvar))) &&
(NULL != propvar.pszVal))
{
// Add the name to the rule
Assert(VT_LPSTR == propvar.vt);
mii.wID = g_vmmDefault[ulIndex].dwMenuID;
mii.dwItemData = (DWORD_PTR) g_vmmDefault[ulIndex].ridFilter;
mii.dwTypeData = propvar.pszVal;
mii.cch = lstrlen(propvar.pszVal);
if (FALSE != InsertMenuItem(hmenu, ulMenu, TRUE, &mii))
{
ulMenu++;
}
}
PropVariantClear(&propvar);
SafeRelease(pIFilter);
}
// Add in the default separator if we added at least one item
if (0 != ulMenu)
{
// Set up the menu items
mii.fMask = MIIM_ID | MIIM_TYPE;
mii.fType = MFT_SEPARATOR;
mii.fState = MFS_ENABLED;
mii.wID = ID_VIEW_DEFAULT_SEPERATOR;
mii.dwItemData = 0;
mii.dwTypeData = 0;
mii.cch = 0;
// Insert the separator
InsertMenuItem(hmenu, ulMenu, TRUE, &mii);
}
exit:
PropVariantClear(&propvar);
SafeRelease(pIFilter);
return;
}
HRESULT CViewMenu::_HrInsertViewMenu(HMENU hmenuView, RULEID ridFilter, DWORD dwMenuID, DWORD dwMenuIDInsert)
{
HRESULT hr = S_OK;
IOERule * pIFilter = NULL;
PROPVARIANT propvar = {0};
MENUITEMINFO mii = {0};
// Get the view from the rules manager
hr = g_pRulesMan->GetRule(ridFilter, RULE_TYPE_FILTER, 0, &pIFilter);
if (FAILED(hr))
{
goto exit;
}
// Get the name from the view
hr = pIFilter->GetProp(RULE_PROP_NAME, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
// Nothing to do if we don't have a name
if (NULL == propvar.pszVal)
{
hr = E_FAIL;
goto exit;
}
// Initialize the menu info
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.fState = MFS_ENABLED;
mii.wID = dwMenuID;
mii.dwItemData = (DWORD_PTR) ridFilter;
mii.dwTypeData = propvar.pszVal;
mii.cch = lstrlen(propvar.pszVal);
// Insert the menu item
if (FALSE == InsertMenuItem(hmenuView, dwMenuIDInsert, FALSE, &mii))
{
hr = E_FAIL;
goto exit;
}
// Set the return value
hr = S_OK;
exit:
PropVariantClear(&propvar);
SafeRelease(pIFilter);
return hr;
}
HRESULT CViewMenu::_HrReloadMRUViewMenu(HMENU hmenuView)
{
HRESULT hr = S_OK;
ULONG ulMenu = 0;
INT nItem = 0;
CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
RULEID ridFilter = RULEID_INVALID;
MENUITEMINFO mii = {0};
// Set up the menu items
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID;
// Delete the old items
for (ulMenu = ID_VIEW_RECENT_0; ulMenu < ID_VIEW_CUSTOMIZE; ulMenu++)
{
if (FALSE != GetMenuItemInfo(hmenuView, ulMenu, FALSE, &mii))
{
RemoveMenu(hmenuView, ulMenu, MF_BYCOMMAND);
}
}
// Add in each of the filters from the mru list
for (nItem = 0, ulMenu = ID_VIEW_RECENT_0;
((-1 != m_pmruList->EnumList(nItem, rgchFilterTag, ARRAYSIZE(rgchFilterTag))) &&
(ulMenu < ID_VIEW_RECENT_SEPERATOR)); nItem++)
{
// Convert the tag string to a rule id
if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilter))
{
continue;
}
// Insert the menu item
if (SUCCEEDED(_HrInsertViewMenu(hmenuView, ridFilter, ulMenu, ID_VIEW_CUSTOMIZE)))
{
ulMenu++;
}
}
// Add in the MRU separator if we added at least one item
if (ID_VIEW_RECENT_0 != ulMenu)
{
// Set up the menu items
mii.fMask = MIIM_ID | MIIM_TYPE;
mii.fType = MFT_SEPARATOR;
mii.fState = MFS_ENABLED;
mii.wID = ID_VIEW_RECENT_SEPERATOR;
mii.dwItemData = 0;
mii.dwTypeData = 0;
mii.cch = 0;
// Insert the separator
InsertMenuItem(hmenuView, ID_VIEW_CUSTOMIZE, FALSE, &mii);
}
// Set the proper return value
hr = S_OK;
return hr;
}
HRESULT CViewMenu::_HrAddExtraViewMenu(HMENU hmenuView, IOEMessageList * pIMsgList)
{
HRESULT hr = S_OK;
ULONGLONG ullFilter = 0;
RULEID ridFilter = RULEID_INVALID;
MENUITEMINFO mii = {0};
BOOL fExtraMenu = FALSE;
IOERule * pIFilter = NULL;
PROPVARIANT propvar = {0};
DWORD dwMenuID = 0;
Assert(NULL != pIMsgList);
// Get the current filter on the message list
hr = pIMsgList->get_FilterMessages(&ullFilter);
if (FAILED(hr))
{
goto exit;
}
ridFilter = (RULEID) ullFilter;
// Initialize the menu info
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_DATA;
// Does the ID_VIEW_CURRENT menu item exist?
fExtraMenu = !!GetMenuItemInfo(hmenuView, ID_VIEW_CURRENT, FALSE, &mii);
// Is the view filter one of the defaults or in the MRU list?
if ((FALSE != FIsFilterReadOnly(ridFilter)) || (FALSE != _FViewInMRUList(ridFilter, NULL)))
{
// Does the ID_VIEW_CURRENT menu item exist?
if (FALSE != fExtraMenu)
{
// Remove the ID_VIEW_CURRENT menu item
RemoveMenu(hmenuView, ID_VIEW_CURRENT, MF_BYCOMMAND);
// Remove the ID_VIEW_CURRENT_SEPERATOR menu item separator
RemoveMenu(hmenuView, ID_VIEW_CURRENT_SEPERATOR, MF_BYCOMMAND);
// Clear out the saved current id
m_ridCurrent = RULEID_INVALID;
}
}
else
{
// Does the ID_VIEW_CURRENT menu item exist?
if (FALSE != fExtraMenu)
{
// Is it different than the current view filter
if (ridFilter != (RULEID) mii.dwItemData)
{
// Get the view from the rules manager
hr = g_pRulesMan->GetRule(ridFilter, RULE_TYPE_FILTER, 0, &pIFilter);
if (FAILED(hr))
{
goto exit;
}
// Get the name from the view
hr = pIFilter->GetProp(RULE_PROP_NAME, 0, &propvar);
if (FAILED(hr))
{
goto exit;
}
// Nothing to do if we don't have a name
if (NULL == propvar.pszVal)
{
hr = E_FAIL;
goto exit;
}
// Initialize the menu info
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_DATA | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.dwItemData = (DWORD_PTR) ridFilter;
mii.dwTypeData = propvar.pszVal;
mii.cch = lstrlen(propvar.pszVal);
// Reset the menu name and data
SetMenuItemInfo(hmenuView, ID_VIEW_CURRENT, FALSE, &mii);
}
}
else
{
// Initialize the menu item info
mii.fMask = MIIM_DATA;
// Figure out which menu to add it before
dwMenuID = (FALSE != GetMenuItemInfo(hmenuView, ID_VIEW_RECENT_0, FALSE, &mii)) ? ID_VIEW_RECENT_0: ID_VIEW_CUSTOMIZE;
// Add the extra menu item
hr = _HrInsertViewMenu(hmenuView, ridFilter, ID_VIEW_CURRENT, dwMenuID);
if (FAILED(hr))
{
goto exit;
}
// Set up the menu item info
mii.fMask = MIIM_ID | MIIM_TYPE;
mii.fType = MFT_SEPARATOR;
mii.fState = MFS_ENABLED;
mii.wID = ID_VIEW_CURRENT_SEPERATOR;
mii.dwItemData = 0;
mii.dwTypeData = 0;
mii.cch = 0;
// Add the extra menu item separator
InsertMenuItem(hmenuView, dwMenuID, FALSE, &mii);
}
// Save the current rule id
m_ridCurrent = ridFilter;
}
// Set the proper return value
hr = S_OK;
exit:
PropVariantClear(&propvar);
SafeRelease(pIFilter);
return hr;
}
VOID CViewMenu::_AddViewToMRU(RULEID ridFilter)
{
CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
// Is there anything to do?
if (RULEID_INVALID == ridFilter)
{
goto exit;
}
// If this isn't a default view
if (FALSE == FIsFilterReadOnly(ridFilter))
{
// Format the rule id as a hex string
wnsprintf(rgchFilterTag, ARRAYSIZE(rgchFilterTag), "0X%08X", PtrToUlong(ridFilter));
// Add the string into the MRU list
m_pmruList->AddString(rgchFilterTag);
}
exit:
return;
}
BOOL CViewMenu::_FViewInMRUList(RULEID ridFilter, DWORD * pdwID)
{
BOOL fRet = FALSE;
INT nItem = 0;
CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
RULEID ridFilterMRU = RULEID_INVALID;
// Initialize the return value
if (NULL != pdwID)
{
*pdwID = -1;
}
// Add in each of the filters from the mru list
for (nItem = 0; -1 != m_pmruList->EnumList(nItem, rgchFilterTag, ARRAYSIZE(rgchFilterTag)); nItem++)
{
// Convert the tag string to a rule id
if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilterMRU))
{
continue;
}
if (ridFilterMRU == ridFilter)
{
fRet = TRUE;
break;
}
}
return fRet;
}
BOOL CViewMenu::_FValiadateMRUList(VOID)
{
BOOL fRet = FALSE;
INT nItem = 0;
CHAR rgchFilterTag[CCH_FILTERTAG_MAX];
RULEID ridFilterMRU = RULEID_INVALID;
IOERule * pIFilter = NULL;
Assert(NULL != m_pmruList);
Assert(NULL != g_pRulesMan);
// Add in each of the filters from the mru list
for (nItem = 0; -1 != m_pmruList->EnumList(nItem, rgchFilterTag, ARRAYSIZE(rgchFilterTag)); nItem++)
{
// Convert the tag string to a rule id
if (FALSE == StrToIntEx(rgchFilterTag, STIF_SUPPORT_HEX, (int *) &ridFilterMRU))
{
continue;
}
// Get the view from the rules manager
if (FAILED(g_pRulesMan->GetRule(ridFilterMRU, RULE_TYPE_FILTER, 0, &pIFilter)))
{
if (-1 == m_pmruList->RemoveString(rgchFilterTag))
{
fRet = FALSE;
goto exit;
}
}
SafeRelease(pIFilter);
}
// Set the return value
fRet = TRUE;
exit:
SafeRelease(pIFilter);
return fRet;
}
///////////////////////////////////////////////////////////////////////////////
//
// HrCreateViewMenu
//
// This creates a view menu.
//
// ppViewMenu - pointer to return the view menu
//
// Returns: S_OK, on success
// E_OUTOFMEMORY, if can't create the View Menu object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT HrCreateViewMenu(DWORD dwFlags, CViewMenu ** ppViewMenu)
{
CViewMenu * pViewMenu = NULL;
HRESULT hr = S_OK;
// Check the incoming params
if (NULL == ppViewMenu)
{
hr = E_INVALIDARG;
goto exit;
}
// Initialize outgoing params
*ppViewMenu = NULL;
// Create the view menu object
pViewMenu = new CViewMenu;
if (NULL == pViewMenu)
{
hr = E_OUTOFMEMORY;
goto exit;
}
// Initialize the view menu
hr = pViewMenu->HrInit(dwFlags);
if (FAILED(hr))
{
goto exit;
}
// Set the outgoing param
*ppViewMenu = pViewMenu;
pViewMenu = NULL;
// Set the proper return value
hr = S_OK;
exit:
if (NULL != pViewMenu)
{
delete pViewMenu;
}
return hr;
}