diff options
Diffstat (limited to 'poezio/core/core.py')
-rw-r--r-- | poezio/core/core.py | 108 |
1 files changed, 83 insertions, 25 deletions
diff --git a/poezio/core/core.py b/poezio/core/core.py index 81ac6e8a..6582402d 100644 --- a/poezio/core/core.py +++ b/poezio/core/core.py @@ -15,7 +15,6 @@ import pipes import sys import shutil import time -import uuid from collections import defaultdict from typing import ( Any, @@ -30,9 +29,11 @@ from typing import ( TYPE_CHECKING, ) from xml.etree import ElementTree as ET +from pathlib import Path -from slixmpp import JID, InvalidJID +from slixmpp import Iq, JID, InvalidJID from slixmpp.util import FileSystemPerJidCache +from slixmpp.xmlstream.xmlstream import InvalidCABundle from slixmpp.xmlstream.handler import Callback from slixmpp.exceptions import IqError, IqTimeout, XMPPError @@ -42,6 +43,7 @@ from poezio import events from poezio import theming from poezio import timed_events from poezio import windows +from poezio import utils from poezio.bookmarks import ( BookmarkList, @@ -274,7 +276,7 @@ class Core: self.key_func.try_execute = self.try_execute # Add handlers - xmpp_event_handlers = [ + xmpp_event_handlers: List[Tuple[str, Callable[..., Any]]] = [ ('attention', self.handler.on_attention), ('carbon_received', self.handler.on_carbon_received), ('carbon_sent', self.handler.on_carbon_sent), @@ -444,7 +446,7 @@ class Core: if value not in ('pep', 'privatexml'): return self.bookmarks.preferred = value - asyncio.ensure_future( + asyncio.create_task( self.bookmarks.save(self.xmpp, core=self) ) @@ -674,6 +676,26 @@ class Core: self.do_command(''.join(char_list), True) self.doupdate() + def loop_exception_handler(self, loop, context) -> None: + """Do not log unhandled iq errors and timeouts""" + handled_exceptions = (IqError, IqTimeout, InvalidCABundle) + if not isinstance(context['exception'], handled_exceptions): + loop.default_exception_handler(context) + elif isinstance(context['exception'], InvalidCABundle): + paths = context['exception'].path + error = ( + 'Poezio could not find a valid CA bundle file automatically. ' + 'Ensure the ca_cert_path configuration is set to a valid ' + 'CA bundle path, generally provided by the \'ca-certificates\' ' + 'package in your distribution.' + ) + if isinstance(paths, (str, Path)): + # error += '\nFound the following value: {path}'.format(path=str(path)) + paths = [paths] + if paths is not None: + error += f"\nThe following values were tried: {str([str(s) for s in paths])}" + self.information(error, 'Error') + def save_config(self): """ Save config in the file just before exit @@ -906,7 +928,9 @@ class Core: """ if not isinstance(self.tabs.current_tab, ChatTab): return False - self.tabs.current_tab.command_say(msg) + asyncio.ensure_future( + self.tabs.current_tab.command_say(msg) + ) return True async def invite(self, jid: JID, room: JID, reason: Optional[str] = None, force_mediated: bool = False) -> bool: @@ -943,7 +967,7 @@ class Core: ) return True - def _impromptu_room_form(self, room): + def _impromptu_room_form(self, room) -> Iq: fields = [ ('hidden', 'FORM_TYPE', 'http://jabber.org/protocol/muc#roomconfig'), ('boolean', 'muc#roomconfig_changesubject', True), @@ -1004,31 +1028,65 @@ class Core: ) return - nick = self.own_nick - localpart = uuid.uuid4().hex - room_str = '{!s}@{!s}'.format(localpart, default_muc) - try: - room = JID(room_str) - except InvalidJID: + # Retries generating a name until we find a non-existing room. + # Abort otherwise. + retries = 3 + while retries > 0: + localpart = utils.pronounceable() + room_str = f'{localpart}@{default_muc}' + try: + room = JID(room_str) + except InvalidJID: + self.information( + f'The generated XMPP address is invalid: {room_str}', + 'Error' + ) + return None + + try: + iq = await self.xmpp['xep_0030'].get_info( + jid=room, + cached=False, + ) + except IqTimeout: + pass + except IqError as exn: + if exn.etype == 'cancel' and exn.condition == 'item-not-found': + log.debug('Found empty room for /impromptu') + break + + retries = retries - 1 + + if retries == 0: self.information( - 'The generated XMPP address is invalid: {!s}'.format(room_str), - 'Error' + 'Couldn\'t generate a room name that isn\'t already used.', + 'Error', ) return None - self.open_new_room(room, nick).join() - iq = self._impromptu_room_form(room) - try: - await iq.send() - except (IqError, IqTimeout): - self.information('Failed to configure impromptu room.', 'Info') - # TODO: destroy? leave room. - return None + self.open_new_room(room, self.own_nick).join() + + async def configure_and_invite(_presence): + iq = self._impromptu_room_form(room) + try: + await iq.send() + except (IqError, IqTimeout): + self.information('Failed to configure impromptu room.', 'Info') + # TODO: destroy? leave room. + return None + + self.information(f'Room {room} created', 'Info') - self.information('Room %s created' % room, 'Info') + for jid in jids: + await self.invite(jid, room, force_mediated=True) + jids_str = ', '.join(jids) + self.information(f'Invited {jids_str} to {room.bare}', 'Info') - for jid in jids: - await self.invite(jid, room, force_mediated=True) + self.xmpp.add_event_handler( + f'muc::{room.bare}::groupchat_subject', + configure_and_invite, + disposable=True, + ) ####################### Tab logic-related things ############################## |