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

Source Code for Module modules.contacts_evolution

  1  """ 
  2  Sync contact information with Evolution on a Desktop. 
  3   
  4  This file is part of Pisi. 
  5   
  6  Pisi is free software: you can redistribute it and/or modify 
  7  it under the terms of the GNU General Public License as published by 
  8  the Free Software Foundation, either version 3 of the License, or 
  9  (at your option) any later version. 
 10   
 11  Pisi is distributed in the hope that it will be useful, 
 12  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  GNU General Public License for more details. 
 15   
 16  You should have received a copy of the GNU General Public License 
 17  along with Pisi.  If not, see <http://www.gnu.org/licenses/>. 
 18  """ 
 19   
 20  from contacts import contacts 
 21  from pisiconstants import * 
 22  import pisiprogress 
 23   
 24  import bsddb 
 25  import vobject   
 26  from vobjecttools import * 
 27  import random 
 28   
29 -class SynchronizationModule(contacts.AbstractContactSynchronizationModule):
30 - def __init__( self, modulesString, config, configsection, folder, verbose=False, soft=False):
31 """ 32 Constructor 33 34 Super class constructor (L{contacts.AbstractContactSynchronizationModule.__init__}) is called. 35 Local variables are initialized. 36 The settings from the configuration file are loaded. 37 38 @param modulesString: is a small string to help you make a unique id. It is the two modules configuration-names concatinated. 39 @param config: is the configuration from ~/.pisi/conf. Use like config.get(configsection,'user') 40 @param configsection: is the configuration from ~/.pisi/conf. Use like config.get(configsection,'user') 41 @param folder: is a string with the location for where your module can save its own files if necessary 42 @param verbose: should make your module "talk" more 43 @param soft: should tell you if you should make changes (ie. save) 44 """ 45 contacts.AbstractContactSynchronizationModule.__init__(self, verbose, soft, modulesString, config, configsection, "Contacts Evolution") 46 self.verbose = verbose 47 self._path = config.get(configsection,'path') 48 self._rawData = {} 49 self._edsIDs = {} 50 pisiprogress.getCallback().verbose("Evolution contacts module loaded")
51 52
53 - def load(self):
54 """ 55 Load all data from backend 56 """ 57 pisiprogress.getCallback().verbose ("Evolution: Loading") 58 pisiprogress.getCallback().progress.push(0, 100) 59 file = bsddb.hashopen(self._path) 60 pisiprogress.getCallback().update("Loading") 61 amount = len(file.keys()) 62 i = 0 63 for key in file.keys(): 64 data = file[key] 65 # print data 66 if not data.startswith('BEGIN:VCARD'): 67 continue 68 comps = vobject.readComponents(data[:len(data)-1]) # there is some problem with a traling white space in each entry 69 for x in comps: 70 # print x.n.value.given 71 72 atts = extractVcfEntry(x) 73 id = contacts.assembleID(atts) 74 c = contacts.Contact(id, atts) 75 self._allContacts[id] = c 76 self._rawData[id] = x 77 self._edsIDs[id] = key 78 i+=1 79 pisiprogress.getCallback().progress.setProgress((i*100) / amount) 80 pisiprogress.getCallback().update('Loading') 81 pisiprogress.getCallback().progress.drop()
82
83 - def _generateEDS_ID(self):
84 """ 85 IDs from EDS look like being a 16 digit Hex String 86 """ 87 st = "" 88 for i in range (16): 89 k = random.randint(0, 15) 90 if k > 9: 91 st += chr(k + 55) 92 else: 93 st += str(k) 94 return 'pas-id-' + st
95
96 - def _applyEDSChangesToVcf(self, j, id):
97 # 1. Add EDS specific ID 98 try: 99 eds_id = self._edsIDs[id] 100 except KeyError: 101 eds_id = self._generateEDS_ID() 102 self._edsIDs[id] = eds_id 103 jid = j.add('uid') 104 jid.value = eds_id 105 106 # 2. Remove postal from addresses 107 try: 108 for addr in j.contents['adr']: 109 try: 110 pos = addr.params['TYPE'].index('POSTAL') 111 del addr.params['TYPE'][pos] 112 except ValueError: 113 pass # fine; no postal in there at all 114 except KeyError: 115 pass # fine; this entry hasn't got any addresses 116 117 # 3. Remove Voice from phone numbers 118 try: 119 for tel in j.contents['tel']: 120 try: 121 pos = tel.params['TYPE'].index('VOICE') 122 del tel.params['TYPE'][pos] 123 except ValueError: 124 pass # fine; no voice in there at all 125 except KeyError: 126 pass # no phone number; that's alright 127 128 129 return eds_id
130
131 - def _saveAdd(self, id, file):
132 c = self.getContact(id) 133 rawContact = createRawVcard(c) 134 eds_id = self._applyEDSChangesToVcf(rawContact, id) 135 file[eds_id] = rawContact.serialize()
136
137 - def _saveDel(self, id, file):
138 key = self._edsIDs[id] 139 del file[key]
140
141 - def _saveModify(self, id, file):
142 self._saveDel(id, file) 143 self._saveAdd(id, file)
144
145 - def saveModifications( self ):
146 """ 147 Save whatever changes have come by 148 """ 149 pisiprogress.getCallback().verbose("Evolution module: I apply %d changes now" %(len(self._history))) 150 151 if len(self._history) == 0: 152 return # don't touch anything if there haven't been any changes 153 154 file = bsddb.hashopen(self._path) 155 for listItem in self._history: 156 action = listItem[0] 157 id = listItem[1] 158 if action == ACTIONID_ADD: 159 pisiprogress.getCallback().verbose("\t\t<evolution contacts> adding %s" %(id)) 160 self._saveAdd(id, file) 161 elif action == ACTIONID_DELETE: 162 pisiprogress.getCallback().verbose("\t\t<evolution contacts> deleting %s" %(id)) 163 self._saveDel(id, file) 164 elif action == ACTIONID_MODIFY: 165 pisiprogress.getCallback().verbose("\t\t<evolution contacts> replacing %s" %(id)) 166 self._saveModify(id, file) 167 168 file.sync()
169