""" This module reads out information from Microsoft Outlook. The function loadInbox() reads all Emails of MsOutlook-inbox folder, optionally it is possible to read the subfolder of the inbox too. The emails will be returnes as Python MIME objects in a list. Tobias Schmid 26.07.2007 """ import win32com.client import ctypes import win32api, win32process, win32con import re from email.mime.multipart import MIMEMultipart from watsup.winGuiAuto import findTopWindow, findControl, findControls, clickButton, \ getComboboxItems, selectComboboxItem, setCheckBox from twisted.internet.defer import Deferred from twisted.internet.task import coiterate from twisted.internet import threads from zope.interface import implements from loops.agent.interfaces import IResource from loops.agent.crawl.base import CrawlingJob as BaseCrawlingJob from loops.agent.crawl.base import Metadata # DEBUG FLAGS DEBUG = 1 DEBUG_WRITELINE = 1 # some constants COMMASPACE = ', ' class CrawlingJob(BaseCrawlingJob): keys = "" inbox = "" subfolders = "" pattern = "" def collect(self): self.collected = [] coiterate(self.crawlOutlook()).addCallback(self.finished) # TODO: addErrback() self.deferred = Deferred() return self.deferred def finished(self, result): self.deferred.callback(self.collected) def crawlOutlook(self): outlookFound = 0 try: oOutlookApp = \ win32com.client.gencache.EnsureDispatch("Outlook.Application") outlookFound = 1 except: print "MSOutlook: unable to load Outlook" records = [] if not outlookFound: return # fetch the params criteria = self.params self.keys = criteria.get('keys') self.inbox = criteria.get('inbox') #boolean self.subfolders = criteria.get('subfolders') #boolean self.pattern = criteria.get('pattern') if self.pattern != '': self.pattern = re.compile(criteria.get('pattern') or '.*') else: self.pattern = None if DEBUG_WRITELINE: print 'MSOutlook.loadInbox() ===> starting' # try to handle the Outlook dialog #d = threads.deferToThread(self.handleOutlookDialog) #d.addCallback(self.printResult) # catch Inbox folder onMAPI = oOutlookApp.GetNamespace("MAPI") ofInbox = \ onMAPI.GetDefaultFolder(win32com.client.constants.olFolderInbox) # fetch the mails of the inbox folder if DEBUG_WRITELINE: print 'MSOutlook.loadInbox() ===> fetch mails of inbox folder' # fetch mails from inbox if self.inbox: self.loadEmail(ofInbox) # fetch mails of inbox subfolders if self.subfolders and self.pattern is None: if DEBUG_WRITELINE: print 'MSOutlook.loadInbox() ===> fetch emails of subfolders' lInboxSubfolders = getattr(ofInbox, 'Folders') for of in range(lInboxSubfolders.__len__()): # get a MAPI-folder object and load its emails self.loadEmail(lInboxSubfolders.Item(of + 1)) # pattern, just read the specified subfolder elif self.subfolders and self.pattern: if DEBUG_WRITELINE: print 'MSOutlook.loadInbox() ===> fetch emails of specified subfolder' lInboxSubfolders = getattr(ofInbox, 'Folders') for of in range(lInboxSubfolders.__len__()): # get a MAPI-folder object and load its emails if self.pattern.match(getattr(lInboxSubfolders.Item(of + 1), 'Name')): self.loadEmail(lInboxSubfolders.Item(of + 1)) #oFolder if DEBUG: print 'number of mails in Inbox:', len(ofInbox.Items) # list of _Folder (subfolder of inbox) lInboxSubfolders = getattr(ofInbox, 'Folders') # get Count-Attribute of _Folders class iInboxSubfoldersCount = getattr(lInboxSubfolders, 'Count') # the Item-Method of the _Folders class returns a MAPIFolder object oFolder = lInboxSubfolders.Item(1) print 'Count of Inbox-SubFolders:', iInboxSubfoldersCount print 'Inbox sub folders (Folder/Mails):' for folder in range(iInboxSubfoldersCount): oFolder = lInboxSubfolders.Item(folder+1) print getattr(oFolder, 'Name'), '/' , len(getattr(oFolder, 'Items')) if DEBUG_WRITELINE: print 'MSOutlook.loadInbox() ===> ending' yield '1' def loadEmail(self, oFolder): # get items of the folder folderItems = getattr(oFolder, 'Items') for item in range(len(folderItems)): mail = folderItems.Item(item+1) if mail.Class == win32com.client.constants.olMail: if self.keys is None: self.keys = [] for key in mail._prop_map_get_: if isinstance(getattr(mail, key), (int, str, unicode)): self.keys.append(key) if DEBUG: self.keys.sort() print 'Fiels\n=======================================' for key in self.keys: print key record = {} for key in self.keys: record[key] = getattr(mail, key) if DEBUG: print str(item) # Create the mime email object msg = self.createEmailMime(record) # list with mime objects self.collected.append((OutlookResource(msg))) def createEmailMime(self, emails): # Create the container (outer) email message. msg = MIMEMultipart() # subject msg['Subject'] = emails['Subject'].encode('utf-8') # sender if emails.has_key('SenderEmailAddress'): sender = str(emails['SenderEmailAddress'].encode('utf-8')) else: sender = str(emails['SenderName'].encode('utf-8')) msg['From'] = sender # CC #msg['CC'] = str(emails['CC'].encode('utf-8')) # ReceivedTime #msg['Date'] = str(emails['ReceivedTime']) #recipients recipients = [] if emails.has_key('Recipients'): for rec in range(emails['Recipients'].__len__()): recipients.append(getattr(emails['Recipients'].Item(rec+1), 'Address')) msg['To'] = COMMASPACE.join(recipients) else: recipients.append(emails['To']) msg['To'] = COMMASPACE.join(recipients) # message msg.preamble = emails['Body'].encode('utf-8') return msg def handleOutlookDialog(self): """ This function handles the outlook dialog, which appears if someone tries to access to MS Outlook. """ hwnd = None while True: hwnd = ctypes.windll.user32.FindWindowExA(None, hwnd, None, None) print 'searching....' if hwnd == None: break else: val = u"\0" * 1024 ctypes.windll.user32.GetWindowTextW(hwnd, val, len(val)) val = val.replace(u"\000", u"") if val and repr(val) == "u'Microsoft Office Outlook'": print repr(val) print '===> MSOutlook dialog box found' #tid, pid = win32process.GetWindowThreadProcessId(hwnd) # get a handle #handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0, pid) # terminate the process by the handle #win32api.TerminateProcess(handle, 0) # close the handle - thankyou #win32api.CloseHandle(handle) # get the Main Control form = findTopWindow(wantedText='Microsoft Office Outlook') controls = findControls(form) # get the check box checkBox = findControl(form, wantedText='Zugriff') setCheckBox(checkBox, 1) # get the combo box comboBox = findControl(form, wantedClass='ComboBox') items = getComboboxItems(comboBox) selectComboboxItem(comboBox, items[3])#'10 Minuten' # finally get the button and click it button = findControl(form, wantedText = 'Erteilen') clickButton(button) print '-> dialog found and handled' break def printResult(self): print '--> Outlook dialog handled' class OutlookResource(object): implements(IResource) def __init__(self, oEmail): self.oEmail = oEmail @property def data(self): return self.oEmail