Commit 340b8bb2 authored by Philipp Hörist's avatar Philipp Hörist
Browse files

Refactor handling of entity caps

- Let nbxmpp handle responding to entity caps requests
- Move code into Caps module
parent 24b177c6
......@@ -38,7 +38,6 @@
from collections import namedtuple
import nbxmpp
from nbxmpp.structs import DiscoIdentity
from gi.repository import Gdk
import gajim
......@@ -148,52 +147,6 @@
gsound_ctx = None
gajim_identity = DiscoIdentity(category='client',
type='pc',
name='Gajim')
gajim_common_features = [
nbxmpp.NS_BYTESTREAM,
nbxmpp.NS_MUC,
nbxmpp.NS_COMMANDS,
nbxmpp.NS_DISCO_INFO,
nbxmpp.NS_LAST,
nbxmpp.NS_DATA,
nbxmpp.NS_ENCRYPTED,
nbxmpp.NS_PING,
nbxmpp.NS_CHATSTATES,
nbxmpp.NS_RECEIPTS,
nbxmpp.NS_TIME_REVISED,
nbxmpp.NS_VERSION,
nbxmpp.NS_ROSTERX,
nbxmpp.NS_SECLABEL,
nbxmpp.NS_CONFERENCE,
nbxmpp.NS_CORRECT,
nbxmpp.NS_EME,
nbxmpp.NS_XHTML_IM,
nbxmpp.NS_HASHES_2,
nbxmpp.NS_HASHES_MD5,
nbxmpp.NS_HASHES_SHA1,
nbxmpp.NS_HASHES_SHA256,
nbxmpp.NS_HASHES_SHA512,
nbxmpp.NS_HASHES_SHA3_256,
nbxmpp.NS_HASHES_SHA3_512,
nbxmpp.NS_HASHES_BLAKE2B_256,
nbxmpp.NS_HASHES_BLAKE2B_512,
nbxmpp.NS_JINGLE,
nbxmpp.NS_JINGLE_FILE_TRANSFER_5,
nbxmpp.NS_JINGLE_XTLS,
nbxmpp.NS_JINGLE_BYTESTREAM,
nbxmpp.NS_JINGLE_IBB,
nbxmpp.NS_AVATAR_METADATA + '+notify',
]
# Optional features gajim supports per account
gajim_optional_features = {} # type: Dict[str, List[str]]
# Capabilities hash per account
caps_hash = {} # type: Dict[str, List[str]]
_dependencies = {
'AVAHI': False,
'PYBONJOUR': False,
......
......@@ -3,6 +3,8 @@
from gi.repository import Gio
import nbxmpp
from gajim.common.i18n import _
from gajim.common.i18n import Q_
......@@ -910,3 +912,40 @@ def is_error(self):
'not-authorized': _('Authentication failed'),
'temporary-auth-failure': _('Authentication currently not possible'),
}
COMMON_FEATURES = [
nbxmpp.NS_BYTESTREAM,
nbxmpp.NS_MUC,
nbxmpp.NS_COMMANDS,
nbxmpp.NS_DISCO_INFO,
nbxmpp.NS_LAST,
nbxmpp.NS_DATA,
nbxmpp.NS_ENCRYPTED,
nbxmpp.NS_PING,
nbxmpp.NS_CHATSTATES,
nbxmpp.NS_RECEIPTS,
nbxmpp.NS_TIME_REVISED,
nbxmpp.NS_VERSION,
nbxmpp.NS_ROSTERX,
nbxmpp.NS_SECLABEL,
nbxmpp.NS_CONFERENCE,
nbxmpp.NS_CORRECT,
nbxmpp.NS_EME,
nbxmpp.NS_XHTML_IM,
nbxmpp.NS_HASHES_2,
nbxmpp.NS_HASHES_MD5,
nbxmpp.NS_HASHES_SHA1,
nbxmpp.NS_HASHES_SHA256,
nbxmpp.NS_HASHES_SHA512,
nbxmpp.NS_HASHES_SHA3_256,
nbxmpp.NS_HASHES_SHA3_512,
nbxmpp.NS_HASHES_BLAKE2B_256,
nbxmpp.NS_HASHES_BLAKE2B_512,
nbxmpp.NS_JINGLE,
nbxmpp.NS_JINGLE_FILE_TRANSFER_5,
nbxmpp.NS_JINGLE_XTLS,
nbxmpp.NS_JINGLE_BYTESTREAM,
nbxmpp.NS_JINGLE_IBB,
nbxmpp.NS_AVATAR_METADATA + '+notify',
]
......@@ -59,9 +59,7 @@
from functools import wraps
import nbxmpp
from nbxmpp.util import compute_caps_hash
from nbxmpp.stringprepare import nameprep
from nbxmpp.structs import DiscoInfo
from nbxmpp.const import Role
from nbxmpp.const import ConnectionProtocol
from nbxmpp.const import ConnectionType
......@@ -1024,50 +1022,31 @@ def get_current_show(account):
return 'offline'
return app.connections[account].status
def update_optional_features(account=None):
if account is not None:
accounts = [account]
else:
accounts = app.connections.keys()
for account_ in accounts:
features = []
app.gajim_optional_features[account_] = features
if app.config.get_per('accounts', account_, 'subscribe_mood'):
features.append(nbxmpp.NS_MOOD + '+notify')
if app.config.get_per('accounts', account_, 'subscribe_activity'):
features.append(nbxmpp.NS_ACTIVITY + '+notify')
if app.config.get_per('accounts', account_, 'subscribe_tune'):
features.append(nbxmpp.NS_TUNE + '+notify')
if app.config.get_per('accounts', account_, 'subscribe_nick'):
features.append(nbxmpp.NS_NICK + '+notify')
if app.config.get_per('accounts', account_, 'subscribe_location'):
features.append(nbxmpp.NS_LOCATION + '+notify')
if app.connections[account_].get_module('Bookmarks').using_bookmark_2:
features.append(nbxmpp.NS_BOOKMARKS_2 + '+notify')
elif app.connections[account_].get_module('Bookmarks').using_bookmark_1:
features.append(nbxmpp.NS_BOOKMARKS + '+notify')
if app.is_installed('AV'):
features.append(nbxmpp.NS_JINGLE_RTP)
features.append(nbxmpp.NS_JINGLE_RTP_AUDIO)
features.append(nbxmpp.NS_JINGLE_RTP_VIDEO)
features.append(nbxmpp.NS_JINGLE_ICE_UDP)
# Give plugins the possibility to add their features
app.plugin_manager.extension_point('update_caps', account_)
disco_info = DiscoInfo(None,
[app.gajim_identity],
app.gajim_common_features + features,
[])
app.caps_hash[account_] = compute_caps_hash(disco_info, compare=False)
# re-send presence with new hash
if not app.account_is_connected(account_):
return
status = app.connections[account_].status
app.connections[account_].change_status(
status, app.connections[account_].status_message)
def get_optional_features(account):
features = []
if app.config.get_per('accounts', account, 'subscribe_mood'):
features.append(nbxmpp.NS_MOOD + '+notify')
if app.config.get_per('accounts', account, 'subscribe_activity'):
features.append(nbxmpp.NS_ACTIVITY + '+notify')
if app.config.get_per('accounts', account, 'subscribe_tune'):
features.append(nbxmpp.NS_TUNE + '+notify')
if app.config.get_per('accounts', account, 'subscribe_nick'):
features.append(nbxmpp.NS_NICK + '+notify')
if app.config.get_per('accounts', account, 'subscribe_location'):
features.append(nbxmpp.NS_LOCATION + '+notify')
if app.connections[account].get_module('Bookmarks').using_bookmark_2:
features.append(nbxmpp.NS_BOOKMARKS_2 + '+notify')
elif app.connections[account].get_module('Bookmarks').using_bookmark_1:
features.append(nbxmpp.NS_BOOKMARKS + '+notify')
if app.is_installed('AV'):
features.append(nbxmpp.NS_JINGLE_RTP)
features.append(nbxmpp.NS_JINGLE_RTP_AUDIO)
features.append(nbxmpp.NS_JINGLE_RTP_VIDEO)
features.append(nbxmpp.NS_JINGLE_ICE_UDP)
# Give plugins the possibility to add their features
app.plugin_manager.extension_point('update_caps', account, features)
return features
def jid_is_blocked(account, jid):
con = app.connections[account]
......
......@@ -19,16 +19,26 @@
import nbxmpp
from nbxmpp.structs import StanzaHandler
from nbxmpp.structs import DiscoIdentity
from nbxmpp.util import is_error_result
from nbxmpp.util import compute_caps_hash
from gajim.common import caps_cache
from gajim.common import app
from gajim.common.const import COMMON_FEATURES
from gajim.common.helpers import get_optional_features
from gajim.common.nec import NetworkEvent
from gajim.common.modules.base import BaseModule
class Caps(BaseModule):
_nbxmpp_extends = 'EntityCaps'
_nbxmpp_methods = [
'caps',
'set_caps'
]
def __init__(self, con):
BaseModule.__init__(self, con)
......@@ -43,6 +53,10 @@ def __init__(self, con):
self._create_suitable_client_caps = \
caps_cache.create_suitable_client_caps
self._identities = [
DiscoIdentity(category='client', type='pc', name='Gajim')
]
def _entity_caps(self, _con, _stanza, properties):
if properties.type.is_error or properties.type.is_unavailable:
return
......@@ -139,6 +153,19 @@ def contact_info_received(self, info):
fjid=str(info.jid),
jid=bare_jid))
def update_caps(self):
if not app.account_is_connected(self._account):
return
optional_features = get_optional_features(self._account)
self.set_caps(self._identities,
COMMON_FEATURES + optional_features,
'https://gajim.org')
app.connections[self._account].change_status(
app.connections[self._account].status,
app.connections[self._account].status_message)
def get_instance(*args, **kwargs):
return Caps(*args, **kwargs), 'Caps'
......@@ -22,7 +22,6 @@
from gajim.common.nec import NetworkIncomingEvent
from gajim.common.nec import NetworkEvent
from gajim.common.modules.base import BaseModule
from gajim.common.helpers import update_optional_features
class Discovery(BaseModule):
......@@ -120,7 +119,7 @@ def _account_info_received(self, result):
if 'urn:xmpp:pep-vcard-conversion:0' in result.features:
self._con.avatar_conversion = True
update_optional_features()
self._con.get_module('Caps').update_caps()
def discover_server_info(self):
# Calling this method starts the connect_maschine()
......@@ -194,23 +193,6 @@ def _answer_disco_info(self, _con, stanza, _properties):
if self._con.get_module('AdHocCommands').command_info_query(stanza):
raise nbxmpp.NodeProcessed
node = stanza.getQuerynode()
iq = stanza.buildReply('result')
query = iq.setQuery()
if node:
query.setAttr('node', node)
query.addChild('identity', attrs=app.gajim_identity._asdict())
client_version = 'http://gajim.org#' + app.caps_hash[self._account]
if node in (None, client_version):
for feature in app.gajim_common_features:
query.addChild('feature', attrs={'var': feature})
for feature in app.gajim_optional_features[self._account]:
query.addChild('feature', attrs={'var': feature})
self._con.connection.send(iq)
raise nbxmpp.NodeProcessed
def disco_muc(self, jid, callback=None):
if not app.account_is_connected(self._account):
return
......
......@@ -371,11 +371,11 @@ def get_presence(self, to=None, typ=None, priority=None,
# we add the avatar sha to our presence
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)
caps = self._con.get_module('Caps').caps
if caps is not None and typ != 'unavailable':
presence.setTag('c',
namespace=nbxmpp.NS_CAPS,
attrs=caps._asdict())
return presence
......
......@@ -67,7 +67,6 @@
from gajim.common import idle
from gajim.common.zeroconf import connection_zeroconf
from gajim.common import caps_cache
from gajim.common import proxy65_manager
from gajim.common import socks5
from gajim.common import helpers
......@@ -1729,9 +1728,6 @@ def enable_account(self, account):
app.sleeper_state[account] = 'off'
app.last_message_time[account] = {}
app.status_before_autoaway[account] = ''
app.gajim_optional_features[account] = []
app.caps_hash[account] = ''
helpers.update_optional_features(account)
# refresh roster
if len(app.connections) >= 2:
# Do not merge accounts if only one exists
......@@ -1774,8 +1770,6 @@ def disable_account(self, account):
del app.sleeper_state[account]
del app.last_message_time[account]
del app.status_before_autoaway[account]
del app.gajim_optional_features[account]
del app.caps_hash[account]
if len(app.connections) >= 2:
# Do not merge accounts if only one exists
self.roster.regroup = app.config.get('mergeaccounts')
......@@ -2005,15 +1999,6 @@ def run(self, application):
app.plugin_manager = plugins.PluginManager()
app.plugin_manager.init_plugins()
helpers.update_optional_features()
# prepopulate data which we are sure of; note: we do not log these info
for account in app.connections:
gajimcaps = caps_cache.capscache[
('sha-1', app.caps_hash[account])]
gajimcaps.identities = [app.gajim_identity]
gajimcaps.features = app.gajim_common_features + \
app.gajim_optional_features[account]
self.roster._before_fill()
for account in app.connections:
app.connections[account].get_module('Roster').load_roster()
......@@ -2162,8 +2147,6 @@ def __init__(self):
app.sleeper_state[a] = 0
app.last_message_time[a] = {}
app.status_before_autoaway[a] = ''
app.gajim_optional_features[a] = []
app.caps_hash[a] = ''
if sys.platform not in ('win32', 'darwin'):
logind.enable()
......
......@@ -3439,7 +3439,7 @@ def on_publish_tune_toggled(self, widget, account):
else:
app.interface.disable_music_listener()
helpers.update_optional_features(account)
app.connections[account].get_module('Caps').update_caps()
def on_publish_location_toggled(self, widget, account):
active = widget.get_active()
......@@ -3449,7 +3449,7 @@ def on_publish_location_toggled(self, widget, account):
else:
app.connections[account].get_module('UserLocation').set_location(None)
helpers.update_optional_features(account)
app.connections[account].get_module('Caps').update_caps()
def on_add_new_contact(self, widget, account):
AddNewContactWindow(account)
......
......@@ -37,8 +37,6 @@ def __init__(self, account, *args):
app.sleeper_state[account] = 0
app.last_message_time[account] = {}
app.status_before_autoaway[account] = ''
app.gajim_optional_features[account] = []
app.caps_hash[account] = ''
app.connections[account] = self
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment