0.2.1: fixes Facebook UIDs > MAX_INT, reported by atilla
[hermes] / package / src / hermes.py
index 81faeac..fe4cdb8 100644 (file)
@@ -2,6 +2,7 @@ import os.path
 import evolution
 from facebook import Facebook, FacebookError
 import twitter
+import trans
 import gnome.gconf
 from contacts import ContactStore
 import names
@@ -25,7 +26,7 @@ class Hermes:
 
 
   # -----------------------------------------------------------------------
-  def __init__(self, callback, twitter = None, facebook = False):
+  def __init__(self, callback, twitter = None, facebook = False, empty = False):
     """Constructor. Passed a callback which must implement three informational
        methods:
        
@@ -44,12 +45,16 @@ class Hermes:
                    
          facebook - boolean indicating if Facebook should be used. Defaults to
                     False.
+
+         empty - boolean indicating if 'empty' contacts consisting of a profile
+                 URL and birthday should be created.
                           """
 
     self.gc       = gnome.gconf.client_get_default()
     self.callback = callback
     self.twitter  = twitter
     self.facebook = facebook
+    self.create_empty = empty
 
     # -- Check the environment is going to work...
     #
@@ -86,7 +91,7 @@ class Hermes:
 
     self.gc.set_string('/apps/maemo/hermes/session_key', session['session_key'])
     self.gc.set_string('/apps/maemo/hermes/secret_key', session['secret'])
-    self.gc.set_int('/apps/maemo/hermes/uid', session['uid'])
+    self.gc.set_string('/apps/maemo/hermes/uid', session['uid'])
 
 
   # -----------------------------------------------------------------------
@@ -97,14 +102,16 @@ class Hermes:
     self.friends = {}
     self.blocked_pictures = []
     self.callback.progress(0, 0)
+    self.friends_by_url = {}
     
     # -- Get a user session and retrieve Facebook friends...
     #
     if self.facebook:
+      print "+++ Opening Facebook..."
       if self.fb.session_key is None:
         self.fb.session_key = self.gc.get_string('/apps/maemo/hermes/session_key')
         self.fb.secret = self.gc.get_string('/apps/maemo/hermes/secret_key')
-        self.fb.uid = self.gc.get_int('/apps/maemo/hermes/uid')
+        self.fb.uid = self.gc.get_string('/apps/maemo/hermes/uid')
 
       # Check the available session is still valid...
       while True:
@@ -116,21 +123,32 @@ class Hermes:
         self.do_fb_login()
 
       # Get the list of friends...
-      attrs = ['uid', 'name', 'pic_big', 'birthday_date', 'profile_url']
+      attrs = ['uid', 'name', 'pic_big', 'birthday_date', 'profile_url', 'first_name', 'last_name', 'website']
       for friend in self.fb.users.getInfo(self.fb.friends.get(), attrs):
-        friend['pic'] = friend[attrs[2]]
-        self.friends[friend['name']] = friend
+        key = unicode(friend['name']).encode('trans')
+        self.friends[key] = friend
+        self.friends_by_url[friend['profile_url']] = friend
+        friend['pic']  = friend[attrs[2]]
+        friend['account'] = 'facebook'
+        if friend['website']:
+          friend['homepage'] = friend['website']
+
         if not friend['pic']:
           self.blocked_pictures.append(friend)
           
+          
     # -- Retrieve following information from Twitter...
     #
     if self.twitter is not None:
+      print "+++ Opening Twitter..."
       (user, passwd) = self.twitter
       api = twitter.Api(username=user, password=passwd)
       users = api.GetFriends()
       for friend in api.GetFriends():
-        self.friends[friend.name] = {'name': friend.name, 'pic': friend.profile_image_url, 'birthday_date': None, 'twitter_url': 'http://twitter.com/%s' % (friend.screen_name), 'homepage' : friend.url}
+        key = unicode(friend.name).encode('trans')
+        url = 'http://twitter.com/%s' % (friend.screen_name)
+        self.friends[key] = {'name': friend.name, 'pic': friend.profile_image_url, 'birthday_date': None, 'twitter_url': url, 'homepage': friend.url, 'account': 'twitter'}
+        self.friends_by_url[url] = self.friends[key]
   
     # TODO What if the user has *no* contacts?
 
@@ -143,14 +161,14 @@ class Hermes:
     # -- Find addresses...
     #
     print "+++ Syncing contacts..."
-    addresses = evolution.ebook.open_addressbook('default')
+    self.addresses = evolution.ebook.open_addressbook('default')
     print "+++ Addressbook opened..."
