diff --git a/mautrix_telegram/config.py b/mautrix_telegram/config.py index 7c07f678..503f6c92 100644 --- a/mautrix_telegram/config.py +++ b/mautrix_telegram/config.py @@ -110,6 +110,7 @@ class Config(BaseBridgeConfig): copy("bridge.encryption.default") copy("bridge.private_chat_portal_meta") copy("bridge.delivery_receipts") + copy("bridge.delivery_error_reports") copy("bridge.initial_power_level_overrides.group") copy("bridge.initial_power_level_overrides.user") diff --git a/mautrix_telegram/example-config.yaml b/mautrix_telegram/example-config.yaml index 219f69d9..f9eca855 100644 --- a/mautrix_telegram/example-config.yaml +++ b/mautrix_telegram/example-config.yaml @@ -217,6 +217,8 @@ bridge: # Whether or not the bridge should send a read receipt from the bridge bot when a message has # been sent to Telegram. delivery_receipts: false + # Whether or not delivery errors should be reported as messages in the Matrix room. + delivery_error_reports: false # Overrides for base power levels. initial_power_level_overrides: diff --git a/mautrix_telegram/portal/base.py b/mautrix_telegram/portal/base.py index ecad8cc8..0a294d5c 100644 --- a/mautrix_telegram/portal/base.py +++ b/mautrix_telegram/portal/base.py @@ -1,5 +1,5 @@ # mautrix-telegram - A Matrix-Telegram puppeting bridge -# Copyright (C) 2019 Tulir Asokan +# Copyright (C) 2020 Tulir Asokan # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -30,7 +30,7 @@ from telethon.tl.types import (Channel, ChannelFull, Chat, ChatFull, ChatInviteE from mautrix.errors import MatrixRequestError, IntentError from mautrix.appservice import AppService, IntentAPI -from mautrix.types import (RoomID, RoomAlias, UserID, EventID, EventType, +from mautrix.types import (RoomID, RoomAlias, UserID, EventID, EventType, MessageEventContent, PowerLevelStateEventContent) from mautrix.util.simple_template import SimpleTemplate from mautrix.util.logging import TraceLogger @@ -136,7 +136,7 @@ class BasePortal(ABC): if mxid: self.by_mxid[mxid] = self - # region Propegrties + # region Properties @property def tgid_full(self) -> Tuple[TelegramID, TelegramID]: @@ -461,6 +461,15 @@ class BasePortal(ABC): type_name if create else None) # endregion + + async def _send_message(self, intent: IntentAPI, content: MessageEventContent, + event_type: EventType = EventType.ROOM_MESSAGE, **kwargs) -> EventID: + if self.encrypted and self.matrix.e2ee: + if intent.api.is_real_user: + content[intent.api.real_user_content_key] = True + event_type, content = await self.matrix.e2ee.encrypt(self.mxid, event_type, content) + return await intent.send_message_event(self.mxid, event_type, content, **kwargs) + # region Abstract methods (cross-called in matrix/metadata/telegram classes) @abstractmethod diff --git a/mautrix_telegram/portal/matrix.py b/mautrix_telegram/portal/matrix.py index 8c3d5e53..8241b4a4 100644 --- a/mautrix_telegram/portal/matrix.py +++ b/mautrix_telegram/portal/matrix.py @@ -1,5 +1,5 @@ # mautrix-telegram - A Matrix-Telegram puppeting bridge -# Copyright (C) 2019 Tulir Asokan +# Copyright (C) 2020 Tulir Asokan # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -25,7 +25,8 @@ from telethon.tl.functions.messages import (EditChatPhotoRequest, EditChatTitleR EditChatAboutRequest) from telethon.tl.functions.channels import EditPhotoRequest, EditTitleRequest, JoinChannelRequest from telethon.errors import (ChatNotModifiedError, PhotoExtInvalidError, - PhotoInvalidDimensionsError, PhotoSaveFileInvalidError) + PhotoInvalidDimensionsError, PhotoSaveFileInvalidError, + RPCError) from telethon.tl.patched import Message, MessageService from telethon.tl.types import ( DocumentAttributeFilename, DocumentAttributeImageSize, GeoPoint, @@ -365,8 +366,22 @@ class PortalMatrix(BasePortal, MautrixBasePortal, ABC): mxid=event_id, edit_index=edit_index).insert() + async def _send_bridge_error(self, msg: str) -> None: + if config["bridge.delivery_error_reports"]: + await self._send_message(self.main_intent, + TextMessageEventContent(msgtype=MessageType.NOTICE, body=msg)) + async def handle_matrix_message(self, sender: 'u.User', content: MessageEventContent, event_id: EventID) -> None: + try: + await self._handle_matrix_message(sender, content, event_id) + except RPCError as e: + if config["bridge.delivery_error_reports"]: + await self._send_bridge_error(f"\u26a0 Your message may not have been bridged: {e}") + raise + + async def _handle_matrix_message(self, sender: 'u.User', content: MessageEventContent, + event_id: EventID) -> None: if not content.body or not content.msgtype: self.log.debug(f"Ignoring message {event_id} in {self.mxid} without body or msgtype") return diff --git a/mautrix_telegram/portal/telegram.py b/mautrix_telegram/portal/telegram.py index e649b4c8..39978228 100644 --- a/mautrix_telegram/portal/telegram.py +++ b/mautrix_telegram/portal/telegram.py @@ -1,5 +1,5 @@ # mautrix-telegram - A Matrix-Telegram puppeting bridge -# Copyright (C) 2019 Tulir Asokan +# Copyright (C) 2020 Tulir Asokan # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -71,14 +71,6 @@ class PortalTelegram(BasePortal, ABC): return f"https://t.me/c/{self.tgid}/{evt.id}" return None - async def _send_message(self, intent: IntentAPI, content: MessageEventContent, - event_type: EventType = EventType.ROOM_MESSAGE, **kwargs) -> EventID: - if self.encrypted and self.matrix.e2ee: - if intent.api.is_real_user: - content[intent.api.real_user_content_key] = True - event_type, content = await self.matrix.e2ee.encrypt(self.mxid, event_type, content) - return await intent.send_message_event(self.mxid, event_type, content, **kwargs) - async def handle_telegram_photo(self, source: 'AbstractUser', intent: IntentAPI, evt: Message, relates_to: RelatesTo = None) -> Optional[EventID]: loc, largest_size = self._get_largest_photo_size(evt.media.photo)