Skip to content

Commit a971bcf

Browse files
committed
Added -e switch: enumeration of existing rules
1 parent 90dfd0a commit a971bcf

File tree

6 files changed

+139
-13
lines changed

6 files changed

+139
-13
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
*.suo
2+
*.aps
23
/XRulez/.vs
34
/XRulez/Bin
45
/XRulez/ipch

CppCommons/Modules/CppTools/CppToolsModule.h

+13-6
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,23 @@ namespace CppTools
5353
struct StringConversions
5454
{
5555
/// String conversion template. Usage: auto mbcs = CppTools::StringConversions::Convert<std::string>(std::to_wstring(42));
56-
template<typename DestinationType, typename ImplicitSourceType> static DestinationType Convert(ImplicitSourceType string)
57-
{ static_assert(true, "Converter works on string types only (string, wstring, char*, wchar_t*)."); return nullptr; }
56+
template<typename DestinationType, typename ImplicitSourceType> static DestinationType Convert(ImplicitSourceType)
57+
{
58+
static_assert(false, "Converter works on string types only (string, wstring, char*, wchar_t*)."); return nullptr;
59+
}
5860

5961
// Specializations for standard strings.
60-
template<> static std::string Convert(const std::string& string) { return string; }
61-
template<> static std::wstring Convert(const std::wstring& string) { return string; }
62-
template<> static std::string Convert(const std::wstring& string) { return Unicode2Mbcs(string); }
63-
template<> static std::wstring Convert(const std::string& string) { return Mbcs2Unicode(string); }
62+
template<> static std::string Convert(std::string string) { return string; }
63+
template<> static std::wstring Convert(std::wstring string) { return string; }
64+
template<> static std::string Convert(std::wstring string) { return Unicode2Mbcs(string); }
65+
template<> static std::wstring Convert(std::string string) { return Mbcs2Unicode(string); }
6466

6567
// Specializations for raw string pointers.
68+
template<> static std::string Convert(char* string) { return string; }
69+
template<> static std::wstring Convert(wchar_t* string) { return string; }
70+
template<> static std::string Convert(wchar_t* string) { return Unicode2Mbcs(string); }
71+
template<> static std::wstring Convert(char* string) { return Mbcs2Unicode(string); }
72+
6673
template<> static std::string Convert(char const* string) { return string; }
6774
template<> static std::wstring Convert(wchar_t const* string) { return string; }
6875
template<> static std::string Convert(wchar_t const* string) { return Unicode2Mbcs(string); }

CppCommons/Modules/MapiTools/ExchangeModifyTable.cpp

+55
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,58 @@ CppTools::XError<bool> MapiTools::ExchangeModifyTable::DeleteRule(LARGE_INTEGER
4242

4343
return true;
4444
}
45+
46+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
47+
std::vector<MapiTools::ExchangeModifyTable::RuleInfo> MapiTools::ExchangeModifyTable::EnumerateRules()
48+
{
49+
// Prepare for enumeration.
50+
auto table = GetMapiTable(); //< Get the table.
51+
CallMapi(table->Restrict(nullptr, TBL_ASYNC)); //< Reset restrictions.
52+
CallMapi(table->SeekRow(BOOKMARK_BEGINNING, 0, NULL)); //< Reset cursor.
53+
54+
// Query table for rows.
55+
LPSRowSet rows;
56+
CallMapi(table->QueryRows(1000, 0, &rows)); //< Maximum 1000 rows.
57+
58+
// Parse returned data.
59+
std::vector<RuleInfo> retVector;
60+
for (unsigned i = 0; i < rows->cRows; ++i)
61+
{
62+
// Pre-fill output entry with invalid/blank data.
63+
std::wstring ruleName = L"[Unknown]", ruleProvider = L"[Unknown]";
64+
LARGE_INTEGER ruleId{ 0xFFffFFff, (LONG)-1 };
65+
ULONG ruleSequenceNo = (ULONG )-1;
66+
67+
// Search through columns, find those we are here for and parse their values.
68+
for (ULONG j = 0; j < rows->aRow[i].cValues; j++)
69+
switch (rows->aRow[i].lpProps[j].ulPropTag)
70+
{
71+
case (PR_RULE_NAME & 0xFFff0000) | PT_STRING8:
72+
ruleName = CppTools::StringConversions::Convert<std::wstring>(rows->aRow[i].lpProps[j].Value.lpszA); break;
73+
74+
case (PR_RULE_NAME & 0xFFff0000) | PT_UNICODE:
75+
ruleName = rows->aRow[i].lpProps[j].Value.lpszW; break;
76+
77+
case (PR_RULE_PROVIDER & 0xFFff0000) | PT_STRING8:
78+
ruleProvider = CppTools::StringConversions::Convert<std::wstring>(rows->aRow[i].lpProps[j].Value.lpszA); break;
79+
80+
case (PR_RULE_PROVIDER & 0xFFff0000) | PT_UNICODE:
81+
ruleProvider = rows->aRow[i].lpProps[j].Value.lpszW; break;
82+
83+
case PR_RULE_ID:
84+
ruleId = rows->aRow[i].lpProps[j].Value.li; break;
85+
86+
case PR_RULE_SEQUENCE:
87+
ruleSequenceNo = rows->aRow[i].lpProps[j].Value.ul; break;
88+
}
89+
90+
// Store parsed rule entry.
91+
retVector.push_back({ ruleName, ruleProvider, ruleId, ruleSequenceNo });
92+
}
93+
94+
// Clean-up and return the data.
95+
if (rows)
96+
FreeProws(rows);
97+
98+
return retVector;
99+
}

CppCommons/Modules/MapiTools/ExchangeModifyTable.h

+14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ namespace MapiTools
2020
/// @return false if rule of provided ID doesn't exist. True if rule was successfully deleted. Other Mapi errors are thrown as MapiException.
2121
CppTools::XError<bool> DeleteRule(LARGE_INTEGER const& ruleId);
2222

23+
/// Structure describing a single inbox rule.
24+
struct RuleInfo
25+
{
26+
std::wstring m_Name; //< Name of the rule.
27+
std::wstring m_Provider; //< Provider of the rule.
28+
LARGE_INTEGER m_Id; //< Rule's ID.
29+
ULONG m_SequenceNo; //< Sequential number.
30+
};
31+
32+
/// Enlists all rules in this table.
33+
/// @return list of rules.
34+
/// @remarks throws MapiException on MAPI call failures.
35+
std::vector<RuleInfo> EnumerateRules();
36+
2337
protected:
2438
/// Protected ctor.
2539
ExchangeModifyTable(LPEXCHANGEMODIFYTABLE exchangeModifyTable) : PointerObject(exchangeModifyTable) { ValidateParam(exchangeModifyTable); }

XRulez/XRulez/Application.cpp

+53-7
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,11 @@ bool XRulez::Application::ExeProcessParameters()
152152
case TEXT('d'): //< Display parameters default (precompiled) values.
153153
return ExeShowDefaultParamsValues(), false;
154154

155-
case TEXT('i'): //< Perform interactive configuration and proceed to message injection.
156-
return ExePerformInteractiveConfiguration(), true;
155+
//case TEXT('i'): //< Perform interactive configuration and proceed to message injection.
156+
//return ExePerformInteractiveConfiguration(), true;
157+
158+
case TEXT('e'): //< Shows all existing rules.
159+
return ExeDisplayAllRules(), true;
157160

158161
case TEXT('h'): //< Display help.
159162
return ExeShowUsage(false), false;
@@ -286,17 +289,17 @@ void XRulez::Application::ExeShowUsage(bool error)
286289
TEXT("\n\nXRulez.exe -a [--profile PROFILE] [--name NAME] [--trigger TRIGGER] [--payload PAYLOAD]")
287290
TEXT("\n\tCreates and adds a new Exchange rule. Default, built-in values (use -d to see them) are used for all omitted params. If profile name is blank then default Outlook profile will be used. Other params must not be blank.")
288291

289-
//TEXT("\n\nXRulez.exe -p")
290-
//TEXT("\n\tChecks if EnableUnsafeClientMailRules security patch KB3191883 for Outlook 2013 and 2016.")
292+
TEXT("\n\nXRulez.exe -e")
293+
TEXT("\n\tDisplays all existing rules.")
291294

292295
TEXT("\n\nXRulez.exe -r")
293296
TEXT("\n\tDisables security patch KB3191883 (re-enables run-actions for Outlook 2010, 2013 and 2016).")
294297

295-
TEXT("\n\nXRulez.exe -i")
296-
TEXT("\n\tPerforms an interactive configuration and proceeds to message injection.")
298+
//TEXT("\n\nXRulez.exe -i")
299+
//TEXT("\n\tPerforms an interactive configuration and proceeds to message injection.")
297300

298301
TEXT("\n\nXRulez.exe -o")
299-
TEXT("\n\tCheck it Outlook is running at the moment.\n") << std::endl;
302+
TEXT("\n\tCheck it Outlook is running at the moment.\n") << std::endl;
300303
}
301304

