2 # -*- coding: utf-8 -*-
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}"
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",
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"
209 "Access Control Properties",
210 "Access Control Properties Property set",
213 "Address Properties",
214 "Address Properties Property set",
215 "Appointment Property set",
219 "Calendar Document Property set",
220 "Calendar Property set",
222 "Common Property set",
226 "Contact Properties",
227 "Container Properties",
228 "Container Properties Property set",
229 "Conversation Actions",
232 "Email Property set",
234 "Exchange Administrative",
235 "ExchangeAdministrative",
236 "ExchangeAdministrative Property set",
238 "ExchangeFolder Property set",
239 "ExchangeMessageReadOnly",
240 "ExchangeMessageStore",
241 "ExchangeNonTransmittableReserved",
242 "Exchange Profile Configuration",
243 "Exchange Property set",
246 "Free/Busy Properties",
247 "General Message Properties",
248 "General Message Properties Property set",
249 "General Report Properties",
250 "History Properties",
254 "ID Properties Property set",
261 "MAPI Display Tables",
263 "MapiEnvelope Property set",
267 "MapiNonTransmittable",
268 "MapiNonTransmittable Property set",
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",
285 "MIME Properties Property set",
286 "Miscellaneous Properties",
287 "Miscellaneous Properties Property set",
288 "Offline Address Book Properties",
289 "Outlook Application",
290 "ProviderDefinedNonTransmittable",
296 "Run-time configuration",
299 "Secure Messaging Properties",
301 "Server-side Rules Properties",
302 "Server-Side Rules Properties",
307 "Structured Documents Property set",
311 "Transport Envelope",
313 "TransportRecipient",
320 def make_properties_list(propsfilename):
324 propsfile = file(propsfilename)
326 for line in propsfile:
327 if line.startswith("2 Structures"):
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
337 propname = line.split()[1]
338 if propertyinfo.has_key("CanonicalName"):
339 properties.append(propertyinfo.copy())
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
348 if line.strip().startswith("Property name:"):
349 propertyname = line.split(":", 1)
350 propertyinfo["PropertyName"] = propertyname[1].strip()
352 if line.strip().startswith("Description:"):
353 description = line.strip().split(":")[1].strip()
355 nextline = propsfile.next().strip()
356 if (nextline.isspace() or (len(nextline) == 0)):
358 description += (" " + nextline)
359 propertyinfo["Description"] = description
361 if line.strip().startswith("Alternate names:"):
362 altname = line.strip().partition(":")[2]
364 nextline = propsfile.next().strip()
365 if (nextline.isspace() or (len(nextline) == 0)):
367 altname += (", " + nextline)
368 propertyinfo["AlternateNames"] = altname
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()
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()
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)
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"
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)
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"
399 if line.strip().startswith("Area:"):
400 areaname = line.strip().split(":")[1].strip()
401 if (knownareas.count(areaname) == 1):
402 propertyinfo["Area"] = areaname
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?)"
407 if line.strip().startswith("References:") or line.strip().startswith("Reference:"):
408 references = line.strip().split(":")[1].strip()
410 nextline = propsfile.next().strip()
411 if (nextline.isspace() or (len(nextline) == 0)):
413 references += (nextline)
414 propertyinfo["References"] = references
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
420 propertyinfo["OXPROPS_Sect"] = "2.%i" % (next_num -1)
422 #The whole file should now be parsed
423 properties.append(propertyinfo)
425 print "Last section parsed was section 2.%(section)i" % { 'section': (next_num-1) }
427 # Debugging dump of everything
429 for entry in properties:
432 extra_private_tags_struct = """\t{ PidTagFolderChildCount, PT_LONG, \"PidTagFolderChildCount\" },
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 */
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" },
533 def make_mapi_properties_file():
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"
541 if (entry.has_key("DataTypeName") == False):
542 print "Section", entry["OXPROPS_Sect"], "has no data type entry"
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")
551 propline += "/* 0x" + format(entry["PropertyId"], "04X") + knowndatatypes[entry["DataTypeName"]][2:] + " */"
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")
560 propline += "/* 0x" + format(entry["PropertyId"], "04X") + "000A" + " */"
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"):
571 if altname.endswith("_W"):
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)
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)
598 # hack until we properly handle named properties
599 proplines.append(temporary_private_tags)
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:
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:
669 # write canonical properties out for lookup
671 f = open('libmapi/property_tags.c', 'w')
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")
680 f.write("\tuint32_t proptag;\n")
681 f.write("\tuint32_t proptype;\n")
682 f.write("\tconst char *propname;\n")
685 for entry in properties:
686 if (entry.has_key("CanonicalName") == False):
687 print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
689 if (entry.has_key("DataTypeName") == False):
690 print "Section", entry["OXPROPS_Sect"], "has no data type entry"
692 if entry.has_key("PropertyId"):
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)
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:
710 f.write("\t{ 0, 0, \"NULL\" }\n")
713 _PUBLIC_ const char *get_proptag_name(uint32_t proptag)
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;
722 if (((proptag & 0xFFFF) == PT_STRING8) ||
723 ((proptag & 0xFFFF) == PT_MV_STRING8)) {
724 proptag += 1; /* try as _UNICODE variant */
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;
734 _PUBLIC_ uint32_t get_proptag_value(const char *propname)
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;
747 _PUBLIC_ uint16_t get_property_type(uint16_t untypedtag)
750 uint16_t current_type;
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) {
761 DEBUG(5, ("%s: type for property '%x' could not be deduced\\n", __FUNCTION__, untypedtag));
769 # write canonical properties out for IDL input
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"
779 if (entry.has_key("DataTypeName") == False):
780 print "Section", entry["OXPROPS_Sect"], "has no data type entry"
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)"
786 propline = "\t" + string.ljust(entry["CanonicalName"], 68)
787 propline += " = 0x" + format(entry["PropertyId"], "04X") + knowndatatypes[entry["DataTypeName"]][2:]
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"
794 proplines.append(propline)
795 propline = "\t" + string.ljust(entry["CanonicalName"] + "_Error", 68)
796 propline += " = 0x" + format(entry["PropertyId"], "04X") + "000A"
798 proplines.append(propline)
799 previous_idl_proptags.append(entry["PropertyId"])
800 sortedproplines = sorted(proplines)
801 for propline in sortedproplines:
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")
812 f.write("\tMAPI_PROP_RESERVED = 0xFFFFFFFF\n")
813 f.write("} MAPITAGS;\n")
816 # write canonical properties out for pyopenchange mapistore
818 previous_idl_proptags = []
819 f = open('pyopenchange/pymapi_properties.c', 'w')
821 /* Automatically generated by script/makepropslist.py. Do not edit */
824 #include "pyopenchange/pymapi.h"
826 int pymapi_add_properties(PyObject *m)
829 for entry in properties:
830 if (entry.has_key("CanonicalName") == False):
831 print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
833 if (entry.has_key("DataTypeName") == False):
834 print "Section", entry["OXPROPS_Sect"], "has no data type entry"
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)"
840 propline = "\tPyModule_AddObject(m, \"" + entry["CanonicalName"] + "\", "
841 propline += "PyInt_FromLong(0x" + format(entry["PropertyId"], "04X")
842 propline += knowndatatypes[entry["DataTypeName"]][2:]
844 proplines.append(propline)
846 propline = "\tPyModule_AddObject(m, \"" + entry["CanonicalName"] + "_Error\", "
847 propline += "PyInt_FromLong(0x" + format(entry["PropertyId"], "04X") + "000A"
849 proplines.append(propline)
850 previous_idl_proptags.append(entry["PropertyId"])
851 sortedproplines = sorted(proplines)
852 for propline in sortedproplines:
860 # write canonical properties out for openchangedb - probably remove this later
862 previous_idl_proptags = []
863 f = open('mapiproxy/libmapiproxy/openchangedb_property.c', 'w')
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"
876 static struct pidtags pidtags[] = {
878 for entry in properties:
879 if (entry.has_key("CanonicalName") == False):
880 print "Section", entry["OXPROPS_Sect"], "has no canonical name entry"
882 if (entry.has_key("DataTypeName") == False):
883 print "Section", entry["OXPROPS_Sect"], "has no data type entry"
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)"
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:
896 f.write("""\t{ 0, NULL }
899 _PUBLIC_ const char *openchangedb_property_get_attribute(uint32_t proptag)
903 for (i = 0; pidtags[i].pidtag; i++) {
904 if (pidtags[i].proptag == proptag) {
905 return pidtags[i].pidtag;
908 DEBUG(0, ("[%s:%d]: Unsupported property tag '0x%.8x'\\n", __FUNCTION__, __LINE__, proptag));
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"])
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"])
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"])
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"])
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"):
966 print "Section", entry["OXPROPS_Sect"], "(" + entry["CanonicalName"] + ") is weird"
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"
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] }
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] }
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"] }
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"] }
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()
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"):
1018 print "\tIn section %(section)s : missing comma in (defining?) references: %(docentry)s" % { 'section': entry["OXPROPS_Sect"], 'docentry': docentry }
1020 print "\tIn section %(section)s : unknown document: %(docname)s" % { 'section': entry["OXPROPS_Sect"], 'docname': docentry }
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'] }
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)
1041 print "\tIn section %(section)s : there is no (defining) reference entry" % { 'section': entry["OXPROPS_Sect"] }
1043 def check_properties_list():
1046 check_duplicate_canonical_names()
1047 check_duplicate_alternative_names()
1048 check_duplicate_propids()
1049 # check_descriptions()
1053 def next_available_id(knownprops, increment):
1055 knownprops.index(increment)
1056 knownprops.remove(increment)
1058 return next_available_id(knownprops, increment)
1063 def find_key(dic, val):
1064 """return the key of dictionary dic given the value"""
1066 for k,v in dic.iteritems():
1070 print "Value %s not found" % val
1072 def make_mapi_named_properties_file():
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"
1084 if (entry.has_key("DataTypeName") == False):
1085 print "Section", entry["OXPROPS_Sect"], "has no data type entry"
1087 if (entry.has_key("PropertyId") == False):
1088 if entry.has_key("PropertySet"):
1089 guid = entry["PropertySet"]
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)"
1101 OOM = "NULL" # use as default
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"):
1113 previous_ldif_lid.append(proplid)
1117 kind = "MNID_STRING"
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)"
1131 previous_ldif_name.append(search_dup)
1133 namedprop = (name, OOM, proplid, propname, knowndatatypes[proptype], kind, guid)
1134 namedprops.append(namedprop)
1136 # It's not a named property
1137 # Store conflicting properties with propid > 0x8000
1138 propid = entry["PropertyId"]
1139 if propid >= 0x8000:
1141 knownprops.index(propid)
1143 knownprops.append(propid)
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" \
1152 "oleguid: %s\n\n" % (cn, cn, str(key), cn)
1153 content += oleguid_ldif
1155 # Write named properties
1156 sortednamedprops = sorted(namedprops, key=lambda namedprops: namedprops[6]) # sort by guid
1157 increment = next_available_id(knownprops, 0x8000)
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" \
1168 "mapped_id: 0x%.4x\n" \
1171 "prop_name: %s\n\n" % (
1172 line[3], oleguid, line[3], line[0], oleguid, increment,
1173 line[2], line[4], line[3])
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" \
1181 "mapped_id: 0x%.4x\n" \
1185 line[2], oleguid, line[2], line[0], oleguid, increment,
1186 line[2], line[4], line[1])
1188 content += named_props_ldif
1191 increment = next_available_id(knownprops, increment)
1193 # Store remaining reserved named properties IDs in attributes
1194 for ids in sorted(knownprops):
1195 attributes += "reserved_tags: 0x%.4x\n" % ids
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" \
1202 "dn: CN=Internal,CN=Server\n" \
1203 "objectClass: Internal\n" \
1204 "objectClass: container\n" \
1205 "objectClass: top\n" \
1207 "mapping_index: 0x0001\n\n" \
1209 "dn: CN=External,CN=Server\n" \
1210 "objectClass: External\n" \
1211 "objectClass: container\n" \
1212 "objectClass: top\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" \
1221 content = start_content + content
1223 # wite named properties buffered file out to LDIF file
1224 f = open('setup/mapistore/mapistore_namedprops_v2.ldif', 'w')
1228 # write named properties defines and structure
1229 f = open('libmapi/mapi_nameid.h', 'w')
1231 /* Automatically generated by script/makepropslist.py. Do not edit */
1232 #ifndef __MAPI_NAMEID_H__
1233 #define __MAPI_NAMEID_H__
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.
1240 struct mapi_nameid_tags {
1247 const char *OLEGUID;
1251 struct mapi_nameid_names {
1253 const char *propname;
1256 struct mapi_nameid {
1257 struct MAPINAMEID *nameid;
1259 struct mapi_nameid_tags *entries;
1262 /* MNID_ID named properties */
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))
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))
1280 # Additional properties
1281 propline = "#define %s %s\n" % (string.ljust("PidLidRemoteTransferSize", 60), string.ljust("0x8f050003", 20))
1284 f.write("#endif /* ! MAPI_NAMEID_H__ */")
1287 # write named properties internal mapping
1288 f = open('libmapi/mapi_nameid_private.h', 'w')
1290 /* Automatically generated by script/makepropslist.py. Do not edit */
1291 #ifndef __MAPI_NAMEID_PRIVATE_H__
1292 #define __MAPI_NAMEID_PRIVATE_H__
1294 static struct mapi_nameid_tags mapi_nameid_tags[] = {
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")
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")
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")
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")
1332 static struct mapi_nameid_names mapi_nameid_names[] = {
1334 for line in sortednamedprops:
1335 propline = "{ %s, \"%s\" },\n" % (string.ljust(line[0], 60), line[0])
1338 # Additional named properties
1339 propline = "{ %s, \"%s\" }\n" % (string.ljust("PidLidRemoteTransferSize", 60), "PidLidRemoteTransferSize")
1341 propline = "{ %s, \"%s\" }\n" % (string.ljust("0x00000000", 60), "NULL")
1346 #endif /* !MAPI_NAMEID_PRIVATE_H__ */
1350 def dump_areas_count():
1352 for area in knownareas:
1355 for entry in properties:
1356 if (entry.has_key("Area") == False):
1357 print "Section", entry["OXPROPS_Sect"], "has no area entry"
1359 areas[entry["Area"]] += 1
1361 for area in knownareas:
1362 print area, ":", areas[area]
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//",
1386 print "Could not fix problem:", retcode
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')
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])
1400 print "Could not convert file to text:", retcode
1403 fix_problems(propsfilename)
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()
1413 if __name__ == "__main__":