Big update to 0.1.0. Improved error handling, syncing, the works...
[hermes] / package / src / contacts.py
index 0b7a1e9..38b4624 100644 (file)
@@ -3,6 +3,18 @@ import os.path
 import urllib
 import Image
 import ImageOps
+import StringIO
+import datetime
+import re
+from pygobject import *
+from ctypes import *
+
+# 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
+
 
 class ContactStore:
   """Provide an API for changing contact data. Abstracts limitations
@@ -17,7 +29,6 @@ class ContactStore:
     """Create a new contact store for modifying contacts in the given
        EBook."""
 
-    self.temp_file = os.tmpnam()
     self.book = book
 
  
@@ -25,8 +36,7 @@ class ContactStore:
   def close(self):
     """Close the store and tidy-up any resources."""
 
-    if (os.path.isfile(self.temp_file)):
-      os.unlink(self.temp_file)
+    pass
 
 
   # -----------------------------------------------------------------------
@@ -35,13 +45,102 @@ class ContactStore:
        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)
+    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))
-      im.save(self.temp_file, "JPEG")
       
     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)
+    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
+    
+    
+  # -----------------------------------------------------------------------
+  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 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())
+      if existing == unique or existing == url:
+        return False
+      elif existing.find(unique) > -1:
+        url_attr = attr
+        break
+      
+    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
+