302305
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -342,6 +345,49 @@ void XRulez::Application::ExePerformInteractiveConfiguration()
342345
GetInputParam("payload path", m_RulePayloadPath);
343346
}
344347

348+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
349+
void XRulez::Application::ExeDisplayAllRules()
350+
{
351+
Comment(TEXT("Retrieving list of existing rules..."));
352+
try
353+
{
354+
// Initialize MapiTools Module.
355+
auto xeInitializeMapi = MapiTools::InitializeMapi(m_IsRunningInMultithreadedProcess, m_IsRunningInWindowsService);
356+
if (xeInitializeMapi.IsFailure())
357+
return ReportError(TEXT("MapiTools::InitializeMapi"), xeInitializeMapi);
358+
SCOPE_GUARD{ MapiTools::UninitializeMapi(); };
359+
360+
// Login to a shared session, then open default message store, then inbox folder, and then enlist all existing rules.
361+
auto ruleList = MapiTools::MapiSession{ MAPI_EXTENDED | MAPI_ALLOW_OTHERS | MAPI_NEW_SESSION | MAPI_USE_DEFAULT | (m_IsRunningInWindowsService ? MAPI_NT_SERVICE : 0), m_ProfileName }
362+
.OpenDefaultMessageStore().OpenDefaultReceiveFolder().OpenRulesTable().EnumerateRules();
363+
364+
// Sort the list.
365+
std::sort(ruleList.begin(), ruleList.end(), [](decltype(ruleList)::value_type const& lhs, decltype(ruleList)::value_type const& rhs) { return lhs.m_SequenceNo < rhs.m_SequenceNo; });
366+
367+
// Display rules on the screen.
368+
Comment(TEXT("Found ") + std::to_tstring(static_cast<unsigned>(ruleList.size())) + TEXT(" rules:\n"));
369+
for (auto const& rule : ruleList)
370+
{
371+
std::wstringstream stream;
372+
stream << std::hex << rule.m_Id.LowPart << rule.m_Id.HighPart;
373+
Comment(TEXT("Rule ID: ") + stream.str());
374+
Comment(TEXT("Rule name: ") + rule.m_Name);
375+
Comment(TEXT("Provider: ") + rule.m_Provider);
376+
Comment(TEXT(""));
377+
}
378+
379+
Comment(TEXT("Done."));
380+
}
381+
catch (CppTools::XException& e)
382+
{
383+
CommentError(TEXT("Error. ") + CppTools::StringConversions::Mbcs2Tstring(e.what()) + TEXT("\n") + e.ComposeFullMessage());
384+
}
385+
catch (std::exception& e)
386+
{
387+
CommentError(TEXT("Error. ") + CppTools::StringConversions::Mbcs2Tstring(e.what()));
388+
}
389+
}
390+
345391
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
346392
void XRulez::Application::ExeListOutlookProfiles()
347393
{

XRulez/XRulez/Application.h

+3
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ namespace XRulez
7878
/// Performs interactive configuration. Should not be called from DLL builds.
7979
void ExePerformInteractiveConfiguration();
8080

81+
/// Shows all existing rules.
82+
void ExeDisplayAllRules();
83+
8184
/// Displays a list of available MAPI profiles. Should not be called from DLL builds.
8285
void ExeListOutlookProfiles();
8386

0 commit comments

Comments
 (0)