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