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