Package native :: Package evolution :: Module evolution
[hide private]
[frames] | no frames]

Source Code for Module native.evolution.evolution

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2004 Roger Binns <rogerb@rogerbinns.com> 
  4  ### Copyright (C) 2004 Peter Pletcher <peterpl@pacbell.net> 
  5  ### 
  6  ### This program is free software; you can redistribute it and/or modify 
  7  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  8  ### 
  9  ### $Id: evolution.py 1442 2004-07-14 05:14:24Z rogerb $ 
 10   
 11  "Be at one with Evolution" 
 12   
 13  # Evolution mostly sucks when compared to Outlook.  The UI and functionality 
 14  # for the address book is a literal copy.  There is no API as such and we 
 15  # just have to delve around the filesystem 
 16   
 17  # root directory is ~/evolution 
 18  # folders are any directory containing a file named folder-metadata.xml 
 19  # note that folders can be nested 
 20  # 
 21  # the folder name is the directory name.  The folder-metadata.xml file 
 22  # does contain description tag, but it isn't normally displayed and 
 23  # is usually empty for user created folders 
 24  # 
 25  # if the folder contains any addressbook entries, then there will 
 26  # be an addressbook.db file 
 27  # 
 28  # the file should be opened using bsddb 
 29  # import bsddb 
 30  # db=bsddb.hashopen("addressbook.db", "r") 
 31  # db.keys() lists keys, db[key] gets item 
 32  # 
 33  # the item contains exactly one field which is a null terminated string 
 34  # containing a vcard 
 35   
 36   
 37  import sys 
 38  import os 
 39  import re 
 40   
 41  if sys.platform!="linux2": 
 42      raise ImportError() 
 43   
 44  try: 
 45      import bsddb 
 46  except: 
 47      raise ImportError() 
 48   
 49   
 50  userdir=os.path.expanduser("~") 
 51  evolutionpath="evolution/local" 
 52  evolutionbasedir=os.path.join(userdir, evolutionpath) 
 53  evolutionexporter = { 
 54      'command'    : "evolution-addressbook-export", 
 55      'folderid'   : "<Evolution Addressbook Exporter>", 
 56      'name'       : "<Evolution Addressbook Exporter>", 
 57      'type'       : ["address book"] 
 58  } 
 59   
