Package modules :: Module contacts_opimd
[hide private]
[frames] | no frames]

Source Code for Module modules.contacts_opimd

  1  """  
  2  Syncronize with OPIMD 
  3   
  4  General information about opimd is available here (L{http://wiki.openmoko.org/wiki/Opimd}). 
  5   
  6  This file is part of Pisi. 
  7   
  8  Pisi is free software: you can redistribute it and/or modify 
  9  it under the terms of the GNU General Public License as published by 
 10  the Free Software Foundation, either version 3 of the License, or 
 11  (at your option) any later version. 
 12   
 13  Pisi is distributed in the hope that it will be useful, 
 14  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  GNU General Public License for more details. 
 17   
 18  You should have received a copy of the GNU General Public License 
 19  along with Pisi.  If not, see <http://www.gnu.org/licenses/> 
 20   
 21  """ 
 22   
 23  import os.path 
 24  import sys,os,re 
 25  import dbus, e_dbus 
 26   
 27  # Allows us to import contact 
 28  sys.path.insert(0,os.path.abspath(__file__+"/../..")) 
 29  from contacts import contacts 
 30  from pisiconstants import * 
 31  import pisiprogress 
 32   
 33  BUSNAME = "org.freesmartphone.opimd" 
 34  PATH_CONTACTS = "/org/freesmartphone/PIM/Contacts" 
 35  INTERFACE_CONTACTS = "org.freesmartphone.PIM.Contacts" 
 36  INTERFACE_QUERY = "org.freesmartphone.PIM.ContactQuery" 
 37  INTERFACE_CONTACT = "org.freesmartphone.PIM.Contact" 
 38  INTERFACE_FIELDS = "org.freesmartphone.PIM.Fields" 
 39   
 40  BACKEND_TYPE_SQLITE = "SQLite-Contacts" 
 41  CONF_FIELDSUPPORT = "field_support" 
 42   
 43   
 44  """Type assignment 
 45   
 46  Available Types are: 
 47  objectpath, phonenumber, address, email, name, date, uri, photo, text, longtext, boolean, timezone, number, integer, generic  
 48   
 49  See U{http://wiki.openmoko.org/wiki/Opimd_redesign#Changes_in_fields} for details. 
 50  """ 
 51  TYPE_DEFS = {  
 52      "Name": 'name',  
 53      "Middlename": 'name',  
 54      "Surname": 'name',  
 55      "Email": 'email',  
 56      "Phone": 'phonenumber',  
 57      "Mobile phone": 'phonenumber',  
 58      "Home phone": 'phonenumber',  
 59      "Work phone": 'phonenumber',  
 60      "HomeStreet": 'address',  
 61      "HomePostalCode": 'address',  
 62      "HomeCity": 'address',  
 63      "HomeCountry": 'address',  
 64      "HomeState": 'address',  
 65      "Organisation": None,  
 66      "BusinessPostalCode": 'address',  
 67      "BusinessStreet": 'address',  
 68      "BusinessCity": 'address',  
 69      "BusinessCountry": 'address',  
 70      "BusinessState": 'address',  
 71      "Fax phone": 'phonenumber',  
 72      "Title": None,  
 73      "Departement": None,  
 74  } 
 75   
