Adapt to nbxmpp API changes

This commit is contained in:
Philipp Hörist 2018-11-25 19:04:06 +01:00
parent cb05671254
commit 5fa56684c7
4 changed files with 151 additions and 126 deletions

View file

@ -48,7 +48,8 @@ if sys.platform in ('win32', 'darwin'):
import certifi import certifi
import OpenSSL.crypto import OpenSSL.crypto
import nbxmpp import nbxmpp
from nbxmpp import Smacks from nbxmpp.const import Realm
from nbxmpp.const import Event
from gajim import common from gajim import common
from gajim.common import helpers from gajim.common import helpers
@ -522,6 +523,9 @@ class Connection(CommonConnection, ConnectionHandlers):
self.last_sent = [] self.last_sent = []
self.password = passwords.get_password(name) self.password = passwords.get_password(name)
self._unregister_account = False
self._unregister_account_cb = None
self.music_track_info = 0 self.music_track_info = 0
self.register_supported = False self.register_supported = False
@ -545,7 +549,7 @@ class Connection(CommonConnection, ConnectionHandlers):
# The SSL Errors that we can override with POSH # The SSL Errors that we can override with POSH
self._posh_errors = [18, 19] self._posh_errors = [18, 19]
self.sm = Smacks(self) # Stream Management self._sm_resume_data = {}
# Register all modules # Register all modules
modules.register(self) modules.register(self)
@ -614,7 +618,6 @@ class Connection(CommonConnection, ConnectionHandlers):
app.nec.push_incoming_event(OurShowEvent(None, conn=self, app.nec.push_incoming_event(OurShowEvent(None, conn=self,
show='connecting')) show='connecting'))
self.retrycount += 1 self.retrycount += 1
self.on_connect_auth = self._discover_server_at_connection
self.connect_and_init(self.old_show, self.status, self.USE_GPG) self.connect_and_init(self.old_show, self.status, self.USE_GPG)
else: else:
log.info('Reconnect successfull') log.info('Reconnect successfull')
@ -625,22 +628,26 @@ class Connection(CommonConnection, ConnectionHandlers):
# We are doing disconnect at so many places, better use one function in all # We are doing disconnect at so many places, better use one function in all
def disconnect(self, on_purpose=False): def disconnect(self, on_purpose=False):
log.info('Disconnect: on_purpose: %s', on_purpose) log.info('Disconnect: on_purpose: %s', on_purpose)
app.interface.music_track_changed(None, None, self.name)
self.get_module('PEP').reset_stored_publish()
self.on_purpose = on_purpose self.on_purpose = on_purpose
self.connected = 0 self.connected = 0
self.time_to_reconnect = None self.time_to_reconnect = None
if self.connection is None:
return
app.interface.music_track_changed(None, None, self.name)
self.get_module('PEP').reset_stored_publish()
self.get_module('VCardAvatars').avatar_advertised = False self.get_module('VCardAvatars').avatar_advertised = False
if on_purpose:
self.sm = Smacks(self) if not on_purpose:
if self.connection: self._sm_resume_data = self.connection.get_resume_data()
# make sure previous connection is completely closed
app.proxy65_manager.disconnect(self.connection) app.proxy65_manager.disconnect(self.connection)
self.terminate_sessions() self.terminate_sessions()
self.remove_all_transfers() self.remove_all_transfers()
self.connection.disconnect() self.connection.disconnect()
ConnectionHandlers._unregister_handlers(self) ConnectionHandlers._unregister_handlers(self)
self.connection = None self.connection = None
def set_oldst(self): # Set old state def set_oldst(self): # Set old state
if self.old_show: if self.old_show:
@ -663,11 +670,10 @@ class Connection(CommonConnection, ConnectionHandlers):
self.old_show = app.SHOW_LIST[self.connected] self.old_show = app.SHOW_LIST[self.connected]
self.connected = 0 self.connected = 0
if not self.on_purpose: if not self.on_purpose:
if not (self.sm and self.sm.resumption): if not self.connection.resume_supported:
app.nec.push_incoming_event(OurShowEvent(None, conn=self, app.nec.push_incoming_event(OurShowEvent(None, conn=self,
show='offline')) show='offline'))
else: else:
self.sm.enabled = False
app.nec.push_incoming_event(OurShowEvent(None, conn=self, app.nec.push_incoming_event(OurShowEvent(None, conn=self,
show='error')) show='error'))
if self.connection: if self.connection:
@ -714,20 +720,38 @@ class Connection(CommonConnection, ConnectionHandlers):
title=_('Connection with account "%s" has been lost') % self.name, title=_('Connection with account "%s" has been lost') % self.name,
msg=_('Reconnect manually.'))) msg=_('Reconnect manually.')))
def _on_resume_failed(self):
# SM resume failed, set all MUCs offline
# and lose the presence state of all contacts
app.nec.push_incoming_event(OurShowEvent(
None, conn=self, show='offline'))
def _event_dispatcher(self, realm, event, data): def _event_dispatcher(self, realm, event, data):
CommonConnection._event_dispatcher(self, realm, event, data) CommonConnection._event_dispatcher(self, realm, event, data)
if realm == nbxmpp.NS_STREAM_MGMT: if realm == Realm.CONNECTING:
if event == 'RESUME FAILED': if event == Event.RESUME_FAILED:
log.info('Resume failed') log.info(event)
self._on_resume_failed() self._on_resume_failed()
elif realm == nbxmpp.NS_REGISTER: elif event == Event.RESUME_SUCCESSFUL:
log.info(event)
self._on_resume_successful()
elif event == Event.AUTH_SUCCESSFUL:
log.info(event)
self._on_auth_successful()
elif event == Event.AUTH_FAILED:
log.error(event)
log.error(data)
self._on_auth_failed(*data)
elif event == Event.SESSION_FAILED:
log.error(event)
elif event == Event.BIND_FAILED:
log.error(event)
elif event == Event.CONNECTION_ACTIVE:
log.info(event)
self._on_connection_active()
return
if realm == nbxmpp.NS_REGISTER:
if event == nbxmpp.features_nb.REGISTER_DATA_RECEIVED: if event == nbxmpp.features_nb.REGISTER_DATA_RECEIVED:
# data is (agent, DataFrom, is_form, error_msg) # data is (agent, DataFrom, is_form, error_msg)
if self.new_account_info and \ if self.new_account_info and \
@ -835,15 +859,7 @@ class Connection(CommonConnection, ConnectionHandlers):
return self.connection, '' return self.connection, ''
log.info('Connect') log.info('Connect')
if self.sm.resuming and self.sm.location: if data:
# If resuming and server gave a location, connect from there
hostname = self.sm.location
self.try_connecting_for_foo_secs = app.config.get_per('accounts',
self.name, 'try_connecting_for_foo_secs')
use_custom = False
proxy = helpers.get_proxy_info(self.name)
elif data:
hostname = data['hostname'] hostname = data['hostname']
self.try_connecting_for_foo_secs = 45 self.try_connecting_for_foo_secs = 45
p = data['proxy'] p = data['proxy']
@ -861,6 +877,9 @@ class Connection(CommonConnection, ConnectionHandlers):
custom_p = data['custom_port'] custom_p = data['custom_port']
else: else:
hostname = app.config.get_per('accounts', self.name, 'hostname') hostname = app.config.get_per('accounts', self.name, 'hostname')
# Connect from location if we resume
hostname = self._sm_resume_data.get('location') or hostname
self.try_connecting_for_foo_secs = app.config.get_per('accounts', self.try_connecting_for_foo_secs = app.config.get_per('accounts',
self.name, 'try_connecting_for_foo_secs') self.name, 'try_connecting_for_foo_secs')
proxy = helpers.get_proxy_info(self.name) proxy = helpers.get_proxy_info(self.name)
@ -1037,6 +1056,9 @@ class Connection(CommonConnection, ConnectionHandlers):
caller=self, caller=self,
idlequeue=app.idlequeue) idlequeue=app.idlequeue)
if self._sm_resume_data:
con.set_resume_data(self._sm_resume_data)
# increase default timeout for server responses # increase default timeout for server responses
nbxmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = \ nbxmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = \
self.try_connecting_for_foo_secs self.try_connecting_for_foo_secs
@ -1284,7 +1306,7 @@ class Connection(CommonConnection, ConnectionHandlers):
auth_mechs = app.config.get_per( auth_mechs = app.config.get_per(
'accounts', self.name, 'authentication_mechanisms').split() 'accounts', self.name, 'authentication_mechanisms').split()
for mech in auth_mechs: for mech in auth_mechs:
if mech not in nbxmpp.auth_nb.SASL_AUTHENTICATION_MECHANISMS | set(['XEP-0078']): if mech not in nbxmpp.auth_nb.SASL_AUTHENTICATION_MECHANISMS:
log.warning('Unknown authentication mechanisms %s', mech) log.warning('Unknown authentication mechanisms %s', mech)
if not auth_mechs: if not auth_mechs:
auth_mechs = None auth_mechs = None
@ -1294,67 +1316,72 @@ class Connection(CommonConnection, ConnectionHandlers):
password=self.password, password=self.password,
resource=self.server_resource, resource=self.server_resource,
sasl=True, sasl=True,
on_auth=self.__on_auth,
auth_mechs=auth_mechs) auth_mechs=auth_mechs)
def _register_handlers(self, con, con_type): def _register_handlers(self, con, con_type):
self.peerhost = con.get_peerhost() self.peerhost = con.get_peerhost()
app.con_types[self.name] = con_type app.con_types[self.name] = con_type
# notify the gui about con_type # notify the gui about con_type
app.nec.push_incoming_event(ConnectionTypeEvent(None, app.nec.push_incoming_event(
conn=self, connection_type=con_type)) ConnectionTypeEvent(None, conn=self, connection_type=con_type))
ConnectionHandlers._register_handlers(self, con, con_type) ConnectionHandlers._register_handlers(self, con, con_type)
def __on_auth(self, con, auth): def _on_auth_successful(self):
log.info('auth') if self._unregister_account:
if not con: self._on_unregister_account_connect()
self.disconnect(on_purpose=True) else:
app.nec.push_incoming_event(ConnectionLostEvent(None, conn=self, self.connection.bind()
title=_('Could not connect to "%s"') % self._hostname,
msg=_('Check your connection or try again later.'))) def _on_auth_failed(self, reason, text):
if self.on_connect_auth: if not app.config.get_per('accounts', self.name, 'savepass'):
self.on_connect_auth(None) # Forget password, it's wrong
self.on_connect_auth = None self.password = None
return log.debug("Couldn't authenticate to %s", self._hostname)
if not self.connected: # We went offline during connecting process self.disconnect(on_purpose=True)
if self.on_connect_auth: app.nec.push_incoming_event(
self.on_connect_auth(None) OurShowEvent(None, conn=self, show='offline'))
self.on_connect_auth = None app.nec.push_incoming_event(InformationEvent(
return None,
if hasattr(con, 'Resource'): conn=self,
self.server_resource = con.Resource level='error',
if con._registered_name is not None: pri_txt=_('Authentication failed with "%s"') % self._hostname,
log.info('Bound JID: %s', con._registered_name) sec_txt=_('Please check your login and password for correctness.')
self.registered_name = con._registered_name ))
def _on_resume_failed(self):
# SM resume failed, set show to offline so we lose the presence
# state of all contacts
app.nec.push_incoming_event(OurShowEvent(
None, conn=self, show='offline'))
def _on_resume_successful(self):
# Connection was successful, reset sm resume data
self._sm_resume_data = {}
self.connected = 2
self.retrycount = 0
self.set_oldst()
def _on_connection_active(self):
# Connection was successful, reset sm resume data
self._sm_resume_data = {}
self.server_resource = self.connection.Resource
self.registered_name = self.connection.get_bound_jid()
log.info('Bound JID: %s', self.registered_name)
if app.config.get_per('accounts', self.name, 'anonymous_auth'): if app.config.get_per('accounts', self.name, 'anonymous_auth'):
# Get jid given by server # Get jid given by server
old_jid = app.get_jid_from_account(self.name) old_jid = app.get_jid_from_account(self.name)
app.config.set_per('accounts', self.name, 'name', con.User) app.config.set_per('accounts', self.name,
'name', self.connection.User)
new_jid = app.get_jid_from_account(self.name) new_jid = app.get_jid_from_account(self.name)
app.nec.push_incoming_event(AnonymousAuthEvent(None, app.nec.push_incoming_event(AnonymousAuthEvent(
conn=self, old_jid=old_jid, new_jid=new_jid)) None, conn=self, old_jid=old_jid, new_jid=new_jid))
if auth:
self.connected = 2 self.connected = 2
self.retrycount = 0 self.retrycount = 0
if self.on_connect_auth: self._discover_server()
self.on_connect_auth(con)
self.on_connect_auth = None
else:
if not app.config.get_per('accounts', self.name, 'savepass'):
# Forget password, it's wrong
self.password = None
log.debug("Couldn't authenticate to %s", self._hostname)
self.disconnect(on_purpose=True)
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
show='offline'))
app.nec.push_incoming_event(InformationEvent(None, conn=self,
level='error', pri_txt=_('Authentication failed with "%s"') % \
self._hostname, sec_txt=_('Please check your login and password'
' for correctness.')))
if self.on_connect_auth:
self.on_connect_auth(None)
self.on_connect_auth = None
# END connect
def send_keepalive(self): def send_keepalive(self):
# nothing received for the last foo seconds # nothing received for the last foo seconds
@ -1434,11 +1461,9 @@ class Connection(CommonConnection, ConnectionHandlers):
def connect_and_init(self, show, msg, sign_msg): def connect_and_init(self, show, msg, sign_msg):
self.continue_connect_info = [show, msg, sign_msg] self.continue_connect_info = [show, msg, sign_msg]
self.on_connect_auth = self._discover_server_at_connection
self.connect_and_auth() self.connect_and_auth()
def _discover_server_at_connection(self, con): def _discover_server(self):
self.connection = con
if not app.account_is_connected(self.name): if not app.account_is_connected(self.name):
return return
@ -1447,15 +1472,10 @@ class Connection(CommonConnection, ConnectionHandlers):
self.pingalives, self.get_module('Ping').send_keepalive_ping) self.pingalives, self.get_module('Ping').send_keepalive_ping)
self.connection.onreceive(None) self.connection.onreceive(None)
# If we are not resuming, we ask for discovery info self.get_module('Discovery').discover_server_info()
# and archiving preferences self.get_module('Discovery').discover_account_info()
if not self.sm.supports_sm or (not self.sm.resuming and self.sm.enabled): self.get_module('Discovery').discover_server_items()
# This starts the connect_machine
self.get_module('Discovery').discover_server_info()
self.get_module('Discovery').discover_account_info()
self.get_module('Discovery').discover_server_items()
self.sm.resuming = False # back to previous state
# Discover Stun server(s) # Discover Stun server(s)
if self._proxy is None: if self._proxy is None:
hostname = app.config.get_per('accounts', self.name, 'hostname') hostname = app.config.get_per('accounts', self.name, 'hostname')
@ -1852,35 +1872,40 @@ class Connection(CommonConnection, ConnectionHandlers):
self.pasword_callback = None self.pasword_callback = None
def unregister_account(self, on_remove_success): def unregister_account(self, on_remove_success):
# no need to write this as a class method and keep the value of self._unregister_account = True
# on_remove_success as a class property as pass it as an argument self._unregister_account_cb = on_remove_success
def _on_unregister_account_connect(con):
self.on_connect_auth = None
self.removing_account = True
if app.account_is_connected(self.name):
hostname = app.config.get_per('accounts', self.name, 'hostname')
iq = nbxmpp.Iq(typ='set', to=hostname)
id_ = self.connection.getAnID()
iq.setID(id_)
iq.setTag(nbxmpp.NS_REGISTER + ' query').setTag('remove')
def _on_answer(con, result):
if result.getID() == id_:
on_remove_success(True)
return
app.nec.push_incoming_event(InformationEvent(
None, dialog_name='unregister-error',
kwargs={'server': hostname, 'error': result.getErrorMsg()}))
on_remove_success(False)
con.RegisterHandler('iq', _on_answer, 'result', system=True)
con.SendAndWaitForResponse(iq)
return
on_remove_success(False)
self.removing_account = False
if self.connected == 0: if self.connected == 0:
self.on_connect_auth = _on_unregister_account_connect
self.connect_and_auth() self.connect_and_auth()
else: else:
_on_unregister_account_connect(self.connection) self._on_unregister_account_connect()
def _on_unregister_account_connect(self):
self.removing_account = True
if app.account_is_connected(self.name):
hostname = app.config.get_per('accounts', self.name, 'hostname')
iq = nbxmpp.Iq(typ='set', to=hostname)
id_ = self.connection.getAnID()
iq.setID(id_)
iq.setTag(nbxmpp.NS_REGISTER + ' query').setTag('remove')
def _on_answer(con, result):
if result.getID() == id_:
self._on_unregister_finished(True)
return
app.nec.push_incoming_event(InformationEvent(
None, dialog_name='unregister-error',
kwargs={'server': hostname, 'error': result.getErrorMsg()}))
self._on_unregister_finished(False)
self.connection.RegisterHandler(
'iq', _on_answer, 'result', system=True)
self.connection.SendAndWaitForResponse(iq)
return
self._on_unregister_finished(False)
self.removing_account = False
def _on_unregister_finished(self, result):
self._unregister_account_cb(result)
self._unregister_account = False
self._unregister_account_cb = None
def _reconnect_alarm(self): def _reconnect_alarm(self):
if not app.config.get_per('accounts', self.name, 'active'): if not app.config.get_per('accounts', self.name, 'active'):

