/////////////////////////////////////////////////////////////////////////////// // // RuleUtil.cpp // /////////////////////////////////////////////////////////////////////////////// #include #include "ruleutil.h" #include "rulesmgr.h" #include "rulesui.h" #include "editrule.h" #include "spamui.h" #include "viewsui.h" #include "rule.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "shlwapip.h" #include "reutil.h" #include // 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(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; }