diff options
Diffstat (limited to 'src/core/handlers.py')
-rw-r--r-- | src/core/handlers.py | 195 |
1 files changed, 124 insertions, 71 deletions
diff --git a/src/core/handlers.py b/src/core/handlers.py index dfcb3223..50dca216 100644 --- a/src/core/handlers.py +++ b/src/core/handlers.py @@ -5,16 +5,19 @@ XMPP-related handlers for the Core class import logging log = logging.getLogger(__name__) +import asyncio import curses +import functools import ssl +import sys import time from hashlib import sha1, sha512 from gettext import gettext as _ from os import path -from sleekxmpp import InvalidJID -from sleekxmpp.stanza import Message -from sleekxmpp.xmlstream.stanzabase import StanzaBase +from slixmpp import InvalidJID +from slixmpp.stanza import Message +from slixmpp.xmlstream.stanzabase import StanzaBase import bookmark import common @@ -49,47 +52,54 @@ def on_session_start_features(self, _): self.xmpp.plugin['xep_0280'].enable() self.xmpp.add_event_handler('carbon_received', self.on_carbon_received) self.xmpp.add_event_handler('carbon_sent', self.on_carbon_sent) - features = self.xmpp.plugin['xep_0030'].get_info(jid=self.xmpp.boundjid.domain, callback=callback, block=False) + + self.xmpp.plugin['xep_0030'].get_info(jid=self.xmpp.boundjid.domain, + callback=callback) def on_carbon_received(self, message): """ Carbon <received/> received """ + def ignore_message(recv): + log.debug('%s has category conference, ignoring carbon', + recv['from'].server) + def receive_message(recv): + recv['to'] = self.xmpp.boundjid.full + if recv['receipt']: + return self.on_receipt(recv) + self.on_normal_message(recv) + recv = message['carbon_received'] if (recv['from'].bare not in roster or - roster[recv['from'].bare].subscription == 'none'): - try: - if fixes.has_identity(self.xmpp, recv['from'].server, - identity='conference'): - log.debug('%s has category conference, ignoring carbon', - recv['from'].server) - return - except: - log.debug('Traceback when getting the identity of a server:', - exc_info=True) - recv['to'] = self.xmpp.boundjid.full - if recv['receipt']: - return self.on_receipt(recv) - self.on_normal_message(recv) + roster[recv['from'].bare].subscription == 'none'): + fixes.has_identity(self.xmpp, recv['from'].server, + identity='conference', + on_true=functools.partial(ignore_message, recv), + on_false=functools.partial(receive_message, recv)) + return + else: + receive_message(recv) def on_carbon_sent(self, message): """ Carbon <sent/> received """ + def ignore_message(sent): + log.debug('%s has category conference, ignoring carbon', + sent['to'].server) + def send_message(sent): + sent['from'] = self.xmpp.boundjid.full + self.on_normal_message(sent) + sent = message['carbon_sent'] if (sent['to'].bare not in roster or roster[sent['to'].bare].subscription == 'none'): - try: - if fixes.has_identity(self.xmpp, sent['to'].server, - identity='conference'): - log.debug('%s has category conference, ignoring carbon', - sent['to'].server) - return - except: - log.debug('Traceback when getting the identity of a server:', - exc_info=True) - sent['from'] = self.xmpp.boundjid.full - self.on_normal_message(sent) + fixes.has_identity(self.xmpp, sent['to'].server, + identity='conference', + on_true=functools.partial(ignore_message, sent), + on_false=functools.partial(send_message, sent)) + else: + send_message(sent) ### Invites ### @@ -171,7 +181,8 @@ def on_message(self, message): def on_normal_message(self, message): """ - When receiving "normal" messages (from someone in our roster) + When receiving "normal" messages (not a private message from a + muc participant) """ if message['type'] == 'error': return self.information(self.get_error_message(message, deprecated=True), 'Error') @@ -630,7 +641,7 @@ def on_chatstate_groupchat_conversation(self, message, state): Chatstate received in a MUC """ nick = message['mucnick'] - room_from = message.getMucroom() + room_from = message.get_mucroom() tab = self.get_tab_by_name(room_from, tabs.MucTab) if tab and tab.get_user_by_name(nick): self.events.trigger('muc_chatstate', message, tab) @@ -828,27 +839,40 @@ def on_groupchat_presence(self, presence): ### Connection-related handlers ### -def on_failed_connection(self): +def on_failed_connection(self, error): """ We cannot contact the remote server """ - self.information(_("Connection to remote server failed"), _('Error')) + self.information(_("Connection to remote server failed: %s" % (error,)), _('Error')) def on_disconnected(self, event): """ When we are disconnected from remote server """ + # Stop the ping plugin. It would try to send stanza on regular basis + self.xmpp.plugin['xep_0199'].disable_keepalive() roster.modified() for tab in self.get_tabs(tabs.MucTab): tab.disconnect() self.information(_("Disconnected from server."), _('Error')) + if not self.legitimate_disconnect and config.get('auto_reconnect', False): + self.information(_("Auto-reconnecting."), _('Info')) + self.xmpp.connect() -def on_failed_auth(self, event): +def on_stream_error(self, event): + """ + When we receive a stream error + """ + if event and event['text']: + self.information(_('Stream error: %s') % event['text'], _('Error')) + +def on_failed_all_auth(self, event): """ Authentication failed """ self.information(_("Authentication failed (bad credentials?)."), _('Error')) + self.legitimate_disconnect = True def on_no_auth(self, event): """ @@ -856,6 +880,7 @@ def on_no_auth(self, event): """ self.information(_("Authentication failed, no login method available."), _('Error')) + self.legitimate_disconnect = True def on_connected(self, event): """ @@ -863,6 +888,12 @@ def on_connected(self, event): """ self.information(_("Connected to server."), 'Info') +def on_connecting(self, event): + """ + Just before we try to connect to the server + """ + self.legitimate_disconnect = False + def on_session_start(self, event): """ Called when we are connected and authenticated @@ -883,32 +914,42 @@ def on_session_start(self, event): self.events.trigger('send_normal_presence', pres) pres.send() bookmark.get_local() + def _join_initial_rooms(bookmarks): + """Join all rooms given in the iterator `bookmarks`""" + for bm in bookmarks: + if bm.autojoin or config.get('open_all_bookmarks'): + tab = self.get_tab_by_name(bm.jid, tabs.MucTab) + nick = bm.nick if bm.nick else self.own_nick + if not tab: + self.open_new_room(bm.jid, nick, False) + self.initial_joins.append(bm.jid) + histo_length = config.get('muc_history_length') + if histo_length == -1: + histo_length = None + if histo_length is not None: + histo_length = str(histo_length) + # do not join rooms that do not have autojoin + # but display them anyway + if bm.autojoin: + muc.join_groupchat(self, bm.jid, nick, + passwd=bm.password, + maxhistory=histo_length, + status=self.status.message, + show=self.status.show) + def _join_remote_only(): + remote_bookmarks = (bm for bm in bookmark.bookmarks if (bm.method in ("pep", "privatexml"))) + _join_initial_rooms(remote_bookmarks) if not self.xmpp.anon and config.get('use_remote_bookmarks'): - bookmark.get_remote(self.xmpp) - for bm in bookmark.bookmarks: - if bm.autojoin or config.get('open_all_bookmarks'): - tab = self.get_tab_by_name(bm.jid, tabs.MucTab) - nick = bm.nick if bm.nick else self.own_nick - if not tab: - self.open_new_room(bm.jid, nick, False) - self.initial_joins.append(bm.jid) - histo_length = config.get('muc_history_length') - if histo_length == -1: - histo_length = None - if histo_length is not None: - histo_length = str(histo_length) - # do not join rooms that do not have autojoin - # but display them anyway - if bm.autojoin: - muc.join_groupchat(self, bm.jid, nick, - passwd=bm.password, - maxhistory=histo_length, - status=self.status.message, - show=self.status.show) + bookmark.get_remote(self.xmpp, _join_remote_only) + # join all the available bookmarks. As of yet, this is just the local + # ones + _join_initial_rooms(bookmark.bookmarks) if config.get('enable_user_nick'): - self.xmpp.plugin['xep_0172'].publish_nick(nick=self.own_nick, callback=dumb_callback, block=False) + self.xmpp.plugin['xep_0172'].publish_nick(nick=self.own_nick, callback=dumb_callback) self.xmpp.plugin['xep_0115'].update_caps() + # Start the ping's plugin regular event + self.xmpp.set_keepalive_values() ### Other handlers ### @@ -974,7 +1015,7 @@ def on_groupchat_subject(self, message): Triggered when the topic is changed. """ nick_from = message['mucnick'] - room_from = message.getMucroom() + room_from = message.get_mucroom() tab = self.get_tab_by_name(room_from, tabs.MucTab) subject = message['subject'] if subject is None or not tab: @@ -1079,7 +1120,7 @@ def incoming_stanza(self, stanza): def validate_ssl(self, pem): """ - Check the server certificate using the sleekxmpp ssl_cert event + Check the server certificate using the slixmpp ssl_cert event """ if config.get('ignore_certificate'): return @@ -1115,19 +1156,31 @@ def validate_ssl(self, pem): input.resize(1, self.current_tab().width, self.current_tab().height-1, 0) input.refresh() self.doupdate() - self.paused = True - while input.value is None: - self.event.wait() - self.current_tab().input = saved_input - self.paused = False - if input.value: - self.information('Setting new certificate: old: %s, new: %s' % (cert, sha2_found_cert), 'Info') - log.debug('Setting certificate to %s', sha2_found_cert) - if not config.silent_set('certificate', sha2_found_cert): - self.information(_('Unable to write in the config file'), 'Error') - else: - self.information('You refused to validate the certificate. You are now disconnected', 'Info') - self.xmpp.disconnect() + old_loop = asyncio.get_event_loop() + new_loop = asyncio.new_event_loop() + asyncio.set_event_loop(new_loop) + new_loop.add_reader(sys.stdin, self.on_input_readable) + future = asyncio.Future() + @asyncio.coroutine + def check_input(future): + while input.value is None: + yield from asyncio.sleep(0.01) + self.current_tab().input = saved_input + self.paused = False + if input.value: + self.information('Setting new certificate: old: %s, new: %s' % (cert, sha2_found_cert), 'Info') + log.debug('Setting certificate to %s', sha2_found_cert) + if not config.silent_set('certificate', sha2_found_cert): + self.information(_('Unable to write in the config file'), 'Error') + else: + self.information('You refused to validate the certificate. You are now disconnected', 'Info') + self.xmpp.disconnect() + new_loop.stop() + asyncio.set_event_loop(old_loop) + asyncio.async(check_input(future)) + new_loop.run_forever() + + else: log.debug('First time. Setting certificate to %s', sha2_found_cert) if not config.silent_set('certificate', sha2_found_cert): |