Przeglądaj źródła

Merge pull request #184 from mautrix/sumner/bri-115-show-incoming-call-notifications

calls: show notifications for call start/end in DMs
Sumner Evans 3 lat temu
rodzic
commit
7f75752e44
2 zmienionych plików z 73 dodań i 0 usunięć
  1. 33 0
      mausignald/types.py
  2. 40 0
      mautrix_signal/signal.py

+ 33 - 0
mausignald/types.py

@@ -385,6 +385,38 @@ class SyncMessage(SerializableAttrs):
     contacts_complete: bool = field(default=False, json="contactsComplete")
 
 
+class OfferMessageType(SerializableEnum):
+    AUDIO_CALL = "AUDIO_CALL"
+    VIDEO_CALL = "VIDEO_CALL"
+
+
+@dataclass
+class OfferMessage(SerializableAttrs):
+    id: int
+    type: OfferMessageType
+
+
+class HangupMessageType(SerializableEnum):
+    NORMAL = "NORMAL"
+    ACCEPTED = "ACCEPTED"
+    DECLINED = "DECLINED"
+    BUSY = "BUSY"
+    NEED_PERMISSION = "NEED_PERMISSION"
+
+
+@dataclass
+class HangupMessage(SerializableAttrs):
+    id: int
+    type: HangupMessageType
+    device_id: int = field(json="deviceId")
+
+
+@dataclass
+class CallMessage(SerializableAttrs):
+    offer_message: Optional[OfferMessage] = field(default=None, json="offerMessage")
+    hangup_message: Optional[HangupMessage] = field(default=None, json="hangupMessage")
+
+
 class MessageType(SerializableEnum):
     CIPHERTEXT = "CIPHERTEXT"
     UNIDENTIFIED_SENDER = "UNIDENTIFIED_SENDER"
@@ -409,6 +441,7 @@ class Message(SerializableAttrs):
     is_unidentified_sender: Optional[bool] = field(json="isUnidentifiedSender", default=None)
     has_legacy_message: bool = field(default=False, json="hasLegacyMessage")
 
+    call_message: Optional[CallMessage] = field(default=None, json="callMessage")
     data_message: Optional[MessageData] = field(default=None, json="dataMessage")
     sync_message: Optional[SyncMessage] = field(default=None, json="syncMessage")
     typing: Optional[TypingNotification] = None

+ 40 - 0
mautrix_signal/signal.py

@@ -19,6 +19,7 @@ from typing import TYPE_CHECKING
 import asyncio
 import logging
 
+from mautrix.types import MessageType
 from mautrix.util.logging import TraceLogger
 
 from mausignald import SignaldClient
@@ -26,6 +27,7 @@ from mausignald.types import (
     Address,
     Message,
     MessageData,
+    OfferMessageType,
     OwnReadReceipt,
     Receipt,
     ReceiptType,
@@ -70,6 +72,8 @@ class SignalHandler(SignaldClient):
             await self.handle_typing(user, sender, evt.typing)
         if evt.receipt:
             await self.handle_receipt(sender, evt.receipt)
+        if evt.call_message:
+            await self.handle_call_message(user, sender, evt)
         if evt.sync_message:
             if evt.sync_message.read_messages:
                 await self.handle_own_receipts(sender, evt.sync_message.read_messages)
@@ -151,6 +155,42 @@ class SignalHandler(SignaldClient):
         if msg.remote_delete:
             await portal.handle_signal_delete(sender, msg.remote_delete.target_sent_timestamp)
 
+    @staticmethod
+    async def handle_call_message(user: "u.User", sender: "pu.Puppet", msg: Message) -> None:
+        assert msg.call_message
+        portal = await po.Portal.get_by_chat_id(
+            sender.address, receiver=user.username, create=True
+        )
+        if not portal.mxid:
+            await portal.create_matrix_room(
+                user, (msg.group_v2 or msg.group or addr_override or sender.address)
+            )
+            if not portal.mxid:
+                user.log.debug(
+                    f"Failed to create room for incoming message {msg.timestamp},"
+                    " dropping message"
+                )
+                return
+
+        msg_html = f'<a href="https://matrix.to/#/{sender.mxid}">{sender.name}</a>'
+        if msg.call_message.offer_message:
+            call_type = {
+                OfferMessageType.AUDIO_CALL: " voice ",
+                OfferMessageType.VIDEO_CALL: " video ",
+            }.get(msg.call_message.offer_message.type, " ")
+            msg_html += (
+                f" started a{call_type}call on Signal. Use the native app to answer the call."
+            )
+            msg_type = MessageType.TEXT
+        elif msg.call_message.hangup_message:
+            msg_html += " ended a call on Signal."
+            msg_type = MessageType.NOTICE
+        else:
+            portal.log.debug(f"Unhandled call message. Likely an ICE message. {msg.call_message}")
+            return
+
+        await sender.intent_for(portal).send_text(portal.mxid, html=msg_html, msgtype=msg_type)
+
     @staticmethod
     async def handle_own_receipts(sender: pu.Puppet, receipts: list[OwnReadReceipt]) -> None:
         for receipt in receipts: