3 import org.maemo.hermes.engine.service
4 from org.maemo.hermes.engine.friend import Friend
6 class Service(org.maemo.hermes.engine.service.Service):
7 """maemo.org backend for Hermes.
9 Copyright (c) Andrew Flegg <andrew@bleb.org> 2010.
10 Released under the Artistic Licence."""
12 #_account_url = "http://hermes.garage.maemo.org/mo-list.csv"
13 _account_url = "file:///home/andrew/src/scratchbox/hermes/www/mo-list.csv"
15 # -----------------------------------------------------------------------
17 """Initialise the maemo.org service."""
19 org.maemo.hermes.engine.service.Service.__init__(self, "maemo.org")
21 self._api_email = api_email
22 self._api_key = api_key
24 self._address_to_contact = {}
25 self._hash_to_address = {}
26 self._hash_has_gravatar = {}
28 self._friends_by_contact = {}
29 self._contacts_by_friend = {}
32 # -----------------------------------------------------------------------
33 def pre_process_contact(self, contact):
34 """Extracts addresses from the contact."""
36 for address in contact.get_emails():
37 self._address_to_contact[address] = contact
40 # -----------------------------------------------------------------------
41 def process_friends(self):
42 self._lookup_addresses()
45 # -----------------------------------------------------------------------
46 def process_contact(self, contact):
47 """On first call (with a contact missing a photo), go get data from
48 Gravatar's servers."""
50 if not self._has_photo(contact):
51 for address in contact.get_emails():
52 hash = self._get_hash_for_address(address)
53 if (self._hash_has_gravatar.has_key(hash) and self._hash_has_gravatar[hash]):
54 friend = Friend(contact.get_name())
55 friend.set_photo_url(self._get_url_for_email_hash(hash))
56 self._register_match(contact, friend)
62 # -----------------------------------------------------------------------
63 def get_unmatched_friends(self):
64 """Will always return empty list - Gravatar only reacts on e-mail
65 addresses from existing contacts."""
70 # -----------------------------------------------------------------------
71 def _get_friends(self):
72 return self._contacts_by_friend.keys()
75 # -----------------------------------------------------------------------
76 def _get_contacts_with_match(self):
77 """Returns a dict with Contact objects as keys and Friend objects as
80 return self._friends_by_contact
83 # -----------------------------------------------------------------------
84 def _register_match(self, contact, friend):
85 friend.set_contact(contact)
86 self._friends_by_contact[contact] = friend
87 self._contacts_by_friend[friend] = contact
89 # -----------------------------------------------------------------------
91 def _has_photo(self, contact):
95 # -----------------------------------------------------------------------
96 def _lookup_addresses(self):
97 """Constructs hashes for address_to_contact, makes call to the Gravatar.com service and updates
98 self._hash_has_gravatar"""
100 addresses = self._address_to_contact.keys()
101 if len(addresses) == 0:
102 self._set_hash_information({})
104 args = { "apikey" : self._api_key}
105 hashes = self._construct_hashes(addresses)
106 args["hashes"] = list(hashes)
108 self._set_hash_information(self._get_hash_info_from_server(args, url))
111 # -----------------------------------------------------------------------
112 def _get_hash_info_from_server(self, args, url):
113 """Makes the actual XML-RPC call - override this for testing"""
115 service = xmlrpclib.ServerProxy(url)
116 return service.grav.exists(args)
119 # -----------------------------------------------------------------------
120 def _set_hash_information(self, hash_info):
121 self._hash_has_gravatar = hash_info
124 # -----------------------------------------------------------------------
125 def _get_url_for_email_hash(self, hash, default="404", size="128"):
126 """Assembles the URL to a gravatar, based on a hash of an e-mail address"""
128 return self._image_url_base + urllib.urlencode({'gravatar_id':hash, 'd':default, 'size':size})
131 # -----------------------------------------------------------------------
132 def _construct_hashes(self, addresses):
133 """Creates hashes for all addresses specified, returning a set of hashes"""
136 for address in addresses:
137 hash = self._get_hash_for_address(address)
138 self._hash_to_address[hash] = address
143 # -----------------------------------------------------------------------
144 def _get_hash_for_address(self, address):
145 return hashlib.md5(address.lower()).hexdigest()