Send all presence through the presence module

This commit is contained in:
Philipp Hörist 2018-09-01 17:07:30 +02:00 committed by Philipp Hörist
parent 42a7dbc79a
commit d4d29f8309
7 changed files with 169 additions and 183 deletions

View File

@ -241,7 +241,6 @@ class Config:
'roster_window_skip_taskbar': [opt_bool, False, _('Don\'t show roster in the system taskbar.')], 'roster_window_skip_taskbar': [opt_bool, False, _('Don\'t show roster in the system taskbar.')],
'use_urgency_hint': [opt_bool, True, _('If true, make the window flash (the default behaviour in most Window Managers) when holding pending events.')], 'use_urgency_hint': [opt_bool, True, _('If true, make the window flash (the default behaviour in most Window Managers) when holding pending events.')],
'notification_timeout': [opt_int, 5], 'notification_timeout': [opt_int, 5],
'send_sha_in_gc_presence': [opt_bool, True, _('Jabberd1.4 does not like sha info when one join a password protected group chat. Turn this option to False to stop sending sha info in group chat presences.')],
'one_message_window': [opt_str, 'always', 'one_message_window': [opt_str, 'always',
#always, never, peracct, pertype should not be translated #always, never, peracct, pertype should not be translated
_('Controls the window where new messages are placed.\n\'always\' - All messages are sent to a single window.\n\'always_with_roster\' - Like \'always\' but the messages are in a single window along with the roster.\n\'never\' - All messages get their own window.\n\'peracct\' - Messages for each account are sent to a specific window.\n\'pertype\' - Each message type (e.g. chats vs. groupchats) is sent to a specific window.')], _('Controls the window where new messages are placed.\n\'always\' - All messages are sent to a single window.\n\'always_with_roster\' - Like \'always\' but the messages are in a single window along with the roster.\n\'never\' - All messages get their own window.\n\'peracct\' - Messages for each account are sent to a specific window.\n\'pertype\' - Each message type (e.g. chats vs. groupchats) is sent to a specific window.')],

View File

