Add mapping for PidLidRemoteTransferSize
[jelmer/openchange-proposed.git/.git] / script / makepropslist.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import argparse
5 import string
6 import subprocess
7 import sys
8 import tempfile
9
10 knownpropsets = { "PSETID_PostRss" :           "{00062041-0000-0000-C000-000000000046}",
11                   "PSETID_Sharing" :           "{00062040-0000-0000-C000-000000000046}",
12                   "PS_PUBLIC_STRINGS" :        "{00020329-0000-0000-C000-000000000046}",
13                   "PSETID_Common" :            "{00062008-0000-0000-C000-000000000046}",
14                   "PSETID_Appointment" :       "{00062002-0000-0000-C000-000000000046}",
15                   "PSETID_Address" :           "{00062004-0000-0000-C000-000000000046}",
16                   "PSETID_Meeting" :           "{6ED8DA90-450B-101B-98DA-00AA003F1305}",
17                   "PSETID_Log" :               "{0006200A-0000-0000-C000-000000000046}",
18                   "PSETID_CalendarAssistant" : "{11000E07-B51B-40D6-AF21-CAA85EDAB1D0}",
19                   "PSETID_Note" :              "{0006200E-0000-0000-C000-000000000046}",
20                   "PSETID_Task":               "{00062003-0000-0000-C000-000000000046}",
21                   "PS_INTERNET_HEADERS" :      "{00020386-0000-0000-C000-000000000046}",
22                   "PSETID_UnifiedMessaging" :  "{4442858E-A9E3-4E80-B900-317A210CC15B}",
23                   "PS_MAPI" :                  "{00020328-0000-0000-C000-000000000046}",
24                   "PSETID_Attachment" :        "{96357f7f-59e1-47d0-99a7-46515c183b54}",
25                   "PSETID_AirSync" :           "{71035549-0739-4DCB-9163-00F0580DBBDF}",
26                   "PSETID_Messaging" :         "{41F28F13-83F4-4114-A584-EEDB5A6B0BFF}"
27                   }
28
29 knowndatatypes = { "PtypInteger16" : "0x0002",
30                    "PtypInteger32" : "0x0003",
31                    "PtypFloating64" : "0x0005",
32                    "PtypBoolean" : "0x000B",
33                    "PtypEmbeddedTable" : "0x000D",
34                    "PtypObject" : "0x000D",
35                    "PtypString8" : "0x001E",
36                    "PtypString" : "0x001F",
37                    "PtypInteger64" : "0x0014",
38                    "PtypBinary" : "0x0102",
39                    "PtypTime" : "0x0040",
40                    "PtypGuid" : "0x0048",
41                    "PtypServerId" : "0x00FB",
42                    "PtypRestriction" : "0x00FD",
43                    "PtypRuleAction" : "0x00FE",
44                    "PtypMultipleInteger32" : "0x1003",
45                    "PtypMultipleString8" : "0x101E",
46                    "PtypMultipleString" : "0x101F",
47                    "PtypMultipleTime" : "0x1040",
48                    "PtypMultipleBinary" : "0x1102",
49                    }
50 datatypemap = { "PtypInteger16" : "PT_SHORT",
51                 "PtypInteger32" : "PT_LONG",
52                 "PtypFloating64" : "PT_DOUBLE",
53                 "PtypBoolean" : "PT_BOOLEAN",
54                 "PtypEmbeddedTable" : "PT_OBJECT",
55                 "PtypObject" : "PT_OBJECT",
56                 "PtypString8" : "PT_STRING8",
57                 "PtypString" : "PT_UNICODE",
58                 "PtypInteger64" : "PT_I8",
59                 "PtypBinary" : "PT_BINARY",
60                 "PtypTime" : "PT_SYSTIME",
61                 "PtypGuid" : "PT_CLSID",
62                 "PtypServerId" : "PT_SVREID",
63                 "PtypRestriction" : "PT_SRESTRICT",
64                 "PtypRuleAction" : "PT_ACTIONS",
65                 "PtypMultipleInteger32" : "PT_MV_LONG",
66                 "PtypMultipleString8" : "PT_MV_STRING8",
67                 "PtypMultipleString" : "PT_MV_UNICODE",
68                 "PtypMultipleTime" : "PT_MV_SYSTIME",
69                 "PtypMultipleBinary" : "PT_MV_BINARY"
70                 }
71
72 knownrefs = [
73         "[MS-ASAIRS]",
74         "[MS-ASCAL]",
75         "[MS-ASCMD]",
76         "[MS-ASCNTC]",
77         "[MS-ASCON]",
78         "[MS-ASDOC]",
79         "[MS-ASDTYPE]",
80         "[MS-ASEMAIL]",
81         "[MS-ASHTTP]",
82         "[MS-ASMS]",
83         "[MS-ASNOTE]",
84         "[MS-ASPROV]",
85         "[MS-ASRM]",
86         "[MS-ASTASK]",
87         "[MS-ASWBXML]",
88         "[MS-CAB]",
89         "[MS-MCI]",
90         "[MS-OXABREF]",
91         "[MS-OXBBODY]",
92         "[MS-OXCDATA]",
93         "[MS-OXCETF]",
94         "[MS-OXCFOLD]",
95         "[MS-OXCFXICS]",
96         "[MS-OXCHGTR]",
97         "[MS-OXCICAL]",
98         "[MS-OXCMAIL]",
99         "[MS-OXCMSG]",
100         "[MS-OXCNOTIF]",
101         "[MS-OXCPERM]",
102         "[MS-OXCPRPT]",
103         "[MS-OXCROPS]",
104         "[MS-OXCRPC]",
105         "[MS-OXCSPAM]",
106         "[MS-OXCSTOR]",
107         "[MS-OXCSYNC]",
108         "[MS-OXCTABL]",
109         "[MS-OXDISCO]",
110         "[MS-OXDOCO]",
111         "[MS-OXDSCLI]",
112         "[MS-OXGLOS]",
113         "[MS-OXIMAP4]",
114         "[MS-OXLDAP]",
115         "[MS-OXMSG]",
116         "[MS-OXMVMBX]",
117         "[MS-OXOABK]",
118         "[MS-OXOABKT]",
119         "[MS-OXOAB]",
120         "[MS-OXOCAL]",
121         "[MS-OXOCFG]",
122         "[MS-OXOCNTC]",
123         "[MS-OXODLGT]",
124         "[MS-OXODOC]",
125         "[MS-OXOFLAG]",
126         "[MS-OXOJRNL]",
127         "[MS-OXOMSG]",
128         "[MS-OXONOTE]",
129         "[MS-OXOPFFB]",
130         "[MS-OXOPOST]",
131         "[MS-OXORMDR]",
132         "[MS-OXORMMS]",
133         "[MS-OXORSS]",
134         "[MS-OXORULE]",
135         "[MS-OXOSFLD]",
136         "[MS-OXOSMIME]",
137         "[MS-OXOSMMS]",
138         "[MS-OXOSRCH]",
139         "[MS-OXOTASK]",
140         "[MS-OXOUM]",
141         "[MS-OXPFOAB]",
142         "[MS-OXPHISH]",
143         "[MS-OXPOP3]",
144         "[MS-OXPROPS]",
145         "[MS-OXPROTO]",
146         "[MS-OXPSVAL]",
147         "[MS-OXREF]",
148         "[MS-OXRTFCP]",
149         "[MS-OXRTFEX]",
150         "[MS-OXSHARE]",
151         "[MS-OXSHRMSG]",
152         "[MS-OXSMTP]",
153         "[MS-OXTNEF]",
154         "[MS-OXVCARD]",
155         "[MS-OXWAVLS]",
156         "[MS-OXWCONFIG]",
157         "[MS-OXWMT]",
158         "[MS-OXWOAB]",
159         "[MS-OXWOOF]",
160         "[MS-OXWSADISC]",
161         "[MS-OXWSATT]",
162         "[MS-OXWSAUTID]",
163         "[MS-OXWSBTRF]",
164         "[MS-OXWSCDATA]",
165         "[MS-OXWSCONT]",
166         "[MS-OXWSCONV]",
167         "[MS-OXWSCORE]",
168         "[MS-OXWSCVTID]",
169         "[MS-OXWSDLGM]",
170         "[MS-OXWSDLIST]",
171         "[MS-OXWSFOLD]",
172         "[MS-OXWSGTRM]",
173         "[MS-OXWSGTZ]",
174         "[MS-OXWSLVID]",
175         "[MS-OXWSMSG]",
176         "[MS-OXWSMSHR]",
177         "[MS-OXWSMTGS]",
178         "[MS-OXWSMTRK]",
179         "[MS-OXWSNTIF]",
180         "[MS-OXWSPOST]",
181         "[MS-OXWSPSNTIF]",
182         "[MS-OXWSRSLNM]",
183         "[MS-OXWSRULES]",
184         "[MS-OXWSSRCH]",
185         "[MS-OXWSSYNC]",
186         "[MS-OXWSTASK]",
187         "[MS-OXWSUSRCFG]",
188         "[MS-OXWSXPROP]",
189         "[MS-OXWUMS]",
190         "[MS-PATCH]",
191         "[MS-XJRNL]",
192         "[MS-XLOGIN]",
193         "[MS-XWDCAL]",
194         "[MS-XWDCNTC]",
195         "[MS-XWDDOC]",
196         "[MS-XWDEXT]",
197         "[MS-XWDFOLD]",
198         "[MS-XWDMAIL]",
199         "[MS-XWDNOTIF]",
200         "[MS-XWDREPL]",
201         "[MS-XWDSEARCH]",
202         "[MS-XWDSTRUCTDOC]",
203         "[MS-XWDVSEC]",
204         "[MS-NSPI]"
205 ]
206
207 knownareas = [
208         "AB Container",
209         "Access Control Properties",
210         "Access Control Properties Property set",
211         "Address book",
212         "Address Book",
213         "Address Properties",
214         "Address Properties Property set",
215         "Appointment Property set",
216         "Archive",
217         "BestBody",
218         "Calendar",
219         "Calendar Document Property set",
220         "Calendar Property set",
221         "Common",
222         "Common Property set",
223         "Conferencing",
224         "Configuration",
225         "Conflict Note",
226         "Contact Properties",
227         "Container Properties",
228         "Container Properties Property set",
229         "Conversation Actions",
230         "Conversations",
231         "Email",
232         "Email Property set",
233         "Exchange",
234         "Exchange Administrative",
235         "ExchangeAdministrative",
236         "ExchangeAdministrative Property set",
237         "ExchangeFolder",
238         "ExchangeFolder Property set",
239         "ExchangeMessageReadOnly",
240         "ExchangeMessageStore",
241         "ExchangeNonTransmittableReserved",
242         "Exchange Profile Configuration",
243         "Exchange Property set",
244         "Flagging",
245         "Folder Properties",
246         "Free/Busy Properties",
247         "General Message Properties",
248         "General Message Properties Property set",
249         "General Report Properties",
250         "History Properties",
251         "IC",
252         "ICS",
253         "ID Properties",
254         "ID Properties Property set",
255         "Journal",
256         "Mail",
257         "MapiAddressBook",
258         "MapiAttachment",
259         "MapiCommon",
260         "MapiContainer",
261         "MAPI Display Tables",
262         "MapiEnvelope",
263         "MapiEnvelope Property set",
264         "MapiMailUser",
265         "MapiMessage",
266         "MapiMessageStore",
267         "MapiNonTransmittable",
268         "MapiNonTransmittable Property set",
269         "MapiRecipient",
270         "MapiStatus",
271         "Meeting Response",
272         "Meetings",
273         "Message Attachment Properties",
274         "Message Attachment Properties Property set",
275         "MessageClassDefinedNonTransmittable",
276         "Message Class Defined Transmittable",
277         "MessageClassDefinedTransmittable",
278         "Message Properties",
279         "Message Properties Property set",
280         "Message Store Properties",
281         "Message Time Properties",
282         "Message Time Properties Property set",
283         "MIME properties",
284         "MIME Properties",
285         "MIME Properties Property set",
286         "Miscellaneous Properties",
287         "Miscellaneous Properties Property set",
288         "Offline Address Book Properties",
289         "Outlook Application",
290         "ProviderDefinedNonTransmittable",
291         "PST Internal",
292         "Reminders",
293         "RenMessageFolder",
294         "RSS",
295         "Rules",
296         "Run-time configuration",
297         "Search",
298         "Secure Messaging",
299         "Secure Messaging Properties",
300         "Server",
301         "Server-side Rules Properties",
302         "Server-Side Rules Properties",
303         "Sharing",
304         "SMS",
305         "Spam",
306         "Sticky Notes",
307         "Structured Documents Property set",
308         "Sync",
309         "Table Properties",
310         "Tasks",
311         "Transport Envelope",
312         "TransportEnvelope",
313         "TransportRecipient",
314         "UM",
315         "Unified Messaging"
316 ]
317
318 properties = []
319
320 def make_properties_list(propsfilename):
321         next_num = 1
322         propname = ""
323         propertyinfo = {}
324         propsfile = file(propsfilename)
325
326         for line in propsfile:
327                 if line.startswith("2     Structures"):
328                         break
329
330         for line in propsfile:
331                 if line.startswith("2."):
332                         section_num = line.split()[0]
333                         sub_section_num = section_num.split(".")[1]
334                         if int(sub_section_num) != next_num:
335                                 print "expected", next_num, "got", sub_section_num
336                         next_num += 1
337                         propname = line.split()[1]
338                         if propertyinfo.has_key("CanonicalName"):
339                                 properties.append(propertyinfo.copy())
340                                 propertyinfo = {}
341                         
342                 if line.strip().startswith("Canonical name:"):
343                         canonicalname = line.strip().split(":")[1].strip()
344                         if ((propname != "") and (propname != canonicalname)):
345                                 print "expected", propname, "got", canonicalname
346                         propertyinfo["CanonicalName"] = canonicalname
347
348                 if line.strip().startswith("Property name:"):
349                         propertyname = line.split(":", 1)
350                         propertyinfo["PropertyName"] = propertyname[1].strip()
351
352                 if line.strip().startswith("Description:"):
353                         description = line.strip().split(":")[1].strip()
354                         while (1):
355                                 nextline = propsfile.next().strip()
356                                 if (nextline.isspace() or (len(nextline) == 0)):
357                                         break
358                                 description += (" " + nextline)
359                         propertyinfo["Description"] = description
360
361                 if line.strip().startswith("Alternate names:"):
362                         altname = line.strip().partition(":")[2]
363                         while (1):
364                                 nextline = propsfile.next().strip()
365                                 if (nextline.isspace() or (len(nextline) == 0)):
366                                         break
367                                 altname += (", " + nextline)
368                         propertyinfo["AlternateNames"] = altname
369
370                 if line.strip().startswith("Data type:"):
371                         datatype = line.strip().split(":")[1].strip()
372                         datatypename, datatypeval = datatype.split(",")
373                         propertyinfo["DataTypeName"] = datatypename.strip()
374                         propertyinfo["DataTypeValue"] = datatypeval.strip()
375
376                 if line.strip().startswith("Property set:"):
377                         propset = line.strip().split(":")[1].strip()
378                         if propset.find(" ") != -1:
379                                 propsetname, propsetval = propset.split(" ")
380                                 propertyinfo["PropertySet"] = propsetname.strip()
381                                 propertyinfo["PropertySetValue"] = propsetval.strip()
382
383                 if line.strip().startswith("Property ID:"):
384                         propid = line.strip().split(":")[1].strip()
385                         if propid.startswith("0x"):
386                                 propertyinfo["PropertyId"] = int(propid, 16)
387                         else:
388                                 print "In section 2.%(section)i (%(propname)s):" % { 'section': (next_num -1), 'propname': propname }
389                                 print "\t", propid, "doesn't appear to have correct (hex) format"
390
391                 if line.strip().startswith("Property long ID (LID):"):
392                         proplid = line.strip().split(":")[1].strip()
393                         if proplid.startswith("0x"):
394                                 propertyinfo["PropertyLid"] = int(proplid, 16)
395                         else:
396                                 print "In section 2.%(section)i (%(propname)s):" % { 'section': (next_num -1), 'propname': propname }
397                                 print "\t", proplid, "doesn't appear to have correct (hex) format"
398
399                 if line.strip().startswith("Area:"):
400                         areaname = line.strip().split(":")[1].strip()
401                         if (knownareas.count(areaname) == 1):
402                                 propertyinfo["Area"] = areaname
403                         else:
404                                 print "In section 2.%(section)i (%(propname)s):" % { 'section': (next_num -1), 'propname': propname }
405                                 print "\t", areaname, "isn't an expected area name (typo?)"
406
407                 if line.strip().startswith("References:") or line.strip().startswith("Reference:"):
408                         references = line.strip().split(":")[1].strip()
409                         while (1):
410                                 nextline = propsfile.next().strip()
411                                 if (nextline.isspace() or (len(nextline) == 0)):
412                                         break
413                                 references += (nextline)
414                         propertyinfo["References"] = references
415
416                 if line.strip().startswith("Defining Reference:") or line.strip().startswith("Defining reference:") or line.strip().startswith("Defining references"):
417                         reference = line.strip().split(":")[1].strip()
418                         propertyinfo["DefiningReference"] = reference
419
420                 propertyinfo["OXPROPS_Sect"] = "2.%i" % (next_num -1)
421
422         #The whole file should now be parsed
423         properties.append(propertyinfo)
424         # sanity check
425         print "Last section parsed was section 2.%(section)i" % { 'section': (next_num-1) }
426
427 # Debugging dump of everything
428 def debug_dump():
429         for entry in properties:
430                 print entry
431
432 extra_private_tags_struct = """\t{ PidTagFolderChildCount,                                             PT_LONG,      \"PidTagFolderChildCount\"                                            },
433 """
434
435 temporary_private_tags = """
436 #define openchange_private_ROOT_FOLDER_FID                  PROP_TAG(PT_I8        , 0xd001) /* 0xd0010014 */
437 #define openchange_private_ROOT_FOLDER_FID_ERROR            PROP_TAG(PT_ERROR     , 0xd001) /* 0xd001000a */
438 #define openchange_private_DEFERRED_ACTIONS_FID             PROP_TAG(PT_I8        , 0xd002) /* 0xd0020014 */
439 #define openchange_private_DEFERRED_ACTIONS_FID_ERROR       PROP_TAG(PT_ERROR     , 0xd002) /* 0xd002000a */
440 #define openchange_private_SPOOLER_QUEUE_FID                PROP_TAG(PT_I8        , 0xd003) /* 0xd0030014 */
441 #define openchange_private_SPOOLER_QUEUE_FID_ERROR          PROP_TAG(PT_ERROR     , 0xd003) /* 0xd003000a */
442 #define openchange_private_IPM_SUBTREE_FID                  PROP_TAG(PT_I8        , 0xd004) /* 0xd0040014 */
443 #define openchange_private_IPM_SUBTREE_FID_ERROR            PROP_TAG(PT_ERROR     , 0xd004) /* 0xd004000a */
444 #define openchange_private_INBOX_FID                        PROP_TAG(PT_I8        , 0xd005) /* 0xd0050014 */
445 #define openchange_private_INBOX_FID_ERROR                  PROP_TAG(PT_ERROR     , 0xd005) /* 0xd005000a */
446 #define openchange_private_OUTBOX_FID                       PROP_TAG(PT_I8        , 0xd006) /* 0xd0060014 */
447 #define openchange_private_OUTBOX_FID_ERROR                 PROP_TAG(PT_ERROR     , 0xd006) /* 0xd006000a */
448 #define openchange_private_SENT_ITEMS_FID                   PROP_TAG(PT_I8        , 0xd007) /* 0xd0070014 */
449 #define openchange_private_SENT_ITEMS_FID_ERROR             PROP_TAG(PT_ERROR     , 0xd007) /* 0xd007000a */
450 #define openchange_private_DELETED_ITEMS_FID                PROP_TAG(PT_I8        , 0xd008) /* 0xd0080014 */
451 #define openchange_private_DELETED_ITEMS_FID_ERROR          PROP_TAG(PT_ERROR     , 0xd008) /* 0xd008000a */
452 #define openchange_private_COMMON_VIEWS_FID                 PROP_TAG(PT_I8        , 0xd009) /* 0xd0090014 */
453 #define openchange_private_COMMON_VIEWS_FID_ERROR           PROP_TAG(PT_ERROR     , 0xd009) /* 0xd009000a */
454 #define openchange_private_SCHEDULE_FID                     PROP_TAG(PT_I8        , 0xd00a) /* 0xd00a0014 */
455 #define openchange_private_SCHEDULE_FID_ERROR               PROP_TAG(PT_ERROR     , 0xd00a) /* 0xd00a000a */
456 #define openchange_private_SEARCH_FID                       PROP_TAG(PT_I8        , 0xd00b) /* 0xd00b0014 */
457 #define openchange_private_SEARCH_FID_ERROR                 PROP_TAG(PT_ERROR     , 0xd00b) /* 0xd00b000a */
458 #define openchange_private_VIEWS_FID                        PROP_TAG(PT_I8        , 0xd00c) /* 0xd00c0014 */
459 #define openchange_private_VIEWS_FID_ERROR                  PROP_TAG(PT_ERROR     , 0xd00c) /* 0xd00c000a */
460 #define openchange_private_SHORTCUTS_FID                    PROP_TAG(PT_I8        , 0xd00d) /* 0xd00d0014 */
461 #define openchange_private_SHORTCUTS_FID_ERROR              PROP_TAG(PT_ERROR     , 0xd00d) /* 0xd00d000a */
462 #define openchange_private_MailboxGUID                      PROP_TAG(PT_CLSID     , 0xd00e) /* 0xd00e0048 */
463 #define openchange_private_MailboxGUID_ERROR                PROP_TAG(PT_ERROR     , 0xd00e) /* 0xd00e000a */
464 #define openchange_private_ReplicaID                        PROP_TAG(PT_SHORT     , 0xd00f) /* 0xd00f0002 */
465 #define openchange_private_ReplicaID_ERROR                  PROP_TAG(PT_ERROR     , 0xd00f) /* 0xd00f000a */
466 #define openchange_private_ReplicaGUID                      PROP_TAG(PT_CLSID     , 0xd010) /* 0xd0100048 */
467 #define openchange_private_ReplicaGUID_ERROR                PROP_TAG(PT_ERROR     , 0xd010) /* 0xd010000a */
468 #define openchange_private_CONTACT_FID                      PROP_TAG(PT_I8        , 0xd011) /* 0xd0110014 */
469 #define openchange_private_CONTACT_FID_ERROR                PROP_TAG(PT_ERROR     , 0xd011) /* 0xd011000a */
470 #define openchange_private_CALENDAR_FID                     PROP_TAG(PT_I8        , 0xd012) /* 0xd0120014 */
471 #define openchange_private_CALENDAR_FID_ERROR               PROP_TAG(PT_ERROR     , 0xd012) /* 0xd012000a */
472 #define openchange_private_JOURNAL_FID                      PROP_TAG(PT_I8        , 0xd013) /* 0xd0130014 */
473 #define openchange_private_JOURNAL_FID_ERROR                PROP_TAG(PT_ERROR     , 0xd013) /* 0xd013000a */
474 #define openchange_private_NOTE_FID                         PROP_TAG(PT_I8        , 0xd014) /* 0xd0140014 */
475 #define openchange_private_NOTE_FID_ERROR                   PROP_TAG(PT_ERROR     , 0xd014) /* 0xd014000a */
476 #define openchange_private_TASK_FID                         PROP_TAG(PT_I8        , 0xd015) /* 0xd0150014 */
477 #define openchange_private_TASK_FID_ERROR                   PROP_TAG(PT_ERROR     , 0xd015) /* 0xd015000a */
478 #define openchange_private_DRAFTS_FID                       PROP_TAG(PT_I8        , 0xd016) /* 0xd0160014 */
479 #define openchange_private_DRAFTS_FID_ERROR                 PROP_TAG(PT_ERROR     , 0xd016) /* 0xd016000a */
480 #define openchange_private_PF_ROOT                          PROP_TAG(PT_I8        , 0xd017) /* 0xd0170014 */
481 #define openchange_private_PF_ROOT_ERROR                    PROP_TAG(PT_ERROR     , 0xd017) /* 0xd017000a */
482 #define openchange_private_PF_IPM_SUBTREE                   PROP_TAG(PT_I8        , 0xd018) /* 0xd0180014 */
483 #define openchange_private_PF_IPM_SUBTREE_ERROR             PROP_TAG(PT_ERROR     , 0xd018) /* 0xd018000a */
484 #define openchange_private_PF_NONIPM_SUBTREE                PROP_TAG(PT_I8        , 0xd019) /* 0xd0190014 */
485 #define openchange_private_PF_NONIPM_SUBTREE_ERROR          PROP_TAG(PT_ERROR     , 0xd019) /* 0xd019000a */
486 #define openchange_private_PF_EFORMS                        PROP_TAG(PT_I8        , 0xd01a) /* 0xd01a0014 */
487 #define openchange_private_PF_EFORMS_ERROR                  PROP_TAG(PT_ERROR     , 0xd01a) /* 0xd01a000a */
488 #define openchange_private_PF_FREEBUSY                      PROP_TAG(PT_I8        , 0xd01b) /* 0xd01b0014 */
489 #define openchange_private_PF_FREEBUSY_ERROR                PROP_TAG(PT_ERROR     , 0xd01b) /* 0xd01b000a */
490 #define openchange_private_PF_OAB                           PROP_TAG(PT_I8        , 0xd01c) /* 0xd01c0014 */
491 #define openchange_private_PF_OAB_ERROR                     PROP_TAG(PT_ERROR     , 0xd01c) /* 0xd01c000a */
492 #define openchange_private_PF_LOCAL_EFORMS                  PROP_TAG(PT_I8        , 0xd01d) /* 0xd01d0014 */
493 #define openchange_private_PF_LOCAL_EFORMS_ERROR            PROP_TAG(PT_ERROR     , 0xd01d) /* 0xd01d000a */
494 #define openchange_private_PF_LOCAL_FREEBUSY                PROP_TAG(PT_I8        , 0xd01e) /* 0xd01e0014 */
495 #define openchange_private_PF_LOCAL_FREEBUSY_ERROR          PROP_TAG(PT_ERROR     , 0xd01e) /* 0xd01e000a */
496 #define openchange_private_PF_LOCAL_OAB                     PROP_TAG(PT_I8        , 0xd01f) /* 0xd01f0014 */
497 #define openchange_private_PF_LOCAL_OAB_ERROR               PROP_TAG(PT_ERROR     , 0xd01f) /* 0xd01f000a */
498 """
499
500 temporary_private_tags_struct = """\t{ openchange_private_ROOT_FOLDER_FID,              PT_I8, "openchange_private_ROOT_FOLDER_FID" },
501         { openchange_private_DEFERRED_ACTIONS_FID,      PT_I8, "openchange_private_DEFERRED_ACTIONS_FID" },
502         { openchange_private_SPOOLER_QUEUE_FID,         PT_I8, "openchange_private_SPOOLER_QUEUE_FID" },
503         { openchange_private_IPM_SUBTREE_FID,           PT_I8, "openchange_private_IPM_SUBTREE_FID" },
504         { openchange_private_INBOX_FID,                 PT_I8, "openchange_private_INBOX_FID" },
505         { openchange_private_OUTBOX_FID,                PT_I8, "openchange_private_OUTBOX_FID" },
506         { openchange_private_SENT_ITEMS_FID,            PT_I8, "openchange_private_SENT_ITEMS_FID" },
507         { openchange_private_DELETED_ITEMS_FID,         PT_I8, "openchange_private_DELETED_ITEMS_FID" },
508         { openchange_private_COMMON_VIEWS_FID,          PT_I8, "openchange_private_COMMON_VIEWS_FID" },
509         { openchange_private_SCHEDULE_FID,              PT_I8, "openchange_private_SCHEDULE_FID" },
510         { openchange_private_SEARCH_FID,                PT_I8, "openchange_private_SEARCH_FID" },
511         { openchange_private_VIEWS_FID,                 PT_I8, "openchange_private_VIEWS_FID" },
512         { openchange_private_SHORTCUTS_FID,             PT_I8, "openchange_private_SHORTCUTS_FID" },
513         { openchange_private_MailboxGUID,               PT_CLSID, "openchange_private_MailboxGUID" },
514         { openchange_private_ReplicaID,                 PT_SHORT, "openchange_private_ReplicaID" },
515         { openchange_private_ReplicaGUID,               PT_CLSID, "openchange_private_ReplicaGUID" },
516         { openchange_private_CONTACT_FID,               PT_I8, "openchange_private_CONTACT_FID" },
517         { openchange_private_CALENDAR_FID,              PT_I8, "openchange_private_CALENDAR_FID" },
518         { openchange_private_JOURNAL_FID,               PT_I8, "openchange_private_JOURNAL_FID" },
519         { openchange_private_NOTE_FID,                  PT_I8, "openchange_private_NOTE_FID" },
520         { openchange_private_TASK_FID,                  PT_I8, "openchange_private_TASK_FID" },
521         { openchange_private_DRAFTS_FID,                PT_I8, "openchange_private_DRAFTS_FID" },
522         { openchange_private_PF_ROOT,                   PT_I8, "openchange_private_PF_ROOT" },
523         { openchange_private_PF_IPM_SUBTREE,            PT_I8, "openchange_private_PF_IPM_SUBTREE" },
524         { openchange_private_PF_NONIPM_SUBTREE,         PT_I8, "openchange_private_PF_NONIPM_SUBTREE" },
525         { openchange_private_PF_EFORMS,                 PT_I8, "openchange_private_PF_EFORMS" },
526         { openchange_private_PF_FREEBUSY,               PT_I8, "openchange_private_PF_FREEBUSY" },
527         { openchange_private_PF_OAB,                    PT_I8, "openchange_private_PF_OAB" },
528         { openchange_private_PF_LOCAL_EFORMS,           PT_I8, "openchange_private_PF_LOCAL_EFORMS" },
529         { openchange_private_PF_LOCAL_FREEBUSY,         PT_I8, "openchange_private_PF_LOCAL_FREEBUSY" },
530         { openchange_private_PF_LOCAL_OAB,              PT_I8, "openchange_private_PF_LOCAL_OAB" },
531 """
532
533 def make_mapi_properties_file():
534         proplines = []
535         altnamelines = []
536         previous_propid_list = []
537         for entry in properties:
538                 if (entry.has_key("CanonicalName") == False):
539                         print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
540                         continue
541                 if (entry.has_key("DataTypeName") == False):
542                         print "Section", entry["OXPROPS_Sect"], "has no data type entry"
543                         continue
544                 if entry.has_key("PropertyId"):
545                         propline = "#define "
546                         propline += string.ljust(entry["CanonicalName"], 68)
547                         propline += " PROP_TAG("
548                         propline += string.ljust(datatypemap[entry["DataTypeName"]], 13) + ", "
549                         propline += "0x" + format(entry["PropertyId"], "04X")
550                         propline += ")  "
551                         propline += "/* 0x" + format(entry["PropertyId"], "04X") + knowndatatypes[entry["DataTypeName"]][2:] + " */"
552                         propline += "\n"
553                         proplines.append(propline)
554                         propline = "#define "
555                         propline += string.ljust(entry["CanonicalName"] + "_Error", 68)
556                         propline += " PROP_TAG("
557                         propline += string.ljust("PT_ERROR", 13) + ", "
558                         propline += "0x" + format(entry["PropertyId"], "04X")
559                         propline += ")  "
560                         propline += "/* 0x" + format(entry["PropertyId"], "04X") + "000A" + " */"
561                         propline += "\n"
562                         proplines.append(propline)
563                         if entry.has_key("AlternateNames"):
564                                 for altname in entry["AlternateNames"].split(","):
565                                         altname = altname.strip()
566                                         if altname.count(" ") > 0:
567                                                 print "skipping non-conforming alternative name:", altname
568                                         elif altname.startswith("PR_"):
569                                                 if altname.endswith("_A"):
570                                                         continue
571                                                 if altname.endswith("_W"):
572                                                         continue
573                                                 if knowndatatypes[entry["DataTypeName"]][2:] == "001F":
574                                                         altline = "#define " + string.ljust(altname + "_UNICODE", 68)
575                                                         altline += " PROP_TAG(PT_UNICODE   , 0x" + format(entry["PropertyId"], "04X") + ")"
576                                                         altline += "  /* 0x" + format(entry["PropertyId"], "04X") + "001F */" + "\n"
577                                                         altnamelines.append(altline)
578                                                         altline = "#define " + string.ljust(altname, 68)
579                                                         altline += " PROP_TAG(PT_STRING8   , 0x" + format(entry["PropertyId"], "04X") + ")"
580                                                         altline += "  /* 0x" + format(entry["PropertyId"], "04X") + "001E */" + "\n"
581                                                         altnamelines.append(altline)
582                                                 elif knowndatatypes[entry["DataTypeName"]][2:] == "101F":
583                                                         altline = "#define " + string.ljust(altname + "_UNICODE", 68)
584                                                         altline += " PROP_TAG(PT_MV_UNICODE, 0x" + format(entry["PropertyId"], "04X") + ")"
585                                                         altline += "  /* 0x" + format(entry["PropertyId"], "04X") + "101F */" + "\n"
586                                                         altnamelines.append(altline)
587                                                         altline = "#define " + string.ljust(altname, 68)
588                                                         altline += " PROP_TAG(PT_MV_STRING8, 0x" + format(entry["PropertyId"], "04X") + ")"
589                                                         altline += "  /* 0x" + format(entry["PropertyId"], "04X") + "101E */" + "\n"
590                                                         altnamelines.append (altline)
591                                                 else:
592                                                         altnamelines.append("#define " + string.ljust(altname, 68) + " " + entry["CanonicalName"] + "\n")
593                                                 altline = "#define " + string.ljust(altname + "_ERROR", 68)
594                                                 altline += " PROP_TAG(PT_ERROR     , 0x" + format(entry["PropertyId"], "04X") + ")"
595                                                 altline += "  /* 0x" + format(entry["PropertyId"], "04X") + "000A */" + "\n"
596                                                 altnamelines.append(altline)
597
598         # hack until we properly handle named properties
599         proplines.append(temporary_private_tags)
600
601         # supplemental properties / alternative names
602         altnamelines.append("#define PidTagFolderChildCount                                               PROP_TAG(PT_LONG      , 0x6638) /* 0x66380003 */\n")
603         altnamelines.append("#define PR_DEFAULT_PROFILE                                                   0x00010102\n")
604         altnamelines.append("#define PR_PROFILE_HOME_SERVER_ADDRS                                         0x6613101e\n")
605         altnamelines.append("#define PR_FID                                                               PidTagFolderId\n")
606         altnamelines.append("#define PR_MID                                                               PidTagMid\n")
607         altnamelines.append("#define PR_INSTANCE_NUM                                                      PidTagInstanceNum\n")
608         altnamelines.append("#define PR_FOLDER_CHILD_COUNT                                                0x66380003\n")
609         altnamelines.append("#define PR_INST_ID                                                           0x674d0014\n")
610         altnamelines.append("#define PR_RULE_MSG_PROVIDER                                                 0x65eb001e\n")
611         altnamelines.append("#define PR_RULE_MSG_NAME                                                     0x65ec001e\n")
612         altnamelines.append("#define PR_TRANSMITTABLE_DISPLAY_NAME_UNICODE                                PidTagTransmittableDisplayName\n")
613         altnamelines.append("#define PR_TRANSMITTABLE_DISPLAY_NAME                                        0x3a20001e\n")
614         altnamelines.append("#define PR_ADDRBOOK_MID                                                      PidTagAddressBookMessageId\n")
615         altnamelines.append("#define PR_FREEBUSY_LAST_MODIFIED                                            PidTagFreeBusyRangeTimestamp\n")
616         altnamelines.append("#define PR_FREEBUSY_START_RANGE                                              PidTagFreeBusyPublishStart\n")
617         altnamelines.append("#define PR_FREEBUSY_END_RANGE                                                PidTagFreeBusyPublishEnd\n")
618         altnamelines.append("#define PR_FREEBUSY_ALL_MONTHS                                               PidTagScheduleInfoMonthsMerged\n")
619         altnamelines.append("#define PR_FREEBUSY_ALL_EVENTS                                               PidTagScheduleInfoFreeBusyMerged\n")
620         altnamelines.append("#define PR_FREEBUSY_TENTATIVE_MONTHS                                         PidTagScheduleInfoMonthsTentative\n")
621         altnamelines.append("#define PR_FREEBUSY_TENTATIVE_EVENTS                                         PidTagScheduleInfoFreeBusyTentative\n")
622         altnamelines.append("#define PR_FREEBUSY_BUSY_MONTHS                                              PidTagScheduleInfoMonthsBusy\n")
623         altnamelines.append("#define PR_FREEBUSY_BUSY_EVENTS                                              PidTagScheduleInfoFreeBusyBusy\n")
624         altnamelines.append("#define PR_FREEBUSY_OOF_MONTHS                                               PidTagScheduleInfoMonthsAway\n")
625         altnamelines.append("#define PR_FREEBUSY_OOF_EVENTS                                               PidTagScheduleInfoFreeBusyAway\n")
626         altnamelines.append("#define PR_REMINDERS_ONLINE_ENTRYID                                          0x36d50102\n")
627         altnamelines.append("#define PR_IPM_PUBLIC_FOLDERS_ENTRYID                                        PidTagIpmPublicFoldersEntryId\n")
628         altnamelines.append("#define PR_PARENT_FID                                                        PidTagParentFolderId\n")
629         altnamelines.append("#define PR_URL_COMP_NAME_SET                                                 PidTagUrlCompNameSet\n")
630         altnamelines.append("#define PR_ASSOC_CONTENT_COUNT                                               PidTagAssociatedContentCount\n")
631         altnamelines.append("#define PR_NTSD_MODIFICATION_TIME                                            0x3FD60040\n")
632         altnamelines.append("#define PR_CREATOR_SID                                                       0x0E580102\n")
633         altnamelines.append("#define PR_LAST_MODIFIER_SID                                                 0x0E590102\n")
634         altnamelines.append("#define PR_EXTENDED_ACL_DATA                                                 0x3FFE0102\n")
635         altnamelines.append("#define PR_FOLDER_XVIEWINFO_E                                                0x36E00102\n")
636         altnamelines.append("#define PR_FOLDER_VIEWLIST                                                   0x36EB0102\n")
637         altnamelines.append("#define PR_DELETED_COUNT_TOTAL                                               0x670B0003\n")
638         altnamelines.append("#define PR_EMS_AB_HOME_MTA                                                   0x8007001F\n")
639         altnamelines.append("#define PR_EMS_AB_ASSOC_NT_ACCOUNT                                           0x80270102\n")
640         altnamelines.append("#define PR_FX_DEL_PROP                                                       PidTagFXDelProp\n")
641         altnamelines.append("#define PR_START_RECIP                                                       PidTagStartRecip\n")
642         altnamelines.append("#define PR_END_RECIP                                                         PidTagEndToRecip\n")
643         altnamelines.append("#define PR_NEW_ATTACH                                                        PidTagNewAttach\n")
644         altnamelines.append("#define PR_END_ATTACH                                                        PidTagEndAttach\n")
645         altnamelines.append("#define PR_ASSOCIATED                                                        PidTagAssociated\n")
646         altnamelines.append("#define PR_INCR_SYNC_CHG                                                     PidTagIncrSyncChg\n")
647         altnamelines.append("#define PR_INCR_SYNC_MSG                                                     PidTagIncrSyncMessage\n")
648         altnamelines.append("#define PR_INCR_SYNC_DEL                                                     PidTagIncrSyncDel\n")
649         altnamelines.append("#define PR_INCR_SYNC_STATE_BEGIN                                             PidTagIncrSyncStateBegin\n")
650         altnamelines.append("#define PR_INCR_SYNC_STATE_END                                               PidTagIncrSyncStateEnd\n")
651         altnamelines.append("#define PR_INCR_SYNC_END                                                     PidTagIncrSyncEnd\n")
652         altnamelines.append("#define PR_DELETED_MSG_COUNT                                                 0x66400003\n")
653         altnamelines.append("#define PR_RECIPIENT_ON_NORMAL_MSG_COUNT                                     0x66af0003\n")
654         altnamelines.append("#define PR_CONVERSATION_KEY                                                  PidTagConversationKey\n")
655         # write properties out to a master header file
656         f = open('libmapi/property_tags.h', 'w')
657         f.write("/* Automatically generated by script/makepropslist.py. Do not edit */\n")
658         sortedproplines = sorted(proplines)
659         for propline in sortedproplines:
660                 f.write(propline)
661         f.close()
662         f = open('libmapi/property_altnames.h', 'w')
663         f.write("/* Automatically generated by script/makepropslist.py. Do not edit */\n")
664         sortedaltnamelines = sorted(altnamelines)
665         for propline in sortedaltnamelines:
666                 f.write(propline)
667         f.close()
668
669         # write canonical properties out for lookup 
670         proplines = []
671         f = open('libmapi/property_tags.c', 'w')
672         proplines = []
673         f.write("/* Automatically generated by script/makepropslist.py. Do not edit */\n")
674         f.write("#include \"libmapi/libmapi.h\"\n")
675         f.write("#include \"libmapi/libmapi_private.h\"\n")
676         f.write("#include \"gen_ndr/ndr_exchange.h\"\n")
677         f.write("#include \"libmapi/property_tags.h\"\n\n")
678         f.write("struct mapi_proptags\n")
679         f.write("{\n")
680         f.write("\tuint32_t     proptag;\n")
681         f.write("\tuint32_t     proptype;\n")
682         f.write("\tconst char   *propname;\n")
683         f.write("};\n")
684         f.write("\n")
685         for entry in properties:
686                 if (entry.has_key("CanonicalName") == False):
687                         print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
688                         continue
689                 if (entry.has_key("DataTypeName") == False):
690                         print "Section", entry["OXPROPS_Sect"], "has no data type entry"
691                         continue
692                 if entry.has_key("PropertyId"):
693                         propline = "\t{ "
694                         propline += string.ljust(entry["CanonicalName"] + ",", 68)
695                         propline += string.ljust(datatypemap[entry["DataTypeName"]] + ",", 14)
696                         propline += string.ljust("\"" + entry["CanonicalName"] + "\"" , 68) + "},\n"
697                         proplines.append(propline)
698                         propline = "\t{ "
699                         propline += string.ljust(entry["CanonicalName"] + "_Error,", 68)
700                         propline += string.ljust("PT_ERROR,", 14)
701                         propline += string.ljust("\"" + entry["CanonicalName"] + "_Error" + "\"" , 68) + "},\n"
702                         proplines.append(propline)
703         proplines.append(extra_private_tags_struct)
704         # this is just a temporary hack till we properly support named properties
705         proplines.append(temporary_private_tags_struct)
706         sortedproplines = sorted(proplines)
707         f.write("static struct mapi_proptags canonical_property_tags[] = {\n")
708         for propline in sortedproplines:
709                 f.write(propline)
710         f.write("\t{ 0,                                                                  0,            \"NULL\"                                                              }\n")
711         f.write("};\n")
712         f.write("""
713 _PUBLIC_ const char *get_proptag_name(uint32_t proptag)
714 {
715         uint32_t idx;
716
717         for (idx = 0; canonical_property_tags[idx].proptag; idx++) {
718                 if (canonical_property_tags[idx].proptag == proptag) { 
719                         return canonical_property_tags[idx].propname;
720                 }
721         }
722         if (((proptag & 0xFFFF) == PT_STRING8) ||
723             ((proptag & 0xFFFF) == PT_MV_STRING8)) {
724                 proptag += 1; /* try as _UNICODE variant */
725         }
726         for (idx = 0; canonical_property_tags[idx].proptag; idx++) {
727                 if (canonical_property_tags[idx].proptag == proptag) { 
728                         return canonical_property_tags[idx].propname;
729                 }
730         }
731         return NULL;
732 }
733
734 _PUBLIC_ uint32_t get_proptag_value(const char *propname)
735 {
736         uint32_t idx;
737
738         for (idx = 0; canonical_property_tags[idx].proptag; idx++) {
739                 if (!strcmp(canonical_property_tags[idx].propname, propname)) { 
740                         return canonical_property_tags[idx].proptag;
741                 }
742         }
743
744         return 0;
745 }
746
747 _PUBLIC_ uint16_t get_property_type(uint16_t untypedtag)
748 {
749         uint32_t        idx;
750         uint16_t        current_type;
751
752         for (idx = 0; canonical_property_tags[idx].proptag; idx++) {
753                 if ((canonical_property_tags[idx].proptag >> 16) == untypedtag) {
754                         current_type = canonical_property_tags[idx].proptype;
755                         if (current_type != PT_ERROR && current_type != PT_STRING8) {
756                                 return current_type;
757                         }
758                 }
759         }
760
761         DEBUG(5, ("%s: type for property '%x' could not be deduced\\n", __FUNCTION__, untypedtag));
762         return 0;
763 }
764
765
766 """)
767         f.close()
768
769         # write canonical properties out for IDL input
770         proplines = []
771         previous_idl_proptags = []
772         f = open('properties_enum.h', 'w')
773         f.write("/* Automatically generated by script/makepropslist.py. Do not edit */\n")
774         f.write("typedef [v1_enum, flag(NDR_PAHEX)] enum {\n")
775         for entry in properties:
776                 if (entry.has_key("CanonicalName") == False):
777                         print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
778                         continue
779                 if (entry.has_key("DataTypeName") == False):
780                         print "Section", entry["OXPROPS_Sect"], "has no data type entry"
781                         continue
782                 if entry.has_key("PropertyId"):
783                         if entry["PropertyId"] in previous_idl_proptags:
784                                 print "Skipping output of enum entry for", entry["CanonicalName"], "(duplicate)"
785                                 continue
786                         propline = "\t" + string.ljust(entry["CanonicalName"], 68)
787                         propline += " = 0x" + format(entry["PropertyId"], "04X") + knowndatatypes[entry["DataTypeName"]][2:]
788                         propline += ",\n"
789                         proplines.append(propline)
790                         if entry["DataTypeName"] == "PtypString":
791                                 propline = "\t" + string.ljust(entry["CanonicalName"] + "_string8", 68)
792                                 propline += " = 0x" + format(entry["PropertyId"], "04X") + "001E"
793                                 propline += ",\n"
794                                 proplines.append(propline)
795                         propline = "\t" + string.ljust(entry["CanonicalName"] + "_Error", 68)
796                         propline += " = 0x" + format(entry["PropertyId"], "04X") + "000A"
797                         propline += ",\n"
798                         proplines.append(propline)
799                         previous_idl_proptags.append(entry["PropertyId"])
800         sortedproplines = sorted(proplines)
801         for propline in sortedproplines:
802                 f.write(propline)
803
804         # Add additional properties, referenced on MSDN but not in MS-OXCPROPS
805         f.write("\t" + string.ljust("PidTagAssociatedContentCount", 68) + " = 0x36170003,\n")
806         f.write("\t" + string.ljust("PidTagFolderChildCount", 68) + " = 0x66380003,\n")
807         f.write("\t" + string.ljust("PidTagDeletedCountTotal", 68) + " = 0x670B0003,\n")
808         f.write("\t" + string.ljust("PidTagIpmPublicFoldersEntryId", 68) + " = 0x66310102,\n")
809         f.write("\t" + string.ljust("PidTagLocalCommitTimeMax", 68) + " = 0x670a0040,\n")
810         f.write("\t" + string.ljust("PidTagConversationKey", 68) + " = 0x000b0102,\n")
811
812         f.write("\tMAPI_PROP_RESERVED                                                   = 0xFFFFFFFF\n")
813         f.write("} MAPITAGS;\n")
814         f.close()
815         
816         # write canonical properties out for pyopenchange mapistore
817         proplines = []
818         previous_idl_proptags = []
819         f = open('pyopenchange/pymapi_properties.c', 'w')
820         f.write("""
821 /* Automatically generated by script/makepropslist.py. Do not edit */
822
823 #include <Python.h>
824 #include "pyopenchange/pymapi.h"
825
826 int pymapi_add_properties(PyObject *m)
827 {
828 """)
829         for entry in properties:
830                 if (entry.has_key("CanonicalName") == False):
831                         print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
832                         continue
833                 if (entry.has_key("DataTypeName") == False):
834                         print "Section", entry["OXPROPS_Sect"], "has no data type entry"
835                         continue
836                 if entry.has_key("PropertyId"):
837                         if entry["PropertyId"] in previous_idl_proptags:
838                                 print "Skipping output of Python bindings entry for", entry["CanonicalName"], "(duplicate)"
839                                 continue
840                         propline = "\tPyModule_AddObject(m, \"" + entry["CanonicalName"] + "\", "
841                         propline += "PyInt_FromLong(0x" +  format(entry["PropertyId"], "04X")
842                         propline += knowndatatypes[entry["DataTypeName"]][2:]
843                         propline +=  "));\n"
844                         proplines.append(propline)
845
846                         propline = "\tPyModule_AddObject(m, \"" + entry["CanonicalName"] + "_Error\", "
847                         propline += "PyInt_FromLong(0x" +  format(entry["PropertyId"], "04X") + "000A"
848                         propline += "));\n"
849                         proplines.append(propline)
850                         previous_idl_proptags.append(entry["PropertyId"])
851         sortedproplines = sorted(proplines)
852         for propline in sortedproplines:
853                 f.write(propline)       
854         f.write("""
855         return 0;
856 }
857 """)
858         f.close()
859
860         # write canonical properties out for openchangedb - probably remove this later
861         proplines = []
862         previous_idl_proptags = []
863         f = open('mapiproxy/libmapiproxy/openchangedb_property.c', 'w')
864         f.write("""
865 /* Automatically generated by script/makepropslist.py. Do not edit */
866 #include "mapiproxy/dcesrv_mapiproxy.h"
867 #include "libmapiproxy.h"
868 #include "libmapi/libmapi.h"
869 #include "libmapi/libmapi_private.h"
870
871 struct pidtags {
872         uint32_t        proptag;
873         const char      *pidtag;
874 };
875
876 static struct pidtags pidtags[] = {
877 """)
878         for entry in properties:
879                 if (entry.has_key("CanonicalName") == False):
880                         print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
881                         continue
882                 if (entry.has_key("DataTypeName") == False):
883                         print "Section", entry["OXPROPS_Sect"], "has no data type entry"
884                         continue
885                 if entry.has_key("PropertyId"):
886                         if entry["PropertyId"] in previous_idl_proptags:
887                                 print "Skipping output of pidtags entry for", entry["CanonicalName"], "(duplicate)"
888                                 continue
889                         propline = "\t{ " + string.ljust(entry["CanonicalName"] + ",", 68)
890                         propline += "\"" + entry["CanonicalName"] + "\" },\n"
891                         proplines.append(propline)
892                         previous_idl_proptags.append(entry["PropertyId"])
893         sortedproplines = sorted(proplines)
894         for propline in sortedproplines:
895                 f.write(propline)
896         f.write("""\t{ 0,                                                                   NULL         }
897 };
898
899 _PUBLIC_ const char *openchangedb_property_get_attribute(uint32_t proptag)
900 {
901         uint32_t i;
902         
903         for (i = 0; pidtags[i].pidtag; i++) {
904                 if (pidtags[i].proptag == proptag) {
905                         return pidtags[i].pidtag;
906                 }
907         }
908         DEBUG(0, ("[%s:%d]: Unsupported property tag '0x%.8x'\\n", __FUNCTION__, __LINE__, proptag));
909         
910         return NULL;
911 }
912 """)
913
914 previous_canonical_names = {}
915 def check_duplicate_canonical_names():
916         print "Checking canonical names:"
917         for entry in properties:
918                 canonicalname = entry["CanonicalName"]
919                 if previous_canonical_names.has_key(canonicalname):
920                         print "\tIn section", entry["OXPROPS_Sect"], ", canonical name:", entry["CanonicalName"], "duplicates name in section", previous_canonical_names[canonicalname]
921                 previous_canonical_names[canonicalname] = (entry["OXPROPS_Sect"])
922
923 def check_duplicate_alternative_names():
924         print "Checking alternative names:"
925         previous_alternative_names = {}
926         for entry in properties:
927                 if entry.has_key("AlternateNames"):
928                         for altname in entry["AlternateNames"].split(", "):
929                                 altname = altname.strip()
930                                 if altname.count(" ") > 0:
931                                         print "\tIn section", entry["OXPROPS_Sect"], ", alternative name:", altname, "contains space"
932                                 if previous_alternative_names.has_key(altname):
933                                         print "\tIn section", entry["OXPROPS_Sect"], ", alternative name:", altname, "duplicates name in section", previous_alternative_names[altname]
934                                 if previous_canonical_names.has_key(altname):
935                                         print "\tIn section", entry["OXPROPS_Sect"], ", alternative name:", altname, "duplicates canonical name in section", previous_alternative_names[altname]
936                                 previous_alternative_names[altname] = (entry["OXPROPS_Sect"])
937
938 def check_duplicate_propids():
939         print "Checking property IDs / LIDs:"
940         previous_propids = {}
941         previous_proplids = {}
942         for entry in properties:
943                 if entry.has_key("PropertyId"):
944                         propnum = entry["PropertyId"]
945                         if previous_propids.has_key(propnum) and propnum < 0x6800:
946                                 print "\tIn section", entry["OXPROPS_Sect"], "(" + entry["CanonicalName"] + ")"
947                                 print "\t\tProperty id 0x" + format(propnum, "04x"), "(" + entry["DataTypeName"] + ") duplicates property id in section", previous_propids[propnum][0], "(" + previous_propids[propnum][1] + ")"
948                         if (entry.has_key("DataTypeName")):
949                                 previous_propids[propnum] = (entry["OXPROPS_Sect"], entry["DataTypeName"])
950                         else:
951                                 previous_propids[propnum] = (entry["OXPROPS_Sect"], "[No DataType]")
952                 elif entry.has_key("PropertyLid"):
953                         propnum = entry["PropertyLid"]
954                         if previous_proplids.has_key(propnum):
955                                 print "\tIn section", entry["OXPROPS_Sect"], "(" + entry["CanonicalName"] + ")"
956                                 print "\t\tProperty LID 0x" + format(propnum, "08x"), "(" + entry["DataTypeName"] + ") duplicates property LID in section", previous_proplids[propnum][0], "(" + previous_proplids[propnum][1] + ")"
957                         if (entry.has_key("DataTypeName")):
958                                 previous_proplids[propnum] = (entry["OXPROPS_Sect"], entry["DataTypeName"])
959                         else:
960                                 previous_proplids[propnum] = (entry["OXPROPS_Sect"], "[No DataTypeName]")
961                 elif entry["CanonicalName"].startswith("PidLid"):
962                         print "Section", entry["OXPROPS_Sect"], "(" + entry["CanonicalName"] + ") has neither LID nor ID"
963                 elif entry["CanonicalName"].startswith("PidName"):
964                         pass
965                 else:
966                         print "Section", entry["OXPROPS_Sect"], "(" + entry["CanonicalName"] + ") is weird"
967
968                 if (entry["CanonicalName"].startswith("PidName") and (entry.has_key("PropertyId") or entry.has_key("PropertyLid"))):
969                         print "Section", entry["OXPROPS_Sect"], "(" + entry["CanonicalName"], "in", entry["PropertySet"] + ") has neither LID or ID"
970
971 def check_proptypes():
972         print "Checking that data types match:"
973         for entry in properties:
974                 datatypename = entry["DataTypeName"]
975                 datatypevalue = entry["DataTypeValue"]
976                 if (knowndatatypes.has_key(datatypename) == False):
977                         print "\tIn section %(section)s : unknown data type %(type)s" % { 'section': entry["OXPROPS_Sect"], 'type': datatypename }
978                 elif (knowndatatypes[datatypename] != datatypevalue):
979                         print "\tIn section %(section)s : got value %(value)i for type %(type)i (expected %(expected)i)" % { 'section': entry["OXPROPS_Sect"], 'value': datatypeval, 'type': datatypename, 'expected': knowndatatype[datatypename] }
980
981 def check_propsets():
982         print "Checking that property sets match:"
983         for entry in properties:
984                 if entry.has_key("PropertySet"):
985                         propsetname = entry["PropertySet"]
986                         propsetvalue = entry["PropertySetValue"]
987                         if (knownpropsets.has_key(propsetname) == False):
988                                 print "\tIn section %(section)s : unknown property set %(propset)s" % { 'section': entry["OXPROPS_Sect"], 'propset': propsetname }
989                         elif (knownpropsets[propsetname] != propsetvalue):
990                                 print "\tIn section %(section)s : got value %(value)s for type %(type)s (expected %(expected)s)" % { 'section': entry["OXPROPS_Sect"], 'value': propsetvalue, 'type': propsetname, 'expected': knownpropsets[propsetname] }
991
992 def check_descriptions():
993         print "Checking for descriptions:"
994         for entry in properties:
995                 if entry.has_key("Description") == False:
996                         print "\tIn section %(section)s : there is no description" % { 'section': entry["OXPROPS_Sect"] }
997
998 def check_areas():
999         print "Checking for areas:"
1000         for entry in properties:
1001                 if entry.has_key("Area") == False:
1002                         print "\tIn section %(section)s : there is no area" % { 'section': entry["OXPROPS_Sect"] }
1003
1004 def check_reference_line(entry, line, isdefining):
1005         if line.endswith(","):
1006                 print "\tIn section %(section)s : trailing comma in (defining?) references" % { 'section': entry["OXPROPS_Sect"] }
1007                 line = line.rstrip(",")
1008         for docentry in line.split(","):
1009                 docentry = docentry.strip()
1010                 if docentry == "":
1011                         print "\tIn section %(section)s : empty (defining) reference section" % { 'section': entry["OXPROPS_Sect"] }
1012                 elif knownrefs.count(docentry) != 1:
1013                         if len(docentry.split(" ")) > 1:
1014                                 if docentry.split(" ")[1].strip().startswith("section"):
1015                                         # thats ok
1016                                         pass
1017                                 else:
1018                                         print "\tIn section %(section)s : missing comma in (defining?) references: %(docentry)s" % { 'section': entry["OXPROPS_Sect"], 'docentry': docentry }
1019                         else:
1020                                 print "\tIn section %(section)s : unknown document: %(docname)s" % { 'section': entry["OXPROPS_Sect"], 'docname': docentry }
1021                 else:
1022                         try:
1023                                 reffile = file("docs/" + docentry + ".txt")
1024                                 reftext = reffile.read().replace(" ", "")
1025                                 if docentry == "[MS-OXCFXICS]":
1026                                         if (reftext.count((entry["CanonicalName"][6:])) < 1):
1027                                                 print "\tIn section %(section)s : (defining) references contains %(docname)s, but %(prop)s wasn't found in that document" % { 'section': entry["OXPROPS_Sect"], 'docname': docentry, 'prop': entry['CanonicalName'] }
1028                                 elif reftext.count(entry["CanonicalName"]) < 1:
1029                                         print "\tIn section %(section)s : (defining) references contains %(docname)s, but %(prop)s wasn't found in that document" % { 'section': entry["OXPROPS_Sect"], 'docname': docentry, 'prop': entry['CanonicalName'] }
1030                         except IOError:
1031                                 pass
1032
1033 def check_references():
1034         print "Checking for references:"
1035         for entry in properties:
1036                 if entry.has_key("References"):
1037                         check_reference_line(entry, entry["References"], False)
1038                 elif entry.has_key("DefiningReference"):
1039                         check_reference_line(entry, entry["DefiningReference"], True)
1040                 else:
1041                         print "\tIn section %(section)s : there is no (defining) reference entry" % { 'section': entry["OXPROPS_Sect"] }
1042
1043 def check_properties_list():
1044         check_proptypes()
1045         check_propsets()
1046         check_duplicate_canonical_names()
1047         check_duplicate_alternative_names()
1048         check_duplicate_propids()
1049         # check_descriptions()
1050         check_areas()
1051         check_references()
1052
1053 def next_available_id(knownprops, increment):
1054         try:
1055                 knownprops.index(increment)
1056                 knownprops.remove(increment)
1057                 increment += 1
1058                 return next_available_id(knownprops, increment)
1059         except ValueError:
1060                 return increment
1061
1062
1063 def find_key(dic, val):
1064         """return the key of dictionary dic given the value"""
1065         try:
1066                 for k,v in dic.iteritems():
1067                         if v == val:
1068                                 return k
1069         except ValueError:
1070                 print "Value %s not found" % val
1071
1072 def make_mapi_named_properties_file():
1073         content = ""
1074         attributes = ""
1075         start_content = ""
1076         namedprops = []
1077         knownprops = []
1078         previous_ldif_lid = []
1079         previous_ldif_name = []
1080         for entry in properties:
1081                 if (entry.has_key("CanonicalName") == False):
1082                         print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
1083                         continue
1084                 if (entry.has_key("DataTypeName") == False):
1085                         print "Section", entry["OXPROPS_Sect"], "has no data type entry"
1086                         continue
1087                 if (entry.has_key("PropertyId") == False):
1088                         if entry.has_key("PropertySet"):
1089                                 guid = entry["PropertySet"]
1090                         else:
1091                                 guid = "[No PropSet]"
1092                         # Its a named property
1093                         name = entry["CanonicalName"]
1094                         proptype = entry["DataTypeName"]
1095                         if entry.has_key("PropertyLid"):
1096                                 proplid = "0x" + format(entry["PropertyLid"], "04x")
1097                                 if proplid in previous_ldif_lid:
1098                                         print "Skipping output for named properties MNID_ID", name, "(duplicate)"
1099                                         continue;
1100                                 kind = "MNID_ID"
1101                                 OOM = "NULL" # use as default
1102                                 propname = "NULL"
1103                                 if entry.has_key("PropertyName"):
1104                                         OOM = entry["PropertyName"].strip()
1105                                 elif entry.has_key("AlternateNames"):
1106                                         altname = entry["AlternateNames"].strip()
1107                                         if altname.startswith("dispid"):
1108                                                 OOM = altname[6:]
1109                                         else:
1110                                                 OOM = altname
1111                                 else:
1112                                         pass
1113                                 previous_ldif_lid.append(proplid)
1114
1115                         else:
1116                                 proplid = "0x0000"
1117                                 kind = "MNID_STRING"
1118                                 OOM = "NULL"
1119                                 propname = "NULL" # use as default
1120                                 if entry.has_key("PropertyName"):
1121                                         propname = entry["PropertyName"].strip()
1122                                 elif entry.has_key("AlternateNames"):
1123                                         for altname in entry["AlternateNames"]:
1124                                                 altname = altname.strip()
1125                                                 if altname.startswith("dispid"):
1126                                                         propname = altname[6:]
1127                                 search_dup = "%s/%s" % (propname, guid)
1128                                 if search_dup in previous_ldif_name:
1129                                         print "Skipping output for named properties MNID_STRING", name, "(duplicate)"
1130                                         continue;
1131                                 previous_ldif_name.append(search_dup)
1132
1133                         namedprop = (name, OOM, proplid, propname, knowndatatypes[proptype], kind, guid)
1134                         namedprops.append(namedprop)
1135                 else:
1136                         # It's not a named property
1137                         # Store conflicting properties with propid > 0x8000
1138                         propid = entry["PropertyId"]
1139                         if propid >= 0x8000:
1140                                 try:
1141                                         knownprops.index(propid)
1142                                 except ValueError:
1143                                         knownprops.append(propid)
1144
1145         # Create the default GUID containers
1146         for key in sorted(knownpropsets):
1147                 cn = knownpropsets[key].strip('{}').lower()
1148                 oleguid_ldif = "dn: CN=%s,CN=External,CN=Server\n"      \
1149                                "objectClass: External\n"                \
1150                                "cn: %s\n"                               \
1151                                "name: %s\n"                             \
1152                                "oleguid: %s\n\n" % (cn, cn, str(key), cn)
1153                 content += oleguid_ldif
1154
1155         # Write named properties
1156         sortednamedprops = sorted(namedprops, key=lambda namedprops: namedprops[6]) # sort by guid
1157         increment = next_available_id(knownprops, 0x8000)
1158
1159         for line in sortednamedprops:
1160                 oleguid = knownpropsets[line[6]].strip('{}').lower()
1161                 if line[5] == "MNID_STRING":
1162                         named_props_ldif = "dn: CN=%s,CN=MNID_STRING,CN=%s,CN=External,CN=Server\n"     \
1163                                            "objectClass: External\n"                                    \
1164                                            "objectClass: MNID_STRING\n"                                 \
1165                                            "cn: %s\n"                                                   \
1166                                            "canonical: %s\n"                                            \
1167                                            "oleguid: %s\n"                                              \
1168                                            "mapped_id: 0x%.4x\n"                                        \
1169                                            "prop_id: %s\n"                                              \
1170                                            "prop_type: %s\n"                                            \
1171                                            "prop_name: %s\n\n" % (
1172                                 line[3], oleguid, line[3], line[0], oleguid, increment,
1173                                 line[2], line[4], line[3])
1174                 else:
1175                         named_props_ldif = "dn: CN=%s,CN=MNID_ID,CN=%s,CN=External,CN=Server\n"         \
1176                                            "objectClass: External\n"                                    \
1177                                            "objectClass: MNID_ID\n"                                     \
1178                                            "cn: %s\n"                                                   \
1179                                            "canonical: %s\n"                                            \
1180                                            "oleguid: %s\n"                                              \
1181                                            "mapped_id: 0x%.4x\n"                                        \
1182                                            "prop_id: %s\n"                                              \
1183                                            "prop_type: %s\n"                                            \
1184                                            "oom: %s\n\n" % (
1185                                 line[2], oleguid, line[2], line[0], oleguid, increment,
1186                                 line[2], line[4], line[1])
1187                 
1188                 content += named_props_ldif
1189
1190                 increment += 1
1191                 increment = next_available_id(knownprops, increment)
1192
1193         # Store remaining reserved named properties IDs in attributes
1194         for ids in sorted(knownprops):
1195                 attributes += "reserved_tags: 0x%.4x\n" % ids
1196
1197         start_content =  "# LDIF file automatically auto-generated by script/makepropslist.py. Do not edit\n\n"
1198         start_content += "dn: CN=Server\n"              \
1199                          "objectClass: top\n"           \
1200                          "cn: Server\n\n"               \
1201                                                         \
1202                          "dn: CN=Internal,CN=Server\n"  \
1203                          "objectClass: Internal\n"      \
1204                          "objectClass: container\n"     \
1205                          "objectClass: top\n"           \
1206                          "cn: Internal\n"               \
1207                          "mapping_index: 0x0001\n\n"    \
1208                                                         \
1209                          "dn: CN=External,CN=Server\n"  \
1210                          "objectClass: External\n"      \
1211                          "objectClass: container\n"     \
1212                          "objectClass: top\n"           \
1213                          "cn: External\n"               \
1214                          "mapping_index: 0x%.4x\n" % increment
1215         start_content += attributes + "\n"
1216         start_content += "dn: CN=Users,CN=Server\n"     \
1217                          "objectClass: container\n"     \
1218                          "objectClass: top\n"           \
1219                          "cn: Users\n\n"
1220
1221         content = start_content + content
1222
1223         # wite named properties buffered file out to LDIF file
1224         f = open('setup/mapistore/mapistore_namedprops_v2.ldif', 'w')
1225         f.write(content)
1226         f.close()
1227
1228         # write named properties defines and structure
1229         f = open('libmapi/mapi_nameid.h', 'w')
1230         f.write("""
1231 /* Automatically generated by script/makepropslist.py. Do not edit */
1232 #ifndef __MAPI_NAMEID_H__
1233 #define __MAPI_NAMEID_H__
1234
1235 /* NOTE TO DEVELOPERS: If this is a MNID_STRING named property, then
1236  * we use the arbitrary 0xa000-0xafff property ID range for internal
1237  * mapping purpose only.
1238  */
1239
1240 struct mapi_nameid_tags {
1241         uint32_t                proptag;
1242         const char              *OOM;
1243         uint16_t                lid;
1244         const char              *Name;
1245         uint32_t                propType;
1246         uint8_t                 ulKind;
1247         const char              *OLEGUID;
1248         uint32_t                position;
1249 };
1250
1251 struct mapi_nameid_names {
1252         uint32_t                proptag;
1253         const char              *propname;
1254 };
1255
1256 struct mapi_nameid {
1257         struct MAPINAMEID       *nameid;
1258         uint16_t                count;
1259         struct mapi_nameid_tags *entries;
1260 };
1261
1262 /* MNID_ID named properties */
1263 """)
1264
1265         for line in sortednamedprops:
1266                 if line[5] == "MNID_ID":
1267                         proptag = "0x%.8x" % (int(line[2], 16) << 16 | int(line[4], 16))
1268                         propline = "#define %s %s\n" % (string.ljust(line[0], 60), string.ljust(proptag, 20))
1269                         f.write(propline)
1270
1271         f.write("\n/* MNID_STRING named properties (internal mapping) */\n")
1272         mnstring_id = 0xa000
1273         for line in sortednamedprops:
1274                 if line[5] == "MNID_STRING":
1275                         proptag = "0x%.8x" % ((mnstring_id << 16) | int(line[4], 16))
1276                         propline = "#define %s %s\n" % (string.ljust(line[0], 60), string.ljust(proptag, 20))
1277                         mnstring_id += 1
1278                         f.write(propline)
1279
1280         # Additional properties
1281         propline = "#define %s %s\n" % (string.ljust("PidLidRemoteTransferSize", 60), string.ljust("0x8f050003", 20))
1282         f.write(propline)
1283
1284         f.write("#endif /* ! MAPI_NAMEID_H__ */")
1285         f.close()
1286
1287         # write named properties internal mapping
1288         f = open('libmapi/mapi_nameid_private.h', 'w')
1289         f.write("""
1290 /* Automatically generated by script/makepropslist.py. Do not edit */
1291 #ifndef __MAPI_NAMEID_PRIVATE_H__
1292 #define __MAPI_NAMEID_PRIVATE_H__
1293
1294 static struct mapi_nameid_tags mapi_nameid_tags[] = {
1295 """)
1296
1297         for line in sortednamedprops:
1298                 if line[5] == "MNID_ID":
1299                         OOM = "\"%s\"" % line[1]
1300                         key = find_key(knowndatatypes, line[4])
1301                         datatype = datatypemap[key]
1302                         propline = "{ %s, %s, %s, %s, %s, %s, %s, %s },\n" % (
1303                                 string.ljust(line[0], 60), string.ljust(OOM, 65), line[2], line[3], 
1304                                 string.ljust(datatype, 15), "MNID_ID", line[6], "0x0")
1305                         f.write(propline)
1306
1307         for line in sortednamedprops:
1308                 if line[5] == "MNID_STRING":
1309                         OOM = "%s" % line[1]
1310                         key = find_key(knowndatatypes, line[4])
1311                         datatype = datatypemap[key]
1312                         propline = "{ %s, %s, %s, \"%s\", %s, %s, %s, %s },\n" % (
1313                                 string.ljust(line[0], 60), string.ljust(OOM, 65), line[2], line[3], 
1314                                 string.ljust(datatype, 15), "MNID_STRING", line[6], "0x0")
1315                         f.write(propline)
1316
1317         # Addtional named properties
1318         propline = "{ %s, %s, %s, %s, %s, %s, %s, %s },\n" % (
1319                 string.ljust("PidLidRemoteTransferSize", 60), string.ljust("\"RemoteTransferSize\"", 65), "0x8f05",
1320                 "NULL", string.ljust("PT_LONG", 15), "MNID_ID", "PSETID_Remote", "0x0")
1321         f.write(propline)
1322
1323         propline = "{ %s, %s, %s, %s, %s, %s, %s, %s }\n" % (
1324                 string.ljust("0x00000000", 60), string.ljust("NULL", 65), "0x0000", "NULL",
1325                 string.ljust("PT_UNSPECIFIED", 15), "0x0", "NULL", "0x0")
1326         f.write(propline)
1327         f.write("""
1328 };
1329 """)
1330
1331         f.write("""
1332 static struct mapi_nameid_names mapi_nameid_names[] = {
1333 """)
1334         for line in sortednamedprops:
1335                 propline = "{ %s, \"%s\" },\n" % (string.ljust(line[0], 60), line[0])
1336                 f.write(propline)
1337
1338         # Additional named properties
1339         propline = "{ %s, \"%s\" }\n" % (string.ljust("PidLidRemoteTransferSize", 60), "PidLidRemoteTransferSize")      
1340
1341         propline = "{ %s, \"%s\" }\n" % (string.ljust("0x00000000", 60), "NULL")
1342         f.write(propline)
1343         f.write("""
1344 };
1345
1346 #endif /* !MAPI_NAMEID_PRIVATE_H__ */
1347 """)
1348         f.close()
1349
1350 def dump_areas_count():
1351         areas = {}
1352         for area in knownareas:
1353                 areas[area] = 0
1354
1355         for entry in properties:
1356                 if (entry.has_key("Area") == False):
1357                       print "Section", entry["OXPROPS_Sect"], "has no area entry"
1358                 else:
1359                       areas[entry["Area"]] += 1
1360
1361         for area in knownareas:
1362                 print area, ":", areas[area]
1363
1364 def fix_problems(propsfilename):
1365         retcode = subprocess.call(["sed", "-i",
1366                                    "-e", "s/.Dta type: PtypBoolean, 0x000B/Data type: PtypBoolean, 0x000B/",
1367                                    "-e", "s/.Data Type: PtypString, 0x001F/Data type: PtypString, 0x001F/",
1368                                    "-e", "s/.Data type: PtyString, 0x001F/Data type: PtypString, 0x001F/",
1369                                    "-e", "s/.Area: MAPI Display Tables\[MS-OXOABK\] section 2.2.3.33/Area: MAPI Display Tables\\nDefining Reference: \[MS-OXOABK\] section 2.2.3.33/",
1370                                    "-e", "s/.Area: ProviderDefinedNonTransmittable\[MS-OXCTABL\] section 2.2.1.2/Area: ProviderDefinedNonTransmittable\\nDefining Reference: \[MS-OXCTABL\] section 2.2.1.2/",
1371                                    "-e", "s/.Area: Server-Side Rules Properties\[MS-OXORULE\] section 2.2.1.3.2.2/Area: Server-Side Rules Properties\\nDefining Reference: \[MS-OXORULE\] section 2.2.1.3.2.2/",
1372                                    "-e", "s/.Area: MapiMailUser\[MS-OXOABK\] section 2.2.4.66/Area: MapiMailUser\\nDefining Reference: \[MS-OXOABK\] section 2.2.4.66/",
1373                                    "-e", "s/.Description: \[MS-OXORULE\] section 2.2.7.3/Defining Reference: \[MS-OXORULE\] section 2.2.7.3/",
1374                                    "-e", "s/.Property set: PSTID_Sharing {00062040-0000-0000-C000-000000000046}/Property set: PSETID_Sharing {00062040-0000-0000-C000-000000000046}/",
1375                                    "-e", "s/.Property set: PSETID_Address {00062004-0000-0000-C000-00000000046}/Property set: PSETID_Address {00062004-0000-0000-C000-000000000046}/",
1376                                    "-e", "s/.Property set: PSETID_Address{00062004-0000-0000-C000-000000000046}/Property set: PSETID_Address {00062004-0000-0000-C000-000000000046}/",
1377                                    "-e", "s/.Property set: PSETID_Appointment {00062002-0000-0000-C000-0000000000046}/Property set: PSETID_Appointment {00062002-0000-0000-C000-000000000046}/",
1378                                    "-e", "s/.Property set: PSETID_Address {00062004-0000-0000-C00-0000000000046}/Property set: PSETID_Address {00062004-0000-0000-C000-000000000046}/",
1379                                    "-e", "s/.Consuming Reference: \[MS-OXCICAL\] Alternate names: PR_NEXT_SEND_ACCT/Consuming Reference: \[MS-OXCICAL\]\\nAlternate names: PR_NEXT_SEND_ACCT/",
1380                                    "-e", "s/.Alternate names: PR_WB_SF_ID//",
1381                                    "-e", "s/.Alternate names: PR_WB_SF_TAG//",
1382                                    "-e", "s/.Alternate names: PR_EMS_AB_DL_MEM_REJECT_PERMS//",
1383                                    "-e", "s/.Alternate names: PR_EMS_AB_DL_MEM_SUBMIT_PERMS//",
1384                                    propsfilename])
1385         if retcode != 0:
1386                 print "Could not fix problem:", retcode
1387                 sys.exit(retcode)
1388
1389 def main():
1390         oxpropsparser = argparse.ArgumentParser(description='Convert MS-OXPROPS to other formats')
1391         oxpropsparser.add_argument('--pdffile', required=True)
1392         oxpropsparser.add_argument('--sanitycheck', action='store_true')
1393         oxpropsparser.add_argument('--sanitycheckonly', action='store_true')
1394
1395         args = oxpropsparser.parse_args()
1396         propsfile = tempfile.mkstemp(suffix='txt')
1397         propsfilename = propsfile[1]
1398         retcode = subprocess.call(["pdftotext", "-nopgbrk", "-layout", args.pdffile, propsfilename])
1399         if retcode != 0:
1400                 print "Could not convert file to text:", retcode
1401                 sys.exit(retcode)
1402
1403         fix_problems(propsfilename)
1404
1405         make_properties_list(propsfilename)
1406         if args.sanitycheck or args.sanitycheckonly:
1407                 check_properties_list() # uses global variable
1408                 # dump_areas_count()
1409         if args.sanitycheckonly == False:
1410                 make_mapi_properties_file()
1411                 make_mapi_named_properties_file()
1412         
1413 if __name__ == "__main__":
1414     main()