mapiutil.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. # General utilities for MAPI and MAPI objects.
  2. # We used to use these old names from the 'types' module...
  3. TupleType=tuple
  4. ListType=list
  5. IntType=int
  6. from pywintypes import TimeType
  7. import pythoncom
  8. from . import mapi, mapitags
  9. prTable = {}
  10. def GetPropTagName(pt):
  11. if not prTable:
  12. for name, value in mapitags.__dict__.items():
  13. if name[:3] == 'PR_':
  14. # Store both the full ID (including type) and just the ID.
  15. # This is so PR_FOO_A and PR_FOO_W are still differentiated,
  16. # but should we get a PT_FOO with PT_ERROR set, we fallback
  17. # to the ID.
  18. # String types should have 3 definitions in mapitags.py
  19. # PR_BODY = PROP_TAG( PT_TSTRING, 4096)
  20. # PR_BODY_W = PROP_TAG( PT_UNICODE, 4096)
  21. # PR_BODY_A = PROP_TAG( PT_STRING8, 4096)
  22. # The following change ensures a lookup using only the the
  23. # property id returns the conditional default.
  24. # PT_TSTRING is a conditional assignment for either PT_UNICODE or
  25. # PT_STRING8 and should not be returned during a lookup.
  26. if mapitags.PROP_TYPE(value) == mapitags.PT_UNICODE or \
  27. mapitags.PROP_TYPE(value) == mapitags.PT_STRING8:
  28. if name[-2:] == '_A' or name[-2:] == '_W':
  29. prTable[value] = name
  30. else:
  31. prTable[mapitags.PROP_ID(value)] = name
  32. else:
  33. prTable[value] = name
  34. prTable[mapitags.PROP_ID(value)] = name
  35. try:
  36. try:
  37. return prTable[pt]
  38. except KeyError:
  39. # Can't find it exactly - see if the raw ID exists.
  40. return prTable[mapitags.PROP_ID(pt)]
  41. except KeyError:
  42. # god-damn bullshit hex() warnings: I don't see a way to get the
  43. # old behaviour without a warning!!
  44. ret = hex(int(pt))
  45. # -0x8000000L -> 0x80000000
  46. if ret[0]=='-': ret = ret[1:]
  47. if ret[-1]=='L': ret = ret[:-1]
  48. return ret
  49. mapiErrorTable = {}
  50. def GetScodeString(hr):
  51. if not mapiErrorTable:
  52. for name, value in mapi.__dict__.items():
  53. if name[:7] in ['MAPI_E_', 'MAPI_W_']:
  54. mapiErrorTable[value] = name
  55. return mapiErrorTable.get(hr, pythoncom.GetScodeString(hr))
  56. ptTable = {}
  57. def GetMapiTypeName(propType, rawType=True):
  58. """Given a mapi type flag, return a string description of the type"""
  59. if not ptTable:
  60. for name, value in mapitags.__dict__.items():
  61. if name[:3] == 'PT_':
  62. # PT_TSTRING is a conditional assignment
  63. # for either PT_UNICODE or PT_STRING8 and
  64. # should not be returned during a lookup.
  65. if name in ['PT_TSTRING', 'PT_MV_TSTRING']:
  66. continue
  67. ptTable[value] = name
  68. if rawType:
  69. propType = propType & ~mapitags.MV_FLAG
  70. return ptTable.get(propType, str(hex(propType)))
  71. def GetProperties(obj, propList):
  72. """Given a MAPI object and a list of properties, return a list of property values.
  73. Allows a single property to be passed, and the result is a single object.
  74. Each request property can be an integer or a string. Of a string, it is
  75. automatically converted to an integer via the GetIdsFromNames function.
  76. If the property fetch fails, the result is None.
  77. """
  78. bRetList = 1
  79. if type(propList) not in [TupleType, ListType]:
  80. bRetList = 0
  81. propList = (propList,)
  82. realPropList = []
  83. rc = []
  84. for prop in propList:
  85. if type(prop)!=IntType: # Integer
  86. props = ( (mapi.PS_PUBLIC_STRINGS, prop), )
  87. propIds = obj.GetIDsFromNames(props, 0)
  88. prop = mapitags.PROP_TAG( mapitags.PT_UNSPECIFIED, mapitags.PROP_ID(propIds[0]))
  89. realPropList.append(prop)
  90. hr, data = obj.GetProps(realPropList,0)
  91. if hr != 0:
  92. data = None
  93. return None
  94. if bRetList:
  95. return [v[1] for v in data]
  96. else:
  97. return data[0][1]
  98. def GetAllProperties(obj, make_tag_names = True):
  99. tags = obj.GetPropList(0)
  100. hr, data = obj.GetProps(tags)
  101. ret = []
  102. for tag, val in data:
  103. if make_tag_names:
  104. hr, tags, array = obj.GetNamesFromIDs( (tag,) )
  105. if type(array[0][1])==type(''):
  106. name = array[0][1]
  107. else:
  108. name = GetPropTagName(tag)
  109. else:
  110. name = tag
  111. ret.append((name, val))
  112. return ret
  113. _MapiTypeMap = {
  114. type(0.0): mapitags.PT_DOUBLE,
  115. type(0): mapitags.PT_I4,
  116. type(''.encode('ascii')): mapitags.PT_STRING8, # bytes
  117. type(''): mapitags.PT_UNICODE, # str
  118. type(None): mapitags.PT_UNSPECIFIED,
  119. # In Python 2.2.2, bool isn't a distinct type (type(1==1) is type(0)).
  120. # (markh thinks the above is trying to say that in 2020, we probably *do*
  121. # want bool in this map? :)
  122. }
  123. def SetPropertyValue(obj, prop, val):
  124. if type(prop)!=IntType:
  125. props = ( (mapi.PS_PUBLIC_STRINGS, prop), )
  126. propIds = obj.GetIDsFromNames(props, mapi.MAPI_CREATE)
  127. if val == (1==1) or val == (1==0):
  128. type_tag = mapitags.PT_BOOLEAN
  129. else:
  130. type_tag = _MapiTypeMap.get(type(val))
  131. if type_tag is None:
  132. raise ValueError("Don't know what to do with '%r' ('%s')" % (val, type(val)))
  133. prop = mapitags.PROP_TAG( type_tag, mapitags.PROP_ID(propIds[0]))
  134. if val is None:
  135. # Delete the property
  136. obj.DeleteProps((prop,))
  137. else:
  138. obj.SetProps(((prop,val),))
  139. def SetProperties( msg, propDict):
  140. """ Given a Python dictionary, set the objects properties.
  141. If the dictionary key is a string, then a property ID is queried
  142. otherwise the ID is assumed native.
  143. Coded for maximum efficiency wrt server calls - ie, maximum of
  144. 2 calls made to the object, regardless of the dictionary contents
  145. (only 1 if dictionary full of int keys)
  146. """
  147. newProps = []
  148. # First pass over the properties we should get IDs for.
  149. for key, val in propDict.items():
  150. if type(key) == str:
  151. newProps.append((mapi.PS_PUBLIC_STRINGS, key))
  152. # Query for the new IDs
  153. if newProps: newIds = msg.GetIDsFromNames(newProps, mapi.MAPI_CREATE)
  154. newIdNo = 0
  155. newProps = []
  156. for key, val in propDict.items():
  157. if type(key) == str:
  158. type_val=type(val)
  159. if type_val == str:
  160. tagType = mapitags.PT_UNICODE
  161. elif type_val==IntType:
  162. tagType = mapitags.PT_I4
  163. elif type_val==TimeType:
  164. tagType = mapitags.PT_SYSTIME
  165. else:
  166. raise ValueError("The type of object %s(%s) can not be written" % (repr(val),type_val))
  167. key = mapitags.PROP_TAG(tagType, mapitags.PROP_ID(newIds[newIdNo]))
  168. newIdNo = newIdNo + 1
  169. newProps.append( (key, val) )
  170. msg.SetProps(newProps)