📄 msgstore.py
字号:
store = self._GetMessageStore(store_id) if flags is None: flags = mapi.MAPI_MODIFY | USE_DEFERRED_ERRORS return store.OpenEntry(item_id, iid, flags) # Normalize an "external" hex ID to an internal binary ID. def NormalizeID(self, item_id): assert type(item_id)==type(()), \ "Item IDs must be a tuple (not a %r)" % item_id try: store_id, entry_id = item_id return mapi.BinFromHex(store_id), mapi.BinFromHex(entry_id) except ValueError: raise MsgStoreException(None, "The specified ID '%s' is invalid" % (item_id,)) def _GetSubFolderIter(self, folder): table = folder.GetHierarchyTable(0) rows = mapi.HrQueryAllRows(table, (PR_ENTRYID, PR_STORE_ENTRYID, PR_DISPLAY_NAME_A), None, None, 0) for (eid_tag, eid), (store_eid_tag, store_eid), (name_tag, name) in rows: item_id = store_eid, eid sub = self._OpenEntry(item_id) table = sub.GetContentsTable(0) yield MAPIMsgStoreFolder(self, item_id, name, table.GetRowCount(0)) for store_folder in self._GetSubFolderIter(sub): yield store_folder def GetFolderGenerator(self, folder_ids, include_sub): for folder_id in folder_ids: try: folder_id = self.NormalizeID(folder_id) except MsgStoreException, details: print "NOTE: Skipping invalid folder", details continue try: folder = self._OpenEntry(folder_id) table = folder.GetContentsTable(0) except pythoncom.com_error, details: # We will ignore *all* such errors for the time # being, but give verbose details for results we don't # know about if IsNotAvailableCOMException(details): print "NOTE: Skipping folder for this session - temporarily unavailable" elif IsNotFoundCOMException(details): print "NOTE: Skipping deleted folder" else: print "WARNING: Unexpected MAPI error opening folder" print GetCOMExceptionString(details) continue rc, props = folder.GetProps( (PR_DISPLAY_NAME_A,), 0) yield MAPIMsgStoreFolder(self, folder_id, props[0][1], table.GetRowCount(0)) if include_sub: for f in self._GetSubFolderIter(folder): yield f def GetFolder(self, folder_id): # Return a single folder given the ID. try: # catch all MAPI errors try: # See if this is an Outlook folder item sid = mapi.BinFromHex(folder_id.StoreID) eid = mapi.BinFromHex(folder_id.EntryID) folder_id = sid, eid except AttributeError: # No 'EntryID'/'StoreID' properties - a 'normal' ID folder_id = self.NormalizeID(folder_id) folder = self._OpenEntry(folder_id) table = folder.GetContentsTable(0) # Ensure we have a long-term ID. rc, props = folder.GetProps( (PR_ENTRYID, PR_DISPLAY_NAME_A), 0) folder_id = folder_id[0], props[0][1] return MAPIMsgStoreFolder(self, folder_id, props[1][1], table.GetRowCount(0)) except pythoncom.com_error, details: raise MsgStoreExceptionFromCOMException(details) def GetMessage(self, message_id): # Return a single message given either the ID, or an Outlook # message representing the object. try: # catch all MAPI exceptions. try: eid = mapi.BinFromHex(message_id.EntryID) sid = mapi.BinFromHex(message_id.Parent.StoreID) message_id = sid, eid except AttributeError: # No 'EntryID'/'StoreID' properties - a 'normal' ID message_id = self.NormalizeID(message_id) mapi_object = self._OpenEntry(message_id) hr, data = mapi_object.GetProps(MAPIMsgStoreMsg.message_init_props,0) return MAPIMsgStoreMsg(self, data) except pythoncom.com_error, details: raise MsgStoreExceptionFromCOMException(details) def YieldReceiveFolders(self, msg_class = "IPM.Note"): # Get the main receive folder for each message store. tab = self.session.GetMsgStoresTable(0) rows = mapi.HrQueryAllRows(tab, (PR_ENTRYID,), # columns to retrieve None, # all rows None, # any sort order is fine 0) # any # of results is fine for row in rows: # get first entry, a (property_tag, value) pair, for PR_ENTRYID eid_tag, store_eid = row[0] try: store = self._GetMessageStore(store_eid) folder_eid, ret_class = store.GetReceiveFolder(msg_class, 0) hex_folder_eid = mapi.HexFromBin(folder_eid) hex_store_eid = mapi.HexFromBin(store_eid) except pythoncom.com_error, details: if not IsNotAvailableCOMException(details): print "ERROR enumerating a receive folder -", details continue try: folder = self.GetFolder((hex_store_eid, hex_folder_eid)) # For 'unconfigured' stores, or "stand-alone" PST files, # this is a root folder - so not what we wan't. Only return # folders with a parent. if folder.GetParent() is not None: yield folder except MsgStoreException, details: print "ERROR opening receive folder -", details # but we just continue continue_MapiTypeMap = { type(0.0): PT_DOUBLE, type(0): PT_I4, type(''): PT_STRING8, type(u''): PT_UNICODE, # In Python 2.2.2, bool isn't a distinct type (type(1==1) is type(0)).# type(1==1): PT_BOOLEAN,}def GetPropFromStream(mapi_object, prop_id): try: stream = mapi_object.OpenProperty(prop_id, pythoncom.IID_IStream, 0, 0) chunks = [] while 1: chunk = stream.Read(4096) if not chunk: break chunks.append(chunk) return "".join(chunks) except pythoncom.com_error, d: print "Error getting property", mapiutil.GetPropTagName(prop_id), \ "from stream:", d return ""def GetPotentiallyLargeStringProp(mapi_object, prop_id, row): got_tag, got_val = row if PROP_TYPE(got_tag) == PT_ERROR: ret = "" if got_val == mapi.MAPI_E_NOT_FOUND: pass # No property for this message. elif got_val == mapi.MAPI_E_NOT_ENOUGH_MEMORY: # Too big for simple properties - get via a stream ret = GetPropFromStream(mapi_object, prop_id) else: tag_name = mapiutil.GetPropTagName(prop_id) err_string = mapiutil.GetScodeString(got_val) print "Warning - failed to get property %s: %s" % (tag_name, err_string) else: ret = got_val return ret# Some nasty stuff for getting RTF out of the messagedef GetHTMLFromRTFProperty(mapi_object, prop_tag = PR_RTF_COMPRESSED): try: rtf_stream = mapi_object.OpenProperty(prop_tag, pythoncom.IID_IStream, 0, 0) html_stream = mapi.WrapCompressedRTFStream(rtf_stream, 0) html = mapi.RTFStreamToHTML(html_stream) except pythoncom.com_error, details: if not IsNotFoundCOMException(details): print "ERROR getting RTF body", details return "" # html may be None if RTF not originally from HTML, but here we # always want a string return html or ''class MAPIMsgStoreFolder: def __init__(self, msgstore, id, name, count): self.msgstore = msgstore self.id = id self.name = name self.count = count def __repr__(self): return "<%s '%s' (%d items), id=%s/%s>" % (self.__class__.__name__, self.name, self.count, mapi.HexFromBin(self.id[0]), mapi.HexFromBin(self.id[1])) def __eq__(self, other): if other is None: return False ceid = self.msgstore.session.CompareEntryIDs return ceid(self.id[0], other.id[0]) and \ ceid(self.id[1], other.id[1]) def __ne__(self, other): return not self.__eq__(other) def GetID(self): return mapi.HexFromBin(self.id[0]), mapi.HexFromBin(self.id[1]) def GetFQName(self): parts = [] parent = self while parent is not None: parts.insert(0, parent.name) try: # Ignore errors fetching parents - the caller just wants the # name - it may not be correctly 'fully qualified', but at # least we get something. parent = parent.GetParent() except MsgStoreException: break # We now end up with [0] being an empty string??, [1] being the # information store root folder name, etc. Outlook etc all just # use the information store name here. if parts and not parts[0]: del parts[0] # Don't catch exceptions on the item itself - that is fatal, # and should be caught by the caller. # Replace the "root" folder name with the information store name # as Outlook, our Folder selector etc do. mapi_store = self.msgstore._GetMessageStore(self.id[0]) hr, data = mapi_store.GetProps((PR_DISPLAY_NAME_A,), 0) name = data[0][1] if parts: # and replace with new name parts[0] = name else: # This can happen for the very root folder (ie, parent of the # top-level folder shown by Outlook. This folder should *never* # be used directly. parts = [name] print "WARNING: It appears you are using the top-level root of " \ "the information store as a folder. You probably don't "\ "want to do that" return "/".join(parts) def _FolderFromMAPIFolder(self, mapifolder): # Finally get the display name. hr, data = mapifolder.GetProps((PR_ENTRYID, PR_DISPLAY_NAME_A,), 0) eid = self.id[0], data[0][1] name = data[1][1] count = mapifolder.GetContentsTable(0).GetRowCount(0) return MAPIMsgStoreFolder(self.msgstore, eid, name, count) def GetParent(self): # return a folder object with the parent, or None if there is no # parent (ie, a top-level folder). Raises an exception if there is # an error fetching the parent (which implies something wrong with the # item itself, rather than this being top-level) try: folder = self.msgstore._OpenEntry(self.id) prop_ids = PR_PARENT_ENTRYID, hr, data = folder.GetProps(prop_ids,0) # Put parent ids together parent_eid = data[0][1] parent_id = self.id[0], parent_eid if hr != 0 or \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -