PyXR

c:\projects\bitpim\src \ native \ outlook \ outlook.py



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2004 Roger Binns <rogerb@rogerbinns.com>
0004 ###
0005 ### This program is free software; you can redistribute it and/or modify
0006 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0007 ###
0008 ### $Id: outlook.py 3022 2006-03-31 03:21:24Z djpham $
0009 
0010 "Be at one with Outlook"
0011 
0012 # Reject if not on Windows
0013 import sys
0014 if sys.platform!="win32":
0015    raise ImportError()
0016 
0017 import common
0018 
0019 # See this recipe on ASPN for how this code started
0020 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/173216
0021 # Chris Somerlot also gave some insights
0022 
0023 import outlook_com
0024 
0025 import pywintypes
0026 
0027 # This is the complete list of field names available
0028 ##    Account
0029 ##    AssistantName
0030 ##    AssistantTelephoneNumber
0031 ##    BillingInformation
0032 ##    Body
0033 ##    Business2TelephoneNumber
0034 ##    BusinessAddress
0035 ##    BusinessAddressCity
0036 ##    BusinessAddressCountry
0037 ##    BusinessAddressPostOfficeBox
0038 ##    BusinessAddressPostalCode
0039 ##    BusinessAddressState
0040 ##    BusinessAddressStreet
0041 ##    BusinessFaxNumber
0042 ##    BusinessHomePage
0043 ##    BusinessTelephoneNumber
0044 ##    CallbackTelephoneNumber
0045 ##    CarTelephoneNumber
0046 ##    Categories
0047 ##    Children
0048 ##    Class
0049 ##    Companies
0050 ##    CompanyAndFullName
0051 ##    CompanyLastFirstNoSpace
0052 ##    CompanyLastFirstSpaceOnly
0053 ##    CompanyMainTelephoneNumber
0054 ##    CompanyName
0055 ##    ComputerNetworkName
0056 ##    ConversationIndex
0057 ##    ConversationTopic
0058 ##    CustomerID
0059 ##    Department
0060 ##    Email1Address
0061 ##    Email1AddressType
0062 ##    Email1DisplayName
0063 ##    Email1EntryID
0064 ##    Email2Address
0065 ##    Email2AddressType
0066 ##    Email2DisplayName
0067 ##    Email2EntryID
0068 ##    Email3Address
0069 ##    Email3AddressType
0070 ##    Email3DisplayName
0071 ##    Email3EntryID
0072 ##    EntryID
0073 ##    FTPSite
0074 ##    FileAs
0075 ##    FirstName
0076 ##    FullName
0077 ##    FullNameAndCompany
0078 ##    Gender
0079 ##    GovernmentIDNumber
0080 ##    Hobby
0081 ##    Home2TelephoneNumber
0082 ##    HomeAddress
0083 ##    HomeAddressCity
0084 ##    HomeAddressCountry
0085 ##    HomeAddressPostOfficeBox
0086 ##    HomeAddressPostalCode
0087 ##    HomeAddressState
0088 ##    HomeAddressStreet
0089 ##    HomeFaxNumber
0090 ##    HomeTelephoneNumber
0091 ##    ISDNNumber
0092 ##    Importance
0093 ##    Initials
0094 ##    InternetFreeBusyAddress
0095 ##    JobTitle
0096 ##    Journal
0097 ##    Language
0098 ##    LastFirstAndSuffix
0099 ##    LastFirstNoSpace
0100 ##    LastFirstNoSpaceCompany
0101 ##    LastFirstSpaceOnly
0102 ##    LastFirstSpaceOnlyCompany
0103 ##    LastName
0104 ##    LastNameAndFirstName
0105 ##    MailingAddress
0106 ##    MailingAddressCity
0107 ##    MailingAddressCountry
0108 ##    MailingAddressPostOfficeBox
0109 ##    MailingAddressPostalCode
0110 ##    MailingAddressState
0111 ##    MailingAddressStreet
0112 ##    ManagerName
0113 ##    MessageClass
0114 ##    MiddleName
0115 ##    Mileage
0116 ##    MobileTelephoneNumber
0117 ##    NetMeetingAlias
0118 ##    NetMeetingServer
0119 ##    NickName
0120 ##    NoAging
0121 ##    OfficeLocation
0122 ##    OrganizationalIDNumber
0123 ##    OtherAddress
0124 ##    OtherAddressCity
0125 ##    OtherAddressCountry
0126 ##    OtherAddressPostOfficeBox
0127 ##    OtherAddressPostalCode
0128 ##    OtherAddressState
0129 ##    OtherAddressStreet
0130 ##    OtherFaxNumber
0131 ##    OtherTelephoneNumber
0132 ##    OutlookInternalVersion
0133 ##    OutlookVersion
0134 ##    PagerNumber
0135 ##    PersonalHomePage
0136 ##    PrimaryTelephoneNumber
0137 ##    Profession
0138 ##    RadioTelephoneNumber
0139 ##    ReferredBy
0140 ##    Saved
0141 ##    SelectedMailingAddress
0142 ##    Sensitivity
0143 ##    Size
0144 ##    Spouse
0145 ##    Subject
0146 ##    Suffix
0147 ##    TTYTDDTelephoneNumber
0148 ##    TelexNumber
0149 ##    Title
0150 ##    UnRead
0151 ##    User1
0152 ##    User2
0153 ##    User3
0154 ##    User4
0155 ##    UserCertificate
0156 ##    WebPage
0157 ##    YomiCompanyName
0158 ##    YomiFirstName
0159 ##YomiLastName
0160 
0161 def getcontacts(folder, keys=None):
0162     """Returns a list of dicts"""
0163 
0164     # There is a gross hack to only return email addresses if they are for SMTP
0165 
0166     res=[]
0167     for oc in range(folder.Items.Count):
0168         contact=folder.Items.Item(oc+1)
0169         if contact.Class == outlook_com.constants.olContact:
0170             record={}
0171             if keys is None:
0172                 keys=[]
0173                 for key in contact._prop_map_get_:
0174                     # work out if it is a property or a method (last field is None for properties)
0175                     if contact._prop_map_get_[key][-1] is None:
0176                         keys.append(key)
0177             for key in keys:
0178                 v=getattr(contact, key)
0179                 if v not in (None, "", "\x00\x00"):
0180                     if isinstance(v, pywintypes.TimeType): # convert from com time
0181                         try:
0182                             v=int(v)
0183                         except ValueError:
0184                             # illegal time value
0185                             continue
0186                     if key=="Categories":
0187                        # for some idiotic reason Outlook uses comma
0188                        # space seperators for this field despite using
0189                        # semi-colon elsewhere for the same field so we
0190                        # munge the data
0191                        v=";".join([x.strip() for x in v.split(",")])
0192                     if key.startswith("Email") and key.endswith("Address"):
0193                        keytype=key+"Type"
0194                        if keytype not in keys:
0195                           if getattr(contact, keytype)!="SMTP":
0196                              continue
0197                           
0198                     record[key]=v
0199             res.append(record)
0200     return res
0201 
0202 def getitemdata(item, record, keys, client):
0203     for k, k_out, convertor_func in keys:
0204         v=getattr(item, k)
0205         if v is None or v=="\x00\x00":
0206             v=''
0207         if convertor_func is not None:
0208             # run through convertor func
0209             try:
0210                 v=convertor_func(record, v, client)
0211             except:
0212                 # failed conversion, skip this field
0213                 raise
0214         # assign in dict if specified
0215         if k_out is not None:
0216             record[k_out]=v
0217     return record
0218 
0219 def getdata(folder, keys=None, preset_dict={}, client=None, post_func=None):
0220     """Returns a list of dicts"""
0221     res=[]
0222     import_errors=[]
0223     if not folder.Items.Count:
0224         # empty folder, just return
0225         return res, import_errors
0226     # prefill keys if necessary
0227     if keys is None:
0228         keys=[]
0229         item=folder.Items.Item(1)
0230         for k in item._prop_map_get_:
0231             if item._prop_map_get_[k][-1] is None:
0232                 keys.append((k, k, None))
0233     # go through the folder and read the data
0234     for i in range(folder.Items.Count):
0235         item=folder.Items.Item(i+1)
0236         record=preset_dict.copy()
0237         try:
0238             getitemdata(item, record, keys, client)
0239             if post_func is None or post_func(item, record, client):
0240                 res.append(record)
0241         except:
0242             import_errors.append(record)
0243     return res, import_errors
0244 
0245 def getfolderfromid(id, default=False, default_type='contacts'):
0246     """Returns a folder object from the supplied id
0247 
0248     @param id: The id of the folder
0249     @param default: If true and the folder can't be found, then return the default"""
0250     onMAPI = getmapinamespace()
0251     try:
0252         folder=onMAPI.GetFolderFromID(id)
0253     except pywintypes.com_error,e:
0254         folder=None
0255         
0256     # ::TODO:: should be supplied default type (contacts, calendar etc)
0257     if default and not folder:
0258         if default_type=='calendar':
0259             default_folder=outlook_com.constants.olFolderCalendar
0260         elif default_type=='notes':
0261             default_folder=outlook_com.constants.olFolderNotes
0262         elif default_type=='tasks':
0263             default_folder=outlook_com.constants.olFolderTasks
0264         else:
0265             # default to contacts, works as before
0266             default_folder=outlook_com.constants.olFolderContacts
0267         folder=onMAPI.GetDefaultFolder(default_folder)
0268     return folder
0269 
0270 def getfoldername(folder):
0271     n=[]
0272     while folder:
0273         try:
0274             n=[folder.Name]+n
0275         except AttributeError:
0276             break # namespace object has no 'Name'
0277         folder=folder.Parent
0278     return " / ".join(n)
0279 
0280 def getfolderid(folder):
0281     return str(folder.EntryID) # de-unicodify it
0282 
0283 def pickfolder():
0284     return getmapinamespace().PickFolder()
0285 
0286 _outlookappobject=None
0287 def getoutlookapp():
0288     global _outlookappobject
0289     if _outlookappobject is None:
0290         _outlookappobject=outlook_com.Application()
0291     return _outlookappobject
0292 
0293 _mapinamespaceobject=None
0294 def getmapinamespace():
0295     global _mapinamespaceobject
0296     if _mapinamespaceobject is None:
0297         _mapinamespaceobject=getoutlookapp().GetNamespace("MAPI")
0298     return _mapinamespaceobject
0299 
0300 def releaseoutlook():
0301     global _mapinamespaceobject
0302     global _outlookappobject
0303     _mapinamespaceobject=None
0304     _outlookappobject=None
0305 
0306 
0307 if __name__=='__main__':
0308     oOutlookApp=outlook_com.Application()
0309     onMAPI = oOutlookApp.GetNamespace("MAPI")
0310 
0311     import guihelper # needed for common.strorunicode symbol
0312 
0313     res=onMAPI.PickFolder()
0314     print res
0315 
0316     contacts=getcontacts(res)
0317     keys={}
0318     for item in contacts:
0319         for k in item.keys():
0320             keys[k]=1
0321     keys=keys.keys()
0322     keys.sort()
0323 
0324     # Print out keys so they can be pasted in elsewhere
0325     for k in keys:
0326         print "   ('%s',  )," % (k,)
0327 
0328     import wx
0329     import wx.grid
0330 
0331     app=wx.PySimpleApp()
0332     import wx.lib.colourdb
0333     wx.lib.colourdb.updateColourDB()
0334 
0335     
0336     f=wx.Frame(None, -1, "Outlookinfo")
0337     g=wx.grid.Grid(f, -1)
0338     g.CreateGrid(len(contacts)+1,len(keys))
0339     g.SetColLabelSize(0)
0340     g.SetRowLabelSize(0)
0341     g.SetMargins(1,0)
0342     g.BeginBatch()
0343     attr=wx.grid.GridCellAttr()
0344     attr.SetBackgroundColour(wx.GREEN)
0345     attr.SetFont(wx.Font(10,wx.SWISS, wx.NORMAL, wx.BOLD))
0346     attr.SetReadOnly(True)
0347     for k in range(len(keys)):
0348         g.SetCellValue(0, k, keys[k])
0349     g.SetRowAttr(0,attr)
0350     # row attributes
0351     oddattr=wx.grid.GridCellAttr()
0352     oddattr.SetBackgroundColour("OLDLACE")
0353     oddattr.SetReadOnly(True)
0354     evenattr=wx.grid.GridCellAttr()
0355     evenattr.SetBackgroundColour("ALICE BLUE")
0356     evenattr.SetReadOnly(True)
0357     for row in range(len(contacts)):
0358         item=contacts[row]
0359         for col in range(len(keys)):
0360             key=keys[col]
0361             v=item.get(key, "")
0362             v=common.strorunicode(v)
0363             g.SetCellValue(row+1, col, v)
0364         g.SetRowAttr(row+1, (evenattr,oddattr)[row%2])
0365 
0366     g.AutoSizeColumns()
0367     g.AutoSizeRows()
0368     g.EndBatch()
0369 
0370     f.Show(True)
0371     app.MainLoop()
0372 

Generated by PyXR 0.9.4