async def handle_matrix_message(self, sender: 'u.User', message: MessageEventContent, event_id: EventID) -> None: puppet = p.Puppet.get_by_custom_mxid(sender.mxid) if puppet and message.get("net.maunium.hangouts.puppet", False): self.log.debug( f"Ignoring puppet-sent message by confirmed puppet user {sender.mxid}" ) return # TODO this probably isn't nice for bridging images, it really only needs to lock the # actual message send call and dedup queue append. async with self.require_send_lock(sender.gid): if message.msgtype == MessageType.TEXT or message.msgtype == MessageType.NOTICE: gid = await self._handle_matrix_text(sender, message) elif message.msgtype == MessageType.EMOTE: gid = await self._handle_matrix_emote(sender, message) elif message.msgtype == MessageType.IMAGE: gid = await self._handle_matrix_image(sender, message) # elif message.msgtype == MessageType.LOCATION: # gid = await self._handle_matrix_location(sender, message) else: self.log.warning(f"Unsupported msgtype in {message}") return if not gid: return self._dedup.appendleft(gid) DBMessage(mxid=event_id, mx_room=self.mxid, gid=gid, receiver=self.receiver, index=0).insert() self._last_bridged_mxid = event_id await self._send_delivery_receipt(event_id)
async def apply_relay_message_format( self, sender: br.BaseUser, content: MessageEventContent ) -> None: if self.relay_formatted_body and content.get("format", None) != Format.HTML: content["format"] = Format.HTML content["formatted_body"] = html.escape(content.body).replace("\n", "<br/>") tpl = self.bridge.config["bridge.relay.message_formats"].get( content.msgtype.value, "$sender_displayname: $message" ) displayname = await self.get_displayname(sender) username, _ = self.az.intent.parse_user_id(sender.mxid) tpl_args = { "sender_mxid": sender.mxid, "sender_username": username, "sender_displayname": html.escape(displayname), "formatted_body": content["formatted_body"], "body": content.body, "message": content.body, } content.body = Template(tpl).safe_substitute(tpl_args) if self.relay_formatted_body and "formatted_body" in content: tpl_args["message"] = content["formatted_body"] content["formatted_body"] = Template(tpl).safe_substitute(tpl_args) if self.relay_emote_to_text and content.msgtype == MessageType.EMOTE: content.msgtype = MessageType.TEXT
async def handle_matrix_message(self, sender: 'u.User', message: MessageEventContent, event_id: EventID) -> None: if ((message.get(self.bridge.real_user_content_key, False) and await p.Puppet.get_by_custom_mxid(sender.mxid))): self.log.debug( f"Ignoring puppet-sent message by confirmed puppet user {sender.mxid}" ) return request_id = int(time.time() * 1000) self._msgts_dedup.appendleft((sender.uuid, request_id)) quote = None if message.get_reply_to(): reply = await DBMessage.get_by_mxid(message.get_reply_to(), self.mxid) # TODO include actual text? either store in db or fetch event from homeserver quote = Quote(id=reply.timestamp, author=Address(uuid=reply.sender), text="") text = message.body attachments: Optional[List[Attachment]] = None attachment_path: Optional[str] = None if message.msgtype == MessageType.EMOTE: text = f"/me {text}" elif message.msgtype.is_media: attachment_path = await self._download_matrix_media(message) attachment = self._make_attachment(message, attachment_path) attachments = [attachment] text = None self.log.trace("Formed outgoing attachment %s", attachment) await self.signal.send(username=sender.username, recipient=self.recipient, body=text, quote=quote, attachments=attachments, timestamp=request_id) msg = DBMessage(mxid=event_id, mx_room=self.mxid, sender=sender.uuid, timestamp=request_id, 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 Matrix message {event_id} -> {request_id}") if attachment_path and self.config["signal.remove_file_after_handling"]: try: os.remove(attachment_path) except FileNotFoundError: pass
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 puppet = p.Puppet.get_by_custom_mxid(sender.mxid) if puppet and content.get("net.maunium.telegram.puppet", False): self.log.debug("Ignoring puppet-sent message by confirmed puppet user %s", sender.mxid) return logged_in = not await sender.needs_relaybot(self) client = sender.client if logged_in else self.bot.client sender_id = sender.tgid if logged_in else self.bot.tgid space = (self.tgid if self.peer_type == "channel" # Channels have their own ID space else (sender.tgid if logged_in else self.bot.tgid)) reply_to = formatter.matrix_reply_to_telegram(content, space, room_id=self.mxid) media = (MessageType.STICKER, MessageType.IMAGE, MessageType.FILE, MessageType.AUDIO, MessageType.VIDEO) if content.msgtype == MessageType.NOTICE: bridge_notices = self.get_config("bridge_notices.default") excepted = sender.mxid in self.get_config("bridge_notices.exceptions") if not bridge_notices and not excepted: return if content.msgtype in (MessageType.TEXT, MessageType.EMOTE, MessageType.NOTICE): await self._pre_process_matrix_message(sender, not logged_in, content) await self._handle_matrix_text(sender_id, event_id, space, client, content, reply_to) elif content.msgtype == MessageType.LOCATION: await self._pre_process_matrix_message(sender, not logged_in, content) await self._handle_matrix_location(sender_id, event_id, space, client, content, reply_to) elif content.msgtype in media: content["net.maunium.telegram.internal.filename"] = content.body try: caption_content: MessageEventContent = sender.command_status["caption"] reply_to = reply_to or formatter.matrix_reply_to_telegram(caption_content, space, room_id=self.mxid) sender.command_status = None except (KeyError, TypeError): caption_content = None if logged_in else TextMessageEventContent(body=content.body) if caption_content: caption_content.msgtype = content.msgtype await self._pre_process_matrix_message(sender, not logged_in, caption_content) await self._handle_matrix_file(sender_id, event_id, space, client, content, reply_to, caption_content) else: self.log.debug(f"Unhandled Matrix event: {content}")
async def handle_matrix_message(self, sender: 'u.User', message: MessageEventContent, event_id: EventID) -> None: if not sender.client: self.log.debug( f"Ignoring message {event_id} as user is not connected") return elif ((message.get(self.bridge.real_user_content_key, False) and await p.Puppet.get_by_custom_mxid(sender.mxid))): self.log.debug( f"Ignoring puppet-sent message by confirmed puppet user {sender.mxid}" ) return request_id = str(sender.client.new_request_id()) self._reqid_dedup.add(request_id) text = message.body media_id = None if message.msgtype == MessageType.EMOTE: text = f"/me {text}" elif message.msgtype.is_media: if message.file and decrypt_attachment: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) else: data = await self.main_intent.download_media(message.url) mime_type = message.info.mimetype or magic.from_buffer(data, mime=True) # TODO this will throw errors if the mime type is not supported # those errors should be sent back to the client upload_resp = await sender.client.upload(data, mime_type=mime_type) media_id = upload_resp.media_id text = "" resp = await sender.client.conversation(self.twid ).send(text, media_id=media_id, request_id=request_id) resp_msg_id = int(resp.entries[0].message.id) self._msgid_dedup.appendleft(resp_msg_id) msg = DBMessage(mxid=event_id, mx_room=self.mxid, twid=resp_msg_id, receiver=self.receiver) await msg.insert() self._reqid_dedup.remove(request_id) await self._send_delivery_receipt(event_id) self.log.debug(f"Handled Matrix message {event_id} -> {resp_msg_id}")
async def _handle_matrix_message(self, sender: 'u.User', message: MessageEventContent, event_id: EventID) -> None: if ((message.get(self.bridge.real_user_content_key, False) and await p.Puppet.get_by_custom_mxid(sender.mxid))): self.log.debug(f"Ignoring puppet-sent message by confirmed puppet user {sender.mxid}") return elif not sender.is_connected: await self._send_bridge_error("You're not connected to Instagram", confirmed=True) return else: self.log.debug(f"Handling Matrix message {event_id} from {sender.mxid}/{sender.igpk}") request_id = str(uuid4()) self._reqid_dedup.add(request_id) if message.msgtype in (MessageType.EMOTE, MessageType.TEXT): text = message.body if message.msgtype == MessageType.EMOTE: text = f"/me {text}" self.log.trace(f"Sending Matrix text from {event_id} with request ID {request_id}") resp = await sender.mqtt.send_text(self.thread_id, text=text, client_context=request_id) elif message.msgtype.is_media: if message.file and decrypt_attachment: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) else: data = await self.main_intent.download_media(message.url) mime_type = message.info.mimetype or magic.from_buffer(data, mime=True) if mime_type != "image/jpeg" and mime_type.startswith("image/"): with BytesIO(data) as inp: img = Image.open(inp) with BytesIO() as out: img.convert("RGB").save(out, format="JPEG", quality=80) data = out.getvalue() mime_type = "image/jpeg" if mime_type == "image/jpeg": self.log.trace(f"Uploading photo from {event_id}") upload_resp = await sender.client.upload_jpeg_photo(data) self.log.trace(f"Broadcasting uploaded photo with request ID {request_id}") # TODO is it possible to do this with MQTT? resp = await sender.client.broadcast(self.thread_id, ThreadItemType.CONFIGURE_PHOTO, client_context=request_id, upload_id=upload_resp.upload_id, allow_full_aspect_ratio="1") else: await self._send_bridge_error("Non-image files are currently not supported", confirmed=True) return else: self.log.debug(f"Unhandled Matrix message {event_id}: " f"unknown msgtype {message.msgtype}") return self.log.trace(f"Got response to message send {request_id}: {resp}") if resp.status != "ok": self.log.warning(f"Failed to handle {event_id}: {resp}") await self._send_bridge_error(resp.payload.message) else: self._msgid_dedup.appendleft(resp.payload.item_id) await DBMessage(mxid=event_id, mx_room=self.mxid, item_id=resp.payload.item_id, receiver=self.receiver, sender=sender.igpk).insert() self._reqid_dedup.remove(request_id) await self._send_delivery_receipt(event_id) self.log.debug(f"Handled Matrix message {event_id} -> {resp.payload.item_id}")