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
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
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
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
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)
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
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:
178 try:
179 fields.AddField(key, value)
180 except:
181 pass
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
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
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
248
277