PageRenderTime 141ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/MrMAPI.cpp

#
C++ | 1200 lines | 1070 code | 75 blank | 55 comment | 174 complexity | 8416f3fe90da1af9adaac7d2acd4e37b MD5 | raw file
  1. #include "stdafx.h"
  2. #include "MrMAPI\MrMAPI.h"
  3. #include "MAPIFunctions.h"
  4. #include "String.h"
  5. #include "InterpretProp2.h"
  6. #include "Smartview\SmartView.h"
  7. #include "MrMAPI\MMAcls.h"
  8. #include "MrMAPI\MMContents.h"
  9. #include "MrMAPI\MMErr.h"
  10. #include "MrMAPI\MMFidMid.h"
  11. #include "MrMAPI\MMFolder.h"
  12. #include "MrMAPI\MMProfile.h"
  13. #include "MrMAPI\MMPropTag.h"
  14. #include "MrMAPI\MMRules.h"
  15. #include "MrMAPI\MMSmartView.h"
  16. #include "MrMAPI\MMStore.h"
  17. #include "MrMAPI\MMMapiMime.h"
  18. #include <shlwapi.h>
  19. #include "ImportProcs.h"
  20. #include "MAPIStoreFunctions.h"
  21. #include "MrMAPI\MMPst.h"
  22. #include "MrMAPI\MMReceiveFolder.h"
  23. #include "NamedPropCache.h"
  24. // Initialize MFC for LoadString support later on
  25. void InitMFC()
  26. {
  27. #pragma warning(push)
  28. #pragma warning(disable:6309)
  29. #pragma warning(disable:6387)
  30. if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) return;
  31. #pragma warning(pop)
  32. }
  33. _Check_return_ HRESULT MrMAPILogonEx(wstring const& lpszProfile, _Deref_out_opt_ LPMAPISESSION* lppSession)
  34. {
  35. HRESULT hRes = S_OK;
  36. ULONG ulFlags = MAPI_EXTENDED | MAPI_NO_MAIL | MAPI_UNICODE | MAPI_NEW_SESSION;
  37. if (lpszProfile.empty()) ulFlags |= MAPI_USE_DEFAULT;
  38. WC_MAPI(MAPILogonEx(NULL, (LPTSTR)(lpszProfile.empty() ? NULL : lpszProfile.c_str()), NULL,
  39. ulFlags,
  40. lppSession));
  41. return hRes;
  42. }
  43. _Check_return_ HRESULT OpenExchangeOrDefaultMessageStore(
  44. _In_ LPMAPISESSION lpMAPISession,
  45. _Deref_out_opt_ LPMDB* lppMDB)
  46. {
  47. if (!lpMAPISession || !lppMDB) return MAPI_E_INVALID_PARAMETER;
  48. HRESULT hRes = S_OK;
  49. LPMDB lpMDB = NULL;
  50. *lppMDB = NULL;
  51. WC_H(OpenMessageStoreGUID(lpMAPISession, pbExchangeProviderPrimaryUserGuid, &lpMDB));
  52. if (FAILED(hRes) || !lpMDB)
  53. {
  54. hRes = S_OK;
  55. WC_H(OpenDefaultMessageStore(lpMAPISession, &lpMDB));
  56. }
  57. if (SUCCEEDED(hRes) && lpMDB)
  58. {
  59. *lppMDB = lpMDB;
  60. }
  61. else
  62. {
  63. if (lpMDB) lpMDB->Release();
  64. if (SUCCEEDED(hRes)) hRes = MAPI_E_CALL_FAILED;
  65. }
  66. return hRes;
  67. } // OpenExchangeOrDefaultMessageStore
  68. enum __CommandLineSwitch
  69. {
  70. switchNoSwitch = 0, // not a switch
  71. switchUnknown, // unknown switch
  72. switchHelp, // '-h'
  73. switchVerbose, // '-v'
  74. switchSearch, // '-s'
  75. switchDecimal, // '-n'
  76. switchFolder, // '-f'
  77. switchOutput, // '-o'
  78. switchDispid, // '-d'
  79. switchType, // '-t'
  80. switchGuid, // '-g'
  81. switchError, // '-e'
  82. switchParser, // '-p'
  83. switchInput, // '-i'
  84. switchBinary, // '-b'
  85. switchAcl, // '-a'
  86. switchRule, // '-r'
  87. switchContents, // '-c'
  88. switchAssociatedContents, // '-h'
  89. switchMoreProperties, // '-m'
  90. switchNoAddins, // '-no'
  91. switchOnline, // '-on'
  92. switchMAPI, // '-ma'
  93. switchMIME, // '-mi'
  94. switchCCSFFlags, // '-cc'
  95. switchRFC822, // '-rf'
  96. switchWrap, // '-w'
  97. switchEncoding, // '-en'
  98. switchCharset, // '-ch'
  99. switchAddressBook, // '-ad'
  100. switchUnicode, // '-u'
  101. switchProfile, // '-pr'
  102. switchXML, // '-x'
  103. switchSubject, // '-su'
  104. switchMessageClass, // '-me'
  105. switchMSG, // '-ms'
  106. switchList, // '-l'
  107. switchChildFolders, // '-chi'
  108. switchFid, // '-fi'
  109. switchMid, // '-mid'
  110. switchFlag, // '-fl'
  111. switchRecent, // '-re'
  112. switchStore, // '-st'
  113. switchVersion, // '-vers'
  114. switchSize, // '-si'
  115. switchPST, // '-pst'
  116. switchProfileSection, // '-profiles'
  117. switchByteSwapped, // '-b'
  118. switchReceiveFolder, // '-receivefolder'
  119. switchSkip, // '-sk'
  120. switchSearchState, // '-searchstate'
  121. };
  122. struct COMMANDLINE_SWITCH
  123. {
  124. __CommandLineSwitch iSwitch;
  125. LPCSTR szSwitch;
  126. };
  127. // All entries before the aliases must be in the
  128. // same order as the __CommandLineSwitch enum.
  129. COMMANDLINE_SWITCH g_Switches[] =
  130. {
  131. { switchNoSwitch, "" },
  132. { switchUnknown, "" },
  133. { switchHelp, "?" },
  134. { switchVerbose, "Verbose" },
  135. { switchSearch, "Search" },
  136. { switchDecimal, "Number" },
  137. { switchFolder, "Folder" },
  138. { switchOutput, "Output" },
  139. { switchDispid, "Dispids" },
  140. { switchType, "Type" },
  141. { switchGuid, "Guids" },
  142. { switchError, "Error" },
  143. { switchParser, "ParserType" },
  144. { switchInput, "Input" },
  145. { switchBinary, "Binary" },
  146. { switchAcl, "Acl" },
  147. { switchRule, "Rules" },
  148. { switchContents, "Contents" },
  149. { switchAssociatedContents, "HiddenContents" },
  150. { switchMoreProperties, "MoreProperties" },
  151. { switchNoAddins, "NoAddins" },
  152. { switchOnline, "Online" },
  153. { switchMAPI, "MAPI" },
  154. { switchMIME, "MIME" },
  155. { switchCCSFFlags, "CCSFFlags" },
  156. { switchRFC822, "RFC822" },
  157. { switchWrap, "Wrap" },
  158. { switchEncoding, "Encoding" },
  159. { switchCharset, "Charset" },
  160. { switchAddressBook, "AddressBook" },
  161. { switchUnicode, "Unicode" },
  162. { switchProfile, "Profile" },
  163. { switchXML, "XML" },
  164. { switchSubject, "Subject" },
  165. { switchMessageClass, "MessageClass" },
  166. { switchMSG, "MSG" },
  167. { switchList, "List" },
  168. { switchChildFolders, "ChildFolders" },
  169. { switchFid, "FID" },
  170. { switchMid, "MID" },
  171. { switchFlag, "Flag" },
  172. { switchRecent, "Recent" },
  173. { switchStore, "Store" },
  174. { switchVersion, "Version" },
  175. { switchSize, "Size" },
  176. { switchPST, "PST" },
  177. { switchProfileSection, "ProfileSection" },
  178. { switchByteSwapped, "ByteSwapped" },
  179. { switchReceiveFolder, "ReceiveFolder" },
  180. { switchSkip, "Skip" },
  181. { switchSearchState, "SearchState" },
  182. // If we want to add aliases for any switches, add them here
  183. { switchHelp, "Help" },
  184. };
  185. ULONG g_ulSwitches = _countof(g_Switches);
  186. extern LPADDIN g_lpMyAddins;
  187. void DisplayUsage(BOOL bFull)
  188. {
  189. printf("MAPI data collection and parsing tool. Supports property tag lookup, error translation,\n");
  190. printf(" smart view processing, rule tables, ACL tables, contents tables, and MAPI<->MIME conversion.\n");
  191. LPADDIN lpCurAddIn = g_lpMyAddins;
  192. if (bFull)
  193. {
  194. if (lpCurAddIn)
  195. {
  196. printf("Addins Loaded:\n");
  197. while (lpCurAddIn)
  198. {
  199. printf(" %ws\n", lpCurAddIn->szName);
  200. lpCurAddIn = lpCurAddIn->lpNextAddIn;
  201. }
  202. }
  203. printf("MrMAPI currently knows:\n");
  204. printf("%6u property tags\n", ulPropTagArray);
  205. printf("%6u dispids\n", ulNameIDArray);
  206. printf("%6u types\n", ulPropTypeArray);
  207. printf("%6u guids\n", ulPropGuidArray);
  208. printf("%6u errors\n", g_ulErrorArray);
  209. printf("%6u smart view parsers\n", ulSmartViewParserTypeArray - 1);
  210. printf("\n");
  211. }
  212. printf("Usage:\n");
  213. printf(" MrMAPI -%s\n", g_Switches[switchHelp].szSwitch);
  214. printf(" MrMAPI [-%s] [-%s] [-%s] [-%s <type>] <property number>|<property name>\n",
  215. g_Switches[switchSearch].szSwitch, g_Switches[switchDispid].szSwitch, g_Switches[switchDecimal].szSwitch, g_Switches[switchType].szSwitch);
  216. printf(" MrMAPI -%s\n", g_Switches[switchGuid].szSwitch);
  217. printf(" MrMAPI -%s <error>\n", g_Switches[switchError].szSwitch);
  218. printf(" MrMAPI -%s <type> -%s <input file> [-%s] [-%s <output file>]\n",
  219. g_Switches[switchParser].szSwitch, g_Switches[switchInput].szSwitch, g_Switches[switchBinary].szSwitch, g_Switches[switchOutput].szSwitch);
  220. printf(" MrMAPI -%s <flag value> [-%s] [-%s] <property number>|<property name>\n",
  221. g_Switches[switchFlag].szSwitch, g_Switches[switchDispid].szSwitch, g_Switches[switchDecimal].szSwitch);
  222. printf(" MrMAPI -%s <flag name>\n",
  223. g_Switches[switchFlag].szSwitch);
  224. printf(" MrMAPI -%s [-%s <profile>] [-%s <folder>]\n", g_Switches[switchRule].szSwitch, g_Switches[switchProfile].szSwitch, g_Switches[switchFolder].szSwitch);
  225. printf(" MrMAPI -%s [-%s <profile>] [-%s <folder>]\n", g_Switches[switchAcl].szSwitch, g_Switches[switchProfile].szSwitch, g_Switches[switchFolder].szSwitch);
  226. printf(" MrMAPI -%s | -%s [-%s <profile>] [-%s <folder>] [-%s <output directory>]\n",
  227. g_Switches[switchContents].szSwitch, g_Switches[switchAssociatedContents].szSwitch, g_Switches[switchProfile].szSwitch, g_Switches[switchFolder].szSwitch, g_Switches[switchOutput].szSwitch);
  228. printf(" [-%s <subject>] [-%s <message class>] [-%s] [-%s] [-%s <count>] [-%s]\n",
  229. g_Switches[switchSubject].szSwitch, g_Switches[switchMessageClass].szSwitch, g_Switches[switchMSG].szSwitch, g_Switches[switchList].szSwitch, g_Switches[switchRecent].szSwitch, g_Switches[switchSkip].szSwitch);
  230. printf(" MrMAPI -%s [-%s <profile>] [-%s <folder>]\n", g_Switches[switchChildFolders].szSwitch, g_Switches[switchProfile].szSwitch, g_Switches[switchFolder].szSwitch);
  231. printf(" MrMAPI -%s -%s <path to input file> -%s <path to output file> [-%s]\n",
  232. g_Switches[switchXML].szSwitch, g_Switches[switchInput].szSwitch, g_Switches[switchOutput].szSwitch, g_Switches[switchSkip].szSwitch);
  233. printf(" MrMAPI -%s [fid] [-%s [mid]] [-%s <profile>]\n",
  234. g_Switches[switchFid].szSwitch, g_Switches[switchMid].szSwitch, g_Switches[switchProfile].szSwitch);
  235. printf(" MrMAPI [<property number>|<property name>] -%s [<store num>] [-%s <profile>]\n",
  236. g_Switches[switchStore].szSwitch, g_Switches[switchProfile].szSwitch);
  237. printf(" MrMAPI [<property number>|<property name>] -%s <folder> [-%s <profile>]\n",
  238. g_Switches[switchFolder].szSwitch, g_Switches[switchProfile].szSwitch);
  239. printf(" MrMAPI -%s -%s <folder> [-%s <profile>]\n",
  240. g_Switches[switchSize].szSwitch, g_Switches[switchFolder].szSwitch, g_Switches[switchProfile].szSwitch);
  241. printf(" MrMAPI -%s | -%s -%s <path to input file> -%s <path to output file> [-%s <conversion flags>]\n",
  242. g_Switches[switchMAPI].szSwitch, g_Switches[switchMIME].szSwitch, g_Switches[switchInput].szSwitch, g_Switches[switchOutput].szSwitch, g_Switches[switchCCSFFlags].szSwitch);
  243. printf(" [-%s] [-%s <Decimal number of characters>] [-%s <Decimal number indicating encoding>]\n",
  244. g_Switches[switchRFC822].szSwitch, g_Switches[switchWrap].szSwitch, g_Switches[switchEncoding].szSwitch);
  245. printf(" [-%s] [-%s] [-%s CodePage CharSetType CharSetApplyType]\n",
  246. g_Switches[switchAddressBook].szSwitch, g_Switches[switchUnicode].szSwitch, g_Switches[switchCharset].szSwitch);
  247. printf(" MrMAPI -%s -%s <path to input file>\n",
  248. g_Switches[switchPST].szSwitch, g_Switches[switchInput].szSwitch);
  249. printf(" MrMAPI -%s [<profile> [-%s <profilesection> [-%s]] -%s <output file>]\n",
  250. g_Switches[switchProfile].szSwitch, g_Switches[switchProfileSection].szSwitch, g_Switches[switchByteSwapped].szSwitch, g_Switches[switchOutput].szSwitch);
  251. printf(" MrMAPI -%s [<store num>] [-%s <profile>]\n", g_Switches[switchReceiveFolder].szSwitch, g_Switches[switchProfile].szSwitch);
  252. printf(" MrMAPI -%s -%s <folder> [-%s <profile>]\n",
  253. g_Switches[switchSearchState].szSwitch, g_Switches[switchFolder].szSwitch, g_Switches[switchProfile].szSwitch);
  254. if (bFull)
  255. {
  256. printf("\n");
  257. printf("All switches may be shortened if the intended switch is unambiguous.\n");
  258. printf("For example, -T may be used instead of -%s.\n", g_Switches[switchType].szSwitch);
  259. }
  260. printf("\n");
  261. printf(" Help:\n");
  262. printf(" -%s Display expanded help.\n", g_Switches[switchHelp].szSwitch);
  263. if (bFull)
  264. {
  265. printf("\n");
  266. printf(" Property Tag Lookup:\n");
  267. printf(" -S (or -%s) Perform substring search.\n", g_Switches[switchSearch].szSwitch);
  268. printf(" With no parameters prints all known properties.\n");
  269. printf(" -D (or -%s) Search dispids.\n", g_Switches[switchDispid].szSwitch);
  270. printf(" -N (or -%s) Number is in decimal. Ignored for non-numbers.\n", g_Switches[switchDecimal].szSwitch);
  271. printf(" -T (or -%s) Print information on specified type.\n", g_Switches[switchType].szSwitch);
  272. printf(" With no parameters prints list of known types.\n");
  273. printf(" When combined with -S, restrict output to given type.\n");
  274. printf(" -G (or -%s) Display list of known guids.\n", g_Switches[switchGuid].szSwitch);
  275. printf("\n");
  276. printf(" Flag Lookup:\n");
  277. printf(" -Fl (or -%s) Look up flags for specified property.\n", g_Switches[switchFlag].szSwitch);
  278. printf(" May be combined with -D and -N switches, but all flag values must be in hex.\n");
  279. printf(" -Fl (or -%s) Look up flag name and output its value.\n", g_Switches[switchFlag].szSwitch);
  280. printf("\n");
  281. printf(" Error Parsing:\n");
  282. printf(" -E (or -%s) Map an error code to its name and vice versa.\n", g_Switches[switchError].szSwitch);
  283. printf(" May be combined with -S and -N switches.\n");
  284. printf("\n");
  285. printf(" Smart View Parsing:\n");
  286. printf(" -P (or -%s) Parser type (number). See list below for supported parsers.\n", g_Switches[switchParser].szSwitch);
  287. printf(" -B (or -%s) Input file is binary. Default is hex encoded text.\n", g_Switches[switchBinary].szSwitch);
  288. printf("\n");
  289. printf(" Rules Table:\n");
  290. printf(" -R (or -%s) Output rules table. Profile optional.\n", g_Switches[switchRule].szSwitch);
  291. printf("\n");
  292. printf(" ACL Table:\n");
  293. printf(" -A (or -%s) Output ACL table. Profile optional.\n", g_Switches[switchAcl].szSwitch);
  294. printf("\n");
  295. printf(" Contents Table:\n");
  296. printf(" -C (or -%s) Output contents table. May be combined with -H. Profile optional.\n", g_Switches[switchContents].szSwitch);
  297. printf(" -H (or -%s) Output associated contents table. May be combined with -C. Profile optional\n", g_Switches[switchAssociatedContents].szSwitch);
  298. printf(" -Su (or -%s) Subject of messages to output.\n", g_Switches[switchSubject].szSwitch);
  299. printf(" -Me (or -%s) Message class of messages to output.\n", g_Switches[switchMessageClass].szSwitch);
  300. printf(" -Ms (or -%s) Output as .MSG instead of XML.\n", g_Switches[switchMSG].szSwitch);
  301. printf(" -L (or -%s) List details to screen and do not output files.\n", g_Switches[switchList].szSwitch);
  302. printf(" -Re (or -%s) Restrict output to the 'count' most recent messages.\n", g_Switches[switchRecent].szSwitch);
  303. printf("\n");
  304. printf(" Child Folders:\n");
  305. printf(" -Chi (or -%s) Display child folders of selected folder.\n", g_Switches[switchChildFolders].szSwitch);
  306. printf("\n");
  307. printf(" MSG File Properties\n");
  308. printf(" -X (or -%s) Output properties of an MSG file as XML.\n", g_Switches[switchXML].szSwitch);
  309. printf("\n");
  310. printf(" MID/FID Lookup\n");
  311. printf(" -Fi (or -%s) Folder ID (FID) to search for.\n", g_Switches[switchFid].szSwitch);
  312. printf(" If -%s is specified without a FID, search/display all folders\n", g_Switches[switchFid].szSwitch);
  313. printf(" -Mid (or -%s) Message ID (MID) to search for.\n", g_Switches[switchMid].szSwitch);
  314. printf(" If -%s is specified without a MID, display all messages in folders specified by the FID parameter.\n", g_Switches[switchMid].szSwitch);
  315. printf("\n");
  316. printf(" Store Properties\n");
  317. printf(" -St (or -%s) Output properties of stores as XML.\n", g_Switches[switchStore].szSwitch);
  318. printf(" If store number is specified, outputs properties of a single store.\n");
  319. printf(" If a property is specified, outputs only that property.\n");
  320. printf("\n");
  321. printf(" Folder Properties\n");
  322. printf(" -F (or -%s) Output properties of a folder as XML.\n", g_Switches[switchFolder].szSwitch);
  323. printf(" If a property is specified, outputs only that property.\n");
  324. printf(" -Size Output size of a folder and all subfolders.\n");
  325. printf(" Use -%s to specify which folder to scan.\n", g_Switches[switchFolder].szSwitch);
  326. printf(" -SearchState Output search folder state.\n");
  327. printf(" Use -%s to specify which folder to scan.\n", g_Switches[switchFolder].szSwitch);
  328. printf("\n");
  329. printf(" MAPI <-> MIME Conversion:\n");
  330. printf(" -Ma (or -%s) Convert an EML file to MAPI format (MSG file).\n", g_Switches[switchMAPI].szSwitch);
  331. printf(" -Mi (or -%s) Convert an MSG file to MIME format (EML file).\n", g_Switches[switchMIME].szSwitch);
  332. printf(" -I (or -%s) Indicates the input file for conversion, either a MIME-formatted EML file or an MSG file.\n", g_Switches[switchInput].szSwitch);
  333. printf(" -O (or -%s) Indicates the output file for the conversion.\n", g_Switches[switchOutput].szSwitch);
  334. printf(" -Cc (or -%s) Indicates specific flags to pass to the converter.\n", g_Switches[switchCCSFFlags].szSwitch);
  335. printf(" Available values (these may be OR'ed together):\n");
  336. printf(" MIME -> MAPI:\n");
  337. printf(" CCSF_SMTP: 0x02\n");
  338. printf(" CCSF_INCLUDE_BCC: 0x20\n");
  339. printf(" CCSF_USE_RTF: 0x80\n");
  340. printf(" MAPI -> MIME:\n");
  341. printf(" CCSF_NOHEADERS: 0x00004\n");
  342. printf(" CCSF_USE_TNEF: 0x00010\n");
  343. printf(" CCSF_8BITHEADERS: 0x00040\n");
  344. printf(" CCSF_PLAIN_TEXT_ONLY: 0x01000\n");
  345. printf(" CCSF_NO_MSGID: 0x04000\n");
  346. printf(" CCSF_EMBEDDED_MESSAGE: 0x08000\n");
  347. printf(" CCSF_PRESERVE_SOURCE: 0x40000\n");
  348. printf(" -Rf (or -%s) (MAPI->MIME only) Indicates the EML should be generated in RFC822 format.\n", g_Switches[switchRFC822].szSwitch);
  349. printf(" If not present, RFC1521 is used instead.\n");
  350. printf(" -W (or -%s) (MAPI->MIME only) Indicates the maximum number of characters in each line in the\n", g_Switches[switchWrap].szSwitch);
  351. printf(" generated EML. Default value is 74. A value of 0 indicates no wrapping.\n");
  352. printf(" -En (or -%s) (MAPI->MIME only) Indicates the encoding type to use. Supported values are:\n", g_Switches[switchEncoding].szSwitch);
  353. printf(" 1 - Base64\n");
  354. printf(" 2 - UUENCODE\n");
  355. printf(" 3 - Quoted-Printable\n");
  356. printf(" 4 - 7bit (DEFAULT)\n");
  357. printf(" 5 - 8bit\n");
  358. printf(" -Ad (or -%s) Pass MAPI Address Book into converter. Profile optional.\n", g_Switches[switchAddressBook].szSwitch);
  359. printf(" -U (or -%s) (MIME->MAPI only) The resulting MSG file should be unicode.\n", g_Switches[switchUnicode].szSwitch);
  360. printf(" -Ch (or -%s) (MIME->MAPI only) Character set - three required parameters:\n", g_Switches[switchCharset].szSwitch);
  361. printf(" CodePage - common values (others supported)\n");
  362. printf(" 1252 - CP_USASCII - Indicates the USASCII character set, Windows code page 1252\n");
  363. printf(" 1200 - CP_UNICODE - Indicates the Unicode character set, Windows code page 1200\n");
  364. printf(" 50932 - CP_JAUTODETECT - Indicates Japanese auto-detect (50932)\n");
  365. printf(" 50949 - CP_KAUTODETECT - Indicates Korean auto-detect (50949)\n");
  366. printf(" 50221 - CP_ISO2022JPESC - Indicates the Internet character set ISO-2022-JP-ESC\n");
  367. printf(" 50222 - CP_ISO2022JPSIO - Indicates the Internet character set ISO-2022-JP-SIO\n");
  368. printf(" CharSetType - supported values (see CHARSETTYPE)\n");
  369. printf(" 0 - CHARSET_BODY\n");
  370. printf(" 1 - CHARSET_HEADER\n");
  371. printf(" 2 - CHARSET_WEB\n");
  372. printf(" CharSetApplyType - supported values (see CSETAPPLYTYPE)\n");
  373. printf(" 0 - CSET_APPLY_UNTAGGED\n");
  374. printf(" 1 - CSET_APPLY_ALL\n");
  375. printf(" 2 - CSET_APPLY_TAG_ALL\n");
  376. printf("\n");
  377. printf(" PST Analysis\n");
  378. printf(" -PST Output statistics of a PST file.\n");
  379. printf(" If a property is specified, outputs only that property.\n");
  380. printf(" -I (or -%s) PST file to be analyzed.\n", g_Switches[switchInput].szSwitch);
  381. printf("\n");
  382. printf(" Profiles\n");
  383. printf(" -Pr (or -%s) Output list of profiles\n", g_Switches[switchProfile].szSwitch);
  384. printf(" If a profile is specified, exports that profile.\n");
  385. printf(" -ProfileSection If specified, output specific profile section.\n");
  386. printf(" -B (or -%s) If specified, profile section guid is byte swapped.\n", g_Switches[switchByteSwapped].szSwitch);
  387. printf(" -O (or -%s) Indicates the output file for profile export.\n", g_Switches[switchOutput].szSwitch);
  388. printf(" Required if a profile is specified.\n");
  389. printf("\n");
  390. printf(" Receive Folder Table\n");
  391. printf(" -%s Displays Receive Folder Table for the specified store\n", g_Switches[switchReceiveFolder].szSwitch);
  392. printf("\n");
  393. printf(" Universal Options:\n");
  394. printf(" -I (or -%s) Input file.\n", g_Switches[switchInput].szSwitch);
  395. printf(" -O (or -%s) Output file or directory.\n", g_Switches[switchOutput].szSwitch);
  396. printf(" -F (or -%s) Folder to scan. Default is Inbox. See list below for supported folders.\n", g_Switches[switchFolder].szSwitch);
  397. printf(" Folders may also be specified by path:\n");
  398. printf(" \"Top of Information Store\\Calendar\"\n");
  399. printf(" Path may be preceeded by entry IDs for special folders using @ notation:\n");
  400. printf(" \"@PR_IPM_SUBTREE_ENTRYID\\Calendar\"\n");
  401. printf(" Path may further be preceeded by store number using # notation, which may either use a store number:\n");
  402. printf(" \"#0\\@PR_IPM_SUBTREE_ENTRYID\\Calendar\"\n");
  403. printf(" Or an entry ID:\n");
  404. printf(" \"#00112233445566...778899AABBCC\\@PR_IPM_SUBTREE_ENTRYID\\Calendar\"\n");
  405. printf(" MrMAPI's special folder constants may also be used:\n");
  406. printf(" \"@12\\Calendar\"\n");
  407. printf(" \"@1\"\n");
  408. printf(" -Pr (or -%s) Profile for MAPILogonEx.\n", g_Switches[switchProfile].szSwitch);
  409. printf(" -M (or -%s) More properties. Tries harder to get stream properties. May take longer.\n", g_Switches[switchMoreProperties].szSwitch);
  410. printf(" -Sk (or -%s) Skip embedded message attachments on export.\n", g_Switches[switchSkip].szSwitch);
  411. printf(" -No (or -%s) No Addins. Don't load any add-ins.\n", g_Switches[switchNoAddins].szSwitch);
  412. printf(" -On (or -%s) Online mode. Bypass cached mode.\n", g_Switches[switchOnline].szSwitch);
  413. printf(" -V (or -%s) Verbose. Turn on all debug output.\n", g_Switches[switchVerbose].szSwitch);
  414. printf("\n");
  415. printf(" MAPI Implementation Options:\n");
  416. printf(" -%s MAPI Version to load - supported values\n", g_Switches[switchVersion].szSwitch);
  417. printf(" Supported values\n");
  418. printf(" 0 - List all available MAPI binaries\n");
  419. printf(" 1 - System MAPI\n");
  420. printf(" 11 - Outlook 2003 (11)\n");
  421. printf(" 12 - Outlook 2007 (12)\n");
  422. printf(" 14 - Outlook 2010 (14)\n");
  423. printf(" 15 - Outlook 2013 (15)\n");
  424. printf(" You can also pass a string, which will load the first MAPI whose path contains the string.\n");
  425. printf("\n");
  426. printf("Smart View Parsers:\n");
  427. // Print smart view options
  428. ULONG i = 1;
  429. for (i = 1; i < ulSmartViewParserTypeArray; i++)
  430. {
  431. _tprintf(_T(" %2u %ws\n"), i, SmartViewParserTypeArray[i].lpszName);
  432. }
  433. printf("\n");
  434. printf("Folders:\n");
  435. // Print Folders
  436. for (i = 1; i < NUM_DEFAULT_PROPS; i++)
  437. {
  438. printf(" %2u %hs\n", i, FolderNames[i]);
  439. }
  440. printf("\n");
  441. printf("Examples:\n");
  442. printf(" MrMAPI PR_DISPLAY_NAME\n");
  443. printf("\n");
  444. printf(" MrMAPI 0x3001001e\n");
  445. printf(" MrMAPI 3001001e\n");
  446. printf(" MrMAPI 3001\n");
  447. printf("\n");
  448. printf(" MrMAPI -n 12289\n");
  449. printf("\n");
  450. printf(" MrMAPI -t PT_LONG\n");
  451. printf(" MrMAPI -t 3102\n");
  452. printf(" MrMAPI -t\n");
  453. printf("\n");
  454. printf(" MrMAPI -s display\n");
  455. printf(" MrMAPI -s display -t PT_LONG\n");
  456. printf(" MrMAPI -t 102 -s display\n");
  457. printf("\n");
  458. printf(" MrMAPI -d dispidReminderTime\n");
  459. printf(" MrMAPI -d 0x8502\n");
  460. printf(" MrMAPI -d -s reminder\n");
  461. printf(" MrMAPI -d -n 34050\n");
  462. printf("\n");
  463. printf(" MrMAPI -p 17 -i webview.txt -o parsed.txt");
  464. }
  465. }
  466. bool bSetMode(_In_ CmdMode* pMode, _In_ CmdMode TargetMode)
  467. {
  468. if (pMode && ((cmdmodeUnknown == *pMode) || (TargetMode == *pMode)))
  469. {
  470. *pMode = TargetMode;
  471. return true;
  472. }
  473. return false;
  474. }
  475. struct OptParser
  476. {
  477. __CommandLineSwitch Switch;
  478. CmdMode Mode;
  479. int MinArgs;
  480. int MaxArgs;
  481. ULONG ulOpt;
  482. };
  483. OptParser g_Parsers[] =
  484. {
  485. { switchHelp, cmdmodeHelp, 0, 0, OPT_INITMFC },
  486. { switchVerbose, cmdmodeUnknown, 0, 0, OPT_VERBOSE | OPT_INITMFC },
  487. { switchNoAddins, cmdmodeUnknown, 0, 0, OPT_NOADDINS },
  488. { switchOnline, cmdmodeUnknown, 0, 0, OPT_ONLINE },
  489. { switchSearch, cmdmodeUnknown, 0, 0, OPT_DOPARTIALSEARCH },
  490. { switchDecimal, cmdmodeUnknown, 0, 0, OPT_DODECIMAL },
  491. { switchFolder, cmdmodeUnknown, 1, 1, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_NEEDFOLDER | OPT_INITMFC },
  492. { switchInput, cmdmodeUnknown, 1, 1, 0 },
  493. { switchOutput, cmdmodeUnknown, 1, 1, 0 },
  494. { switchProfile, cmdmodeUnknown, 0, 1, OPT_PROFILE },
  495. { switchMoreProperties, cmdmodeUnknown, 0, 0, OPT_RETRYSTREAMPROPS },
  496. { switchSkip, cmdmodeUnknown, 0, 0, OPT_SKIPATTACHMENTS },
  497. { switchDispid, cmdmodePropTag, 0, 0, OPT_DODISPID },
  498. { switchType, cmdmodePropTag, 0, 1, OPT_DOTYPE },
  499. { switchFlag, cmdmodeUnknown, 1, 1, 0 }, // can't know until we parse the argument
  500. { switchGuid, cmdmodeGuid, 0, 0, 0 },
  501. { switchError, cmdmodeErr, 0, 0, 0 },
  502. { switchParser, cmdmodeSmartView, 1, 1, OPT_INITMFC | OPT_NEEDINPUTFILE },
  503. { switchBinary, cmdmodeSmartView, 0, 0, OPT_BINARYFILE },
  504. { switchAcl, cmdmodeAcls, 0, 0, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC | OPT_NEEDFOLDER },
  505. { switchRule, cmdmodeRules, 0, 0, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC | OPT_NEEDFOLDER },
  506. { switchContents, cmdmodeContents, 0, 0, OPT_DOCONTENTS | OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC },
  507. { switchAssociatedContents, cmdmodeContents, 0, 0, OPT_DOASSOCIATEDCONTENTS | OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC },
  508. { switchSubject, cmdmodeContents, 0, 0, 0 },
  509. { switchMSG, cmdmodeContents, 0, 0, OPT_MSG },
  510. { switchList, cmdmodeContents, 0, 0, OPT_LIST },
  511. { switchRecent, cmdmodeContents, 1, 1, 0 },
  512. { switchXML, cmdmodeXML, 0, 0, OPT_NEEDMAPIINIT | OPT_INITMFC | OPT_NEEDINPUTFILE },
  513. { switchFid, cmdmodeFidMid, 0, 1, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC | OPT_NEEDSTORE },
  514. { switchMid, cmdmodeFidMid, 0, 1, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC | OPT_MID },
  515. { switchStore, cmdmodeStoreProperties, 0, 1, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC },
  516. { switchChildFolders, cmdmodeChildFolders, 0, 1, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC | OPT_NEEDFOLDER },
  517. { switchMAPI, cmdmodeMAPIMIME, 0, 0, OPT_NEEDMAPIINIT | OPT_INITMFC | OPT_NEEDINPUTFILE | OPT_NEEDOUTPUTFILE },
  518. { switchMIME, cmdmodeMAPIMIME, 0, 0, OPT_NEEDMAPIINIT | OPT_INITMFC | OPT_NEEDINPUTFILE | OPT_NEEDOUTPUTFILE },
  519. { switchCCSFFlags, cmdmodeMAPIMIME, 1, 1, 0 },
  520. { switchRFC822, cmdmodeMAPIMIME, 1, 1, 0 },
  521. { switchWrap, cmdmodeMAPIMIME, 1, 1, 0 },
  522. { switchEncoding, cmdmodeMAPIMIME, 1, 1, 0 },
  523. { switchCharset, cmdmodeMAPIMIME, 3, 3, 0 },
  524. { switchAddressBook, cmdmodeMAPIMIME, 0, 0, OPT_NEEDMAPILOGON }, // special case which needs a logon
  525. { switchUnicode, cmdmodeMAPIMIME, 0, 0, 0 },
  526. { switchSize, cmdmodeFolderSize, 0, 0, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC | OPT_NEEDFOLDER },
  527. { switchPST, cmdmodePST, 0, 0, OPT_NEEDINPUTFILE },
  528. { switchVersion, cmdmodeUnknown, 1, 1, 0 },
  529. { switchProfileSection, cmdmodeProfile, 1, 1, OPT_PROFILE | OPT_NEEDMAPIINIT | OPT_INITMFC },
  530. { switchByteSwapped, cmdmodeProfile, 0, 0, OPT_PROFILE | OPT_NEEDMAPIINIT | OPT_INITMFC },
  531. { switchReceiveFolder, cmdmodeReceiveFolder, 0, 1, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_NEEDSTORE | OPT_INITMFC },
  532. { switchSearchState, cmdmodeSearchState, 0, 1, OPT_NEEDMAPIINIT | OPT_NEEDMAPILOGON | OPT_INITMFC | OPT_NEEDFOLDER },
  533. { switchNoSwitch, cmdmodeUnknown, 0, 0, 0 },
  534. };
  535. MYOPTIONS::MYOPTIONS()
  536. {
  537. Mode = cmdmodeUnknown;
  538. ulOptions = 0;
  539. ulTypeNum = 0;
  540. ulSVParser = 0;
  541. ulStore = 0;
  542. ulFolder = 0;
  543. ulMAPIMIMEFlags = 0;
  544. ulConvertFlags = 0;
  545. ulWrapLines = 0;
  546. ulEncodingType = 0;
  547. ulCodePage = 0;
  548. ulFlagValue = 0;
  549. ulCount = 0;
  550. bByteSwapped = false;
  551. cSetType = CHARSET_BODY;
  552. cSetApplyType = CSET_APPLY_UNTAGGED;
  553. lpMAPISession = NULL;
  554. lpMDB = NULL;
  555. lpFolder = NULL;
  556. }
  557. OptParser* GetParser(__CommandLineSwitch Switch)
  558. {
  559. int i = 0;
  560. for (i = 0; i < _countof(g_Parsers); i++)
  561. {
  562. if (Switch == g_Parsers[i].Switch) return &g_Parsers[i];
  563. }
  564. return NULL;
  565. }
  566. // Checks if szArg is an option, and if it is, returns which option it is
  567. // We return the first match, so g_Switches should be ordered appropriately
  568. __CommandLineSwitch ParseArgument(_In_z_ LPCSTR szArg)
  569. {
  570. if (!szArg || !szArg[0]) return switchNoSwitch;
  571. ULONG i = 0;
  572. LPCSTR szSwitch = NULL;
  573. // Check if this is a switch at all
  574. switch (szArg[0])
  575. {
  576. case '-':
  577. case '/':
  578. case '\\':
  579. if (szArg[1] != 0) szSwitch = &szArg[1];
  580. break;
  581. default:
  582. return switchNoSwitch;
  583. break;
  584. }
  585. for (i = 0; i < g_ulSwitches; i++)
  586. {
  587. // If we have a match
  588. if (StrStrIA(g_Switches[i].szSwitch, szSwitch) == g_Switches[i].szSwitch)
  589. {
  590. return g_Switches[i].iSwitch;
  591. }
  592. }
  593. return switchUnknown;
  594. }
  595. // Parses command line arguments and fills out MYOPTIONS
  596. bool ParseArgs(_In_ int argc, _In_count_(argc) char * argv[], _Out_ MYOPTIONS * pRunOpts)
  597. {
  598. LPSTR szEndPtr = NULL;
  599. pRunOpts->ulTypeNum = ulNoMatch;
  600. pRunOpts->ulFolder = DEFAULT_INBOX;
  601. if (!pRunOpts) return false;
  602. if (1 == argc) return false;
  603. bool bHitError = false;
  604. for (int i = 1; i < argc; i++)
  605. {
  606. __CommandLineSwitch iSwitch = ParseArgument(argv[i]);
  607. OptParser* opt = GetParser(iSwitch);
  608. if (opt)
  609. {
  610. pRunOpts->ulOptions |= opt->ulOpt;
  611. if (cmdmodeUnknown != opt->Mode && cmdmodeHelp != pRunOpts->Mode)
  612. {
  613. if (!bSetMode(&pRunOpts->Mode, opt->Mode))
  614. {
  615. // resetting our mode here, switch to help
  616. pRunOpts->Mode = cmdmodeHelp;
  617. bHitError = true;
  618. }
  619. }
  620. // Make sure we have the minimum number of args
  621. // Commands with variable argument counts can special case themselves
  622. if (opt->MinArgs > 0)
  623. {
  624. int iArg = 0;
  625. for (iArg = 1; iArg <= opt->MinArgs; iArg++)
  626. {
  627. if (argc <= i + iArg || switchNoSwitch != ParseArgument(argv[i + iArg]))
  628. {
  629. // resetting our mode here, switch to help
  630. pRunOpts->Mode = cmdmodeHelp;
  631. bHitError = true;
  632. }
  633. }
  634. }
  635. }
  636. if (!bHitError) switch (iSwitch)
  637. {
  638. // Global flags
  639. case switchFolder:
  640. pRunOpts->ulFolder = strtoul(argv[i + 1], &szEndPtr, 10);
  641. if (!pRunOpts->ulFolder)
  642. {
  643. pRunOpts->lpszFolderPath = LPCSTRToWstring(argv[i + 1]);
  644. pRunOpts->ulFolder = DEFAULT_INBOX;
  645. }
  646. i++;
  647. break;
  648. case switchInput:
  649. pRunOpts->lpszInput = LPCSTRToWstring(argv[i + 1]);
  650. i++;
  651. break;
  652. case switchOutput:
  653. pRunOpts->lpszOutput = LPCSTRToWstring(argv[i + 1]);
  654. i++;
  655. break;
  656. case switchProfile:
  657. // If we have a next argument and it's not an option, parse it as a profile name
  658. if (i + 1 < argc && switchNoSwitch == ParseArgument(argv[i + 1]))
  659. {
  660. pRunOpts->lpszProfile = LPCSTRToWstring(argv[i + 1]);
  661. i++;
  662. }
  663. break;
  664. case switchProfileSection:
  665. pRunOpts->lpszProfileSection = LPCSTRToWstring(argv[i + 1]);
  666. i++;
  667. break;
  668. case switchByteSwapped:
  669. pRunOpts->bByteSwapped = true;
  670. break;
  671. case switchVersion:
  672. pRunOpts->lpszVersion = LPCSTRToWstring(argv[i + 1]);
  673. i++;
  674. break;
  675. // Proptag parsing
  676. case switchType:
  677. // If we have a next argument and it's not an option, parse it as a type
  678. if (i + 1 < argc && switchNoSwitch == ParseArgument(argv[i + 1]))
  679. {
  680. pRunOpts->ulTypeNum = PropTypeNameToPropType(LPCTSTRToWstring(argv[i + 1]));
  681. i++;
  682. }
  683. break;
  684. case switchFlag:
  685. // If we have a next argument and it's not an option, parse it as a flag
  686. pRunOpts->lpszFlagName = LPCSTRToWstring(argv[i + 1]);
  687. pRunOpts->ulFlagValue = strtoul(argv[i + 1], &szEndPtr, 16);
  688. // Set mode based on whether the flag string was completely parsed as a number
  689. if (NULL == szEndPtr[0])
  690. {
  691. if (!bSetMode(&pRunOpts->Mode, cmdmodePropTag)) { bHitError = true; break; }
  692. pRunOpts->ulOptions |= OPT_DOFLAG;
  693. }
  694. else
  695. {
  696. if (!bSetMode(&pRunOpts->Mode, cmdmodeFlagSearch)) { bHitError = true; break; }
  697. }
  698. i++;
  699. break;
  700. // Smart View parsing
  701. case switchParser:
  702. pRunOpts->ulSVParser = strtoul(argv[i + 1], &szEndPtr, 10);
  703. i++;
  704. break;
  705. // Contents tables
  706. case switchSubject:
  707. pRunOpts->lpszSubject = LPCSTRToWstring(argv[i + 1]);
  708. i++;
  709. break;
  710. case switchMessageClass:
  711. pRunOpts->lpszMessageClass = LPCSTRToWstring(argv[i + 1]);
  712. i++;
  713. break;
  714. case switchRecent:
  715. pRunOpts->ulCount = strtoul(argv[i + 1], &szEndPtr, 10);
  716. i++;
  717. break;
  718. // FID / MID
  719. case switchFid:
  720. if (i + 1 < argc && switchNoSwitch == ParseArgument(argv[i + 1]))
  721. {
  722. pRunOpts->lpszFid = LPCSTRToWstring(argv[i + 1]);
  723. i++;
  724. }
  725. break;
  726. case switchMid:
  727. if (i + 1 < argc && switchNoSwitch == ParseArgument(argv[i + 1]))
  728. {
  729. pRunOpts->lpszMid = LPCSTRToWstring(argv[i + 1]);
  730. i++;
  731. }
  732. else
  733. {
  734. // We use the blank string to remember the -mid parameter was passed and save having an extra flag
  735. // TODO: Check if this works
  736. pRunOpts->lpszMid = L"";
  737. }
  738. break;
  739. // Store Properties / Receive Folder:
  740. case switchStore:
  741. case switchReceiveFolder:
  742. if (i + 1 < argc && switchNoSwitch == ParseArgument(argv[i + 1]))
  743. {
  744. pRunOpts->ulStore = strtoul(argv[i + 1], &szEndPtr, 10);
  745. // If we parsed completely, this was a store number
  746. if (NULL == szEndPtr[0])
  747. {
  748. // Increment ulStore so we can use to distinguish an unset value
  749. pRunOpts->ulStore++;
  750. i++;
  751. }
  752. // Else it was a naked option - leave it on the stack
  753. }
  754. break;
  755. // MAPIMIME
  756. case switchMAPI:
  757. pRunOpts->ulMAPIMIMEFlags |= MAPIMIME_TOMAPI;
  758. break;
  759. case switchMIME:
  760. pRunOpts->ulMAPIMIMEFlags |= MAPIMIME_TOMIME;
  761. break;
  762. case switchCCSFFlags:
  763. pRunOpts->ulConvertFlags = strtoul(argv[i + 1], &szEndPtr, 10);
  764. i++;
  765. break;
  766. case switchRFC822:
  767. pRunOpts->ulMAPIMIMEFlags |= MAPIMIME_RFC822;
  768. break;
  769. case switchWrap:
  770. pRunOpts->ulWrapLines = strtoul(argv[i + 1], &szEndPtr, 10);
  771. pRunOpts->ulMAPIMIMEFlags |= MAPIMIME_WRAP;
  772. i++;
  773. break;
  774. case switchEncoding:
  775. pRunOpts->ulEncodingType = strtoul(argv[i + 1], &szEndPtr, 10);
  776. pRunOpts->ulMAPIMIMEFlags |= MAPIMIME_ENCODING;
  777. i++;
  778. break;
  779. case switchCharset:
  780. pRunOpts->ulCodePage = strtoul(argv[i + 1], &szEndPtr, 10);
  781. pRunOpts->cSetType = (CHARSETTYPE)strtoul(argv[i + 2], &szEndPtr, 10);
  782. if (pRunOpts->cSetType > CHARSET_WEB) { bHitError = true; break; }
  783. pRunOpts->cSetApplyType = (CSETAPPLYTYPE)strtoul(argv[i + 3], &szEndPtr, 10);
  784. if (pRunOpts->cSetApplyType > CSET_APPLY_TAG_ALL) { bHitError = true; break; }
  785. pRunOpts->ulMAPIMIMEFlags |= MAPIMIME_CHARSET;
  786. i += 3;
  787. break;
  788. case switchAddressBook:
  789. pRunOpts->ulMAPIMIMEFlags |= MAPIMIME_ADDRESSBOOK;
  790. break;
  791. case switchUnicode:
  792. pRunOpts->ulMAPIMIMEFlags |= MAPIMIME_UNICODE;
  793. break;
  794. case switchNoSwitch:
  795. // naked option without a flag - we only allow one of these
  796. if (!pRunOpts->lpszUnswitchedOption.empty()) { bHitError = true; break; } // He's already got one, you see.
  797. pRunOpts->lpszUnswitchedOption = LPCSTRToWstring(argv[i]);
  798. break;
  799. case switchUnknown:
  800. // display help
  801. bHitError = true;
  802. break;
  803. }
  804. }
  805. if (bHitError)
  806. {
  807. pRunOpts->Mode = cmdmodeHelp;
  808. return false;
  809. }
  810. // Having processed the command line, we may not have determined a mode.
  811. // Some modes can be presumed by the switches we did see.
  812. // If we didn't get a mode set but we saw OPT_NEEDFOLDER, assume we're in folder dumping mode
  813. if (cmdmodeUnknown == pRunOpts->Mode && pRunOpts->ulOptions & OPT_NEEDFOLDER) pRunOpts->Mode = cmdmodeFolderProps;
  814. // If we didn't get a mode set, but we saw OPT_PROFILE, assume we're in profile dumping mode
  815. if (cmdmodeUnknown == pRunOpts->Mode && pRunOpts->ulOptions & OPT_PROFILE)
  816. {
  817. pRunOpts->Mode = cmdmodeProfile;
  818. pRunOpts->ulOptions |= OPT_NEEDMAPIINIT | OPT_INITMFC;
  819. }
  820. // If we didn't get a mode set, assume we're in prop tag mode
  821. if (cmdmodeUnknown == pRunOpts->Mode) pRunOpts->Mode = cmdmodePropTag;
  822. // If we weren't passed an output file/directory, remember the current directory
  823. if (pRunOpts->lpszOutput.empty() && pRunOpts->Mode != cmdmodeSmartView && pRunOpts->Mode != cmdmodeProfile)
  824. {
  825. char strPath[_MAX_PATH];
  826. GetCurrentDirectoryA(_MAX_PATH, strPath);
  827. pRunOpts->lpszOutput = LPCSTRToWstring(strPath);
  828. }
  829. // Validate that we have bare minimum to run
  830. if (pRunOpts->ulOptions & OPT_NEEDINPUTFILE && pRunOpts->lpszInput.empty()) return false;
  831. if (pRunOpts->ulOptions & OPT_NEEDOUTPUTFILE && pRunOpts->lpszOutput.empty()) return false;
  832. switch (pRunOpts->Mode)
  833. {
  834. case cmdmodePropTag:
  835. if (!(pRunOpts->ulOptions & OPT_DOTYPE) && !(pRunOpts->ulOptions & OPT_DOPARTIALSEARCH) && (pRunOpts->lpszUnswitchedOption.empty())) return false;
  836. if ((pRunOpts->ulOptions & OPT_DOPARTIALSEARCH) && (pRunOpts->ulOptions & OPT_DOTYPE) && ulNoMatch == pRunOpts->ulTypeNum) return false;
  837. if ((pRunOpts->ulOptions & OPT_DOFLAG) && ((pRunOpts->ulOptions & OPT_DOPARTIALSEARCH) || (pRunOpts->ulOptions & OPT_DOTYPE))) return false;
  838. break;
  839. case cmdmodeSmartView:
  840. if (!pRunOpts->ulSVParser) return false;
  841. break;
  842. case cmdmodeContents:
  843. if (!(pRunOpts->ulOptions & OPT_DOCONTENTS) && !(pRunOpts->ulOptions & OPT_DOASSOCIATEDCONTENTS)) return false;
  844. break;
  845. case cmdmodeMAPIMIME:
  846. #define CHECKFLAG(__flag) ((pRunOpts->ulMAPIMIMEFlags & (__flag)) == (__flag))
  847. // Can't convert both ways at once
  848. if (CHECKFLAG(MAPIMIME_TOMAPI) && CHECKFLAG(MAPIMIME_TOMIME)) return false;
  849. // Make sure there's no MIME-only options specified in a MIME->MAPI conversion
  850. if (CHECKFLAG(MAPIMIME_TOMAPI) &&
  851. (CHECKFLAG(MAPIMIME_RFC822) ||
  852. CHECKFLAG(MAPIMIME_ENCODING) ||
  853. CHECKFLAG(MAPIMIME_WRAP)))
  854. return false;
  855. // Make sure there's no MAPI-only options specified in a MAPI->MIME conversion
  856. if (CHECKFLAG(MAPIMIME_TOMIME) &&
  857. (CHECKFLAG(MAPIMIME_CHARSET) ||
  858. CHECKFLAG(MAPIMIME_UNICODE)))
  859. return false;
  860. break;
  861. case cmdmodeProfile:
  862. if (!pRunOpts->lpszProfile.empty() && pRunOpts->lpszOutput.empty()) return false;
  863. if (pRunOpts->lpszProfile.empty() && !pRunOpts->lpszOutput.empty()) return false;
  864. if (!pRunOpts->lpszProfileSection.empty() && pRunOpts->lpszProfile.empty()) return false;
  865. break;
  866. default:
  867. break;
  868. }
  869. // Didn't fail - return true
  870. return true;
  871. }
  872. void PrintArgs(_In_ MYOPTIONS ProgOpts)
  873. {
  874. DebugPrint(DBGGeneric, L"Mode = %d\n", ProgOpts.Mode);
  875. DebugPrint(DBGGeneric, L"ulOptions = 0x%08X\n", ProgOpts.ulOptions);
  876. DebugPrint(DBGGeneric, L"ulTypeNum = 0x%08X\n", ProgOpts.ulTypeNum);
  877. if (!ProgOpts.lpszUnswitchedOption.empty()) DebugPrint(DBGGeneric, L"lpszUnswitchedOption = %ws\n", ProgOpts.lpszUnswitchedOption.c_str());
  878. if (!ProgOpts.lpszFlagName.empty()) DebugPrint(DBGGeneric, L"lpszFlagName = %ws\n", ProgOpts.lpszFlagName.c_str());
  879. if (!ProgOpts.lpszFolderPath.empty()) DebugPrint(DBGGeneric, L"lpszFolderPath = %ws\n", ProgOpts.lpszFolderPath.c_str());
  880. if (!ProgOpts.lpszInput.empty()) DebugPrint(DBGGeneric, L"lpszInput = %ws\n", ProgOpts.lpszInput.c_str());
  881. if (!ProgOpts.lpszMessageClass.empty()) DebugPrint(DBGGeneric, L"lpszMessageClass = %ws\n", ProgOpts.lpszMessageClass.c_str());
  882. if (!ProgOpts.lpszMid.empty()) DebugPrint(DBGGeneric, L"lpszMid = %ws\n", ProgOpts.lpszMid.c_str());
  883. if (!ProgOpts.lpszOutput.empty()) DebugPrint(DBGGeneric, L"lpszOutput = %ws\n", ProgOpts.lpszOutput.c_str());
  884. if (!ProgOpts.lpszProfile.empty()) DebugPrint(DBGGeneric, L"lpszProfile = %ws\n", ProgOpts.lpszProfile.c_str());
  885. if (!ProgOpts.lpszProfileSection.empty()) DebugPrint(DBGGeneric, L"lpszProfileSection = %ws\n", ProgOpts.lpszProfileSection.c_str());
  886. if (!ProgOpts.lpszSubject.empty()) DebugPrint(DBGGeneric, L"lpszSubject = %ws\n", ProgOpts.lpszSubject.c_str());
  887. if (!ProgOpts.lpszVersion.empty()) DebugPrint(DBGGeneric, L"lpszVersion = %ws\n", ProgOpts.lpszVersion.c_str());
  888. }
  889. // Returns true if we've done everything we need to do and can exit the program.
  890. // Returns false to continue work.
  891. bool LoadMAPIVersion(wstring lpszVersion)
  892. {
  893. // Load DLLS and get functions from them
  894. ImportProcs();
  895. DebugPrint(DBGGeneric, L"LoadMAPIVersion(%ws)\n", lpszVersion);
  896. LPWSTR szPath = NULL;
  897. MAPIPathIterator* mpi = new MAPIPathIterator(true);
  898. if (mpi)
  899. {
  900. ULONG ulVersion = wstringToUlong(lpszVersion, 10);
  901. if (ulVersion == NULL)
  902. {
  903. DebugPrint(DBGGeneric, L"Got a string\n");
  904. wstringToLower(lpszVersion);
  905. for (;;)
  906. {
  907. szPath = mpi->GetNextMAPIPath();
  908. if (!szPath) break;
  909. _wcslwr(szPath);
  910. if (wcsstr(szPath, lpszVersion.c_str()))
  911. {
  912. break;
  913. }
  914. delete[] szPath;
  915. szPath = NULL;
  916. }
  917. }
  918. else if (0 == ulVersion)
  919. {
  920. DebugPrint(DBGGeneric, L"Listing MAPI\n");
  921. for (;;)
  922. {
  923. szPath = mpi->GetNextMAPIPath();
  924. if (!szPath) break;
  925. _wcslwr(szPath);
  926. printf("MAPI path: %ws\n", szPath);
  927. delete[] szPath;
  928. szPath = NULL;
  929. }
  930. return true;
  931. }
  932. else
  933. {
  934. DebugPrint(DBGGeneric, L"Got a number %u\n", ulVersion);
  935. switch (ulVersion)
  936. {
  937. case 1: // system
  938. szPath = mpi->GetMAPISystemDir();
  939. break;
  940. case 11: // Outlook 2003 (11)
  941. szPath = mpi->GetInstalledOutlookMAPI(oqcOffice11);
  942. break;
  943. case 12: // Outlook 2007 (12)
  944. szPath = mpi->GetInstalledOutlookMAPI(oqcOffice12);
  945. break;
  946. case 14: // Outlook 2010 (14)
  947. szPath = mpi->GetInstalledOutlookMAPI(oqcOffice14);
  948. break;
  949. case 15: // Outlook 2013 (15)
  950. szPath = mpi->GetInstalledOutlookMAPI(oqcOffice15);
  951. break;
  952. }
  953. }
  954. }
  955. if (szPath)
  956. {
  957. DebugPrint(DBGGeneric, L"Found MAPI path %ws\n", szPath);
  958. HMODULE hMAPI = NULL;
  959. HRESULT hRes = S_OK;
  960. WC_D(hMAPI, MyLoadLibraryW(szPath));
  961. SetMAPIHandle(hMAPI);
  962. delete[] szPath;
  963. }
  964. delete mpi;
  965. return false;
  966. }
  967. void main(_In_ int argc, _In_count_(argc) char * argv[])
  968. {
  969. HRESULT hRes = S_OK;
  970. bool bMAPIInit = false;
  971. SetDllDirectory("");
  972. MyHeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
  973. // Set up our property arrays or nothing works
  974. MergeAddInArrays();
  975. RegKeys[regkeyDO_SMART_VIEW].ulCurDWORD = 1;
  976. RegKeys[regkeyUSE_GETPROPLIST].ulCurDWORD = 1;
  977. RegKeys[regkeyPARSED_NAMED_PROPS].ulCurDWORD = 1;
  978. RegKeys[regkeyCACHE_NAME_DPROPS].ulCurDWORD = 1;
  979. MYOPTIONS ProgOpts;
  980. bool bGoodCommandLine = ParseArgs(argc, argv, &ProgOpts);
  981. // Must be first after ParseArgs
  982. if (ProgOpts.ulOptions & OPT_INITMFC)
  983. {
  984. InitMFC();
  985. }
  986. if (ProgOpts.ulOptions & OPT_VERBOSE)
  987. {
  988. RegKeys[regkeyDEBUG_TAG].ulCurDWORD = 0xFFFFFFFF;
  989. PrintArgs(ProgOpts);
  990. }
  991. if (!(ProgOpts.ulOptions & OPT_NOADDINS))
  992. {
  993. RegKeys[regkeyLOADADDINS].ulCurDWORD = true;
  994. LoadAddIns();
  995. }
  996. if (!ProgOpts.lpszVersion.empty())
  997. {
  998. if (LoadMAPIVersion(ProgOpts.lpszVersion)) return;
  999. }
  1000. if (cmdmodeHelp == ProgOpts.Mode || !bGoodCommandLine)
  1001. {
  1002. DisplayUsage(cmdmodeHelp == ProgOpts.Mode || bGoodCommandLine);
  1003. }
  1004. else
  1005. {
  1006. if (ProgOpts.ulOptions & OPT_ONLINE)
  1007. {
  1008. RegKeys[regKeyMAPI_NO_CACHE].ulCurDWORD = true;
  1009. RegKeys[regkeyMDB_ONLINE].ulCurDWORD = true;
  1010. }
  1011. // Log on to MAPI if needed
  1012. if (ProgOpts.ulOptions & OPT_NEEDMAPIINIT)
  1013. {
  1014. WC_MAPI(MAPIInitialize(NULL));
  1015. if (FAILED(hRes))
  1016. {
  1017. printf("Error initializing MAPI: 0x%08x\n", hRes);
  1018. }
  1019. else
  1020. {
  1021. bMAPIInit = true;
  1022. }
  1023. }
  1024. if (bMAPIInit && ProgOpts.ulOptions & OPT_NEEDMAPILOGON)
  1025. {
  1026. WC_H(MrMAPILogonEx(ProgOpts.lpszProfile, &ProgOpts.lpMAPISession));
  1027. if (FAILED(hRes)) printf("MAPILogonEx returned an error: 0x%08x\n", hRes);
  1028. }
  1029. // If they need a folder get it and store at the same time from the folder id
  1030. if (ProgOpts.lpMAPISession && ProgOpts.ulOptions & OPT_NEEDFOLDER)
  1031. {
  1032. WC_H(HrMAPIOpenStoreAndFolder(ProgOpts.lpMAPISession, ProgOpts.ulFolder, ProgOpts.lpszFolderPath, &ProgOpts.lpMDB, &ProgOpts.lpFolder));
  1033. if (FAILED(hRes)) printf("HrMAPIOpenStoreAndFolder returned an error: 0x%08x\n", hRes);
  1034. }
  1035. else if (ProgOpts.lpMAPISession && ProgOpts.ulOptions & OPT_NEEDSTORE)
  1036. {
  1037. // They asked us for a store, if they passed a store index give them that one
  1038. if (ProgOpts.ulStore != 0)
  1039. {
  1040. // Decrement by one here on the index since we incremented during parameter parsing
  1041. // This is so zero indicate they did not specify a store
  1042. WC_H(OpenStore(ProgOpts.lpMAPISession, ProgOpts.ulStore - 1, &ProgOpts.lpMDB));
  1043. if (FAILED(hRes)) printf("OpenStore returned an error: 0x%08x\n", hRes);
  1044. }
  1045. else
  1046. {
  1047. // If they needed a store but didn't specify, get the default one
  1048. WC_H(OpenExchangeOrDefaultMessageStore(ProgOpts.lpMAPISession, &ProgOpts.lpMDB));
  1049. if (FAILED(hRes)) printf("OpenExchangeOrDefaultMessageStore returned an error: 0x%08x\n", hRes);
  1050. }
  1051. }
  1052. switch (ProgOpts.Mode)
  1053. {
  1054. case cmdmodePropTag:
  1055. DoPropTags(ProgOpts);
  1056. break;
  1057. case cmdmodeGuid:
  1058. DoGUIDs(ProgOpts);
  1059. break;
  1060. case cmdmodeSmartView:
  1061. DoSmartView(ProgOpts);
  1062. break;
  1063. case cmdmodeAcls:
  1064. DoAcls(ProgOpts);
  1065. break;
  1066. case cmdmodeRules:
  1067. DoRules(ProgOpts);
  1068. break;
  1069. case cmdmodeErr:
  1070. DoErrorParse(ProgOpts);
  1071. break;
  1072. case cmdmodeContents:
  1073. DoContents(ProgOpts);
  1074. break;
  1075. case cmdmodeXML:
  1076. DoMSG(ProgOpts);
  1077. break;
  1078. case cmdmodeFidMid:
  1079. DoFidMid(ProgOpts);
  1080. break;
  1081. case cmdmodeStoreProperties:
  1082. DoStore(ProgOpts);
  1083. break;
  1084. case cmdmodeMAPIMIME:
  1085. DoMAPIMIME(ProgOpts);
  1086. break;
  1087. case cmdmodeChildFolders:
  1088. DoChildFolders(ProgOpts);
  1089. break;
  1090. case cmdmodeFlagSearch:
  1091. DoFlagSearch(ProgOpts);
  1092. break;
  1093. case cmdmodeFolderProps:
  1094. DoFolderProps(ProgOpts);
  1095. break;
  1096. case cmdmodeFolderSize:
  1097. DoFolderSize(ProgOpts);
  1098. break;
  1099. case cmdmodePST:
  1100. DoPST(ProgOpts);
  1101. break;
  1102. case cmdmodeProfile:
  1103. DoProfile(ProgOpts);
  1104. break;
  1105. case cmdmodeReceiveFolder:
  1106. DoReceiveFolder(ProgOpts);
  1107. break;
  1108. case cmdmodeSearchState:
  1109. DoSearchState(ProgOpts);
  1110. break;
  1111. }
  1112. }
  1113. UninitializeNamedPropCache();
  1114. if (bMAPIInit)
  1115. {
  1116. if (ProgOpts.lpFolder) ProgOpts.lpFolder->Release();
  1117. if (ProgOpts.lpMDB) ProgOpts.lpMDB->Release();
  1118. if (ProgOpts.lpMAPISession) ProgOpts.lpMAPISession->Release();
  1119. MAPIUninitialize();
  1120. }
  1121. if (!(ProgOpts.ulOptions & OPT_NOADDINS))
  1122. {
  1123. UnloadAddIns();
  1124. }
  1125. }