import urllib
import Image
import ImageOps
+import StringIO
+import datetime
+import re
+from pygobject import *
+from ctypes import *
-class ContactStore:
- """Provide an API for changing contact data. Abstracts limitations
- in the evolution-python bindings.
-
- Copyright (c) Andrew Flegg <andrew@bleb.org> 2009.
- Released under the Artistic Licence."""
-
+# Constants from http://library.gnome.org/devel/libebook/stable/EContact.html#EContactField
+ebook = CDLL('libebook-1.2.so.5')
+E_CONTACT_HOMEPAGE_URL = 42
+E_CONTACT_PHOTO = 94
+E_CONTACT_BIRTHDAY_DATE = 107
- # -----------------------------------------------------------------------
- def __init__(self, book):
- """Create a new contact store for modifying contacts in the given
- EBook."""
- self.temp_file = os.tmpnam()
- self.book = book
-
-
- # -----------------------------------------------------------------------
- def close(self):
- """Close the store and tidy-up any resources."""
-
- if (os.path.isfile(self.temp_file)):
- os.unlink(self.temp_file)
+class ContactStore:
+ """Provide an API for changing contact data. Abstracts limitations
+ in the evolution-python bindings.
+ Copyright (c) Andrew Flegg <andrew@bleb.org> 2009.
+ Released under the Artistic Licence."""
- # -----------------------------------------------------------------------
- def set_photo(self, contact, url):
- """Set the given contact's photo to the picture found at the URL. If the
- photo is wider than it is tall, it will be cropped with a bias towards
- the top of the photo."""
- urllib.urlretrieve(url, self.temp_file)
- im = Image.open(self.temp_file)
- (w, h) = im.size
- if (h > w):
- print "Shrinking photo for %s as it's %d x %d" % (contact.get_name(), w, h)
- im = ImageOps.fit(im, (w, w), Image.NEAREST, 0, (0, 0.1))
- im.save(self.temp_file, "JPEG")
+ # -----------------------------------------------------------------------
+ def __init__(self, book):
+ """Create a new contact store for modifying contacts in the given
+ EBook."""
+
+ self.book = book
+
+
+ # -----------------------------------------------------------------------
+ def close(self):
+ """Close the store and tidy-up any resources."""
+
+ pass
+
+
+ # -----------------------------------------------------------------------
+ def set_photo(self, contact, url):
+ """Set the given contact's photo to the picture found at the URL. If the
+ photo is wider than it is tall, it will be cropped with a bias towards
+ the top of the photo."""
+
+ f = urllib.urlopen(url)
+ data = ''
+ while True:
+ read_data = f.read()
+ data += read_data
+ if not read_data:
+ break
+
+ im = Image.open(StringIO.StringIO(data))
+ (w, h) = im.size
+ if (h > w):
+ print "Shrinking photo for %s as it's %d x %d" % (contact.get_name(), w, h)
+ im = ImageOps.fit(im, (w, w), Image.NEAREST, 0, (0, 0.1))
+
+ print "Updating photo for %s" % (contact.get_name())
+ f = StringIO.StringIO()
+ im.save(f, "JPEG")
+ image_data = f.getvalue()
+ photo = EContactPhoto()
+ photo.type = 0
+ photo.data = EContactPhoto_data()
+ photo.data.inlined = EContactPhoto_inlined()
+ photo.data.inlined.mime_type = cast(create_string_buffer("image/jpeg"), c_char_p)
+ photo.data.inlined.length = len(image_data)
+ photo.data.inlined.data = cast(create_string_buffer(image_data), c_void_p)
+ ebook.e_contact_set(hash(contact), E_CONTACT_PHOTO, addressof(photo))
+ return True
- print "Updating photo for %s" % (contact.get_name())
- os.spawnl(os.P_WAIT, '/opt/hermes/bin/contact-update', 'contact-update', contact.get_name(), '--photo', 'image/jpeg', self.temp_file)
+
+ # -----------------------------------------------------------------------
+ def set_birthday(self, contact, day, month, year = 0):
+ if year == 0:
+ year = datetime.date.today().year
+
+ birthday = EContactDate()
+ birthday.year = year
+ birthday.month = month
+ birthday.day = day
+ print "Setting birthday for [%s] to %d-%d-%d" % (contact.get_name(), year, month, day)
+ ebook.e_contact_set(hash(contact), E_CONTACT_BIRTHDAY_DATE, addressof(birthday))
+ return True
+
+
+ # -----------------------------------------------------------------------
+ def get_urls(self, contact):
+ """Return a list of URLs which are associated with this contact."""
+
+ urls = []
+ ai = GList.new(ebook.e_contact_get_attributes(hash(contact), E_CONTACT_HOMEPAGE_URL))
+ while ai.has_next():
+ attr = ai.next(as_a = EVCardAttribute)
+ if not attr:
+ raise Exception("Unexpected null attribute for [" + contact.get_name() + "] with URLs " + urls)
+ urls.append(string_at(attr.value().next()))
+
+ return urls
+
+
+ # -----------------------------------------------------------------------
+ def add_url(self, contact, str, unique = ''):
+ """Add a new URL to the set of URLs for the given contact."""
+
+ urls = re.findall('(?:(?:ftp|https?):\/\/|\\bwww\.|\\bftp\.)[,\w\.\-\/@:%?&=%+#~_$\*]+[\w=\/&=+#]', str, re.I | re.S)
+ updated = False
+ for url in urls:
+ updated = self._add_url(contact, url, unique or re.sub('(?:.*://)?(\w+(?:[\w\.])*).*', '\\1', url)) or updated
+
+ return updated
+
+
+ # -----------------------------------------------------------------------
+ def _add_url(self, contact, url, unique):
+ """Do the work of adding a unique URL to a contact."""
+
+ url_attr = None
+ ai = GList.new(ebook.e_contact_get_attributes(hash(contact), E_CONTACT_HOMEPAGE_URL))
+ while ai.has_next():
+ attr = ai.next(as_a = EVCardAttribute)
+ existing = string_at(attr.value().next())
+ #print "Existing URL [%s] when adding [%s] to [%s] with constraint [%s]" % (existing, url, contact.get_name(), unique)
+ if existing == unique or existing == url:
+ return False
+ elif existing.find(unique) > -1:
+ url_attr = attr
+
+ if not url_attr:
+ ai.add()
+ url_attr = EVCardAttribute()
+ url_attr.group = ''
+ url_attr.name = 'URL'
+
+ val = GList()
+ print "Setting URL for [%s] to [%s]" % (contact.get_name(), url)
+ val.set(create_string_buffer(url))
+ ai.set(addressof(url_attr))
+ url_attr.values = cast(addressof(val), POINTER(GList))
+ ebook.e_contact_set_attributes(hash(contact), E_CONTACT_HOMEPAGE_URL, addressof(ai))
+ return True
+