summaryrefslogtreecommitdiff
path: root/src/core/handlers.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/handlers.py')
-rw-r--r--src/core/handlers.py195
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):