예제 #1
0
파일: bot.py 프로젝트: maubot/reminder
 async def _send_reminder(self, reminder: ReminderInfo) -> None:
     if len(reminder.users) == 0:
         self.log.debug(
             f"Cancelling reminder {reminder}, no users left to remind")
         return
     wait = (reminder.date - datetime.now(tz=pytz.UTC)).total_seconds()
     if wait > 0:
         self.log.debug(f"Waiting {wait} seconds to send {reminder}")
         await asyncio.sleep(wait)
     else:
         self.log.debug(f"Sending {reminder} immediately")
     users = " ".join(reminder.users)
     users_html = " ".join(
         f"<a href='https://matrix.to/#/{user_id}'>{user_id}</a>"
         for user_id in reminder.users)
     content = TextMessageEventContent(
         msgtype=MessageType.TEXT,
         body=f"{users}: {reminder.message}",
         format=Format.HTML,
         formatted_body=f"{users_html}: {escape(reminder.message)}")
     content["xyz.maubot.reminder"] = {
         "id": reminder.id,
         "message": reminder.message,
         "targets": list(reminder.users),
         "reply_to": reminder.reply_to,
     }
     if reminder.reply_to:
         content.set_reply(await
                           self.client.get_event(reminder.room_id,
                                                 reminder.reply_to))
     await self.client.send_message(reminder.room_id, content)
예제 #2
0
    async def handle_signal_message(self, sender: 'p.Puppet',
                                    message: MessageData) -> None:
        if (sender.uuid, message.timestamp) in self._msgts_dedup:
            self.log.debug(
                f"Ignoring message {message.timestamp} by {sender.uuid}"
                " as it was already handled (message.timestamp in dedup queue)"
            )
            return
        old_message = await DBMessage.get_by_signal_id(sender.uuid,
                                                       message.timestamp,
                                                       self.chat_id,
                                                       self.receiver)
        if old_message is not None:
            self.log.debug(
                f"Ignoring message {message.timestamp} by {sender.uuid}"
                " as it was already handled (message.id found in database)")
            return
        self.log.debug(
            f"Started handling message {message.timestamp} by {sender.uuid}")
        self.log.trace(f"Message content: {message}")
        self._msgts_dedup.appendleft((sender.uuid, message.timestamp))
        intent = sender.intent_for(self)
        await intent.set_typing(self.mxid, False)
        event_id = None
        reply_to = await self._find_quote_event_id(message.quote)

        for attachment in message.all_attachments:
            content = await self._handle_signal_attachment(intent, attachment)
            if content:
                if reply_to and not message.body:
                    # If there's no text, set the first image as the reply
                    content.set_reply(reply_to)
                    reply_to = None
                event_id = await self._send_message(
                    intent, content, timestamp=message.timestamp)

        if message.body:
            content = TextMessageEventContent(msgtype=MessageType.TEXT,
                                              body=message.body)
            if reply_to:
                content.set_reply(reply_to)
            event_id = await self._send_message(intent,
                                                content,
                                                timestamp=message.timestamp)

        if event_id:
            msg = DBMessage(mxid=event_id,
                            mx_room=self.mxid,
                            sender=sender.uuid,
                            timestamp=message.timestamp,
                            signal_chat_id=self.chat_id,
                            signal_receiver=self.receiver)
            await msg.insert()
            await self._send_delivery_receipt(event_id)
            self.log.debug(
                f"Handled Signal message {message.timestamp} -> {event_id}")
        else:
            self.log.debug(f"Didn't get event ID for {message.timestamp}")
예제 #3
0
 async def _add_facebook_reply(self, content: TextMessageEventContent,
                               reply: str) -> None:
     if reply:
         message = DBMessage.get_by_fbid(reply, self.fb_receiver)
         if message:
             evt = await self.main_intent.get_event(message.mx_room,
                                                    message.mxid)
             if evt:
                 if isinstance(evt.content, TextMessageEventContent):
                     evt.content.trim_reply_fallback()
                 content.set_reply(evt)
