diff --git a/gajim/common/modules/user_avatar.py b/gajim/common/modules/user_avatar.py index e29283780..d4246e75e 100644 --- a/gajim/common/modules/user_avatar.py +++ b/gajim/common/modules/user_avatar.py @@ -15,134 +15,67 @@ # XEP-0084: User Avatar import logging -import base64 -import binascii import nbxmpp from gajim.common import app -from gajim.common.const import PEPEventType -from gajim.common.exceptions import StanzaMalformed -from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData +from gajim.common.modules.base import BaseModule +from gajim.common.modules.util import event_node log = logging.getLogger('gajim.c.m.user_avatar') -class UserAvatarData(AbstractPEPData): +class UserAvatar(BaseModule): - type_ = PEPEventType.AVATAR + _nbxmpp_extends = 'UserAvatar' + _nbxmpp_methods = [ + 'request_avatar' + ] + def __init__(self, con): + BaseModule.__init__(self, con) + self._register_pubsub_handler(self._avatar_metadata_received) -class UserAvatar(AbstractPEPModule): + @event_node(nbxmpp.NS_AVATAR_METADATA) + def _avatar_metadata_received(self, _con, _stanza, properties): + data = properties.pubsub_event.data + empty = properties.pubsub_event.empty + jid = str(properties.jid) + own_jid = self._con.get_own_jid().getBare() - name = 'user-avatar' - namespace = 'urn:xmpp:avatar:metadata' - pep_class = UserAvatarData - store_publish = False - _log = log - - def get_pubsub_avatar(self, jid, item_id): - log.info('Request: %s %s', jid, item_id) - self._con.get_module('PubSub').send_pb_retrieve( - jid, 'urn:xmpp:avatar:data', item_id, self._avatar_received) - - def _validate_avatar_node(self, stanza): - jid = stanza.getFrom() - if jid is None: - jid = self._con.get_own_jid().getStripped() - else: - jid = jid.getStripped() - - if nbxmpp.isErrorNode(stanza): - raise StanzaMalformed(stanza.getErrorMsg()) - - pubsub_node = stanza.getTag('pubsub') - if pubsub_node is None: - raise StanzaMalformed('No pubsub node', stanza) - - items_node = pubsub_node.getTag('items') - if items_node is None: - raise StanzaMalformed('No items node', stanza) - - if items_node.getAttr('node') != 'urn:xmpp:avatar:data': - raise StanzaMalformed('Wrong namespace', stanza) - - item = items_node.getTag('item') - if item is None: - raise StanzaMalformed('No item node', stanza) - - sha = item.getAttr('id') - data_tag = item.getTag('data', namespace='urn:xmpp:avatar:data') - if sha is None or data_tag is None: - raise StanzaMalformed('No id attr or data node found', stanza) - - data = data_tag.getData() - if data is None: - raise StanzaMalformed('Data node empty', stanza) - - data = base64.b64decode(data.encode('utf-8')) - - return jid, sha, data - - def _avatar_received(self, _con, stanza): - try: - jid, sha, data = self._validate_avatar_node(stanza) - except (StanzaMalformed, binascii.Error) as error: - log.warning('Error: %s %s', stanza.getFrom(), error) - return - - log.info('Received Avatar: %s %s', jid, sha) - app.interface.save_avatar(data) - - if self._con.get_own_jid().bareMatch(jid): - app.config.set_per('accounts', self._account, 'avatar_sha', sha) - else: - own_jid = self._con.get_own_jid().getStripped() - app.logger.set_avatar_sha(own_jid, jid, sha) - - app.contacts.set_avatar(self._account, jid, sha) - app.interface.update_avatar(self._account, jid) - - def _extract_info(self, item): - metadata = item.getTag('metadata', namespace=self.namespace) - if metadata is None: - raise StanzaMalformed('No metadata node') - - info = metadata.getTags('info', one=True) - if not info: - return None - - avatar = info.getAttrs() - return avatar or None - - def _notification_received(self, jid, user_pep): - avatar = user_pep.data - own_jid = self._con.get_own_jid() - if avatar is None: + if empty: # Remove avatar log.info('Remove: %s', jid) - app.contacts.set_avatar(self._account, str(jid), None) - app.logger.set_avatar_sha(own_jid.getStripped(), str(jid), None) - app.interface.update_avatar(self._account, str(jid)) + app.contacts.set_avatar(self._account, jid, None) + app.logger.set_avatar_sha(own_jid, jid, None) + app.interface.update_avatar(self._account, jid) else: - if own_jid.bareMatch(jid): + if properties.is_self_message: sha = app.config.get_per( 'accounts', self._account, 'avatar_sha') else: - sha = app.contacts.get_avatar_sha(self._account, str(jid)) + sha = app.contacts.get_avatar_sha(self._account, jid) - if sha == avatar['id']: - log.info('Avatar already known: %s %s', - jid, avatar['id']) + if sha == data.id: + log.info('Avatar already known: %s %s', jid, data.id) return - self.get_pubsub_avatar(jid, avatar['id']) - def _build_node(self, data): - raise NotImplementedError + log.info('Request: %s %s', jid, data.id) + self._nbxmpp('UserAvatar').request_avatar( + jid, data.id, callback=self._avatar_received) - def send(self, data): - # Not implemented yet - return + def _avatar_received(self, result): + log.info('Received Avatar: %s %s', result.jid, result.sha) + app.interface.save_avatar(result.data) + + if self._con.get_own_jid().bareMatch(result.jid): + app.config.set_per('accounts', self._account, 'avatar_sha', result.sha) + else: + own_jid = self._con.get_own_jid().getBare() + app.logger.set_avatar_sha(own_jid, str(result.jid), result.sha) + + app.contacts.set_avatar(self._account, str(result.jid), result.sha) + app.interface.update_avatar(self._account, str(result.jid)) def get_instance(*args, **kwargs):