View file

@ -27,7 +27,7 @@ from distutils.version import LooseVersion as V
# Install _() in namespace # Install _() in namespace
from gajim.common import i18n from gajim.common import i18n
_MIN_NBXMPP_VER = "0.6.8" _MIN_NBXMPP_VER = "0.9.90"
_MIN_GTK_VER = "3.22.0" _MIN_GTK_VER = "3.22.0"

View file

@ -176,7 +176,7 @@ class ServerInfoDialog(Gtk.Dialog):
con.get_module('Blocking').supported, con.get_module('Blocking').supported,
nbxmpp.NS_BLOCKING, None), nbxmpp.NS_BLOCKING, None),
Feature('XEP-0198: Stream Management', Feature('XEP-0198: Stream Management',
con.sm.enabled, nbxmpp.NS_STREAM_MGMT, None), con.connection.sm_enabled, nbxmpp.NS_STREAM_MGMT, None),
Feature('XEP-0258: Security Labels in XMPP', Feature('XEP-0258: Security Labels in XMPP',
con.get_module('SecLabels').supported, con.get_module('SecLabels').supported,
nbxmpp.NS_SECLABEL, None), nbxmpp.NS_SECLABEL, None),

View file

@ -22,7 +22,7 @@ test_suite = test
install_requires = install_requires =
cssutils>=1.0.2 cssutils>=1.0.2
keyring keyring
nbxmpp>=0.6.8,<0.7.0 nbxmpp>=0.9.90
precis-i18n>=1.0.0 precis-i18n>=1.0.0
pyOpenSSL>=0.12 pyOpenSSL>=0.12