@ -38,7 +38,6 @@ import socket
import operator import operator
import string import string
import time import time
import hmac
import hashlib import hashlib
import json import json
import logging import logging
@ -60,12 +59,10 @@ from gajim.common import helpers
from gajim.common import app from gajim.common import app
from gajim.common import gpg from gajim.common import gpg
from gajim.common import passwords from gajim.common import passwords
from gajim.common import i18n
from gajim.common import idle from gajim.common import idle
from gajim.common.connection_handlers import * from gajim.common.connection_handlers import *
from gajim.common.contacts import GC_Contact from gajim.common.contacts import GC_Contact
from gajim.common import modules from gajim.common import modules
from gajim.gtkgui_helpers import get_action
log = logging.getLogger('gajim.c.connection') log = logging.getLogger('gajim.c.connection')
@ -474,10 +471,11 @@ class CommonConnection:
if self.connection: if self.connection:
app.nec.push_incoming_event(BeforeChangeShowEvent(None, app.nec.push_incoming_event(BeforeChangeShowEvent(None,
conn=self, show=show, message=msg)) conn=self, show=show, message=msg))
p = nbxmpp.Presence(typ = 'unavailable')
p = self.add_sha(p, False) p = self.get_module('Presence').get_presence(
if msg: typ='unavailable',
p.setStatus(msg) status=msg,
caps=False)
self.connection.RegisterDisconnectHandler(self._on_disconnected) self.connection.RegisterDisconnectHandler(self._on_disconnected)
self.connection.send(p, now=True) self.connection.send(p, now=True)
@ -542,7 +540,6 @@ class Connection(CommonConnection, ConnectionHandlers):
# server {'icq': ['icq.server.com', 'icq2.server.com'], } # server {'icq': ['icq.server.com', 'icq2.server.com'], }
self.streamError = '' self.streamError = ''
self.secret_hmac = str(random.random())[2:].encode('utf-8')
self.removing_account = False self.removing_account = False
# We only request POSH once # We only request POSH once
@ -1351,9 +1348,6 @@ class Connection(CommonConnection, ConnectionHandlers):
self.on_connect_auth = None self.on_connect_auth = None
# END connect # END connect
def add_lang(self, stanza):
stanza.setAttr('xml:lang', i18n.LANG)
def send_keepalive(self): def send_keepalive(self):
# nothing received for the last foo seconds # nothing received for the last foo seconds
if self.connection: if self.connection:
@ -1372,15 +1366,15 @@ class Connection(CommonConnection, ConnectionHandlers):
# offline presence first as it's required by XEP-0126 # offline presence first as it's required by XEP-0126
if self.connected > 1 and self.get_module('PrivacyLists').supported: if self.connected > 1 and self.get_module('PrivacyLists').supported:
self.on_purpose = True self.on_purpose = True
p = nbxmpp.Presence(typ='unavailable')
p = self.add_sha(p, False)
if msg:
p.setStatus(msg)
self.remove_all_transfers() self.remove_all_transfers()
self.connection.send(p) self.get_module('Presence').send_presence(
typ='unavailable',
status=msg,
caps=False)
# try to set the privacy rule # try to set the privacy rule
iq = self.get_module('PrivacyLists').set_invisible_rule( self.get_module('PrivacyLists').set_invisible_rule(
callback=self._continue_invisible, callback=self._continue_invisible,
msg=msg, msg=msg,
signed=signed, signed=signed,
@ -1394,13 +1388,12 @@ class Connection(CommonConnection, ConnectionHandlers):
self.connected = app.SHOW_LIST.index('invisible') self.connected = app.SHOW_LIST.index('invisible')
self.status = msg self.status = msg
priority = app.get_priority(self.name, 'invisible') priority = app.get_priority(self.name, 'invisible')
p = nbxmpp.Presence(priority=priority)
p = self.add_sha(p, True) self.get_module('Presence').send_presence(
if msg: priority=priority,
p.setStatus(msg) status=msg,
if signed: sign=signed)
p.setTag(nbxmpp.NS_SIGNED + ' x').setData(signed)
self.connection.send(p)
self.priority = priority self.priority = priority
app.nec.push_incoming_event(OurShowEvent(None, conn=self, app.nec.push_incoming_event(OurShowEvent(None, conn=self,
show='invisible')) show='invisible'))
@ -1486,20 +1479,21 @@ class Connection(CommonConnection, ConnectionHandlers):
if not msg: if not msg:
msg = '' msg = ''
if show == 'offline': if show == 'offline':
p = nbxmpp.Presence(typ='unavailable', to=jid) self.get_module('Presence').send_presence(
p = self.add_sha(p, False) jid,
if msg: 'unavailable',
p.setStatus(msg) caps=False,
status=msg)
else: else:
signed = self.get_signed_presence(msg) signed = self.get_signed_presence(msg)
priority = app.get_priority(self.name, sshow) priority = app.get_priority(self.name, sshow)
p = nbxmpp.Presence(typ=None, priority=priority, show=sshow, to=jid) self.get_module('Presence').send_presence(
p = self.add_sha(p) jid,
if msg: priority=priority,
p.setStatus(msg) show=sshow,
if signed: status=msg,
p.setTag(nbxmpp.NS_SIGNED + ' x').setData(signed) sign=signed)
self.connection.send(p)
def _change_to_invisible(self, msg): def _change_to_invisible(self, msg):
signed = self.get_signed_presence(msg) signed = self.get_signed_presence(msg)
@ -1512,18 +1506,16 @@ class Connection(CommonConnection, ConnectionHandlers):
def _update_status(self, show, msg, idle_time=None): def _update_status(self, show, msg, idle_time=None):
xmpp_show = helpers.get_xmpp_show(show) xmpp_show = helpers.get_xmpp_show(show)
priority = app.get_priority(self.name, xmpp_show) priority = app.get_priority(self.name, xmpp_show)
p = nbxmpp.Presence(typ=None, priority=priority, show=xmpp_show)
p = self.add_sha(p)
if msg:
p.setStatus(msg)
signed = self.get_signed_presence(msg) signed = self.get_signed_presence(msg)
if signed:
p.setTag(nbxmpp.NS_SIGNED + ' x').setData(signed) self.get_module('Presence').send_presence(
if idle_time: priority=priority,
idle_node = p.setTag('idle', namespace=nbxmpp.NS_IDLE) show=xmpp_show,
idle_node.setAttr('since', idle_time) status=msg,
sign=signed,
idle_time=idle_time)
if self.connection: if self.connection:
self.connection.send(p)
self.priority = priority self.priority = priority
app.nec.push_incoming_event(OurShowEvent(None, conn=self, app.nec.push_incoming_event(OurShowEvent(None, conn=self,
show=show)) show=show))
@ -1654,9 +1646,12 @@ class Connection(CommonConnection, ConnectionHandlers):
if not app.account_is_connected(self.name): if not app.account_is_connected(self.name):
return return
show = helpers.get_xmpp_show(app.SHOW_LIST[self.connected]) show = helpers.get_xmpp_show(app.SHOW_LIST[self.connected])
p = nbxmpp.Presence(to=agent, typ=ptype, show=show)
p = self.add_sha(p, ptype != 'unavailable') self.get_module('Presence').send_presence(
self.connection.send(p) agent,
ptype,
show=show,
caps=ptype != 'unavailable')
def send_captcha(self, jid, form_node): def send_captcha(self, jid, form_node):
if not app.account_is_connected(self.name): if not app.account_is_connected(self.name):
@ -1697,56 +1692,19 @@ class Connection(CommonConnection, ConnectionHandlers):
password, change_nick, rejoin)) password, change_nick, rejoin))
def _join_gc(self, nick, show, room_jid, password, change_nick, rejoin): def _join_gc(self, nick, show, room_jid, password, change_nick, rejoin):
# Check time first in the FAST table
last_date = app.logger.get_room_last_message_time(
self.name, room_jid)
if not last_date:
last_date = 0
p = nbxmpp.Presence(to='%s/%s' % (room_jid, nick),
show=show, status=self.status)
h = hmac.new(self.secret_hmac, room_jid.encode('utf-8'), hashlib.md5).\
hexdigest()[:6]
id_ = self.connection.getAnID()
id_ = 'gajim_muc_' + id_ + '_' + h
p.setID(id_)
if app.config.get('send_sha_in_gc_presence'):
p = self.add_sha(p)
self.add_lang(p)
if change_nick: if change_nick:
self.connection.send(p) self.get_module('Presence').send_presence(
return '%s/%s' % (room_jid, nick),
show=show,
t = p.setTag(nbxmpp.NS_MUC + ' x') status=self.status)
if muc_caps_cache.has_mam(room_jid):
# The room is MAM capable dont get MUC History
t.setTag('history', {'maxchars': '0'})
else: else:
# Request MUC History (not MAM) self.get_module('MUC').send_muc_join_presence(
tags = {} '%s/%s' % (room_jid, nick),
timeout = app.config.get_per('rooms', room_jid, show=show,
'muc_restore_timeout') status=self.status,
if timeout is None or timeout == -2: room_jid=room_jid,
timeout = app.config.get('muc_restore_timeout') password=password,
if last_date == 0 and timeout >= 0: rejoin=rejoin)
last_date = time.time() - timeout * 60
elif not rejoin and timeout >= 0:
last_date = max(last_date, time.time() - timeout * 60)
last_date = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(
last_date))
tags['since'] = last_date
nb = app.config.get_per('rooms', room_jid, 'muc_restore_lines')
if nb is None or nb == -2:
nb = app.config.get('muc_restore_lines')
if nb >= 0:
tags['maxstanzas'] = nb
if tags:
t.setTag('history', tags)
if password:
t.setTagData('password', password)
self.connection.send(p)
def _nec_gc_message_outgoing(self, obj): def _nec_gc_message_outgoing(self, obj):
if obj.account != self.name: if obj.account != self.name:
@ -1809,26 +1767,20 @@ class Connection(CommonConnection, ConnectionHandlers):
if show == 'offline': if show == 'offline':
ptype = 'unavailable' ptype = 'unavailable'
xmpp_show = helpers.get_xmpp_show(show) xmpp_show = helpers.get_xmpp_show(show)
p = nbxmpp.Presence(to='%s/%s' % (jid, nick), typ=ptype,
show=xmpp_show, status=status) idle_time = None
h = hmac.new(self.secret_hmac, jid.encode('utf-8'), hashlib.md5).\ if auto and app.is_installed('IDLE') and app.config.get('autoaway'):
hexdigest()[:6] idle_sec = idle.Monitor.get_idle_sec()
id_ = self.connection.getAnID() idle_time = time.strftime('%Y-%m-%dT%H:%M:%SZ',
id_ = 'gajim_muc_' + id_ + '_' + h time.gmtime(time.time() - idle_sec))
p.setID(id_)
if app.config.get('send_sha_in_gc_presence') and show != 'offline': self.get_module('Presence').send_presence(
p = self.add_sha(p, ptype != 'unavailable') '%s/%s' % (jid, nick),
self.add_lang(p) typ=ptype,
if auto: show=xmpp_show,
if app.is_installed('IDLE') and app.config.get('autoaway'): status=status,
idle_sec = idle.Monitor.get_idle_sec() caps=ptype != 'unavailable',
idle_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', idle_time=idle_time)
time.gmtime(time.time() - idle_sec))
idle_node = p.setTag('idle', namespace=nbxmpp.NS_IDLE)
idle_node.setAttr('since', idle_time)
# send instantly so when we go offline, status is sent to gc before we
# disconnect from jabber server
self.connection.send(p)
def get_password(self, callback, type_): def get_password(self, callback, type_):
if app.config.get_per('accounts', self.name, 'anonymous_auth') and \ if app.config.get_per('accounts', self.name, 'anonymous_auth') and \

