comparison src/plugins/plugin_xep_0054.py @ 594:e629371a28d3

Fix pep8 support in src/plugins.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 18 Jan 2013 17:55:35 +0100
parents beaf6bec2fcd
children 84a6e83157c2
comparison
equal deleted inserted replaced
593:70bae685d05c 594:e629371a28d3
29 29
30 from zope.interface import implements 30 from zope.interface import implements
31 31
32 from wokkel import disco, iwokkel 32 from wokkel import disco, iwokkel
33 33
34 from base64 import b64decode,b64encode 34 from base64 import b64decode, b64encode
35 from hashlib import sha1 35 from hashlib import sha1
36 from sat.core import exceptions 36 from sat.core import exceptions
37 from sat.memory.persistent import PersistentDict 37 from sat.memory.persistent import PersistentDict
38 import Image 38 import Image
39 from cStringIO import StringIO 39 from cStringIO import StringIO
45 45
46 AVATAR_PATH = "avatars" 46 AVATAR_PATH = "avatars"
47 47
48 IQ_GET = '/iq[@type="get"]' 48 IQ_GET = '/iq[@type="get"]'
49 NS_VCARD = 'vcard-temp' 49 NS_VCARD = 'vcard-temp'
50 VCARD_REQUEST = IQ_GET + '/vCard[@xmlns="' + NS_VCARD + '"]' #TODO: manage requests 50 VCARD_REQUEST = IQ_GET + '/vCard[@xmlns="' + NS_VCARD + '"]' # TODO: manage requests
51 51
52 PRESENCE = '/presence' 52 PRESENCE = '/presence'
53 NS_VCARD_UPDATE = 'vcard-temp:x:update' 53 NS_VCARD_UPDATE = 'vcard-temp:x:update'
54 VCARD_UPDATE = PRESENCE + '/x[@xmlns="' + NS_VCARD_UPDATE + '"]' 54 VCARD_UPDATE = PRESENCE + '/x[@xmlns="' + NS_VCARD_UPDATE + '"]'
55 55
56 PLUGIN_INFO = { 56 PLUGIN_INFO = {
57 "name": "XEP 0054 Plugin", 57 "name": "XEP 0054 Plugin",
58 "import_name": "XEP-0054", 58 "import_name": "XEP-0054",
59 "type": "XEP", 59 "type": "XEP",
60 "protocols": ["XEP-0054", "XEP-0153"], 60 "protocols": ["XEP-0054", "XEP-0153"],
61 "dependencies": [], 61 "dependencies": [],
62 "main": "XEP_0054", 62 "main": "XEP_0054",
63 "handler": "yes", 63 "handler": "yes",
64 "description": _("""Implementation of vcard-temp""") 64 "description": _("""Implementation of vcard-temp""")
65 } 65 }
66
66 67
67 class XEP_0054(object): 68 class XEP_0054(object):
68 #TODO: - check that nickname is ok 69 #TODO: - check that nickname is ok
69 # - refactor the code/better use of Wokkel 70 # - refactor the code/better use of Wokkel
70 # - get missing values 71 # - get missing values
74 self.host = host 75 self.host = host
75 self.avatar_path = os.path.join(self.host.memory.getConfig('', 'local_dir'), AVATAR_PATH) 76 self.avatar_path = os.path.join(self.host.memory.getConfig('', 'local_dir'), AVATAR_PATH)
76 if not os.path.exists(self.avatar_path): 77 if not os.path.exists(self.avatar_path):
77 os.makedirs(self.avatar_path) 78 os.makedirs(self.avatar_path)
78 self.avatars_cache = PersistentDict(NS_VCARD) 79 self.avatars_cache = PersistentDict(NS_VCARD)
79 self.avatars_cache.load() #FIXME: resulting deferred must be correctly managed 80 self.avatars_cache.load() # FIXME: resulting deferred must be correctly managed
80 host.bridge.addMethod("getCard", ".plugin", in_sign='ss', out_sign='s', method=self.getCard) 81 host.bridge.addMethod("getCard", ".plugin", in_sign='ss', out_sign='s', method=self.getCard)
81 host.bridge.addMethod("getAvatarFile", ".plugin", in_sign='s', out_sign='s', method=self.getAvatarFile) 82 host.bridge.addMethod("getAvatarFile", ".plugin", in_sign='s', out_sign='s', method=self.getAvatarFile)
82 host.bridge.addMethod("setAvatar", ".plugin", in_sign='ss', out_sign='', method=self.setAvatar, async = True) 83 host.bridge.addMethod("setAvatar", ".plugin", in_sign='ss', out_sign='', method=self.setAvatar, async=True)
83 host.trigger.add("presence_available", self.presenceTrigger) 84 host.trigger.add("presence_available", self.presenceTrigger)
84 85
85 def getHandler(self, profile): 86 def getHandler(self, profile):
86 return XEP_0054_handler(self) 87 return XEP_0054_handler(self)
87 88
142 info(_('Photo of type [%s] found') % str(elem)) 143 info(_('Photo of type [%s] found') % str(elem))
143 if elem.name == 'BINVAL': 144 if elem.name == 'BINVAL':
144 debug(_('Decoding binary')) 145 debug(_('Decoding binary'))
145 decoded = b64decode(str(elem)) 146 decoded = b64decode(str(elem))
146 image_hash = sha1(decoded).hexdigest() 147 image_hash = sha1(decoded).hexdigest()
147 filename = self.avatar_path+'/'+image_hash 148 filename = self.avatar_path + '/' + image_hash
148 if not os.path.exists(filename): 149 if not os.path.exists(filename):
149 with open(filename,'wb') as file: 150 with open(filename, 'wb') as file:
150 file.write(decoded) 151 file.write(decoded)
151 debug(_("file saved to %s") % image_hash) 152 debug(_("file saved to %s") % image_hash)
152 else: 153 else:
153 debug(_("file [%s] already in cache") % image_hash) 154 debug(_("file [%s] already in cache") % image_hash)
154 return image_hash 155 return image_hash
155 156
156 @inlineCallbacks 157 @inlineCallbacks
157 def vCard2Dict(self, vcard, target, profile): 158 def vCard2Dict(self, vcard, target, profile):
158 """Convert a VCard to a dict, and save binaries""" 159 """Convert a VCard to a dict, and save binaries"""
159 debug (_("parsing vcard")) 160 debug(_("parsing vcard"))
160 dictionary = {} 161 dictionary = {}
161 162
162 for elem in vcard.elements(): 163 for elem in vcard.elements():
163 if elem.name == 'FN': 164 if elem.name == 'FN':
164 dictionary['fullname'] = unicode(elem) 165 dictionary['fullname'] = unicode(elem)
171 dictionary['email'] = unicode(elem) 172 dictionary['email'] = unicode(elem)
172 elif elem.name == 'BDAY': 173 elif elem.name == 'BDAY':
173 dictionary['birthday'] = unicode(elem) 174 dictionary['birthday'] = unicode(elem)
174 elif elem.name == 'PHOTO': 175 elif elem.name == 'PHOTO':
175 dictionary["avatar"] = yield threads.deferToThread(self.save_photo, elem) 176 dictionary["avatar"] = yield threads.deferToThread(self.save_photo, elem)
176 if not dictionary["avatar"]: #can happen in case of e.g. empty photo elem 177 if not dictionary["avatar"]: # can happen in case of e.g. empty photo elem
177 del dictionary['avatar'] 178 del dictionary['avatar']
178 else: 179 else:
179 self.update_cache(target, 'avatar', dictionary['avatar'], profile) 180 self.update_cache(target, 'avatar', dictionary['avatar'], profile)
180 else: 181 else:
181 info (_('FIXME: [%s] VCard tag is not managed yet') % elem.name) 182 info(_('FIXME: [%s] VCard tag is not managed yet') % elem.name)
182 183
183 returnValue(dictionary) 184 returnValue(dictionary)
184 185
185 def vcard_ok(self, answer, profile): 186 def vcard_ok(self, answer, profile):
186 """Called after the first get IQ""" 187 """Called after the first get IQ"""
187 debug (_("VCard found")) 188 debug(_("VCard found"))
188 189
189 if answer.firstChildElement().name == "vCard": 190 if answer.firstChildElement().name == "vCard":
190 _jid, steam = self.host.getJidNStream(profile) 191 _jid, steam = self.host.getJidNStream(profile)
191 try: 192 try:
192 from_jid = jid.JID(answer["from"]) 193 from_jid = jid.JID(answer["from"])
193 except KeyError: 194 except KeyError:
194 from_jid = _jid.userhostJID() 195 from_jid = _jid.userhostJID()
195 d = self.vCard2Dict(answer.firstChildElement(), from_jid, profile) 196 d = self.vCard2Dict(answer.firstChildElement(), from_jid, profile)
196 d.addCallback(lambda data: self.host.bridge.actionResult("RESULT", answer['id'], data, profile)) 197 d.addCallback(lambda data: self.host.bridge.actionResult("RESULT", answer['id'], data, profile))
197 else: 198 else:
198 error (_("FIXME: vCard not found as first child element")) 199 error(_("FIXME: vCard not found as first child element"))
199 self.host.bridge.actionResult("SUPPRESS", answer['id'], {}, profile) #FIXME: maybe an error message would be better 200 self.host.bridge.actionResult("SUPPRESS", answer['id'], {}, profile) # FIXME: maybe an error message would be better
200 201
201 def vcard_err(self, failure, profile): 202 def vcard_err(self, failure, profile):
202 """Called when something is wrong with registration""" 203 """Called when something is wrong with registration"""
203 error (_("Can't find VCard of %s") % failure.value.stanza['from']) 204 error(_("Can't find VCard of %s") % failure.value.stanza['from'])
204 self.host.bridge.actionResult("SUPPRESS", failure.value.stanza['id'], {}, profile) #FIXME: maybe an error message would be better 205 self.host.bridge.actionResult("SUPPRESS", failure.value.stanza['id'], {}, profile) # FIXME: maybe an error message would be better
205 206
206 def getCard(self, target_s, profile_key='@DEFAULT@'): 207 def getCard(self, target_s, profile_key='@DEFAULT@'):
207 """Ask server for VCard 208 """Ask server for VCard
208 @param target_s: jid from which we want the VCard 209 @param target_s: jid from which we want the VCard
209 @result: id to retrieve the profile""" 210 @result: id to retrieve the profile"""
210 current_jid, xmlstream = self.host.getJidNStream(profile_key) 211 current_jid, xmlstream = self.host.getJidNStream(profile_key)
211 if not xmlstream: 212 if not xmlstream:
212 error (_('Asking vcard for a non-existant or not connected profile')) 213 error(_('Asking vcard for a non-existant or not connected profile'))
213 return "" 214 return ""
214 profile = self.host.memory.getProfileName(profile_key) 215 profile = self.host.memory.getProfileName(profile_key)
215 to_jid = jid.JID(target_s) 216 to_jid = jid.JID(target_s)
216 debug(_("Asking for %s's VCard") % to_jid.userhost()) 217 debug(_("Asking for %s's VCard") % to_jid.userhost())
217 reg_request=IQ(xmlstream,'get') 218 reg_request = IQ(xmlstream, 'get')
218 reg_request["from"]=current_jid.full() 219 reg_request["from"] = current_jid.full()
219 reg_request["to"] = to_jid.userhost() 220 reg_request["to"] = to_jid.userhost()
220 reg_request.addElement('vCard', NS_VCARD) 221 reg_request.addElement('vCard', NS_VCARD)
221 reg_request.send(to_jid.userhost()).addCallbacks(self.vcard_ok, self.vcard_err, callbackArgs=[profile], errbackArgs=[profile]) 222 reg_request.send(to_jid.userhost()).addCallbacks(self.vcard_ok, self.vcard_err, callbackArgs=[profile], errbackArgs=[profile])
222 return reg_request["id"] 223 return reg_request["id"]
223 224
224 def getAvatarFile(self, avatar_hash): 225 def getAvatarFile(self, avatar_hash):
225 """Give the full path of avatar from hash 226 """Give the full path of avatar from hash
226 @param hash: SHA1 hash 227 @param hash: SHA1 hash
227 @return full_path 228 @return full_path
228 """ 229 """
229 filename = self.avatar_path+'/'+avatar_hash 230 filename = self.avatar_path + '/' + avatar_hash
230 if not os.path.exists(filename): 231 if not os.path.exists(filename):
231 error (_("Asking for an uncached avatar [%s]") % avatar_hash) 232 error(_("Asking for an uncached avatar [%s]") % avatar_hash)
232 return "" 233 return ""
233 return filename 234 return filename
234 235
235 def _buildSetAvatar(self, vcard_set, filepath): 236 def _buildSetAvatar(self, vcard_set, filepath):
236 try: 237 try:
257 # A proper full VCard management should be done (and more generaly a public/private profile) 258 # A proper full VCard management should be done (and more generaly a public/private profile)
258 client = self.host.getClient(profile_key) 259 client = self.host.getClient(profile_key)
259 if not client: 260 if not client:
260 raise exceptions.NotConnectedProfileError(_('Trying to set avatar for a non-existant or not connected profile')) 261 raise exceptions.NotConnectedProfileError(_('Trying to set avatar for a non-existant or not connected profile'))
261 262
262 vcard_set = IQ(client.xmlstream,'set') 263 vcard_set = IQ(client.xmlstream, 'set')
263 d = threads.deferToThread(self._buildSetAvatar, vcard_set, filepath) 264 d = threads.deferToThread(self._buildSetAvatar, vcard_set, filepath)
264 265
265 def elementBuilt(result): 266 def elementBuilt(result):
266 """Called once the image is at the right size/format, and the vcard set element is build""" 267 """Called once the image is at the right size/format, and the vcard set element is build"""
267 set_avatar_elt, img_hash = result 268 set_avatar_elt, img_hash = result
268 self.avatars_cache[client.jid.userhost()] = img_hash # we need to update the hash, so we can send a new presence 269 self.avatars_cache[client.jid.userhost()] = img_hash # we need to update the hash, so we can send a new presence
269 # element with the right hash 270 # element with the right hash
270 return set_avatar_elt.send().addCallback(lambda ignore: client.presence.available()) 271 return set_avatar_elt.send().addCallback(lambda ignore: client.presence.available())
271 272
272 d.addCallback(elementBuilt) 273 d.addCallback(elementBuilt)
273 274
294 """Request for VCard's nickname 295 """Request for VCard's nickname
295 return the cached nickname if exists, else get VCard 296 return the cached nickname if exists, else get VCard
296 """ 297 """
297 from_jid = jid.JID(presence['from']) 298 from_jid = jid.JID(presence['from'])
298 #FIXME: wokkel's data_form should be used here 299 #FIXME: wokkel's data_form should be used here
299 x_elem = filter (lambda x:x.name == "x", presence.elements())[0] #We only want the "x" element 300 x_elem = filter(lambda x: x.name == "x", presence.elements())[0] # We only want the "x" element
300 for elem in x_elem.elements(): 301 for elem in x_elem.elements():
301 if elem.name == 'photo': 302 if elem.name == 'photo':
302 _hash = str(elem) 303 _hash = str(elem)
303 old_avatar = self.plugin_parent.get_cache(from_jid, 'avatar', self.parent.profile) 304 old_avatar = self.plugin_parent.get_cache(from_jid, 'avatar', self.parent.profile)
304 if not old_avatar or old_avatar != _hash: 305 if not old_avatar or old_avatar != _hash: