Refactor improvements from Fredrik Wendt; and initial LinkedIn and
[hermes] / package / src / org / maemo / hermes / engine / gravatar / service.py
diff --git a/package/src/org/maemo/hermes/engine/gravatar/service.py b/package/src/org/maemo/hermes/engine/gravatar/service.py
new file mode 100644 (file)
index 0000000..2f4c66b
--- /dev/null
@@ -0,0 +1,130 @@
+import urllib, hashlib, xmlrpclib
+import gnome.gconf
+import org.maemo.hermes.engine.service
+
+from org.maemo.hermes.engine.names import canonical
+
+class Service(org.maemo.hermes.engine.service.Service):
+    """Gravatar backend for Hermes.
+       
+       Copyright (c) Fredrik Wendt <fredrik@wendt.se> 2010.
+       Released under the Artistic Licence."""
+       
+    _image_url_base = "http://www.gravatar.com/avatar.php?"
+       
+    # -----------------------------------------------------------------------
+    def __init__(self):
+        """Initialise the Gravatar service"""
+        
+        self._gc = gnome.gconf.client_get_default()
+        self._address_to_contact = {}
+        self._hash_to_address= {}
+        self._hash_has_gravatar = {}
+        self._empty_cache = True
+        
+        self._api_email = self._gc.get_string('/apps/maemo/hermes/gravatar_api_email')
+        self._api_key = self._gc.get_string('/apps/maemo/hermes/gravatar_api_key')
+        self._api_email = 'maemohermes@wendt.se'
+        self._api_key = 'b14ec179822b' # FIXME
+        if self._api_key is None or self._api_email is None:
+            raise Exception('No Gravatar application keys found. Installation error.') 
+        self._api_url = 'https://secure.gravatar.com/xmlrpc?user=' + hashlib.md5(self._api_email).hexdigest()
+   
+
+    # -----------------------------------------------------------------------
+    def get_name(self):
+        return "Gravatar"
+    
+    
+    # -----------------------------------------------------------------------
+    def get_friends(self):
+        """Returns 'None' since manual mapping is not supported."""
+        
+        return None
+
+    
+    # -----------------------------------------------------------------------
+    def pre_process_contact(self, contact):
+        """Extracts addresses from the contact."""
+        for address in contact.get_emails():
+            self._address_to_contact[address] = contact
+    
+    
+    # -----------------------------------------------------------------------
+    def process_contact(self, contact, friend):
+        """On first call (with a contact missing a photo), go get gravatar existense data from the service."""
+        
+        if not self._has_photo(contact):
+            if self._empty_cache:
+                self._lookup_addresses()
+            for address in contact.get_emails():
+                hash = self._get_hash_for_address(address)
+                if (self._hash_has_gravatar[hash]):
+                    friend.set_photo_url(self._get_url_for_email_hash(hash))
+
+    
+    # -----------------------------------------------------------------------
+    def finalise(self, updated, overwrite=True):
+        """We could make a new pass over all updated contacts, in the event that another service
+           added a new e-mail address to a contact (still missing a photo) that has a gravatar setup."""
+
+        pass
+        # It's plausible that info@company.com addresses would be present for several
+        # contacts, but unlikely that there'd be a gravatar set up for such generic
+        # addresses - the point of gravatar is to make it more personal ...
+        
+        # we only look at contacts that has no photo (unless 
+#        for contact in self._contacts:
+#            if not overwrite or not self._has_photo(contact):
+#                for address in contact.get_emails():
+#                    self._address_to_contact[address] = contact
+#        self._lookup_addresses()
+#        for hash in self._hash_has_gravatar:
+#            if self._hash_has_gravatar[hash]:
+#                address = self._hash_to_address[hash]
+#                contact = self._address_to_contact[address]
+#                if not self._has_photo(contact):
+#                    url = self._get_url_for_email_hash(hash)
+#                    contact.set_photo(url)
+#                    updated.add(contact)
+        
+    # -----------------------------------------------------------------------
+    # FIXME
+    def _has_photo(self, contact):
+        return False
+    
+        
+    # -----------------------------------------------------------------------
+    def _lookup_addresses(self):
+        """Constructs hashes for address_to_contact, makes call to the Gravatar.com service and updates
+        self._hash_has_gravatar"""
+        
+        args = { "apikey" : self._api_key}
+        args["hashes"] = list(self._construct_hashes(self._address_to_contact.keys()))
+        service = xmlrpclib.ServerProxy(self._api_url)
+        self._hash_has_gravatar = service.grav.exists(args)
+        self._empty_cache = False
+    
+
+    # -----------------------------------------------------------------------
+    def _get_url_for_email_hash(self, hash, default="404", size="128"):
+        """Assembles the URL to a gravatar, based on a hash of an e-mail address"""
+    
+        return self._image_url_base + urllib.urlencode({'gravatar_id':hash, 'd':default, 'size':size})
+    
+    
+    # -----------------------------------------------------------------------
+    def _construct_hashes(self, addresses):
+        """Creates hashes for all addresses specified, returning a set of hashes"""
+    
+        result = set()
+        for address in addresses:
+            hash = self._get_hash_for_address(address)
+            self._hash_to_address[hash] = address
+            result.add(hash)
+    
+        return result
+
+    # -----------------------------------------------------------------------
+    def _get_hash_for_address(self, address):
+        return hashlib.md5(address.lower()).hexdigest()
\ No newline at end of file