comparison sat/plugins/plugin_xep_0054.py @ 3277:cf07641b764d

plugin identity: fixed infinite loop on nicknames update
author Goffi <goffi@goffi.org>
date Mon, 18 May 2020 23:52:34 +0200
parents 7aa01e262e05
children 8de63fe6b5c9
comparison
equal deleted inserted replaced
3276:81c8910db91f 3277:cf07641b764d
46 try: 46 try:
47 from twisted.words.protocols.xmlstream import XMPPHandler 47 from twisted.words.protocols.xmlstream import XMPPHandler
48 except ImportError: 48 except ImportError:
49 from wokkel.subprotocols import XMPPHandler 49 from wokkel.subprotocols import XMPPHandler
50 50
51 IMPORT_NAME = "XEP-0054"
51 52
52 PLUGIN_INFO = { 53 PLUGIN_INFO = {
53 C.PI_NAME: "XEP 0054 Plugin", 54 C.PI_NAME: "XEP 0054 Plugin",
54 C.PI_IMPORT_NAME: "XEP-0054", 55 C.PI_IMPORT_NAME: IMPORT_NAME,
55 C.PI_TYPE: "XEP", 56 C.PI_TYPE: "XEP",
56 C.PI_PROTOCOLS: ["XEP-0054", "XEP-0153"], 57 C.PI_PROTOCOLS: ["XEP-0054", "XEP-0153"],
57 C.PI_DEPENDENCIES: ["IDENTITY"], 58 C.PI_DEPENDENCIES: ["IDENTITY"],
58 C.PI_RECOMMENDATIONS: [], 59 C.PI_RECOMMENDATIONS: [],
59 C.PI_MAIN: "XEP_0054", 60 C.PI_MAIN: "XEP_0054",
79 80
80 def __init__(self, host): 81 def __init__(self, host):
81 log.info(_("Plugin XEP_0054 initialization")) 82 log.info(_("Plugin XEP_0054 initialization"))
82 self.host = host 83 self.host = host
83 self._i = host.plugins['IDENTITY'] 84 self._i = host.plugins['IDENTITY']
84 self._i.register('avatar', self.getAvatar, self.setAvatar) 85 self._i.register(IMPORT_NAME, 'avatar', self.getAvatar, self.setAvatar)
85 self._i.register('nicknames', self.getNicknames, self.setNicknames) 86 self._i.register(IMPORT_NAME, 'nicknames', self.getNicknames, self.setNicknames)
86 host.trigger.add("presence_available", self.presenceAvailableTrigger) 87 host.trigger.add("presence_available", self.presenceAvailableTrigger)
87 88
88 def getHandler(self, client): 89 def getHandler(self, client):
89 return XEP_0054_handler(self) 90 return XEP_0054_handler(self)
90 91
104 async def profileConnecting(self, client): 105 async def profileConnecting(self, client):
105 client._xep_0054_avatar_hashes = persistent.PersistentDict( 106 client._xep_0054_avatar_hashes = persistent.PersistentDict(
106 NS_VCARD, client.profile) 107 NS_VCARD, client.profile)
107 await client._xep_0054_avatar_hashes.load() 108 await client._xep_0054_avatar_hashes.load()
108 109
109 def getCache(self, client, entity_jid, name):
110 """return cached value for jid
111
112 @param entity_jid(jid.JID): target contact
113 @param name(unicode): name of the value ('nick' or 'avatar')
114 @return(unicode, None): wanted value or None"""
115 entity_jid = self._i.getIdentityJid(client, entity_jid)
116 try:
117 data = self.host.memory.getEntityData(client, entity_jid, [name])
118 except exceptions.UnknownEntityError:
119 return None
120 return data.get(name)
121
122 def savePhoto(self, client, photo_elt, entity_jid): 110 def savePhoto(self, client, photo_elt, entity_jid):
123 """Parse a <PHOTO> photo_elt and save the picture""" 111 """Parse a <PHOTO> photo_elt and save the picture"""
124 # XXX: this method is launched in a separate thread 112 # XXX: this method is launched in a separate thread
125 try: 113 try:
126 mime_type = str(next(photo_elt.elements(NS_VCARD, "TYPE"))) 114 mime_type = str(next(photo_elt.elements(NS_VCARD, "TYPE")))
182 vcard_dict["fullname"] = str(elem) 170 vcard_dict["fullname"] = str(elem)
183 elif elem.name == "NICKNAME": 171 elif elem.name == "NICKNAME":
184 nickname = vcard_dict["nickname"] = str(elem) 172 nickname = vcard_dict["nickname"] = str(elem)
185 await self._i.update( 173 await self._i.update(
186 client, 174 client,
175 IMPORT_NAME,
187 "nicknames", 176 "nicknames",
188 [nickname], 177 [nickname],
189 entity_jid 178 entity_jid
190 ) 179 )
191 elif elem.name == "URL": 180 elif elem.name == "URL":
214 203
215 if avatar_hash: 204 if avatar_hash:
216 avatar_cache = self.host.common_cache.getMetadata(avatar_hash) 205 avatar_cache = self.host.common_cache.getMetadata(avatar_hash)
217 await self._i.update( 206 await self._i.update(
218 client, 207 client,
208 IMPORT_NAME,
219 "avatar", 209 "avatar",
220 { 210 {
221 'path': avatar_cache['path'], 211 'path': avatar_cache['path'],
222 'media_type': avatar_cache['mime_type'], 212 'media_type': avatar_cache['mime_type'],
223 'cache_uid': avatar_hash 213 'cache_uid': avatar_hash
224 }, 214 },
225 entity_jid 215 entity_jid
226 ) 216 )
227 else: 217 else:
228 await self._i.update(client, "avatar", None, entity_jid) 218 await self._i.update(
219 client, IMPORT_NAME, "avatar", None, entity_jid)
229 else: 220 else:
230 log.debug("FIXME: [{}] VCard_elt tag is not managed yet".format(elem.name)) 221 log.debug("FIXME: [{}] VCard_elt tag is not managed yet".format(elem.name))
231 222
232 return vcard_dict 223 return vcard_dict
233 224
286 entity_jid = self._i.getIdentityJid(client, entity_jid) 277 entity_jid = self._i.getIdentityJid(client, entity_jid)
287 log.debug(f"Asking for {entity_jid}'s VCard") 278 log.debug(f"Asking for {entity_jid}'s VCard")
288 try: 279 try:
289 vcard_elt = await self.getVCardElement(client, entity_jid) 280 vcard_elt = await self.getVCardElement(client, entity_jid)
290 except exceptions.DataError: 281 except exceptions.DataError:
291 self._i.update(client, "avatar", None, entity_jid) 282 self._i.update(client, IMPORT_NAME, "avatar", IMPORT_NAME, None, entity_jid)
292 except Exception as e: 283 except Exception as e:
293 log.warning(_( 284 log.warning(_(
294 "Can't get vCard for {entity_jid}: {e}" 285 "Can't get vCard for {entity_jid}: {e}"
295 ).format(entity_jid=entity_jid, e=e)) 286 ).format(entity_jid=entity_jid, e=e))
296 else: 287 else:
311 except KeyError: 302 except KeyError:
312 log.debug(f"avatar for {entity_jid} is not in cache, we retrieve it") 303 log.debug(f"avatar for {entity_jid} is not in cache, we retrieve it")
313 vcard = await self.getCard(client, entity_jid) 304 vcard = await self.getCard(client, entity_jid)
314 if vcard is None: 305 if vcard is None:
315 return None 306 return None
316 avatar_hash = hashes_cache[entity_jid.full()] 307 try:
308 avatar_hash = hashes_cache[entity_jid.full()]
309 except KeyError:
310 if 'avatar' in vcard:
311 raise exceptions.InternalError(
312 "No avatar hash while avatar is found in vcard")
313 return None
317 314
318 if not avatar_hash: 315 if not avatar_hash:
319 return None 316 return None
320 317
321 avatar_cache = self.host.common_cache.getMetadata(avatar_hash) 318 avatar_cache = self.host.common_cache.getMetadata(avatar_hash)
505 502
506 await hashes_cache.aset(entity_jid.full(), new_hash) 503 await hashes_cache.aset(entity_jid.full(), new_hash)
507 504
508 if not new_hash: 505 if not new_hash:
509 await self.plugin_parent._i.update( 506 await self.plugin_parent._i.update(
510 client, "avatar", None, entity_jid) 507 client, IMPORT_NAME, "avatar", None, entity_jid)
511 # the avatar has been removed, no need to go further 508 # the avatar has been removed, no need to go further
512 return 509 return
513 510
514 avatar_cache = self.host.common_cache.getMetadata(new_hash) 511 avatar_cache = self.host.common_cache.getMetadata(new_hash)
515 if avatar_cache is not None: 512 if avatar_cache is not None:
516 log.debug( 513 log.debug(
517 f"New avatar found for [{entity_jid}], it's already in cache, we use it" 514 f"New avatar found for [{entity_jid}], it's already in cache, we use it"
518 ) 515 )
519 await self.plugin_parent._i.update( 516 await self.plugin_parent._i.update(
520 client, 517 client,
521 "avatar", 518 IMPORT_NAME, "avatar",
522 { 519 {
523 'path': avatar_cache['path'], 520 'path': avatar_cache['path'],
524 'media_type': avatar_cache['mime_type'], 521 'media_type': avatar_cache['mime_type'],
525 'cache_uid': new_hash, 522 'cache_uid': new_hash,
526 }, 523 },