76 -class SynchronizationModule(contacts.AbstractContactSynchronizationModule):
77 """ 78 The implementation of the interface L{contacts.AbstractContactSynchronizationModule} for OPIMD persistence backend 79 """
80 - def __init__( self, modulesString, config, configsection, folder, verbose=False, soft=False):
81 """ 82 Constructor 83 84 Super class constructor (L{contacts.AbstractContactSynchronizationModule.__init__}) is called. 85 Local variables are initialized. 86 """ 87 contacts.AbstractContactSynchronizationModule.__init__(self, verbose, soft, modulesString, config, configsection, "OPIMD") 88 pisiprogress.getCallback().verbose('contact opimd module loaded using file') 89 try: 90 mode = config.get(configsection, CONF_FIELDSUPPORT) 91 self._fieldSupport = mode and mode.lower() == "true" 92 except: 93 self._fieldSupport = False 94 self._idMappingInternalGlobal = {} 95 self._idMappingGlobalInternal = {}
96
97 - def _extractValue(self, atts, attName, contactObject, opimdField):
98 """ 99 Supporting function to extract a single attribute value 100 """ 101 atts[attName] = contactObject.GetContent().get(opimdField) 102 if not atts[attName]: 103 atts[attName] = ''
104
105 - def load(self):
106 """ 107 Loads all attributes for all contact entries from the OPIMD backend 108 109 For each entry a new L{contacts.contacts.Contact} instance is created and stored in the instance dictionary L{contacts.AbstractContactSynchronizationModule._allContacts}. 110 """ 111 pisiprogress.getCallback().verbose("OPIMD: Loading") 112 113 bus = dbus.SystemBus(mainloop = e_dbus.DBusEcoreMainLoop()) 114 dbusObject = bus.get_object(BUSNAME, PATH_CONTACTS) 115 contactsInterface = dbus.Interface(dbusObject, dbus_interface= INTERFACE_CONTACTS) 116 query = contactsInterface.Query({}) 117 118 dbusObject = bus.get_object(BUSNAME, query) 119 query = dbus.Interface(dbusObject, dbus_interface=INTERFACE_QUERY) 120 count = query.GetResultCount() 121 122 pisiprogress.getCallback().progress.setProgress(20) # we guess that the actual query took up 20 % of the time - the remaining 80 % are taken by parsing the content ... 123 pisiprogress.getCallback().update('Loading') 124 i=0 125 for contact in query.GetMultipleResults(count): 126 atts = {} 127 128 dbusObject = bus.get_object(BUSNAME, contact.get('Path')) 129 contactObject = dbus.Interface(dbusObject, dbus_interface= INTERFACE_CONTACT) 130 131 self._extractValue(atts, 'firstname', contactObject, 'Name') 132 self._extractValue(atts, 'middlename', contactObject, 'Middlename') 133 self._extractValue(atts, 'lastname', contactObject, 'Surname') 134 self._extractValue(atts, 'email', contactObject, 'E-mail') 135 self._extractValue(atts, 'mobile', contactObject, 'Phone') 136 if not atts['mobile']: 137 self._extractValue(atts, 'mobile', contactObject, 'Mobile phone') 138 self._extractValue(atts, 'phone', contactObject, 'Home phone') 139 self._extractValue(atts, 'officePhone', contactObject, 'Work phone') 140 self._extractValue(atts, 'fax', contactObject, 'Fax phone') 141 142 self._extractValue(atts, 'title', contactObject, 'Title') 143 self._extractValue(atts, 'businessOrganisation', contactObject, 'Organisation') 144 self._extractValue(atts, 'businessDepartment', contactObject, 'Departement') 145 146 self._extractValue(atts, 'businessStreet', contactObject, 'BusinessStreet') 147 self._extractValue(atts, 'businessPostalCode', contactObject, 'BusinessPostalCode') 148 self._extractValue(atts, 'businessCity', contactObject, 'BusinessCity') 149 self._extractValue(atts, 'businessCountry', contactObject, 'BusinessCountry') 150 self._extractValue(atts, 'businessState', contactObject, 'BusinessState') 151 152 self._extractValue(atts, 'homeStreet', contactObject, 'HomeStreet') 153 self._extractValue(atts, 'homePostalCode', contactObject, 'HomePostalCode') 154 self._extractValue(atts, 'homeCity', contactObject, 'HomeCity') 155 self._extractValue(atts, 'homeCountry', contactObject, 'HomeCountry') 156 self._extractValue(atts, 'homeState', contactObject, 'HomeState') 157 158 id = contacts.assembleID(atts) 159 c = contacts.Contact(id, atts) 160 self._allContacts[id] = c 161 self._idMappingGlobalInternal[id] = contact.get('Path') 162 self._idMappingInternalGlobal[contact.get('Path')] = id 163 164 i+=1 165 pisiprogress.getCallback().progress.setProgress(20 + ((i*80) / count)) 166 pisiprogress.getCallback().update('Loading')
167
168 - def _checkAndApplyTypes(self):
169 """ 170 Makes sure that all required types for PISI are available in OPIMD. 171 """ 172 bus = dbus.SystemBus(mainloop = e_dbus.DBusEcoreMainLoop()) 173 dbusObject = bus.get_object(BUSNAME, PATH_CONTACTS) 174 fields = dbus.Interface(dbusObject, dbus_interface=INTERFACE_FIELDS) 175 176 for key, value in TYPE_DEFS.items(): 177 if value: # do not proceed if NONE 178 try: 179 fields.AddField(key, value) 180 except: 181 pass # don't care about that - we have checked that before; can't add twice
182
183 - def _saveOneEntry(self, fields, fieldName, contact, attribute):
184 try: 185 fields[fieldName] = contact.attributes[attribute] 186 except KeyError: 187 fields[fieldName] = "" 188 if not fields[fieldName]: 189 fields[fieldName] = ""
190
191 - def _saveOperationAdd(self, id):
192 """ 193 Making changes permanent: Add a single contact instance to backend 194 """ 195 contact = self.getContact(id) 196 197 bus = dbus.SystemBus(mainloop = e_dbus.DBusEcoreMainLoop()) 198 dbusObject = bus.get_object(BUSNAME, PATH_CONTACTS) 199 contacts = dbus.Interface(dbusObject, dbus_interface=INTERFACE_CONTACTS) 200 201 if self._fieldSupport: 202 self._checkAndApplyTypes() 203 204 fields = {} 205 self._saveOneEntry(fields, 'Name', contact,'firstname' ) 206 self._saveOneEntry(fields, 'Surname', contact, 'lastname') 207 self._saveOneEntry(fields, 'Middlename', contact,'middlename' ) 208 self._saveOneEntry(fields, 'E-mail', contact, 'email') 209 self._saveOneEntry(fields, 'Mobile phone', contact, 'mobile') 210 self._saveOneEntry(fields, 'Work phone', contact, 'officePhone') 211 self._saveOneEntry(fields, 'Home phone', contact, 'phone') 212 self._saveOneEntry(fields, 'Fax phone', contact,'fax' ) 213 214 self._saveOneEntry(fields, 'Title', contact, 'title') 215 self._saveOneEntry(fields, 'Organisation', contact,'businessOrganisation' ) 216 self._saveOneEntry(fields, 'Departement', contact, 'businessDepartment') 217 218 self._saveOneEntry(fields, 'BusinessStreet', contact, 'businessStreet') 219 self._saveOneEntry(fields, 'BusinessPostalCode', contact, 'businessPostalCode') 220 self._saveOneEntry(fields, 'BusinessCity', contact, 'businessCity') 221 self._saveOneEntry(fields, 'BusinessCountry', contact, 'businessCountry') 222 self._saveOneEntry(fields, 'BusinessState', contact, 'businessState') 223 224 self._saveOneEntry(fields, 'HomeStreet', contact,'homeStreet' ) 225 self._saveOneEntry(fields, 'HomePostalCode', contact, 'homePostalCode') 226 self._saveOneEntry(fields, 'HomeCity', contact,'homeCity' ) 227 self._saveOneEntry(fields, 'HomeCountry', contact, 'homeCountry') 228 self._saveOneEntry(fields,'HomeState' , contact, 'homeState') 229 230 contacts.Add(fields)
231
232 - def _saveOperationDelete(self, id):
233 """ 234 Making changes permanent: Remove a single contact instance from backend 235 """ 236 path = self._idMappingGlobalInternal[id] 237 bus = dbus.SystemBus(mainloop = e_dbus.DBusEcoreMainLoop()) 238 dbusObject = bus.get_object(BUSNAME, path) 239 contactObject = dbus.Interface(dbusObject, dbus_interface= INTERFACE_CONTACT) 240 contactObject.Delete()
241
242 - def _saveOperationModify(self, id):
243 """ 244 Making changes permanent: Update a single contact instance in backend 245 """ 246 self._saveOperationDelete(id) 247 self._saveOperationAdd(id)
248
249 - def saveModifications(self):
250 """ 251 Save whatever changes have come by 252 253 The history of actions for this data source is iterated. For each item in there the corresponding action is carried out on the item in question. 254 This function is just a dispatcher to one of the three functions L{_saveOperationAdd}, L{_saveOperationDelete} or L{_saveOperationModify}. 255 """ 256 pisiprogress.getCallback().verbose("OPIMD module: I apply %d changes now" %(len(self._history))) 257 258 i=0 259 for listItem in self._history: 260 action = listItem[0] 261 id = listItem[1] 262 if action == ACTIONID_ADD: 263 pisiprogress.getCallback().verbose( "\t\t<opimd> adding %s" %(id)) 264 self._saveOperationAdd(id) 265 elif action == ACTIONID_DELETE: 266 pisiprogress.getCallback().verbose("\t\t<opimd> deleting %s" %(id)) 267 self._saveOperationDelete(id) 268 elif action == ACTIONID_MODIFY: 269 pisiprogress.getCallback().verbose("\t\t<opimd> replacing %s" %(id)) 270 self._saveOperationModify(id) 271 i+=1 272 pisiprogress.getCallback().progress.setProgress(i * 90 / len(self._history)) 273 pisiprogress.getCallback().update('Storing') 274 275 pisiprogress.getCallback().progress.setProgress(100) 276 pisiprogress.getCallback().update('Storing')
277