internal: move and split muc message handling

This commit is contained in:
mathieui 2022-02-10 16:31:13 +01:00
parent 1f95f25a87
commit cf3d06fb0a
2 changed files with 138 additions and 95 deletions

View file

@ -478,7 +478,7 @@ class HandlerCore:
else: else:
contact.name = '' contact.name = ''
async def on_groupchat_message(self, message: Message): async def on_groupchat_message(self, message: Message) -> None:
""" """
Triggered whenever a message is received from a multi-user chat room. Triggered whenever a message is received from a multi-user chat room.
""" """
@ -495,99 +495,8 @@ class HandlerCore:
muc.leave_groupchat( muc.leave_groupchat(
self.core.xmpp, room_from, self.core.own_nick, msg='') self.core.xmpp, room_from, self.core.own_nick, msg='')
return return
valid_message = await tab.handle_message(message)
nick_from = message['mucnick'] if valid_message and 'message' in config.getstr('beep_on').split():
user = tab.get_user_by_name(nick_from)
if user and user in tab.ignores:
return
await self.core.events.trigger_async('muc_msg', message, tab)
use_xhtml = config.get_by_tabname('enable_xhtml_im', room_from)
tmp_dir = get_image_cache()
body = xhtml.get_body_from_message_stanza(
message, use_xhtml=use_xhtml, extract_images_to=tmp_dir)
# TODO: #3314. Is this a MUC reflection?
# Is this an encrypted message? Is so ignore.
# It is not possible in the OMEMO case to decrypt these messages
# since we don't encrypt for our own device (something something
# forward secrecy), but even for non-FS encryption schemes anyway
# messages shouldn't have changed after a round-trip to the room.
# Otherwire replace the matching message we sent.
if not body:
return
old_state = tab.state
delayed, date = common.find_delayed_tag(message)
is_history = not tab.joined and delayed
replaced = False
if message.xml.find('{urn:xmpp:message-correct:0}replace') is not None:
replaced_id = message['replace']['id']
if replaced_id != '' and config.get_by_tabname(
'group_corrections', message['from'].bare):
try:
delayed_date = date or datetime.now()
if tab.modify_message(
body,
replaced_id,
message['id'],
time=delayed_date,
delayed=delayed,
nickname=nick_from,
user=user):
await self.core.events.trigger_async('highlight', message, tab)
replaced = True
except CorrectionError:
log.debug('Unable to correct a message', exc_info=True)
if not replaced:
ui_msg: Union[InfoMessage, PMessage]
# Messages coming from MUC barejid (Server maintenance, IRC mode
# changes from biboumi, etc.) are displayed as info messages.
highlight = False
if message['from'].resource:
highlight = tab.message_is_highlight(body, nick_from, is_history)
ui_msg = PMessage(
txt=body,
time=date,
nickname=nick_from,
history=is_history,
delayed=delayed,
identifier=message['id'],
jid=message['from'],
user=user,
highlight=highlight,
)
typ = 1
else:
ui_msg = InfoMessage(
txt=body,
time=date,
identifier=message['id'],
)
typ = 2
tab.add_message(ui_msg)
if highlight:
await self.core.events.trigger_async('highlight', message, tab)
if message['from'].resource == tab.own_nick:
tab.set_last_sent_message(message, correct=replaced)
if tab is self.core.tabs.current_tab:
tab.text_win.refresh()
tab.info_header.refresh(tab, tab.text_win, user=tab.own_user)
tab.input.refresh()
self.core.doupdate()
elif tab.state != old_state:
self.core.refresh_tab_win()
current = self.core.tabs.current_tab
if hasattr(current, 'input') and current.input:
current.input.refresh()
self.core.doupdate()
if 'message' in config.getstr('beep_on').split():
if (not config.get_by_tabname('disable_beep', room_from) if (not config.get_by_tabname('disable_beep', room_from)
and self.core.own_nick != message['from'].resource): and self.core.own_nick != message['from'].resource):
curses.beep() curses.beep()

View file