예제 #4
0
 async def _handle_instagram_reel_share(
         self, source: 'u.User', intent: IntentAPI,
         item: ThreadItem) -> Optional[EventID]:
     media = item.reel_share.media
     prefix_html = None
     if item.reel_share.type == ReelShareType.REPLY:
         if item.reel_share.reel_owner_id == source.igpk:
             prefix = "Replied to your story"
         else:
             username = media.user.username
             prefix = f"Sent @{username}'s story"
             user_link = f'<a href="https://www.instagram.com/{username}/">@{username}</a>'
             prefix_html = f"Sent {user_link}'s story"
     elif item.reel_share.type == ReelShareType.REACTION:
         prefix = "Reacted to your story"
     else:
         self.log.debug(
             f"Unsupported reel share type {item.reel_share.type}")
         return None
     prefix_content = TextMessageEventContent(msgtype=MessageType.NOTICE,
                                              body=prefix)
     if prefix_html:
         prefix_content.format = Format.HTML
         prefix_content.formatted_body = prefix_html
     content = TextMessageEventContent(msgtype=MessageType.TEXT,
                                       body=item.reel_share.text)
     await self._send_message(intent,
                              prefix_content,
                              timestamp=item.timestamp // 1000)
     if isinstance(media, ExpiredMediaItem):
         # TODO send message about expired story
         pass
     else:
         fake_item_id = f"fi.mau.instagram.reel_share.{item.user_id}.{media.pk}"
         existing = await DBMessage.get_by_item_id(fake_item_id,
                                                   self.receiver)
         if existing:
             # If the user already reacted or replied to the same reel share item,
             # use a Matrix reply instead of reposting the image.
             content.set_reply(existing.mxid)
         else:
             media_event_id = await self._handle_instagram_media(
                 source, intent, item)
             await DBMessage(mxid=media_event_id,
                             mx_room=self.mxid,
                             item_id=fake_item_id,
                             receiver=self.receiver,
                             sender=media.user.pk).insert()
     return await self._send_message(intent,
                                     content,
                                     timestamp=item.timestamp // 1000)
async def _add_reply_header(source: 'AbstractUser', content: TextMessageEventContent, evt: Message,
                            main_intent: IntentAPI):
    space = (evt.to_id.channel_id
             if isinstance(evt, Message) and isinstance(evt.to_id, PeerChannel)
             else source.tgid)

    msg = DBMessage.get_one_by_tgid(TelegramID(evt.reply_to_msg_id), space)
    if not msg:
        return

    content.relates_to = RelatesTo(rel_type=RelationType.REFERENCE, event_id=msg.mxid)

    try:
        event: MessageEvent = await main_intent.get_event(msg.mx_room, msg.mxid)
        if isinstance(event.content, TextMessageEventContent):
            event.content.trim_reply_fallback()
        content.set_reply(event)
    except MatrixRequestError:
        pass
예제 #6
0
async def _add_reply_header(source: 'AbstractUser', content: TextMessageEventContent, evt: Message,
                            main_intent: IntentAPI):
    space = (evt.peer_id.channel_id
             if isinstance(evt, Message) and isinstance(evt.peer_id, PeerChannel)
             else source.tgid)

    msg = DBMessage.get_one_by_tgid(TelegramID(evt.reply_to.reply_to_msg_id), space)
    if not msg:
        return

    content.relates_to = RelatesTo(rel_type=RelationType.REPLY, event_id=msg.mxid)

    try:
        event: MessageEvent = await main_intent.get_event(msg.mx_room, msg.mxid)
        if isinstance(event.content, TextMessageEventContent):
            event.content.trim_reply_fallback()
        puppet = await pu.Puppet.get_by_mxid(event.sender, create=False)
        content.set_reply(event, displayname=puppet.displayname if puppet else event.sender)
    except MatrixRequestError:
        log.exception("Failed to get event to add reply fallback")
예제 #7
0
async def _add_reply_header(source: au.AbstractUser,
                            content: TextMessageEventContent, evt: Message,
                            main_intent: IntentAPI) -> None:
    space = (evt.peer_id.channel_id if isinstance(evt, Message)
             and isinstance(evt.peer_id, PeerChannel) else source.tgid)

    msg = await DBMessage.get_one_by_tgid(
        TelegramID(evt.reply_to.reply_to_msg_id), space)
    if not msg:
        return

    try:
        event = await main_intent.get_event(msg.mx_room, msg.mxid)
        if event.type == EventType.ROOM_ENCRYPTED and source.bridge.matrix.e2ee:
            event = await source.bridge.matrix.e2ee.decrypt(event)
        if isinstance(event.content, TextMessageEventContent):
            event.content.trim_reply_fallback()
        puppet = await pu.Puppet.get_by_mxid(event.sender, create=False)
        content.set_reply(
            event, displayname=puppet.displayname if puppet else event.sender)
    except Exception:
        log.exception("Failed to get event to add reply fallback")
        content.set_reply(msg.mxid)
예제 #8
0
    async def handle_signal_message(self, source: 'u.User', sender: 'p.Puppet',
                                    message: MessageData) -> None:
        if (sender.address, message.timestamp) in self._msgts_dedup:
            self.log.debug(
                f"Ignoring message {message.timestamp} by {sender.uuid}"
                " as it was already handled (message.timestamp in dedup queue)"
            )
            await self.signal.send_receipt(source.username,
                                           sender.address,
                                           timestamps=[message.timestamp])
            return
        old_message = await DBMessage.get_by_signal_id(sender.address,
                                                       message.timestamp,
                                                       self.chat_id,
                                                       self.receiver)
        if old_message is not None:
            self.log.debug(
                f"Ignoring message {message.timestamp} by {sender.uuid}"
                " as it was already handled (message.id found in database)")
            await self.signal.send_receipt(source.username,
                                           sender.address,
                                           timestamps=[message.timestamp])
            return
        self.log.debug(
            f"Started handling message {message.timestamp} by {sender.uuid}")
        self.log.trace(f"Message content: {message}")
        self._msgts_dedup.appendleft((sender.address, message.timestamp))
        intent = sender.intent_for(self)
        await intent.set_typing(self.mxid, False)
        event_id = None
        reply_to = await self._find_quote_event_id(message.quote)

        if message.sticker:
            if not message.sticker.attachment.incoming_filename:
                self.log.debug(
                    "Downloading sticker from signal, as no incoming filename was defined: %s",
                    message.sticker.attachment)
                try:
                    async with StickersClient() as client:
                        sticker_data = await client.download_sticker(
                            message.sticker.sticker_id,
                            message.sticker.pack_id, message.sticker.pack_key)

                    path = os.path.join(
                        self.config["signal.outgoing_attachment_dir"],
                        f"{message.sticker.pack_id}_{message.sticker.sticker_id}"
                    )
                    with open(path, "wb") as file:
                        file.write(sticker_data)
                    message.sticker.attachment.incoming_filename = path
                except Exception as ex:
                    self.log.warning("Failed to download sticker: %s", ex)

            if message.sticker.attachment.incoming_filename:
                content = await self._handle_signal_attachment(
                    intent, message.sticker.attachment)
                if reply_to:
                    content.set_reply(reply_to)
                    reply_to = None
                event_id = await self._send_message(
                    intent,
                    content,
                    timestamp=message.timestamp,
                    event_type=EventType.STICKER)

        for attachment in message.attachments:
            if not attachment.incoming_filename:
                self.log.warning(
                    "Failed to bridge attachment, no incoming filename: %s",
                    attachment)
                continue
            content = await self._handle_signal_attachment(intent, attachment)
            if reply_to and not message.body:
                # If there's no text, set the first image as the reply
                content.set_reply(reply_to)
                reply_to = None
            event_id = await self._send_message(intent,
                                                content,
                                                timestamp=message.timestamp)

        if message.body:
            content = TextMessageEventContent(msgtype=MessageType.TEXT,
                                              body=message.body)
            if reply_to:
                content.set_reply(reply_to)
            event_id = await self._send_message(intent,
                                                content,
                                                timestamp=message.timestamp)

        if event_id:
            msg = DBMessage(mxid=event_id,
                            mx_room=self.mxid,
                            sender=sender.address,
                            timestamp=message.timestamp,
                            signal_chat_id=self.chat_id,
                            signal_receiver=self.receiver)
            await msg.insert()
            await self.signal.send_receipt(source.username,
                                           sender.address,
                                           timestamps=[message.timestamp])
            await self._send_delivery_receipt(event_id)
            self.log.debug(
                f"Handled Signal message {message.timestamp} -> {event_id}")
        else:
            self.log.debug(f"Didn't get event ID for {message.timestamp}")