1 import urllib, hashlib, xmlrpclib
2 import org.maemo.hermes.engine.service
4 class Service(org.maemo.hermes.engine.service.Service):
5 """Gravatar backend for Hermes.
7 Copyright (c) Fredrik Wendt <fredrik@wendt.se> 2010.
8 Released under the Artistic Licence."""
10 _image_url_base = "http://www.gravatar.com/avatar.php?"
12 # -----------------------------------------------------------------------
13 def __init__(self, api_email, api_key):
14 """Initialise the Gravatar service.
16 api_email is the email address to use when talking to the backend.
17 api_key is the "secret" key used when talking to the backend
19 self._api_email = api_email
20 self._api_key = api_key
21 if self._api_key is None or self._api_email is None:
22 raise Exception('No Gravatar application keys found. Installation error.')
24 self._address_to_contact = {}
25 self._hash_to_address = {}
26 self._hash_has_gravatar = {}
27 self._empty_cache = True
29 self._friends_by_contact = {}
30 self._contacts_by_friend = {}
32 self._api_url = 'https://secure.gravatar.com/xmlrpc?user=' + hashlib.md5(self._api_email).hexdigest()
35 # -----------------------------------------------------------------------
40 # -----------------------------------------------------------------------
41 def pre_process_contact(self, contact):
42 """Extracts addresses from the contact."""
43 for address in contact.get_emails():
44 self._address_to_contact[address] = contact
47 # -----------------------------------------------------------------------
48 def process_contact(self, contact):
49 """On first call (with a contact missing a photo), go get data from Gravatar's servers."""
51 if not self._has_photo(contact):
52 for address in contact.get_emails():
53 hash = self._get_hash_for_address(address)
54 if (self._hash_has_gravatar.has_key(hash) and self._hash_has_gravatar[hash]):
55 friend = self._create_friend(contact.get_name())
56 friend.set_photo_url(self._get_url_for_email_hash(hash))
57 self._register_match(contact, friend)
63 # -----------------------------------------------------------------------
64 def process_friends(self):
65 self._lookup_addresses()
68 # -----------------------------------------------------------------------
69 def get_friends(self):
70 return self._contacts_by_friend.keys()
73 def get_contacts_with_match(self):
74 """Returns a dict with Contact objects as keys and Friend objects as values"""
75 return self._friends_by_contact
78 def get_unmatched_friends(self):
79 """Will always return None - Gravatar only reacts on e-mail address input."""
85 # -----------------------------------------------------------------------
86 def _register_match(self, contact, friend):
87 friend.set_contact(contact)
88 self._friends_by_contact[contact] = friend
89 self._contacts_by_friend[friend] = contact
91 # -----------------------------------------------------------------------
93 def _has_photo(self, contact):
97 # -----------------------------------------------------------------------
98 def _lookup_addresses(self):
99 """Constructs hashes for address_to_contact, makes call to the Gravatar.com service and updates
100 self._hash_has_gravatar"""
102 addresses = self._address_to_contact.keys()
103 if len(addresses) == 0:
104 self._set_hash_information({})
106 args = { "apikey" : self._api_key}
107 hashes = self._construct_hashes(addresses)
108 args["hashes"] = list(hashes)
110 self._set_hash_information(self._get_hash_info_from_server(args, url))
113 # -----------------------------------------------------------------------
114 def _get_hash_info_from_server(self, args, url):
115 """Makes the actual XML-RPC call - override this for testing"""
117 service = xmlrpclib.ServerProxy(url)
118 return service.grav.exists(args)
121 # -----------------------------------------------------------------------
122 def _set_hash_information(self, hash_info):
123 self._hash_has_gravatar = hash_info
124 self._empty_cache = False
127 # -----------------------------------------------------------------------
128 def _get_url_for_email_hash(self, hash, default="404", size="128"):
129 """Assembles the URL to a gravatar, based on a hash of an e-mail address"""
131 return self._image_url_base + urllib.urlencode({'gravatar_id':hash, 'd':default, 'size':size})
134 # -----------------------------------------------------------------------
135 def _construct_hashes(self, addresses):
136 """Creates hashes for all addresses specified, returning a set of hashes"""
139 for address in addresses:
140 hash = self._get_hash_for_address(address)
141 self._hash_to_address[hash] = address
146 # -----------------------------------------------------------------------
147 def _get_hash_for_address(self, address):
148 return hashlib.md5(address.lower()).hexdigest()