60 -def getcontacts(folder):
61 """Returns the contacts as a list of string vcards 62 63 Note that the Windows EOL convention is used""" 64 65 if folder == evolutionexporter['folderid']: 66 return getcontacts_evoexporter() 67 68 dir=os.path.expanduser(folder) 69 p=os.path.join(dir, "addressbook.db") 70 if not os.path.isfile(p): 71 # ok, this is not an address book folder 72 if not os.path.isfile(os.path.join(dir, "folder-metadata.xml")): 73 raise ValueError("Supplied folder is not a folder! "+folder) 74 raise ValueError("Folder does not contain contacts! "+folder) 75 res=[] 76 db=bsddb.hashopen(p, 'r') 77 for key in db.keys(): 78 if key.startswith("PAS-DB-VERSION"): # no need for this field 79 continue 80 data=db[key] 81 while data[-1]=="\x00": # often has actual null on the end 82 data=data[:-1] 83 res.append(data) 84 db.close() 85 return res
86
87 -class EvolutionExportException(Exception):
88 pass
89
90 -def getcontacts_evoexporter():
91 """Get the cards by running evolution-addressbook-export 92 93 Note that this code returns all the contacts as a single 94 string item. It seemed silly to split them apart when 95 the caller then just puts them back together as one 96 string""" 97 evo_export = os.popen(evolutionexporter['command']) 98 evo_cards = evo_export.read() 99 evo_export_status = evo_export.close() 100 if evo_export_status is not None: 101 raise EvolutionExportException("%s failed with code %s" % (evolutionexporter['command'], `evo_export_status`)) 102 return [evo_cards]
103
104 -def getfsfolders(basedir=evolutionbasedir):
105 106 res={} 107 children=[] 108 109 for f in os.listdir(basedir): 110 p=os.path.join(basedir, f) 111 112 # deal with child folders (depth first) 113 if os.path.isdir(p): 114 f=getfsfolders(p) 115 if len(f): 116 children.extend(f) 117 continue 118 119 # if we have any children, sort them 120 if len(children): 121 lc=[ (child['name'], child) for child in children] # decorate 122 lc.sort() # sort 123 children=[child for _, child in lc] # un-decorate 124 125 126 # do we have a meta-data file? 127 if not os.path.isfile(os.path.join(basedir, "folder-metadata.xml")): 128 return children 129 130 # ok, what type is this folder 131 t=[] 132 for file,type in ( ("mbox", "mailbox"), ("calendar.ics", "calendar"), ("addressbook.db", "address book"), 133 ("tasks.ics", "tasks") ): 134 if os.path.isfile(os.path.join(basedir, file)): 135 t.append(type) 136 137 entry={} 138 entry['dirpath']=basedir 139 entry['name']=os.path.basename(basedir) 140 entry['folderid']=basedir.replace(userdir, "~", 1) 141 entry['type']=t 142 if len(children): 143 entry['children']=children 144 # tell children who their daddy is 145 for c in children: 146 c['parent']=entry 147 148 return [entry]
149
150 -def getspecialfolders():
151 "Return a list of any special folders" 152 153 # the only one we look for currently is evolution-addressbook-export 154 # command 155 evo_version = os.popen(evolutionexporter['command'] + " --version") 156 evo_version_result = evo_version.read() 157 evo_version_status = evo_version.close() 158 if evo_version_status is not None: 159 return [] 160 # it doesn't work with earlier versions of evolution, so we do a version 161 # check 162 if evo_version_result.startswith("Gnome evolution 1.4"): 163 return [evolutionexporter] 164 else: 165 return []
166
167 -def getfolders():
168 return getspecialfolders()+getfsfolders()
169
170 -def pickfolder(selectedid=None, parent=None, title="Select Evolution Folder"):
171 # we do the imports etc in the function so that this file won't 172 # require gui code unless this function is called 173 174 import wx 175 import wx.gizmos 176 177 dlg=wx.Dialog(parent, -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, size=(450,350)) 178 vbs=wx.BoxSizer(wx.VERTICAL) 179 180 tl=wx.gizmos.TreeListCtrl(dlg, -1, style=wx.TR_DEFAULT_STYLE|wx.TR_HIDE_ROOT) 181 182 tl.AddColumn("Name") 183 tl.SetMainColumn(0) 184 tl.AddColumn("Type") 185 tl.SetColumnWidth(0, 300) 186 187 188 189 def addnode(parent, item, selected): 190 node=tl.AppendItem(parent, item['name']) 191 if selected==item['folderid']: 192 tl.SelectItem(node) 193 tl.SetItemText(node, ", ".join(item['type']), 1) 194 tl.SetPyData(node, item) 195 if item.has_key("children"): 196 for child in item['children']: 197 addnode(node, child, selected) 198 tl.Expand(node)
199 200 root=tl.AddRoot("?") 201 tl.SetPyData(root, None) 202 203 for f in getfolders(): 204 addnode(root, f, selectedid) 205 206 # select first folder if nothing is selected 207 if tl.GetPyData(tl.GetSelection()) is None: 208 child,_=tl.GetFirstChild(root, 1234) 209 tl.SelectItem(child) 210 211 vbs.Add(tl, 1, wx.EXPAND|wx.ALL, 5) 212 213 vbs.Add(wx.StaticLine(dlg, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL, 5) 214 215 vbs.Add(dlg.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALIGN_CENTRE|wx.ALL, 5) 216 217 dlg.SetSizer(vbs) 218 dlg.SetAutoLayout(True) 219 220 if dlg.ShowModal()==wx.ID_OK: 221 folderid=tl.GetPyData(tl.GetSelection())['folderid'] 222 else: 223 folderid=None 224 dlg.Destroy() 225 return folderid 226 227 # we use a pathname like "~/evolution/local/Contacts" as the folder id 228 # and the same as a "folder" 229
230 -class Match:
231 - def __init__(self, folder):
232 self.folder=folder
233
234 -def getfolderfromid(id, default=False):
235 "Return a folder object given the id" 236 237 f=_findfolder(id) 238 if f is not None: 239 return f['folderid'] 240 241 if default: 242 # look for a default 243 for f in getfolders(): 244 if "address book" in f['type']: 245 return f["folderid"] 246 # brute force 247 return getfolders()[0]['folderid'] 248 249 return None
250
251 -def __findfolder(node, id):
252 "Recursive function to locate a folder, using Match exception to return the found folder" 253 if node['folderid']==id: 254 raise Match(node) 255 for c in node.get("children", []): 256 __findfolder(c, id)
257
258 -def _findfolder(id):
259 for f in getfolders(): 260 try: 261 __findfolder(f, id) 262 except Match,m: 263 return m.folder # we found it 264 return None
265 266
267 -def getfoldername(id):
268 f=_findfolder(id) 269 if f is None: 270 raise AttributeError("No such folder "+id) 271 272 n=[] 273 while f: 274 n=[f['name']]+n 275 f=f.get('parent',None) 276 277 return " / ".join(n)
278
279 -def getfolderid(folder):
280 return folder
281 282 283 if __name__=="__main__": 284 # a folder selector 285 import wx 286 import wx.gizmos 287 288 app=wx.PySimpleApp() 289 290 folder=pickfolder() 291 print folder 292 293 print "\n".join(getcontacts(folder)) 294