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,16 +628,20 @@ 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()
@ -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)
app.nec.push_incoming_event(ConnectionLostEvent(None, conn=self,
title=_('Could not connect to "%s"') % self._hostname,
msg=_('Check your connection or try again later.')))
if self.on_connect_auth:
self.on_connect_auth(None)
self.on_connect_auth = None
return
if not self.connected: # We went offline during connecting process
if self.on_connect_auth:
self.on_connect_auth(None)
self.on_connect_auth = None
return
if hasattr(con, 'Resource'):
self.server_resource = con.Resource
if con._registered_name is not None:
log.info('Bound JID: %s', con._registered_name)
self.registered_name = con._registered_name
if app.config.get_per('accounts', self.name, 'anonymous_auth'):
# Get jid given by server
old_jid = app.get_jid_from_account(self.name)
app.config.set_per('accounts', self.name, 'name', con.User)
new_jid = app.get_jid_from_account(self.name)
app.nec.push_incoming_event(AnonymousAuthEvent(None,
conn=self, old_jid=old_jid, new_jid=new_jid))
if auth:
self.connected = 2
self.retrycount = 0
if self.on_connect_auth:
self.on_connect_auth(con)
self.on_connect_auth = None
else: else:
self.connection.bind()
def _on_auth_failed(self, reason, text):
if not app.config.get_per('accounts', self.name, 'savepass'): if not app.config.get_per('accounts', self.name, 'savepass'):
# Forget password, it's wrong # Forget password, it's wrong
self.password = None self.password = None
log.debug("Couldn't authenticate to %s", self._hostname) log.debug("Couldn't authenticate to %s", self._hostname)
self.disconnect(on_purpose=True) self.disconnect(on_purpose=True)
app.nec.push_incoming_event(OurShowEvent(None, conn=self, app.nec.push_incoming_event(
show='offline')) OurShowEvent(None, conn=self, show='offline'))
app.nec.push_incoming_event(InformationEvent(None, conn=self, app.nec.push_incoming_event(InformationEvent(
level='error', pri_txt=_('Authentication failed with "%s"') % \ None,
self._hostname, sec_txt=_('Please check your login and password' conn=self,
' for correctness.'))) level='error',
if self.on_connect_auth: pri_txt=_('Authentication failed with "%s"') % self._hostname,
self.on_connect_auth(None) sec_txt=_('Please check your login and password for correctness.')
self.on_connect_auth = None ))
# END connect
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'):
# Get jid given by server
old_jid = app.get_jid_from_account(self.name)
app.config.set_per('accounts', self.name,
'name', self.connection.User)
new_jid = app.get_jid_from_account(self.name)
app.nec.push_incoming_event(AnonymousAuthEvent(
None, conn=self, old_jid=old_jid, new_jid=new_jid))
self.connected = 2
self.retrycount = 0
self._discover_server()
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
# and archiving preferences
if not self.sm.supports_sm or (not self.sm.resuming and self.sm.enabled):
# This starts the connect_machine
self.get_module('Discovery').discover_server_info() self.get_module('Discovery').discover_server_info()
self.get_module('Discovery').discover_account_info() self.get_module('Discovery').discover_account_info()
self.get_module('Discovery').discover_server_items() 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,10 +1872,14 @@ 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): if self.connected == 0:
self.on_connect_auth = None self.connect_and_auth()
else:
self._on_unregister_account_connect()
def _on_unregister_account_connect(self):
self.removing_account = True self.removing_account = True
if app.account_is_connected(self.name): if app.account_is_connected(self.name):
hostname = app.config.get_per('accounts', self.name, 'hostname') hostname = app.config.get_per('accounts', self.name, 'hostname')
@ -1865,22 +1889,23 @@ class Connection(CommonConnection, ConnectionHandlers):
iq.setTag(nbxmpp.NS_REGISTER + ' query').setTag('remove') iq.setTag(nbxmpp.NS_REGISTER + ' query').setTag('remove')
def _on_answer(con, result): def _on_answer(con, result):
if result.getID() == id_: if result.getID() == id_:
on_remove_success(True) self._on_unregister_finished(True)
return return
app.nec.push_incoming_event(InformationEvent( app.nec.push_incoming_event(InformationEvent(
None, dialog_name='unregister-error', None, dialog_name='unregister-error',
kwargs={'server': hostname, 'error': result.getErrorMsg()})) kwargs={'server': hostname, 'error': result.getErrorMsg()}))
on_remove_success(False) self._on_unregister_finished(False)
con.RegisterHandler('iq', _on_answer, 'result', system=True) self.connection.RegisterHandler(
con.SendAndWaitForResponse(iq) 'iq', _on_answer, 'result', system=True)
self.connection.SendAndWaitForResponse(iq)
return return
on_remove_success(False) self._on_unregister_finished(False)
self.removing_account = False self.removing_account = False
if self.connected == 0:
self.on_connect_auth = _on_unregister_account_connect def _on_unregister_finished(self, result):
self.connect_and_auth() self._unregister_account_cb(result)
else: self._unregister_account = False
_on_unregister_account_connect(self.connection) 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