⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msgstore.py

📁 用python实现的邮件过滤器
💻 PY
📖 第 1 页 / 共 5 页
字号:
               self.msgstore.session.CompareEntryIDs(parent_eid, self.id[1]):                # No parent EID, or EID same as ours.                return None            parent = self.msgstore._OpenEntry(parent_id)            # Finally get the item itself            return self._FolderFromMAPIFolder(parent)        except pythoncom.com_error, details:            raise MsgStoreExceptionFromCOMException(details)    def OpenEntry(self, iid = None, flags = None):        return self.msgstore._OpenEntry(self.id, iid, flags)    def GetOutlookItem(self):        try:            hex_item_id = mapi.HexFromBin(self.id[1])            hex_store_id = mapi.HexFromBin(self.id[0])            return self.msgstore.outlook.Session.GetFolderFromID(hex_item_id, hex_store_id)        except pythoncom.com_error, details:            raise MsgStoreExceptionFromCOMException(details)    def GetMessageGenerator(self, only_filter_candidates = True):        folder = self.OpenEntry()        table = folder.GetContentsTable(0)        table.SetColumns(MAPIMsgStoreMsg.message_init_props, 0)        if only_filter_candidates:            # Limit ourselves to IPM.* objects - ie, messages.            restriction = (mapi.RES_PROPERTY,   # a property restriction                           (mapi.RELOP_GE,      # >=                            PR_MESSAGE_CLASS_A,   # of the this prop                            (PR_MESSAGE_CLASS_A, "IPM."))) # with this value            table.Restrict(restriction, 0)        while 1:            # Getting 70 at a time was the random number that gave best            # perf for me ;)            rows = table.QueryRows(70, 0)            if len(rows) == 0:                break            for row in rows:                # Our restriction helped, but may not have filtered                # every message we don't want to touch.                # Note no exception will be raised below if the message is                # moved under us, as we don't need to access any properties.                msg = MAPIMsgStoreMsg(self.msgstore, row)                if not only_filter_candidates or msg.IsFilterCandidate():                    yield msg    def GetNewUnscoredMessageGenerator(self, scoreFieldName):        folder = self.msgstore._OpenEntry(self.id)        table = folder.GetContentsTable(0)        # Resolve the field name        resolve_props = ( (mapi.PS_PUBLIC_STRINGS, scoreFieldName), )        resolve_ids = folder.GetIDsFromNames(resolve_props, 0)        field_id = PROP_TAG( PT_DOUBLE, PROP_ID(resolve_ids[0]))        # Setup the properties we want to read.        table.SetColumns(MAPIMsgStoreMsg.message_init_props, 0)        # Set up the restriction        # Need to check message-flags        # (PR_CONTENT_UNREAD is optional, and somewhat unreliable        # PR_MESSAGE_FLAGS & MSGFLAG_READ is the official way)        prop_restriction = (mapi.RES_BITMASK,   # a bitmask restriction                               (mapi.BMR_EQZ,      # when bit is clear                                PR_MESSAGE_FLAGS,                                MSGFLAG_READ))        exist_restriction = mapi.RES_EXIST, (field_id,)        not_exist_restriction = mapi.RES_NOT, (exist_restriction,)        # A restriction for the message class        class_restriction = (mapi.RES_PROPERTY,   # a property restriction                             (mapi.RELOP_GE,      # >=                              PR_MESSAGE_CLASS_A,   # of the this prop                              (PR_MESSAGE_CLASS_A, "IPM."))) # with this value        # Put the final restriction together        restriction = (mapi.RES_AND, (prop_restriction,                                      not_exist_restriction,                                      class_restriction))        table.Restrict(restriction, 0)        while 1:            rows = table.QueryRows(70, 0)            if len(rows) == 0:                break            for row in rows:                # Note no exception will be raised below if the message is                # moved under us, as we don't need to access any properties.                msg = MAPIMsgStoreMsg(self.msgstore, row)                if msg.IsFilterCandidate():                    yield msg    def IsReceiveFolder(self, msg_class = "IPM.Note"):        # Is this folder the nominated "receive folder" for its store?        try:            mapi_store = self.msgstore._GetMessageStore(self.id[0])            eid, ret_class = mapi_store.GetReceiveFolder(msg_class, 0)            return mapi_store.CompareEntryIDs(eid, self.id[1])        except pythoncom.com_error:            # Error getting the receive folder from the store (or maybe  our            # store - but that would be insane!).  Either way, we can't be it!            return False    def CreateFolder(self, name, comments = None, type = None,                     open_if_exists = False, flags = None):        if type is None: type = mapi.FOLDER_GENERIC        if flags is None: flags = 0        if open_if_exists: flags |= mapi.OPEN_IF_EXISTS        folder = self.OpenEntry()        ret = folder.CreateFolder(type, name, comments, None, flags)        return self._FolderFromMAPIFolder(ret)    def GetItemCount(self):        try:            folder = self.OpenEntry()            return folder.GetContentsTable(0).GetRowCount(0)        except pythoncom.com_error, details:            raise MsgStoreExceptionFromCOMException(details)            # EmptyFolder() *permanently* deletes ALL messages and subfolders from    # this folder without deleting the folder itself.    #    # WORD OF WARNING:  This is a *very dangerous* function that has the    # potential to destroy a user's mail.  Don't even *think* about calling    # this function on anything but the Certain Spam folder!    def EmptyFolder(self, parentWindow):        try:            folder = self.OpenEntry()            folder.EmptyFolder(parentWindow, None, FOLDER_DIALOG)        except pythoncom.com_error, details:            raise MsgStoreExceptionFromCOMException(details)    def DoesFolderHaveOutlookField(self, field_name):        # Returns True if the specified folder has an *Outlook* field with        # the given name, False if the folder does not have it, or None        # if we can't tell, or there was an error, etc.        # We have discovered that Outlook stores 'Fields' for a folder as a        # PR_USERFIELDS field in the hidden, 'associated' message with        # message class IPC.MS.REN.USERFIELDS.  This is a binary property        # which is undocumented, but probably could be reverse-engineered        # with a little effort (see 'dump_props --dump-folder-user-props' for        # an example of the raw data.  For now, the simplest thing appears        # to be to check for a \0 character, followed by the property name        # as an ascii string.        try:            folder = self.msgstore._OpenEntry(self.id)            table = folder.GetContentsTable(mapi.MAPI_ASSOCIATED)            restriction = (mapi.RES_PROPERTY,                          (mapi.RELOP_EQ,                           PR_MESSAGE_CLASS_A,                           (PR_MESSAGE_CLASS_A, 'IPC.MS.REN.USERFIELDS')))            cols = (PR_USERFIELDS,)            table.SetColumns(cols, 0)            rows = mapi.HrQueryAllRows(table, cols, restriction, None, 0)            if len(rows)>1:                print "Eeek - only expecting one row from IPC.MS.REN.USERFIELDS"                print "got", repr(rows)                return None            if len(rows)==0:                # New folders with no userdefined fields do not have such a row,                # but this is a clear indication it does not exist.                return False            row = rows[0]            val = GetPotentiallyLargeStringProp(folder, cols[0], row[0])        except pythoncom.com_error, details:            raise MsgStoreExceptionFromCOMException(details)        if type(val) != type(''):            print "Value type incorrect - expected string, got", repr(val)            return None        return val.find("\0" + field_name) >= 0    def DeleteMessages(self, message_things):        # A *permanent* delete - MAPI has no concept of 'Deleted Items',        # only Outlook does.  If you want a "soft" delete, you must locate        # deleted item (via a special ID) and move it to there yourself        # message_things may be ID tuples, or MAPIMsgStoreMsg instances.        real_ids = []        for thing in message_things:            if isinstance(thing, MAPIMsgStoreMsg):                real_ids.append( thing.id[1] )                thing.mapi_object = thing.id = thing.folder_id = None            else:                real_ids.append(self.msgstore.NormalizeID(thing)[1])        try:            folder = self.msgstore._OpenEntry(self.id)            # Nuke my MAPI reference, and set my ID to None            rc = folder.DeleteMessages(real_ids, 0, None, 0)        except pythoncom.com_error, details:            raise MsgStoreExceptionFromCOMException(details)    def CreateTemporaryMessage(self, msg_flags = None):        # Create a message designed to be used temporarily.  It is your        # responsibility to delete when you are done with it.        # If msg_flags is not None, it should be an integer for the        # PR_MESSAGE_FLAGS property.  Note that Outlook appears to refuse        # to set user properties on a message marked as 'unsent', which        # is the default.  Setting to, eg, 1 marks it as a "not unsent, read"        # message, which works fine with user properties.        try:            folder = self.msgstore._OpenEntry(self.id)            imsg = folder.CreateMessage(None, 0)            if msg_flags is not None:                props = (PR_MESSAGE_FLAGS,msg_flags),                imsg.SetProps(props)            imsg.SaveChanges(0)            hr, data = imsg.GetProps((PR_ENTRYID, PR_STORE_ENTRYID), 0)            eid = data[0][1]            storeid = data[1][1]            msg_id = mapi.HexFromBin(storeid), mapi.HexFromBin(eid)        except pythoncom.com_error, details:            raise MsgStoreExceptionFromCOMException(details)        return self.msgstore.GetMessage(msg_id)class MAPIMsgStoreMsg:    # All the properties we must initialize a message with.    # These include all the IDs we need, parent IDs, any properties needed    # to determine if this is a "filterable" message, etc    message_init_props = (PR_ENTRYID, PR_STORE_ENTRYID, PR_SEARCH_KEY,                          PR_PARENT_ENTRYID, # folder ID                          PR_MESSAGE_CLASS_A, # 'IPM.Note' etc                          PR_RECEIVED_BY_ENTRYID, # who received it                          PR_SUBJECT_A,                          PR_TRANSPORT_MESSAGE_HEADERS_A,                          )    def __init__(self, msgstore, prop_row):        self.msgstore = msgstore        self.mapi_object = None        # prop_row is a single mapi property row, with fields as above.        # NOTE: We can't trust these properties for "large" values        # (ie, strings, PT_BINARY, objects etc.), as they sometimes come        # from the IMAPITable (which has a 255 limit on property values)        # and sometimes from the object itself (which has no restriction).        # This limitation is documented by MAPI.        # Thus, we don't trust "PR_TRANSPORT_MESSAGE_HEADERS_A" more than        # to ask "does the property exist?"        tag, eid = prop_row[0] # ID        tag, store_eid = prop_row[1]        tag, searchkey = prop_row[2]        tag, parent_eid = prop_row[3]        tag, msgclass = prop_row[4]        recby_tag, recby = prop_row[5]        tag, subject = prop_row[6]        headers_tag, headers = prop_row[7]        self.id = store_eid, eid        self.folder_id = store_eid, parent_eid        self.msgclass = msgclass        self.subject = subject        has_headers = PROP_TYPE(headers_tag)==PT_STRING8        # Search key is the only reliable thing after a move/copy operation        # only problem is that it can potentially be changed - however, the        # Outlook client provides no such (easy/obvious) way        # (ie, someone would need to really want to change it <wink>)        # Thus, searchkey is our long-lived message key.        self.searchkey = searchkey        # To check if a message has ever been received, we check the        # PR_RECEIVED_BY_ENTRYID flag.  Tim wrote in an old comment that        # An article on the web said the distinction can't be made with 100%        # certainty, but that a good heuristic is to believe that a        # msg has been received iff at least one of these properties        # has a sensible value: RECEIVED_BY_EMAIL_ADDRESS, RECEIVED_BY_NAME,        # RECEIVED_BY_ENTRYID PR_TRANSPORT_MESSAGE_HEADERS        # But MarkH can't find it, and believes and tests that        # PR_RECEIVED_BY_ENTRYID is all we need (but has since discovered a        # couple of messages without any PR_RECEIVED_BY properties - but *with*        # PR_TRANSPORT_MESSAGE_HEADERS - *sigh*)        self.was_received = PROP_TYPE(recby_tag) == PT_BINARY or has_headers        self.dirty = False        # For use with the spambayes.message messageinfo database.        self.stored_attributes = ['c', 't', 'original_folder',                                  'date_modified']        self.t = None        self.c = None        self.date_modified = None        self.original_folder = None

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -