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