-    store = ContactStore(addresses)
+    self.store = ContactStore(self.addresses)
     print "+++ Contact store created..."
     self.updated = []
     self.unmatched = []
     self.matched = []
-    contacts = addresses.get_all_contacts()
+    contacts = self.addresses.get_all_contacts()
     contacts.sort(key=lambda obj: obj.get_name())
     current = 0
     maximum = len(contacts)
@@ -158,42 +176,87 @@ class Hermes:
       current += 1
       self.callback.progress(current, maximum)
       found = False
-      for name in names.variants(contact.get_name()):
-        if name in self.friends:
-          friend = self.friends[name]
-          found = True
-          updated = False
+      updated = False
       
-          if friend['pic'] and (resync or contact.get_property('photo') is None):
-            updated = store.set_photo(contact, friend['pic']) or updated
-        
-          if friend['birthday_date'] and (resync or contact.get_property('birth-date') is None):
-            date_str = friend['birthday_date'].split('/')
-            date_str.append('0')
-            updated = store.set_birthday(contact, int(date_str[1]),
-                                                  int(date_str[0]),
-                                                  int(date_str[2])) or updated
-
-          if 'profile_url' in friend and friend['profile_url']:
-            updated = store.add_url(contact, friend['profile_url'], unique='facebook.com') or updated
-            
-          if 'twitter_url' in friend and friend['twitter_url']:
-            updated = store.add_url(contact, friend['twitter_url'], unique='twitter.com') or updated
-            
-          if 'homepage' in friend and friend['homepage']:
-            updated = store.add_url(contact, friend['homepage']) or updated
-    
+      # Try match on existing URL...
+      for url in self.store.get_urls(contact):
+        if url in self.friends_by_url:
+          updated = self.update_contact(contact, self.friends_by_url[url], resync)
+          found = True
           if updated:
-            self.updated.append(contact)
-            addresses.commit_contact(contact)
-            print "Saved changes to [%s]" % (contact.get_name())
-            
-          break
+            break
+
+      # Fallback to names...
+      if not found:
+        for name in names.variants(contact.get_name()):
+          if name in self.friends:
+            updated = self.update_contact(contact, self.friends[name], resync)
+            found = True
+            if updated:
+              break
+   
+      # Keep track of updated stuff...
+      if updated:
+        self.updated.append(contact)
+        self.addresses.commit_contact(contact)
+        print "Saved changes to [%s]" % (contact.get_name())
       
       if found:
         self.matched.append(contact)
       else:
         self.unmatched.append(contact)
 
-    store.close()
+    # -- Create 'empty' contacts with birthdays...
+    #
+    if self.create_empty:
+      for name in self.friends:
+        friend = self.friends[name]
+        if 'contact' in friend or 'birthday_date' not in friend or not friend['birthday_date']:
+          continue
+
+        contact = evolution.ebook.EContact()
+        contact.props.full_name = friend['name']
+        contact.props.given_name = friend['first_name']
+        contact.props.family_name = friend['last_name']
+
+        self.update_contact(contact, friend)
+   
+        self.addresses.add_contact(contact)
+        self.updated.append(contact)
+        self.addresses.commit_contact(contact)
+
+        print "Created [%s]" % (contact.get_name())
+        self.matched.append(contact)
+
+    self.store.close()
+
+
+  # -----------------------------------------------------------------------
+  def update_contact(self, contact, friend, resync = False):
+    """Update the given contact with information from the 'friend'
+       dictionary."""
+
+    updated = False
+    friend['contact'] = contact
+      
+    if friend['pic'] and (resync or contact.get_property('photo') is None):
+      updated = self.store.set_photo(contact, friend['pic']) or updated
+        
+    if friend['birthday_date'] and (resync or contact.get_property('birth-date') is None):
+      date_str = friend['birthday_date'].split('/')
+      date_str.append('0')
+      updated = self.store.set_birthday(contact, int(date_str[1]),
+                                                 int(date_str[0]),
+                                                 int(date_str[2])) or updated
+
+    if 'profile_url' in friend and friend['profile_url']:
+      updated = self.store.add_url(contact, friend['profile_url'], unique='facebook.com') or updated
+            
+    if 'twitter_url' in friend and friend['twitter_url']:
+      updated = self.store.add_url(contact, friend['twitter_url'], unique='twitter.com') or updated
+            
+    if 'homepage' in friend and friend['homepage']:
+      updated = self.store.add_url(contact, friend['homepage']) or updated
+
+    return updated