Big update to 0.1.0. Improved error handling, syncing, the works...
[hermes] / package / src / contacts.py
1 import os
2 import os.path
3 import urllib
4 import Image
5 import ImageOps
6 import StringIO
7 import datetime
8 import re
9 from pygobject import *
10 from ctypes import *
11
12 # Constants from http://library.gnome.org/devel/libebook/stable/EContact.html#EContactField
13 ebook = CDLL('libebook-1.2.so.5')
14 E_CONTACT_HOMEPAGE_URL = 42
15 E_CONTACT_PHOTO = 94
16 E_CONTACT_BIRTHDAY_DATE = 107
17
18
19 class ContactStore:
20   """Provide an API for changing contact data. Abstracts limitations
21      in the evolution-python bindings.
22
23      Copyright (c) Andrew Flegg <andrew@bleb.org> 2009.
24      Released under the Artistic Licence."""
25
26
27   # -----------------------------------------------------------------------
28   def __init__(self, book):
29     """Create a new contact store for modifying contacts in the given
30        EBook."""
31
32     self.book = book
33
34  
35   # -----------------------------------------------------------------------
36   def close(self):
37     """Close the store and tidy-up any resources."""
38
39     pass
40
41
42   # -----------------------------------------------------------------------
43   def set_photo(self, contact, url):
44     """Set the given contact's photo to the picture found at the URL. If the
45        photo is wider than it is tall, it will be cropped with a bias towards
46        the top of the photo."""
47
48     f = urllib.urlopen(url)
49     data = ''
50     while True:
51       read_data = f.read()
52       data += read_data
53       if not read_data:
54         break
55
56     im = Image.open(StringIO.StringIO(data))
57     (w, h) = im.size
58     if (h > w):
59       print "Shrinking photo for %s as it's %d x %d" % (contact.get_name(), w, h)
60       im = ImageOps.fit(im, (w, w), Image.NEAREST, 0, (0, 0.1))
61       
62     print "Updating photo for %s" % (contact.get_name())
63     f = StringIO.StringIO()
64     im.save(f, "JPEG")
65     image_data = f.getvalue()
66     photo = EContactPhoto()
67     photo.type = 0
68     photo.data = EContactPhoto_data()
69     photo.data.inlined = EContactPhoto_inlined()
70     photo.data.inlined.mime_type = cast(create_string_buffer("image/jpeg"), c_char_p)
71     photo.data.inlined.length = len(image_data)
72     photo.data.inlined.data = cast(create_string_buffer(image_data), c_void_p)
73     ebook.e_contact_set(hash(contact), E_CONTACT_PHOTO, addressof(photo))
74     return True
75     
76     
77   # -----------------------------------------------------------------------
78   def set_birthday(self, contact, day, month, year = 0):
79     if year == 0:
80       year = datetime.date.today().year
81       
82     birthday = EContactDate()
83     birthday.year = year
84     birthday.month = month
85     birthday.day = day
86     print "Setting birthday for [%s] to %d-%d-%d" % (contact.get_name(), year, month, day)
87     ebook.e_contact_set(hash(contact), E_CONTACT_BIRTHDAY_DATE, addressof(birthday))
88     return True
89     
90     
91   # -----------------------------------------------------------------------
92   def get_urls(self, contact):
93     """Return a list of URLs which are associated with this contact."""
94
95     urls = []
96     ai = GList.new(ebook.e_contact_get_attributes(hash(contact), E_CONTACT_HOMEPAGE_URL))
97     while ai.has_next():
98       attr = ai.next(as_a = EVCardAttribute)
99       if not attr:
100         raise Exception("Unexpected null attribute for [" + contact.get_name() + "] with URLs " + urls)
101       urls.append(string_at(attr.value().next()))
102       
103     return urls
104
105     
106   # -----------------------------------------------------------------------
107   def add_url(self, contact, str, unique = ''):
108     """Add a new URL to the set of URLs for the given contact."""
109
110     urls = re.findall('(?:(?:ftp|https?):\/\/|\\bwww\.|\\bftp\.)[,\w\.\-\/@:%?&=%+#~_$\*]+[\w=\/&=+#]', str, re.I | re.S)
111     updated = False
112     for url in urls:
113       updated = self._add_url(contact, url, unique or url) or updated
114
115     return updated
116
117
118   # -----------------------------------------------------------------------
119   def _add_url(self, contact, url, unique):
120     """Do the work of adding a unique URL to a contact."""
121
122     url_attr = None
123     ai = GList.new(ebook.e_contact_get_attributes(hash(contact), E_CONTACT_HOMEPAGE_URL))
124     while ai.has_next():
125       attr = ai.next(as_a = EVCardAttribute)
126       existing = string_at(attr.value().next())
127       if existing == unique or existing == url:
128         return False
129       elif existing.find(unique) > -1:
130         url_attr = attr
131         break
132       
133     if not url_attr:
134       ai.add()
135       url_attr = EVCardAttribute()
136       url_attr.group = ''
137       url_attr.name = 'URL'
138     
139     val = GList()
140     print "Setting URL for [%s] to [%s]" % (contact.get_name(), url)
141     val.set(create_string_buffer(url))
142     ai.set(addressof(url_attr))
143     url_attr.values = cast(addressof(val), POINTER(GList))
144     ebook.e_contact_set_attributes(hash(contact), E_CONTACT_HOMEPAGE_URL, addressof(ai))
145     return True
146