from __future__ import generators
# Utilities for our sandbox
import os
import pythoncom
from win32com.mapi import mapi, mapiutil
from win32com.mapi.mapitags import *
from win32com.client import Dispatch
class MAPIDriver:
def __init__(self, read_only = False):
old_cwd = os.getcwd()
mapi.MAPIInitialize(None)
logonFlags = (mapi.MAPI_NO_MAIL |
mapi.MAPI_EXTENDED |
mapi.MAPI_USE_DEFAULT)
self.session = mapi.MAPILogonEx(0, None, None, logonFlags)
if read_only:
self.mapi_flags = mapi.MAPI_DEFERRED_ERRORS
else:
self.mapi_flags = mapi.MAPI_DEFERRED_ERRORS | mapi.MAPI_BEST_ACCESS
self.outlook = None
os.chdir(old_cwd)
def _GetMAPIFlags(self, mapi_flags = None):
if mapi_flags is None:
mapi_flags = self.mapi_flags
return mapi_flags
def GetOutlookFolder(self, item):
if self.outlook is None:
self.outlook = Dispatch("Outlook.Application")
hr, props = item.GetProps((PR_ENTRYID,PR_STORE_ENTRYID), 0)
(tag, eid), (tag, store_eid) = props
eid = mapi.HexFromBin(eid)
store_eid = mapi.HexFromBin(store_eid)
return self.outlook.Session.GetFolderFromID(eid, store_eid)
def GetMessageStores(self):
tab = self.session.GetMsgStoresTable(0)
rows = mapi.HrQueryAllRows(tab,
(PR_ENTRYID, PR_DISPLAY_NAME_A, PR_DEFAULT_STORE), # columns to retrieve
None, # all rows
None, # any sort order is fine
0) # any # of results is fine
for row in rows:
(eid_tag, eid), (name_tag, name), (def_store_tag, def_store) = row
# Open the store.
try:
store = self.session.OpenMsgStore(
0, # no parent window
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 |
mapi.MAPI_DEFERRED_ERRORS)
yield store, name, def_store
except pythoncom.com_error, details:
hr, msg, exc, arg_err = details
if hr== mapi.MAPI_E_FAILONEPROVIDER:
# not logged on etc.
pass
else:
print "Error opening message store", details, "- ignoring"
def _FindSubfolder(self, store, folder, find_name):
find_name = find_name.lower()
table = folder.GetHierarchyTable(0)
rows = mapi.HrQueryAllRows(table, (PR_ENTRYID, PR_DISPLAY_NAME_A), None, None, 0)
for (eid_tag, eid), (name_tag, name), in rows:
if name.lower() == find_name:
return store.OpenEntry(eid, None, mapi.MAPI_DEFERRED_ERRORS)
return None
def FindFolder(self, name):
assert name
names = [n.lower() for n in name.split("\\")]
if names[0]:
store_name = None
for store, name, is_default in self.GetMessageStores():
if is_default:
store_name = name.lower()
break
if store_name is None:
raise RuntimeError, "Can't find a default message store"
folder_names = names
else:
store_name = names[1]
folder_names = names[2:]
# Find the store with the name
for store, name, is_default in self.GetMessageStores():
if name.lower() == store_name:
folder_store = store
break
else:
raise ValueError, "The store '%s' can not be located" % (store_name,)
hr, data = store.GetProps((PR_IPM_SUBTREE_ENTRYID,), 0)
subtree_eid = data[0][1]
folder = folder_store.OpenEntry(subtree_eid, None, mapi.MAPI_DEFERRED_ERRORS)
for name in folder_names:
folder = self._FindSubfolder(folder_store, folder, name)
if folder is None:
raise ValueError, "The subfolder '%s' can not be located" % (name,)
return folder
def GetAllItems(self, folder, mapi_flags = None):
mapi_flags = self._GetMAPIFlags(mapi_flags)
table = folder.GetContentsTable(0)
table.SetColumns((PR_ENTRYID,PR_STORE_ENTRYID), 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:
(tag, eid), (tag, store_eid) = row
store = self.session.OpenMsgStore(0, store_eid, None, mapi_flags)
item = store.OpenEntry(eid, None, mapi_flags)
yield item
def GetItemsWithValue(self, folder, prop_tag, prop_val, mapi_flags = None):
mapi_flags = self._GetMAPIFlags(mapi_flags)
tab = folder.GetContentsTable(0)
# Restriction for the table: get rows where our prop values match
restriction = (mapi.RES_CONTENT, # a property restriction
(mapi.FL_SUBSTRING | mapi.FL_IGNORECASE | mapi.FL_LOOSE, # fuzz level
prop_tag, # of the given prop
(prop_tag, prop_val))) # with given val
rows = mapi.HrQueryAllRows(tab,
(PR_ENTRYID, PR_STORE_ENTRYID), # columns to retrieve
restriction, # only these rows
None, # any sort order is fine
0) # any # of results is fine
for row in rows:
(tag, eid),(tag, store_eid) = row
store = self.session.OpenMsgStore(0, store_eid, None, mapi_flags)
item = store.OpenEntry(eid, None, mapi_flags)
yield item
def DumpTopLevelFolders(self):
print "Top-level folder names are:"
for store, name, is_default in self.GetMessageStores():
# Find the folder with the content.
hr, data = store.GetProps((PR_IPM_SUBTREE_ENTRYID,), 0)
subtree_eid = data[0][1]
folder = store.OpenEntry(subtree_eid, None, mapi.MAPI_DEFERRED_ERRORS)
# Now the top-level folders in the store.
table = folder.GetHierarchyTable(0)
rows = mapi.HrQueryAllRows(table, (PR_DISPLAY_NAME_A), None, None, 0)
for (name_tag, folder_name), in rows:
print " \\%s\\%s" % (name, folder_name)
def GetFolderNameDoc(self):
def_store_name = "<??unknown??>"
for store, name, is_def in self.GetMessageStores():
if is_def:
def_store_name = name
return """\
Folder name is a hierarchical 'path' name, using '\\'
as the path separator. If the folder name begins with a
\\, it must be a fully-qualified name, including the message
store name. For example, as your default store is currently named
'%s', your Inbox can be specified either as:
-f "Inbox"
or
-f "\\%s\\Inbox"
""" % (def_store_name, def_store_name)
if __name__=='__main__':
print "This is a utility script for the other scripts in this directory"
syntax highlighted by Code2HTML, v. 0.9.1