From d4d29f8309ce4739b0684d9b85cf18ef4e7afb8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20H=C3=B6rist?= Date: Sat, 1 Sep 2018 17:07:30 +0200 Subject: [PATCH] Send all presence through the presence module --- gajim/common/config.py | 1 - gajim/common/connection.py | 184 ++++++++------------- gajim/common/connection_handlers.py | 27 +-- gajim/common/connection_handlers_events.py | 10 +- gajim/common/modules/muc.py | 52 ++++++ gajim/common/modules/presence.py | 67 ++++---- gajim/common/modules/vcard_avatars.py | 11 +- 7 files changed, 169 insertions(+), 183 deletions(-) diff --git a/gajim/common/config.py b/gajim/common/config.py index 3fb649e1d..e0deedc1a 100644 --- a/gajim/common/config.py +++ b/gajim/common/config.py @@ -241,7 +241,6 @@ class Config: '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.')], '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', #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.')], diff --git a/gajim/common/connection.py b/gajim/common/connection.py index dfb8f6379..97c92a71e 100644 --- a/gajim/common/connection.py +++ b/gajim/common/connection.py @@ -38,7 +38,6 @@ import socket import operator import string import time -import hmac import hashlib import json import logging @@ -60,12 +59,10 @@ from gajim.common import helpers from gajim.common import app from gajim.common import gpg from gajim.common import passwords -from gajim.common import i18n from gajim.common import idle from gajim.common.connection_handlers import * from gajim.common.contacts import GC_Contact from gajim.common import modules -from gajim.gtkgui_helpers import get_action log = logging.getLogger('gajim.c.connection') @@ -474,10 +471,11 @@ class CommonConnection: if self.connection: app.nec.push_incoming_event(BeforeChangeShowEvent(None, conn=self, show=show, message=msg)) - p = nbxmpp.Presence(typ = 'unavailable') - p = self.add_sha(p, False) - if msg: - p.setStatus(msg) + + p = self.get_module('Presence').get_presence( + typ='unavailable', + status=msg, + caps=False) self.connection.RegisterDisconnectHandler(self._on_disconnected) self.connection.send(p, now=True) @@ -542,7 +540,6 @@ class Connection(CommonConnection, ConnectionHandlers): # server {'icq': ['icq.server.com', 'icq2.server.com'], } self.streamError = '' - self.secret_hmac = str(random.random())[2:].encode('utf-8') self.removing_account = False # We only request POSH once @@ -1351,9 +1348,6 @@ class Connection(CommonConnection, ConnectionHandlers): self.on_connect_auth = None # END connect - def add_lang(self, stanza): - stanza.setAttr('xml:lang', i18n.LANG) - def send_keepalive(self): # nothing received for the last foo seconds if self.connection: @@ -1372,15 +1366,15 @@ class Connection(CommonConnection, ConnectionHandlers): # offline presence first as it's required by XEP-0126 if self.connected > 1 and self.get_module('PrivacyLists').supported: 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.connection.send(p) + self.get_module('Presence').send_presence( + typ='unavailable', + status=msg, + caps=False) # 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, msg=msg, signed=signed, @@ -1394,13 +1388,12 @@ class Connection(CommonConnection, ConnectionHandlers): self.connected = app.SHOW_LIST.index('invisible') self.status = msg priority = app.get_priority(self.name, 'invisible') - p = nbxmpp.Presence(priority=priority) - p = self.add_sha(p, True) - if msg: - p.setStatus(msg) - if signed: - p.setTag(nbxmpp.NS_SIGNED + ' x').setData(signed) - self.connection.send(p) + + self.get_module('Presence').send_presence( + priority=priority, + status=msg, + sign=signed) + self.priority = priority app.nec.push_incoming_event(OurShowEvent(None, conn=self, show='invisible')) @@ -1486,20 +1479,21 @@ class Connection(CommonConnection, ConnectionHandlers): if not msg: msg = '' if show == 'offline': - p = nbxmpp.Presence(typ='unavailable', to=jid) - p = self.add_sha(p, False) - if msg: - p.setStatus(msg) + self.get_module('Presence').send_presence( + jid, + 'unavailable', + caps=False, + status=msg) + else: signed = self.get_signed_presence(msg) priority = app.get_priority(self.name, sshow) - p = nbxmpp.Presence(typ=None, priority=priority, show=sshow, to=jid) - p = self.add_sha(p) - if msg: - p.setStatus(msg) - if signed: - p.setTag(nbxmpp.NS_SIGNED + ' x').setData(signed) - self.connection.send(p) + self.get_module('Presence').send_presence( + jid, + priority=priority, + show=sshow, + status=msg, + sign=signed) def _change_to_invisible(self, msg): signed = self.get_signed_presence(msg) @@ -1512,18 +1506,16 @@ class Connection(CommonConnection, ConnectionHandlers): def _update_status(self, show, msg, idle_time=None): xmpp_show = helpers.get_xmpp_show(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) - if signed: - p.setTag(nbxmpp.NS_SIGNED + ' x').setData(signed) - if idle_time: - idle_node = p.setTag('idle', namespace=nbxmpp.NS_IDLE) - idle_node.setAttr('since', idle_time) + + self.get_module('Presence').send_presence( + priority=priority, + show=xmpp_show, + status=msg, + sign=signed, + idle_time=idle_time) + if self.connection: - self.connection.send(p) self.priority = priority app.nec.push_incoming_event(OurShowEvent(None, conn=self, show=show)) @@ -1654,9 +1646,12 @@ class Connection(CommonConnection, ConnectionHandlers): if not app.account_is_connected(self.name): return 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.connection.send(p) + + self.get_module('Presence').send_presence( + agent, + ptype, + show=show, + caps=ptype != 'unavailable') def send_captcha(self, jid, form_node): if not app.account_is_connected(self.name): @@ -1697,56 +1692,19 @@ class Connection(CommonConnection, ConnectionHandlers): 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: - self.connection.send(p) - return - - t = p.setTag(nbxmpp.NS_MUC + ' x') - if muc_caps_cache.has_mam(room_jid): - # The room is MAM capable dont get MUC History - t.setTag('history', {'maxchars': '0'}) + self.get_module('Presence').send_presence( + '%s/%s' % (room_jid, nick), + show=show, + status=self.status) 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: - t.setTag('history', tags) - - if password: - t.setTagData('password', password) - self.connection.send(p) + self.get_module('MUC').send_muc_join_presence( + '%s/%s' % (room_jid, nick), + show=show, + status=self.status, + room_jid=room_jid, + password=password, + rejoin=rejoin) def _nec_gc_message_outgoing(self, obj): if obj.account != self.name: @@ -1809,26 +1767,20 @@ class Connection(CommonConnection, ConnectionHandlers): if show == 'offline': ptype = 'unavailable' xmpp_show = helpers.get_xmpp_show(show) - p = nbxmpp.Presence(to='%s/%s' % (jid, nick), typ=ptype, - show=xmpp_show, status=status) - h = hmac.new(self.secret_hmac, 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') and show != 'offline': - p = self.add_sha(p, ptype != 'unavailable') - self.add_lang(p) - if auto: - if app.is_installed('IDLE') and app.config.get('autoaway'): - idle_sec = idle.Monitor.get_idle_sec() - idle_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', - 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) + + idle_time = None + if auto and app.is_installed('IDLE') and app.config.get('autoaway'): + idle_sec = idle.Monitor.get_idle_sec() + idle_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', + time.gmtime(time.time() - idle_sec)) + + self.get_module('Presence').send_presence( + '%s/%s' % (jid, nick), + typ=ptype, + show=xmpp_show, + status=status, + caps=ptype != 'unavailable', + idle_time=idle_time) def get_password(self, callback, type_): if app.config.get_per('accounts', self.name, 'anonymous_auth') and \ diff --git a/gajim/common/connection_handlers.py b/gajim/common/connection_handlers.py index 5346a717a..78567a33f 100644 --- a/gajim/common/connection_handlers.py +++ b/gajim/common/connection_handlers.py @@ -422,20 +422,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, app.ged.remove_event_handler('agent-removed', ged.CORE, 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): log.debug('ErrorCB') 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']: return priority = app.get_priority(self.name, sshow) - p = nbxmpp.Presence(typ=None, priority=priority, show=sshow) - if msg: - p.setStatus(msg) - if signed: - p.setTag(nbxmpp.NS_SIGNED + ' x').setData(signed) - p = self.add_sha(p) + + self.get_module('Presence').send_presence( + priority=priority, + show=sshow, + status=msg, + sign=signed) if self.connection: - self.connection.send(p) self.priority = priority app.nec.push_incoming_event(OurShowEvent(None, conn=self, show=show)) diff --git a/gajim/common/connection_handlers_events.py b/gajim/common/connection_handlers_events.py index aad7269aa..a14dae536 100644 --- a/gajim/common/connection_handlers_events.py +++ b/gajim/common/connection_handlers_events.py @@ -288,7 +288,7 @@ PresenceHelperEvent): xtags = self.stanza.getTags('x') for x in xtags: namespace = x.getNamespace() - if namespace == nbxmpp.NS_MUC_USER: + if namespace in (nbxmpp.NS_MUC_USER, nbxmpp.NS_MUC): self.is_gc = True elif namespace == nbxmpp.NS_SIGNED: sig_tag = x @@ -296,14 +296,6 @@ PresenceHelperEvent): # XEP-0091 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._generate_show() self._generate_prio() diff --git a/gajim/common/modules/muc.py b/gajim/common/modules/muc.py index 5063e3479..07d718f26 100644 --- a/gajim/common/modules/muc.py +++ b/gajim/common/modules/muc.py @@ -15,6 +15,7 @@ # XEP-0045: Multi-User Chat # XEP-0249: Direct MUC Invitations +import time import logging import nbxmpp @@ -23,6 +24,7 @@ from gajim.common import i18n from gajim.common.modules import dataforms from gajim.common import app from gajim.common import helpers +from gajim.common.caps_cache import muc_caps_cache from gajim.common.nec import NetworkIncomingEvent log = logging.getLogger('gajim.c.m.muc') @@ -50,6 +52,56 @@ class MUC: self._con.muc_jid['jabber'] = from_ 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): if not app.account_is_connected(self._account): return diff --git a/gajim/common/modules/presence.py b/gajim/common/modules/presence.py index 7f7bf969b..caaf4028a 100644 --- a/gajim/common/modules/presence.py +++ b/gajim/common/modules/presence.py @@ -75,9 +75,7 @@ class Presence: raise nbxmpp.NodeProcessed if auto_auth or is_transport or jid in self.jids_for_auto_auth: - presence = nbxmpp.Presence(fjid, 'subscribed') - presence = self._add_sha(presence) - self._con.connection.send(presence) + self.send_presence(fjid, 'subscribed') if not status: status = _('I would like to add you to my roster.') @@ -124,17 +122,13 @@ class Presence: if not app.account_is_connected(self._account): return log.info('Subscribed: %s', jid) - presence = nbxmpp.Presence(jid, 'subscribed') - presence = self._add_sha(presence) - self._con.connection.send(presence) + self.send_presence(jid, 'subscribed') def unsubscribed(self, jid): if not app.account_is_connected(self._account): return log.info('Unsubscribed: %s', jid) - presence = nbxmpp.Presence(jid, 'unsubscribed') - presence = self._add_sha(presence) - self._con.connection.send(presence) + self.send_presence(jid, 'unsubscribed') def unsubscribe(self, jid, remove_auth=True): if not app.account_is_connected(self._account): @@ -150,7 +144,7 @@ class Presence: self._con.getRoster().Unsubscribe(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=''): if not app.account_is_connected(self._account): return @@ -172,29 +166,40 @@ class Presence: item.addChild('group').setData(group) self._con.connection.send(iq) - presence = nbxmpp.Presence(jid, 'subscribe') - if user_nick: - nick = presence.setTag('nick', namespace=nbxmpp.NS_NICK) - nick.setData(user_nick) - presence = self._add_sha(presence) - if msg: - presence.setStatus(msg) + self.send_presence(jid, 'subscribe', msg) + + def get_presence(self, to=None, typ=None, priority=None, + show=None, status=None, nick=None, caps=True, + sign=None, idle_time=None): + presence = nbxmpp.Presence(to, typ, priority, show, status) + 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) - 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): show = stanza.getShow() diff --git a/gajim/common/modules/vcard_avatars.py b/gajim/common/modules/vcard_avatars.py index 8baf348dd..e462bacf1 100644 --- a/gajim/common/modules/vcard_avatars.py +++ b/gajim/common/modules/vcard_avatars.py @@ -173,10 +173,12 @@ class VCardAvatars: log.debug('Avatar already advertised') return 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) - pres = self._con.add_sha(pres) - self._con.connection.send(pres) + + self._con.get_module('Presence').send_presence( + priority=self._con.priority, + show=show, + status=self._con.status) + self.avatar_advertised = True app.interface.update_avatar(self._account, self._con.get_own_jid().getStripped()) @@ -189,7 +191,6 @@ class VCardAvatars: log.info('Send avatar presence to: %s %s', node.getTo() or own_jid, sha or 'no sha advertised') update.setTagData('photo', sha) - return node def get_instance(*args, **kwargs):