1 """Additional layer to vobject site-package"""
2
3 from pisiconstants import *
4 import vobject
5 import datetime
6 from events import events
7
8 """Indentifies a phone entry as home phone"""
9 VCF_PHONETYPE_HOME = [['HOME', 'VOICE'], ['VOICE', 'HOME'], ['HOME']]
10 """Indentifies a phone entry as work phone"""
11 VCF_PHONETYPE_WORK = [['WORK', 'VOICE'], ['VOICE', 'WORK'], ['WORK']]
12 """Indentifies a phone entry as mobile phone"""
13 VCF_PHONETYPE_MOBILE = [['CELL', 'VOICE'], ['VOICE', 'CELL'], ['CELL'], ['VOICE']]
14 """Indentifies a phone entry as fax"""
15 VCF_PHONETYPE_FAX = [['FAX']]
16 """Entries to remove before comparing"""
17 VCF_PHONETYPE_IGNORELIST = ['OTHER']
18
19 """Indentifies an address entry as home address"""
20 VCF_ADDRESSTYPE_HOME = [['HOME', 'POSTAL'], ['POSTAL', 'HOME'], ['HOME']]
21 """Indentifies an address entry as work address"""
22 VCF_ADDRESSTYPE_WORK = [['WORK', 'POSTAL'], ['POSTAL', 'WORK'], ['WORK']]
23
24
26 """
27 Supporting function for pulling information out of a attribute
28
29 Gets around problems with non available attributes without the need for checking this beforehand for each attribute.
30 """
31 try:
32 ret = None
33 exec "ret = " + st
34 return ret
35 except AttributeError:
36 return ''
37
38
39
40
41
43 """
44 Walks an entire vobject vcard entity and stores all information in a dictionary, which is returned in the end
45
46 For mapping the PISI rules are applied.
47 """
48 atts = {}
49 atts['firstname'] = _extractAtt(x, 'x.n.value.given')
50 atts['middlename'] = _extractAtt(x, 'x.n.value.additional')
51 atts['lastname'] = _extractAtt(x, 'x.n.value.family')
52
53 atts['email'] = _extractAtt(x, 'x.email.value')
54 atts['title'] = _extractAtt(x, 'x.title.value')
55
56
57 try:
58 for tel in x.contents['tel']:
59 if not tel.params.has_key('TYPE'):
60 if defaultPhonetype:
61 atts[defaultPhonetype] = tel.value
62 else:
63 for i in range(len(tel.params['TYPE'])):
64 tel.params['TYPE'][i] = tel.params['TYPE'][i].upper()
65 for ign in VCF_PHONETYPE_IGNORELIST:
66 try:
67 del tel.params['TYPE'][tel.params['TYPE'].index(ign)]
68 except ValueError:
69 pass
70 if tel.params['TYPE'] in VCF_PHONETYPE_HOME:
71 atts['phone'] = tel.value
72 elif tel.params['TYPE'] in VCF_PHONETYPE_MOBILE:
73 atts['mobile'] = tel.value
74 elif tel.params['TYPE'] in VCF_PHONETYPE_WORK:
75 atts['officePhone'] = tel.value
76 elif tel.params['TYPE'] in VCF_PHONETYPE_FAX:
77 atts['fax'] = tel.value
78 except KeyError:
79 pass
80
81
82 try:
83 for addr in x.contents['adr']:
84 for i in range(len(addr.params['TYPE'])):
85 addr.params['TYPE'][i] = addr.params['TYPE'][i].upper()
86 if addr.params['TYPE'] in VCF_ADDRESSTYPE_HOME:
87 atts['homeStreet'] = addr.value.street
88 atts['homeCity'] = addr.value.city
89 atts['homeState'] = addr.value.region
90 atts['homePostalCode'] = addr.value.code
91 atts['homeCountry'] = addr.value.country
92 elif addr.params['TYPE'] in VCF_ADDRESSTYPE_WORK:
93 atts['businessStreet'] = addr.value.street
94 atts['businessCity'] = addr.value.city
95 atts['businessState'] = addr.value.region
96 atts['businessPostalCode'] = addr.value.code
97 atts['businessCountry'] = addr.value.country
98 except KeyError:
99 pass
100
101 try:
102 atts['businessOrganisation'] = x.org.value[0]
103 atts['businessDepartment'] = x.org.value[1]
104 except:
105 pass
106 return atts
107
108
109
110
111
112
113
115 """
116 Supporting function for adding a single attribute to vcard raw object
117 """
118 try:
119 v = None
120 if value != None:
121 exec ("v =" + value)
122 if v != None and v != '':
123 j.add(att)
124 exec ("j." + att + ".value = " + value)
125 for param in params:
126 exec("j." + att + "." + param[0] + "=" + param[1] )
127 except KeyError:
128 pass
129
131 family = c.attributes['lastname']
132 if family == None:
133 family = ''
134 given = c.attributes['firstname']
135 if given == None:
136 given = ''
137 additional = c.attributes['middlename']
138 if additional == None:
139 additional = ''
140 if family == '' and given == '' and additional == '':
141 c.prettyPrint()
142 nameEntry = vobject.vcard.Name(family = family, given = given, additional = additional)
143 n = j.add('n')
144 n.value = nameEntry
145
147 """
148 Create and append phone entry
149
150 Phone entries are a bit tricky - you cannot access each of them directly as they all have the same attribute key (tel). Consequently, we have to access the dictionary for phones directly.
151 """
152 try:
153 if type in VCF_PHONETYPE_HOME:
154 value = c.attributes['phone']
155 elif type in VCF_PHONETYPE_WORK:
156 value = c.attributes['officePhone']
157 elif type in VCF_PHONETYPE_MOBILE:
158 value = c.attributes['mobile']
159 elif type in VCF_PHONETYPE_FAX:
160 value = c.attributes['fax']
161 if value == '' or value == None:
162 return
163 tel = j.add('tel')
164 tel.value = value
165 tel.type_param = type
166 except KeyError:
167 pass
168
170 try:
171 return dict[att]
172 except KeyError:
173 return ''
174
176 """
177 Create and append address entry
178
179 Entry is only created if city is set.
180 """
181 if type in VCF_ADDRESSTYPE_HOME:
182 street = _attFromDict(c.attributes, 'homeStreet')
183 postalCode = _attFromDict(c.attributes, 'homePostalCode')
184 city = _attFromDict(c.attributes, 'homeCity')
185 country = _attFromDict(c.attributes, 'homeCountry')
186 state = _attFromDict(c.attributes, 'homeState')
187 elif type in VCF_ADDRESSTYPE_WORK:
188 street = _attFromDict(c.attributes, 'businessStreet')
189 postalCode = _attFromDict(c.attributes, 'businessPostalCode')
190 city = _attFromDict(c.attributes, 'businessCity')
191 country = _attFromDict(c.attributes, 'businessCountry')
192 state = _attFromDict(c.attributes, 'businessState')
193 if city == None or city == '':
194 return
195 addr = j.add('adr')
196 addr.value = vobject.vcard.Address(street = street, code = postalCode, city = city, country = country, region = state)
197 addr.type_param = type
198
200 """
201 Creates an entry for business organzation und unit.
202 """
203 if c.attributes.has_key('businessOrganisation'):
204 o = c.attributes['businessOrganisation']
205 if o == None or o == '':
206 return
207 list = []
208 list.append(o)
209 if c.attributes.has_key('businessDepartment'):
210 ou = c.attributes['businessDepartment']
211 if ou != None and ou != '':
212 list.append(ou)
213 j.add('org')
214 j.org.value = list
215
217 """
218 Converts internal contact entry to VObject format
219 """
220 j = vobject.vCard()
221 _createNameAttribute(c, j)
222
223 if c.attributes['firstname']:
224 if c.attributes['lastname']:
225 fn = c.attributes['firstname'] + ' ' + c.attributes['lastname']
226 else:
227 fn = c.attributes['firstname']
228 else:
229 fn = c.attributes['lastname']
230 _createRawAttribute(c, j, 'fn', "'''" + fn + "'''")
231 _createRawAttribute(c, j, 'title', "c.attributes['title']")
232
233 _createRawAttribute(c, j, 'email', "c.attributes['email']", [['type_param', "'INTERNET'"]])
234 _createPhoneAttribute(c, j, VCF_PHONETYPE_HOME[0])
235 _createPhoneAttribute(c, j, VCF_PHONETYPE_WORK[0])
236 _createPhoneAttribute(c, j, VCF_PHONETYPE_MOBILE[0])
237 _createPhoneAttribute(c, j, VCF_PHONETYPE_FAX[0])
238
239 _createAddressAttribute(c, j, VCF_ADDRESSTYPE_HOME[0])
240 _createAddressAttribute(c, j, VCF_ADDRESSTYPE_WORK[0])
241 _createBusinessDetails(c, j)
242 return j
243
267
268
269
270
271
273 """
274 Transforms VObject recurrence information into PISI internal object L{events.Recurrence}
275 """
276 if _extractAtt(x, 'x.dtend.value'):
277 end = x.dtend
278 else:
279 end = None
280 rec = events.Recurrence()
281 rec.initFromAttributes(x.rrule, x.dtstart, end, allDay)
282 return rec
283
285 atts = {}
286 atts['start'] = _extractAtt(x, 'x.dtstart.value')
287 atts['end'] = _extractAtt(x, 'x.dtend.value')
288 if type(x.dtstart.value) ==datetime.date:
289 atts['allday'] = True
290 else:
291 atts['allday'] = False
292
293
294
295
296
297 if type (atts['start']) == unicode:
298 if atts['start'].endswith('Z'):
299 atts['start'] = datetime.datetime.strptime(atts['start'], "%Y%m%dT%H%M%SZ")
300 else:
301 atts['start'] = datetime.datetime.strptime(atts['start'], "%Y%m%dT%H%M%S")
302 if type (atts['end']) == unicode:
303 if atts['end'].endswith('Z'):
304 atts['end'] = datetime.datetime.strptime(atts['end'], "%Y%m%dT%H%M%SZ")
305 else:
306 atts['end'] = datetime.datetime.strptime(atts['end'], "%Y%m%dT%H%M%S")
307
308
309 if atts['start'].tzinfo == None:
310 atts['start'] = atts['start'].replace(tzinfo = events.UTC())
311 if atts['end'].tzinfo == None:
312 atts['end'] = atts['end'].replace(tzinfo = events.UTC())
313 atts['title'] = _extractAtt(x, 'x.summary.value')
314 atts['description'] = _extractAtt(x, 'x.description.value')
315 atts['location'] = _extractAtt(x, 'x.location.value')
316 try:
317 atts['alarmmin'] = x.valarm.trigger.value.days * 24 * 60 + x.valarm.trigger.value.seconds / 60
318 atts['alarm'] = True
319 except AttributeError:
320 atts['alarm'] = False
321 atts['alarmmin'] = 0
322
323 try:
324 atts['recurrence'] = _extractRecurrence(x, atts['allday'] )
325 except AttributeError:
326 atts['recurrence'] = None
327 updated = _extractAtt(x, 'x.last_modified.value')
328
329 if x.contents.has_key('x-pisi-id'):
330 globalId = x.contents['x-pisi-id'][0].value
331 else:
332 globalId = None
333
334 return atts, globalId, updated
335
336
337
338
339
340
342 """
343 Transforms PISI internal recurrence information (L{events.Recurrence}) into vobject representation
344 """
345 if c.attributes['recurrence']:
346 rec = c.attributes['recurrence']
347 cal.add('rrule')
348 cal.rrule = rec.getRRule()
349
351 """
352 Transforms PISI internal alarm information (1 single integer for minutes) into vobject representation
353 """
354 if c.attributes['alarm']:
355 mins = c.attributes['alarmmin']
356 days = mins / (24 * 60)
357 seconds = (mins - days*(24*60)) * 60
358 cal.add("valarm")
359 cal.valarm.add("trigger")
360 cal.valarm.trigger.value=datetime.timedelta(days,seconds)
361
362 -def createRawEventEntry(c, stupidMode = False):
363 """
364 Transforms PISI internal Calendar event information (L{events.Event}) into vobject representation
365 """
366 frame = vobject.iCalendar()
367 frame.add('vevent')
368 cal = frame.vevent
369 cal.add('dtstart')
370 if c.attributes['allday']:
371 if type(c.attributes['start']) == datetime.datetime:
372 c.attributes['start'] = c.attributes['start'].date()
373 if type(c.attributes['end']) == datetime.datetime:
374 c.attributes['end'] = c.attributes['end'].date()
375 cal.dtstart.value = c.attributes['start']
376 cal.add('dtend')
377 cal.dtend.value = c.attributes['end']
378 if c.attributes['title']:
379 cal.add('summary')
380 cal.summary.value = c.attributes['title']
381 if c.attributes['description']:
382 cal.add('description')
383 cal.description.value = c.attributes['description']
384 if c.attributes['location']:
385 cal.add('location')
386 cal.location.value = c.attributes['location']
387 cal.add('x-pisi-id')
388 cal.contents['x-pisi-id'][0].value = c.attributes['globalid']
389 _createRecurrencePart(c, cal)
390 _createAlarmPart(c, cal)
391 cal.add('last-modified')
392 cal.last_modified.value = datetime.datetime.now(events.UTC())
393 return cal
394