7 from org.maemo.hermes.engine.names import canonical, variants
8 from pygobject import *
11 # Constants from http://library.gnome.org/devel/libebook/stable/EContact.html#EContactField
12 ebook = CDLL('libebook-1.2.so.5')
13 E_CONTACT_HOMEPAGE_URL = 42
16 E_CONTACT_BIRTHDAY_DATE = 107
20 """Provide an abstraction of contact, working around limitations
21 in the evolution-python bindings. Properties are defined at:
23 http://library.gnome.org/devel/libebook/stable/EContact.html#id3066469
25 Copyright (c) Andrew Flegg <andrew@bleb.org> 2009.
26 Released under the Artistic Licence."""
29 # -----------------------------------------------------------------------
30 def __init__(self, book, econtact):
31 """Create a new contact store for modifying contacts in the given
35 self._contact = econtact
36 self._identifiers = self._find_ids()
37 self._mapped_to = set([])
40 # -----------------------------------------------------------------------
42 """Return a set of the identifiers which should be used to match this
43 contact. Includes variants of first name, last name, nickname and
44 email address. These are all Unicode-normalised into the traditional
48 for name in variants(self._contact.get_name()):
49 result.add(canonical(name))
51 for name in variants(self._contact.get_property('nickname')):
52 result.add(canonical(name))
54 for email in self.get_emails():
55 user = canonical(email.split('@')[0])
62 # -----------------------------------------------------------------------
64 """Return this contact's name."""
66 return self._contact.get_name() or self._contact.get_property('nickname')
69 # -----------------------------------------------------------------------
70 def get_identifiers(self):
71 """Return the lowercase, Unicode-normalised, all-alphabetic
72 versions of identifiers for this contact."""
74 return self._identifiers
77 # -----------------------------------------------------------------------
78 def get_econtact(self):
79 """Return the EContact which backs this contact."""
84 # -----------------------------------------------------------------------
85 def add_mapping(self, id):
86 """Record the fact that this contact is mapped against a provider.
87 'id' MUST match the string returned by Provider.get_id()."""
89 self._mapped_to.add(id)
92 # ----------------------------------------------------------------------
93 def get_mappings(self):
94 """Return the set of IDs of providers which are mapped to this contact.
95 The data can only be relied upon after services have run."""
97 return self._mapped_to
100 # -----------------------------------------------------------------------
102 """Return the photo property, or None. The result is of type
105 photo = self._contact.get_property('photo')
106 return cast(c_void_p(hash(photo)), POINTER(EContactPhoto))
109 # -----------------------------------------------------------------------
110 def set_photo(self, url):
111 """Set the given contact's photo to the picture found at the URL. If the
112 photo is wider than it is tall, it will be cropped with a bias towards
113 the top of the photo."""
116 f = urllib.urlopen(url)
124 im = Image.open(StringIO.StringIO(data))
127 ##print u"Shrinking photo for %s as it's %d x %d" % (self._contact.get_name(), w, h)
128 im = ImageOps.fit(im, (w, w), Image.NEAREST, 0, (0, 0.1))
130 ## print u"Updating photo for %s" % (self._contact.get_name())
131 f = StringIO.StringIO()
133 image_data = f.getvalue()
134 photo = EContactPhoto()
136 photo.data = EContactPhoto_data()
137 photo.data.inlined = EContactPhoto_inlined()
138 photo.data.inlined.mime_type = cast(create_string_buffer("image/jpeg"), c_char_p)
139 photo.data.inlined.length = len(image_data)
140 photo.data.inlined.data = cast(create_string_buffer(image_data), c_void_p)
141 ebook.e_contact_set(hash(self._contact), E_CONTACT_PHOTO, addressof(photo))
144 print "FAILED to get photo from URL %s" % url
148 # -----------------------------------------------------------------------
149 def set_birthday(self, day, month, year = 0):
150 """Set the birthday for this contact to the given day, month and year."""
153 year = datetime.date.today().year
155 birthday = EContactDate()
157 birthday.month = month
159 print u"Setting birthday for [%s] to %d-%d-%d" % (self._contact.get_name(), year, month, day)
160 ebook.e_contact_set(hash(self._contact), E_CONTACT_BIRTHDAY_DATE, addressof(birthday))
164 # -----------------------------------------------------------------------
165 def set_nickname(self, nickname):
166 """Set the nickname for this contact to the given nickname."""
168 # FIXME does this work?
169 self._contact.set_property('nickname', nickname)
170 #ebook.e_contact_set(hash(self._contact), E_NICKNAME, addressof(nickname))
173 # -----------------------------------------------------------------------
174 def get_emails(self):
175 """Return the email addresses associated with this contact."""
178 ai = GList.new(ebook.e_contact_get_attributes(hash(self._contact), E_CONTACT_EMAIL))
180 attr = ai.next(as_a = EVCardAttribute)
182 raise Exception(u"Unexpected null attribute for [" + self._contact.get_name() + "] with emails " + emails)
183 emails.append(string_at(attr.value().next()))
189 # -----------------------------------------------------------------------
191 """Return a list of URLs which are associated with this contact."""
194 ai = GList.new(ebook.e_contact_get_attributes(hash(self._contact), E_CONTACT_HOMEPAGE_URL))
196 attr = ai.next(as_a = EVCardAttribute)
198 raise Exception(u"Unexpected null attribute for [" + self._contact.get_name() + "] with URLs " + urls)
199 urls.append(string_at(attr.value().next()))
204 # -----------------------------------------------------------------------
205 def add_url(self, str, unique = ''):
206 """Add a new URL to the set of URLs for the given contact."""
208 urls = re.findall('(?:(?:ftp|https?):\/\/|\\bwww\.|\\bftp\.)[,\w\.\-\/@:%?&=%+#~_$\*]+[\w=\/&=+#]', str, re.I | re.S)
211 updated = self._add_url(url, unique or re.sub('(?:.*://)?(\w+(?:[\w\.])*).*', '\\1', url)) or updated
216 # -----------------------------------------------------------------------
217 def _add_url(self, url, unique):
218 """Do the work of adding a unique URL to a contact."""
221 ai = GList.new(ebook.e_contact_get_attributes(hash(self._contact), E_CONTACT_HOMEPAGE_URL))
223 attr = ai.next(as_a = EVCardAttribute)
224 existing = string_at(attr.value().next())
225 #print "Existing URL [%s] when adding [%s] to [%s] with constraint [%s]" % (existing, url, contact.get_name(), unique)
226 if existing == unique or existing == url:
228 elif existing.find(unique) > -1:
233 url_attr = EVCardAttribute()
235 url_attr.name = 'URL'
238 ##print u"Setting URL for [%s] to [%s]" % (self._contact.get_name(), url)
239 val.set(create_string_buffer(url))
240 ai.set(addressof(url_attr))
241 url_attr.values = cast(addressof(val), POINTER(GList))
242 ebook.e_contact_set_attributes(hash(self._contact), E_CONTACT_HOMEPAGE_URL, addressof(ai))