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

📄 msgstore.py

📁 用python实现的邮件过滤器
💻 PY
📖 第 1 页 / 共 5 页
字号:
from __future__ import generatorsimport sys, os, reimport localetry:    True, Falseexcept NameError:    # Maintain compatibility with Python 2.2    True, False = 1, 0# MAPI imports etc.from win32com.client import Dispatch, constantsfrom win32com.mapi import mapi, mapiutilfrom win32com.mapi.mapitags import *import pythoncomimport winerrortry:    PR_USERFIELDS # only in new win32allexcept NameError:    PR_USERFIELDS = 0x36E30102 # PROP_TAG(PT_BINARY, 0x36e3)# Additional MAPI constants we dont have in PythonMESSAGE_MOVE = 0x1 # from MAPIdefs.hMSGFLAG_READ = 0x1 # from MAPIdefs.hMSGFLAG_UNSENT = 0x00000008MYPR_BODY_HTML_A = 0x1013001e # magic <wink>MYPR_BODY_HTML_W = 0x1013001f # dittoMYPR_MESSAGE_ID_A = 0x1035001E # more magic (message id field used for Exchange)CLEAR_READ_FLAG = 0x00000004CLEAR_RN_PENDING = 0x00000020CLEAR_NRN_PENDING = 0x00000040SUPPRESS_RECEIPT = 0x1FOLDER_DIALOG = 0x00000002USE_DEFERRED_ERRORS = mapi.MAPI_DEFERRED_ERRORS # or set to zero to see what changes <wink>#import warnings#if sys.version_info >= (2, 3):#    # sick off the new hex() warnings!#    warnings.filterwarnings("ignore", category=FutureWarning, append=1)# Nod to our automated test suite.  Currently supports a hack so our test# message is filtered, and also for raising exceptions at key times.# see tester.py for more details.test_suite_running = Falsetest_suite_failure_request = Nonetest_suite_failure = None# Set to the number of times we should fail, or None for all times.test_suite_failure_count = None# Sometimes the test suite will request that we simulate MAPI errors.def help_test_suite(checkpoint_name):    global test_suite_failure_request, test_suite_failure_count    if test_suite_running and \       test_suite_failure_request == checkpoint_name:        if test_suite_failure_count:            test_suite_failure_count -= 1            if test_suite_failure_count==0:                test_suite_failure_request = None        raise test_suite_failure[0], test_suite_failure[1]# Exceptions raised by this module.  Raw MAPI exceptions should never# be raised to the caller.class MsgStoreException(Exception):    def __init__(self, mapi_exception, extra_msg = None):        self.mapi_exception = mapi_exception        self.extra_msg = extra_msg        Exception.__init__(self, mapi_exception, extra_msg)    def __str__(self):        try:            if self.mapi_exception is not None:                err_str = GetCOMExceptionString(self.mapi_exception)            else:                err_str = self.extra_msg or ''            return "%s: %s" % (self.__class__.__name__, err_str)         # Python silently consumes exceptions here, and uses         # <unprintable object>        except:            print "FAILED to str() a MsgStore exception!"            import traceback            traceback.print_exc()# Exception raised when you attempt to get a message or folder that doesn't# exist.  Usually means you are querying an ID that *was* valid, but has# since been moved or deleted.# Note you may get this exception "getting" objects (such as messages or# folders), or accessing properties once the object was created (the message# may be moved under us at any time)class NotFoundException(MsgStoreException):    pass# Exception raised when you try and modify a "read only" object.# Only currently examples are Hotmail and IMAP folders.class ReadOnlyException(MsgStoreException):    pass# The object has changed since it was opened.class ObjectChangedException(MsgStoreException):    pass# Utility functions for exceptions.  Convert a COM exception to the best# manager exception.def MsgStoreExceptionFromCOMException(com_exc):    if IsNotFoundCOMException(com_exc):        return NotFoundException(com_exc)    if IsReadOnlyCOMException(com_exc):        return ReadOnlyException(com_exc)    scode = NormalizeCOMException(com_exc)[0]    # And simple scode based ones.    if scode == mapi.MAPI_E_OBJECT_CHANGED:        return ObjectChangedException(com_exc)    return MsgStoreException(com_exc)def NormalizeCOMException(exc_val):    hr, msg, exc, arg_err = exc_val    if hr == winerror.DISP_E_EXCEPTION and exc:        # 'client' exception - unpack 'exception object'        wcode, source, msg, help1, help2, hr = exc    return hr, msg, exc, arg_err# Build a reasonable string from a COM exception tupledef GetCOMExceptionString(exc_val):    hr, msg, exc, arg_err = NormalizeCOMException(exc_val)    err_string = mapiutil.GetScodeString(hr)    return "Exception 0x%x (%s): %s" % (hr, err_string, msg)# Does this exception probably mean "object not found"?def IsNotFoundCOMException(exc_val):    hr, msg, exc, arg_err = NormalizeCOMException(exc_val)    return hr in [mapi.MAPI_E_OBJECT_DELETED, mapi.MAPI_E_NOT_FOUND]# Does this exception probably mean "object not available 'cos you ain't logged# in, or 'cos the server is down"?def IsNotAvailableCOMException(exc_val):    hr, msg, exc, arg_err = NormalizeCOMException(exc_val)    return hr == mapi.MAPI_E_FAILONEPROVIDERdef IsReadOnlyCOMException(exc_val):    # This seems to happen for IMAP mails (0x800cccd3)    # and also for hotmail messages (0x8004dff7)    known_failure_codes = -2146644781, -2147164169    exc_val = NormalizeCOMException(exc_val)    return exc_val[0] in known_failure_codesdef ReportMAPIError(manager, what, exc_val):    hr, exc_msg, exc, arg_err = exc_val    if hr == mapi.MAPI_E_TABLE_TOO_BIG:        err_msg = what + _(" failed as one of your\r\n" \                    "Outlook folders is full.  Futher operations are\r\n" \                    "likely to fail until you clean up this folder.\r\n\r\n" \                    "This message will not be reported again until SpamBayes\r\n"\                    "is restarted.")    else:        err_msg = what + _(" failed due to an unexpected Outlook error.\r\n") \                  + GetCOMExceptionString(exc_val) + "\r\n\r\n" + \                  _("It is recommended you restart Outlook at the earliest opportunity\r\n\r\n" \                    "This message will not be reported again until SpamBayes\r\n"\                    "is restarted.")    manager.ReportErrorOnce(err_msg)# Our objects.class MAPIMsgStore:    # Stash exceptions in the class for ease of use by consumers.    MsgStoreException = MsgStoreException    NotFoundException = NotFoundException    ReadOnlyException = ReadOnlyException    ObjectChangedException = ObjectChangedException    def __init__(self, outlook = None):        self.outlook = outlook        cwd = os.getcwd() # remember the cwd - mapi changes it under us!        mapi.MAPIInitialize(None)        logonFlags = (mapi.MAPI_NO_MAIL |                      mapi.MAPI_EXTENDED |                      mapi.MAPI_USE_DEFAULT)        self.session = mapi.MAPILogonEx(0, None, None, logonFlags)        # Note that if the CRT still has a default "C" locale, MAPILogonEx()        # will change it.  See locale comments in addin.py        locale.setlocale(locale.LC_NUMERIC, "C")        self.mapi_msg_stores = {}        self.default_store_bin_eid = None        os.chdir(cwd)    def Close(self):        self.mapi_msg_stores = None        self.session.Logoff(0, 0, 0)        self.session = None        mapi.MAPIUninitialize()    def GetProfileName(self):        # Return the name of the MAPI profile currently in use.        # XXX - note - early win32all versions are missing        # GetStatusTable :(        try:            self.session.GetStatusTable        except AttributeError:            # We try and recover from this when win32all is updated, so no need to whinge.            return None        MAPI_SUBSYSTEM = 39        restriction = mapi.RES_PROPERTY, (mapi.RELOP_EQ, PR_RESOURCE_TYPE,                                          (PR_RESOURCE_TYPE, MAPI_SUBSYSTEM))        table = self.session.GetStatusTable(0)        rows = mapi.HrQueryAllRows(table,                                    (PR_DISPLAY_NAME_A,),   # columns to retrieve                                    restriction,     # only these rows                                    None,            # any sort order is fine                                    0)               # any # of results is fine        assert len(rows)==1, "Should be exactly one row"        (tag, val), = rows[0]        # I can't convince MAPI to give me the Unicode name, so we assume        # encoded as MBCS.        return val.decode("mbcs", "ignore")    def _GetMessageStore(self, store_eid): # bin eid.        try:            # Will usually be pre-fetched, so fast-path out            return self.mapi_msg_stores[store_eid]        except KeyError:            pass        given_store_eid = store_eid        if store_eid is None:            # Find the EID for the default store.            tab = self.session.GetMsgStoresTable(0)            # Restriction for the table:  get rows where PR_DEFAULT_STORE is true.            # There should be only one.            restriction = (mapi.RES_PROPERTY,   # a property restriction                           (mapi.RELOP_EQ,      # check for equality                            PR_DEFAULT_STORE,   # of the PR_DEFAULT_STORE prop                            (PR_DEFAULT_STORE, True))) # with True            rows = mapi.HrQueryAllRows(tab,                                       (PR_ENTRYID,),   # columns to retrieve                                       restriction,     # only these rows                                       None,            # any sort order is fine                                       0)               # any # of results is fine            # get first entry, a (property_tag, value) pair, for PR_ENTRYID            row = rows[0]            eid_tag, store_eid = row[0]            self.default_store_bin_eid = store_eid        # Open it.        store = self.session.OpenMsgStore(                                0,      # no parent window                                store_eid,    # msg store to open                                None,   # IID; accept default IMsgStore                                # need write access to add score fields                                mapi.MDB_WRITE |                                    # we won't send or receive email                                    mapi.MDB_NO_MAIL |                                    USE_DEFERRED_ERRORS)        # cache it        self.mapi_msg_stores[store_eid] = store        if given_store_eid is None: # The default store            self.mapi_msg_stores[None] = store        return store    def GetRootFolder(self, store_id = None):        # if storeID is None, gets the root folder from the default store.        store = self._GetMessageStore(store_id)        hr, data = store.GetProps((PR_ENTRYID, PR_IPM_SUBTREE_ENTRYID), 0)        store_eid = data[0][1]        subtree_eid = data[1][1]        eid = mapi.HexFromBin(store_eid), mapi.HexFromBin(subtree_eid)        return self.GetFolder(eid)    def _OpenEntry(self, id, iid = None, flags = None):        # id is already normalized.        store_id, item_id = id

⌨️ 快捷键说明

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