View File

@ -422,20 +422,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream,
app.ged.remove_event_handler('agent-removed', ged.CORE, app.ged.remove_event_handler('agent-removed', ged.CORE,
self._nec_agent_removed) self._nec_agent_removed)
def add_sha(self, p, send_caps=True):
p = self.get_module('VCardAvatars').add_update_node(p)
if send_caps:
return self._add_caps(p)
return p
def _add_caps(self, p):
''' advertise our capabilities in presence stanza (xep-0115)'''
c = p.setTag('c', namespace=nbxmpp.NS_CAPS)
c.setAttr('hash', 'sha-1')
c.setAttr('node', 'http://gajim.org')
c.setAttr('ver', app.caps_hash[self.name])
return p
def _ErrorCB(self, con, iq_obj): def _ErrorCB(self, con, iq_obj):
log.debug('ErrorCB') log.debug('ErrorCB')
app.nec.push_incoming_event(IqErrorReceivedEvent(None, conn=self, app.nec.push_incoming_event(IqErrorReceivedEvent(None, conn=self,
@ -582,15 +568,14 @@ class ConnectionHandlers(ConnectionSocks5Bytestream,
if show not in ['offline', 'online', 'chat', 'away', 'xa', 'dnd']: if show not in ['offline', 'online', 'chat', 'away', 'xa', 'dnd']:
return return
priority = app.get_priority(self.name, sshow) priority = app.get_priority(self.name, sshow)
p = nbxmpp.Presence(typ=None, priority=priority, show=sshow)
if msg: self.get_module('Presence').send_presence(
p.setStatus(msg) priority=priority,
if signed: show=sshow,
p.setTag(nbxmpp.NS_SIGNED + ' x').setData(signed) status=msg,
p = self.add_sha(p) sign=signed)
if self.connection: if self.connection:
self.connection.send(p)
self.priority = priority self.priority = priority
app.nec.push_incoming_event(OurShowEvent(None, conn=self, app.nec.push_incoming_event(OurShowEvent(None, conn=self,
show=show)) show=show))

View File

@ -288,7 +288,7 @@ PresenceHelperEvent):
xtags = self.stanza.getTags('x') xtags = self.stanza.getTags('x')
for x in xtags: for x in xtags:
namespace = x.getNamespace() namespace = x.getNamespace()
if namespace == nbxmpp.NS_MUC_USER: if namespace in (nbxmpp.NS_MUC_USER, nbxmpp.NS_MUC):
self.is_gc = True self.is_gc = True
elif namespace == nbxmpp.NS_SIGNED: elif namespace == nbxmpp.NS_SIGNED:
sig_tag = x sig_tag = x
@ -296,14 +296,6 @@ PresenceHelperEvent):
# XEP-0091 # XEP-0091
self._generate_timestamp(self.stanza.timestamp) self._generate_timestamp(self.stanza.timestamp)
if not self.is_gc and self.id_ and self.id_.startswith('gajim_muc_') \
and self.ptype == 'error':
# Error presences may not include sent stanza, so we don't detect
# it's a muc presence. So detect it by ID
h = hmac.new(self.conn.secret_hmac, self.jid.encode('utf-8'),
hashlib.md5).hexdigest()[:6]
if self.id_.split('_')[-1] == h:
self.is_gc = True
self.status = self.stanza.getStatus() or '' self.status = self.stanza.getStatus() or ''
self._generate_show() self._generate_show()
self._generate_prio() self._generate_prio()

View File

@ -15,6 +15,7 @@
# XEP-0045: Multi-User Chat # XEP-0045: Multi-User Chat
# XEP-0249: Direct MUC Invitations # XEP-0249: Direct MUC Invitations
import time
import logging import logging
import nbxmpp import nbxmpp
@ -23,6 +24,7 @@ from gajim.common import i18n
from gajim.common.modules import dataforms from gajim.common.modules import dataforms
from gajim.common import app from gajim.common import app
from gajim.common import helpers from gajim.common import helpers
from gajim.common.caps_cache import muc_caps_cache
from gajim.common.nec import NetworkIncomingEvent from gajim.common.nec import NetworkIncomingEvent
log = logging.getLogger('gajim.c.m.muc') log = logging.getLogger('gajim.c.m.muc')
@ -50,6 +52,56 @@ class MUC:
self._con.muc_jid['jabber'] = from_ self._con.muc_jid['jabber'] = from_
raise nbxmpp.NodeProcessed raise nbxmpp.NodeProcessed
def send_muc_join_presence(self, *args, room_jid=None, password=None,
rejoin=False, **kwargs):
if not app.account_is_connected(self._account):
return
presence = self._con.get_module('Presence').get_presence(
*args, **kwargs)
if room_jid is not None:
self._add_history_query(presence, room_jid, rejoin)
if password is not None:
presence.setTagData('password', password)
log.debug('Send MUC join presence:\n%s', presence)
self._con.connection.send(presence)
def _add_history_query(self, presence, room_jid, rejoin):
last_date = app.logger.get_room_last_message_time(
self._account, room_jid)
if not last_date:
last_date = 0
history = presence.setTag(nbxmpp.NS_MUC + ' x')
if muc_caps_cache.has_mam(room_jid):
# The room is MAM capable dont get MUC History
history.setTag('history', {'maxchars': '0'})
else:
# Request MUC History (not MAM)
tags = {}
timeout = app.config.get_per('rooms', room_jid,
'muc_restore_timeout')
if timeout is None or timeout == -2:
timeout = app.config.get('muc_restore_timeout')
if last_date == 0 and timeout >= 0:
last_date = time.time() - timeout * 60
elif not rejoin and timeout >= 0:
last_date = max(last_date, time.time() - timeout * 60)
last_date = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(
last_date))
tags['since'] = last_date
nb = app.config.get_per('rooms', room_jid, 'muc_restore_lines')
if nb is None or nb == -2:
nb = app.config.get('muc_restore_lines')
if nb >= 0:
tags['maxstanzas'] = nb
if tags:
history.setTag('history', tags)
def set_subject(self, room_jid, subject): def set_subject(self, room_jid, subject):
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
return return

View File

@ -75,9 +75,7 @@ class Presence:
raise nbxmpp.NodeProcessed raise nbxmpp.NodeProcessed
if auto_auth or is_transport or jid in self.jids_for_auto_auth: if auto_auth or is_transport or jid in self.jids_for_auto_auth:
presence = nbxmpp.Presence(fjid, 'subscribed') self.send_presence(fjid, 'subscribed')
presence = self._add_sha(presence)
self._con.connection.send(presence)
if not status: if not status:
status = _('I would like to add you to my roster.') status = _('I would like to add you to my roster.')
@ -124,17 +122,13 @@ class Presence:
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
return return
log.info('Subscribed: %s', jid) log.info('Subscribed: %s', jid)
presence = nbxmpp.Presence(jid, 'subscribed') self.send_presence(jid, 'subscribed')
presence = self._add_sha(presence)
self._con.connection.send(presence)
def unsubscribed(self, jid): def unsubscribed(self, jid):
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
return return
log.info('Unsubscribed: %s', jid) log.info('Unsubscribed: %s', jid)
presence = nbxmpp.Presence(jid, 'unsubscribed') self.send_presence(jid, 'unsubscribed')
presence = self._add_sha(presence)
self._con.connection.send(presence)
def unsubscribe(self, jid, remove_auth=True): def unsubscribe(self, jid, remove_auth=True):
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
@ -150,7 +144,7 @@ class Presence:
self._con.getRoster().Unsubscribe(jid) self._con.getRoster().Unsubscribe(jid)
self._con.getRoster().setItem(jid) self._con.getRoster().setItem(jid)
def subscribe(self, jid, msg='', name='', groups=None, def subscribe(self, jid, msg=None, name='', groups=None,
auto_auth=False, user_nick=''): auto_auth=False, user_nick=''):
if not app.account_is_connected(self._account): if not app.account_is_connected(self._account):
return return
@ -172,29 +166,40 @@ class Presence:
item.addChild('group').setData(group) item.addChild('group').setData(group)
self._con.connection.send(iq) self._con.connection.send(iq)
presence = nbxmpp.Presence(jid, 'subscribe') self.send_presence(jid, 'subscribe', msg)
if user_nick:
nick = presence.setTag('nick', namespace=nbxmpp.NS_NICK) def get_presence(self, to=None, typ=None, priority=None,
nick.setData(user_nick) show=None, status=None, nick=None, caps=True,
presence = self._add_sha(presence) sign=None, idle_time=None):
if msg: presence = nbxmpp.Presence(to, typ, priority, show, status)
presence.setStatus(msg) if nick is not None:
nick_tag = presence.setTag('nick', namespace=nbxmpp.NS_NICK)
nick_tag.setData(nick)
if sign:
presence.setTag(nbxmpp.NS_SIGNED + ' x').setData(sign)
if idle_time is not None:
idle_node = presence.setTag('idle', namespace=nbxmpp.NS_IDLE)
idle_node.setAttr('since', idle_time)
self._con.get_module('VCardAvatars').add_update_node(presence)
if caps:
attrs = {'hash': 'sha-1',
'node': 'http://gajim.org',
'ver': app.caps_hash[self._account]}
presence.setTag('c', namespace=nbxmpp.NS_CAPS, attrs=attrs)
return presence
def send_presence(self, *args, **kwargs):
if not app.account_is_connected(self._account):
return
presence = self.get_presence(*args, **kwargs)
log.debug('Send presence:\n%s', presence)
self._con.connection.send(presence) self._con.connection.send(presence)
def _add_sha(self, presence, send_caps=True):
vcard = self._con.get_module('VCardAvatars')
presence = vcard.add_update_node(presence)
if send_caps:
return self._add_caps(presence)
return presence
def _add_caps(self, presence):
c = presence.setTag('c', namespace=nbxmpp.NS_CAPS)
c.setAttr('hash', 'sha-1')
c.setAttr('node', 'http://gajim.org')
c.setAttr('ver', app.caps_hash[self._account])
return presence
def parse_show(stanza): def parse_show(stanza):
show = stanza.getShow() show = stanza.getShow()

View File

@ -173,10 +173,12 @@ class VCardAvatars:
log.debug('Avatar already advertised') log.debug('Avatar already advertised')
return return
show = helpers.get_xmpp_show(app.SHOW_LIST[self._con.connected]) show = helpers.get_xmpp_show(app.SHOW_LIST[self._con.connected])
pres = nbxmpp.Presence(typ=None, priority=self._con.priority,
show=show, status=self._con.status) self._con.get_module('Presence').send_presence(
pres = self._con.add_sha(pres) priority=self._con.priority,
self._con.connection.send(pres) show=show,
status=self._con.status)
self.avatar_advertised = True self.avatar_advertised = True
app.interface.update_avatar(self._account, app.interface.update_avatar(self._account,
self._con.get_own_jid().getStripped()) self._con.get_own_jid().getStripped())
@ -189,7 +191,6 @@ class VCardAvatars:
log.info('Send avatar presence to: %s %s', log.info('Send avatar presence to: %s %s',
node.getTo() or own_jid, sha or 'no sha advertised') node.getTo() or own_jid, sha or 'no sha advertised')
update.setTagData('photo', sha) update.setTagData('photo', sha)
return node
def get_instance(*args, **kwargs): def get_instance(*args, **kwargs):