@ -18,6 +18,7 @@ import random
import re import re
import functools import functools
from copy import copy from copy import copy
from dataclasses import dataclass
from datetime import datetime from datetime import datetime
from typing import ( from typing import (
cast, cast,
@ -44,12 +45,13 @@ from poezio import timed_events
from poezio import windows from poezio import windows
from poezio import xhtml from poezio import xhtml
from poezio.common import to_utc from poezio.common import to_utc
from poezio.config import config from poezio.config import config, get_image_cache
from poezio.core.structs import Command from poezio.core.structs import Command
from poezio.decorators import refresh_wrapper, command_args_parser from poezio.decorators import refresh_wrapper, command_args_parser
from poezio.logger import logger from poezio.logger import logger
from poezio.log_loader import LogLoader, MAMFiller from poezio.log_loader import LogLoader, MAMFiller
from poezio.roster import roster from poezio.roster import roster
from poezio.text_buffer import CorrectionError
from poezio.theming import get_theme, dump_tuple from poezio.theming import get_theme, dump_tuple
from poezio.user import User from poezio.user import User
from poezio.core.structs import Completion, Status from poezio.core.structs import Completion, Status
@ -73,6 +75,18 @@ NS_MUC_USER = 'http://jabber.org/protocol/muc#user'
COMPARE_USERS_LAST_TALKED = lambda x: x.last_talked COMPARE_USERS_LAST_TALKED = lambda x: x.last_talked
@dataclass
class MessageData:
message: SMessage
delayed: bool
date: Optional[datetime]
nick: str
user: Optional[User]
room_from: str
body: str
is_history: bool
class MucTab(ChatTab): class MucTab(ChatTab):
""" """
The tab containing a multi-user-chat room. The tab containing a multi-user-chat room.
@ -482,6 +496,126 @@ class MucTab(ChatTab):
self.general_jid) and not self.input.get_text(): self.general_jid) and not self.input.get_text():
self.send_chat_state('active') self.send_chat_state('active')
async def handle_message(self, message: SMessage) -> bool:
"""Parse an incoming message
Returns False if the message was dropped silently.
"""
room_from = message['from'].bare
nick_from = message['mucnick']
user = self.get_user_by_name(nick_from)
if user and user in self.ignores:
return False
await self.core.events.trigger_async('muc_msg', message, self)
use_xhtml = config.get_by_tabname('enable_xhtml_im', room_from)
tmp_dir = get_image_cache()
body = xhtml.get_body_from_message_stanza(
message, use_xhtml=use_xhtml, extract_images_to=tmp_dir)
# TODO: #3314. Is this a MUC reflection?
# Is this an encrypted message? Is so ignore.
# It is not possible in the OMEMO case to decrypt these messages
# since we don't encrypt for our own device (something something
# forward secrecy), but even for non-FS encryption schemes anyway
# messages shouldn't have changed after a round-trip to the room.
# Otherwire replace the matching message we sent.
if not body:
return False
old_state = self.state
delayed, date = common.find_delayed_tag(message)
is_history = not self.joined and delayed
mdata = MessageData(
message, delayed, date, nick_from, user, room_from, body,
is_history
)
replaced = False
if message.xml.find('{urn:xmpp:message-correct:0}replace') is not None:
replaced = await self._handle_correction_message(mdata)
if not replaced:
await self._handle_normal_message(mdata)
if mdata.nick == self.own_nick:
self.set_last_sent_message(message, correct=replaced)
self._refresh_after_message(old_state)
return True
def _refresh_after_message(self, old_state: str) -> None:
"""Refresh the appropriate UI after a message is received"""
if self is self.core.tabs.current_tab:
self.refresh()
elif self.state != old_state:
self.core.refresh_tab_win()
current = self.core.tabs.current_tab
current.refresh_input()
self.core.doupdate()
async def _handle_correction_message(self, message: MessageData) -> bool:
"""Process a correction message.
Returns true if a message was actually corrected.
"""
replaced_id = message.message['replace']['id']
if replaced_id != '' and config.get_by_tabname(
'group_corrections', message.room_from):
try:
delayed_date = message.date or datetime.now()
modify_hl = self.modify_message(
message.body,
replaced_id,
message.message['id'],
time=delayed_date,
delayed=message.delayed,
nickname=message.nick,
user=message.user
)
if modify_hl:
await self.core.events.trigger_async(
'highlight',
message.message,
self
)
return True
except CorrectionError:
log.debug('Unable to correct a message', exc_info=True)
return False
async def _handle_normal_message(self, message: MessageData) -> None:
"""
Process the non-correction groupchat message.
"""
ui_msg: Union[InfoMessage, Message]
# Messages coming from MUC barejid (Server maintenance, IRC mode
# changes from biboumi, etc.) have no nick/resource and are displayed
# as info messages.
highlight = False
if message.nick:
highlight = self.message_is_highlight(
message.body, message.nick, message.is_history
)
ui_msg = Message(
txt=message.body,
time=message.date,
nickname=message.nick,
history=message.is_history,
delayed=message.delayed,
identifier=message.message['id'],
jid=message.message['from'],
user=message.user,
highlight=highlight,
)
else:
ui_msg = InfoMessage(
txt=message.body,
time=message.date,
identifier=message.message['id'],
)
self.add_message(ui_msg)
if highlight:
await self.core.events.trigger_async('highlight', message, self)
def handle_presence(self, presence: Presence) -> None: def handle_presence(self, presence: Presence) -> None:
"""Handle MUC presence""" """Handle MUC presence"""
self.reset_lag() self.reset_lag()