1use libsignal_core::DeviceId;
2use libsignal_protocol::{ProtocolAddress, ServiceId};
3use prost::Message;
4use std::fmt;
5use uuid::Uuid;
6
7pub use crate::{
8 proto::{
9 attachment_pointer::Flags as AttachmentPointerFlags,
10 data_message::Flags as DataMessageFlags, data_message::Reaction,
11 sync_message, AttachmentPointer, CallMessage, DataMessage,
12 DecryptionErrorMessage, EditMessage, GroupContextV2, NullMessage,
13 PniSignatureMessage, ReceiptMessage, StoryMessage, SyncMessage,
14 TypingMessage,
15 },
16 push_service::ServiceError,
17 ServiceIdExt,
18};
19
20mod data_message;
21mod story_message;
22
23#[derive(Clone, Debug)]
24pub struct Metadata {
25 pub sender: ServiceId,
26 pub destination: ServiceId,
27 pub sender_device: DeviceId,
28 pub timestamp: u64,
29 pub needs_receipt: bool,
30 pub unidentified_sender: bool,
31 pub was_plaintext: bool,
32
33 pub server_guid: Option<Uuid>,
37}
38
39impl fmt::Display for Metadata {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 write!(
42 f,
43 "Metadata {{ sender: {}, guid: {} }}",
44 self.sender.service_id_string(),
45 self.server_guid
47 .map(|u| u.to_string())
48 .as_deref()
49 .unwrap_or("None"),
50 )
51 }
52}
53
54impl Metadata {
55 pub(crate) fn protocol_address(
56 &self,
57 ) -> Result<ProtocolAddress, libsignal_core::InvalidDeviceId> {
58 self.sender.to_protocol_address(self.sender_device)
59 }
60}
61
62#[derive(Clone, Debug)]
63pub struct Content {
64 pub metadata: Metadata,
65 pub body: ContentBody,
66}
67
68impl Content {
69 pub fn from_body(body: impl Into<ContentBody>, metadata: Metadata) -> Self {
70 Self {
71 metadata,
72 body: body.into(),
73 }
74 }
75
76 pub fn from_proto(
78 p: crate::proto::Content,
79 metadata: Metadata,
80 ) -> Result<Self, ServiceError> {
81 #[allow(clippy::manual_map)]
87 if let Some(msg) = p.data_message {
88 Ok(Self::from_body(msg, metadata))
89 } else if let Some(msg) = p.sync_message {
90 Ok(Self::from_body(msg, metadata))
91 } else if let Some(msg) = p.call_message {
92 Ok(Self::from_body(msg, metadata))
93 } else if let Some(msg) = p.receipt_message {
94 Ok(Self::from_body(msg, metadata))
95 } else if let Some(msg) = p.typing_message {
96 Ok(Self::from_body(msg, metadata))
97 } else if let Some(msg) = p.decryption_error_message {
100 Ok(Self {
101 metadata,
102 body: ContentBody::DecryptionErrorMessage(
103 DecryptionErrorMessage::decode(msg.as_ref())?,
104 ),
105 })
106 } else if let Some(msg) = p.story_message {
107 Ok(Self::from_body(msg, metadata))
108 } else if let Some(msg) = p.pni_signature_message {
109 Ok(Self::from_body(msg, metadata))
110 } else if let Some(msg) = p.edit_message {
111 Ok(Self::from_body(msg, metadata))
112 } else if let Some(msg) = p.null_message {
113 Ok(Self::from_body(msg, metadata))
114 } else {
115 Err(ServiceError::UnsupportedContent)
116 }
117 }
118}
119
120impl fmt::Display for ContentBody {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 match self {
123 Self::NullMessage(_) => write!(f, "NullMessage"),
124 Self::DataMessage(m) => {
125 match (&m.body, &m.reaction, m.attachments.len()) {
126 (Some(body), _, 0) => {
127 write!(f, "DataMessage({})", body)
128 },
129 (Some(body), _, n) => {
130 write!(f, "DataMessage({}, attachments: {n})", body)
131 },
132 (None, Some(emoji), _) => {
133 write!(
134 f,
135 "DataMessage(reaction: {})",
136 emoji.emoji.as_deref().unwrap_or("None")
137 )
138 },
139 (None, _, n) if n > 0 => {
140 write!(f, "DataMessage(attachments: {n})")
141 },
142 _ => {
143 write!(f, "{self:?}")
144 },
145 }
146 },
147 Self::SynchronizeMessage(_) => write!(f, "SynchronizeMessage"),
148 Self::CallMessage(_) => write!(f, "CallMessage"),
149 Self::ReceiptMessage(_) => write!(f, "ReceiptMessage"),
150 Self::TypingMessage(_) => write!(f, "TypingMessage"),
151 Self::DecryptionErrorMessage(_) => {
153 write!(f, "DecryptionErrorMessage")
154 },
155 Self::StoryMessage(_) => write!(f, "StoryMessage"),
156 Self::PniSignatureMessage(_) => write!(f, "PniSignatureMessage"),
157 Self::EditMessage(_) => write!(f, "EditMessage"),
158 }
159 }
160}
161
162#[derive(Clone, Debug)]
163#[allow(clippy::large_enum_variant)]
164pub enum ContentBody {
165 NullMessage(NullMessage),
166 DataMessage(DataMessage),
167 SynchronizeMessage(SyncMessage),
168 CallMessage(CallMessage),
169 ReceiptMessage(ReceiptMessage),
170 TypingMessage(TypingMessage),
171 DecryptionErrorMessage(DecryptionErrorMessage),
173 StoryMessage(StoryMessage),
174 PniSignatureMessage(PniSignatureMessage),
175 EditMessage(EditMessage),
176}
177
178impl ContentBody {
179 pub fn into_proto(self) -> crate::proto::Content {
180 match self {
181 Self::NullMessage(msg) => crate::proto::Content {
182 null_message: Some(msg),
183 ..Default::default()
184 },
185 Self::DataMessage(msg) => crate::proto::Content {
186 data_message: Some(msg),
187 ..Default::default()
188 },
189 Self::SynchronizeMessage(msg) => crate::proto::Content {
190 sync_message: Some(msg),
191 ..Default::default()
192 },
193 Self::CallMessage(msg) => crate::proto::Content {
194 call_message: Some(msg),
195 ..Default::default()
196 },
197 Self::ReceiptMessage(msg) => crate::proto::Content {
198 receipt_message: Some(msg),
199 ..Default::default()
200 },
201 Self::TypingMessage(msg) => crate::proto::Content {
202 typing_message: Some(msg),
203 ..Default::default()
204 },
205 Self::DecryptionErrorMessage(msg) => crate::proto::Content {
212 decryption_error_message: Some(msg.encode_to_vec()),
213 ..Default::default()
214 },
215 Self::StoryMessage(msg) => crate::proto::Content {
216 story_message: Some(msg),
217 ..Default::default()
218 },
219 Self::PniSignatureMessage(msg) => crate::proto::Content {
220 pni_signature_message: Some(msg),
221 ..Default::default()
222 },
223 Self::EditMessage(msg) => crate::proto::Content {
224 edit_message: Some(msg),
225 ..Default::default()
226 },
227 }
228 }
229}
230
231macro_rules! impl_from_for_content_body {
232 ($enum:ident ($t:ty)) => {
233 impl From<$t> for ContentBody {
234 fn from(inner: $t) -> ContentBody {
235 ContentBody::$enum(inner)
236 }
237 }
238 };
239}
240
241impl_from_for_content_body!(NullMessage(NullMessage));
242impl_from_for_content_body!(DataMessage(DataMessage));
243impl_from_for_content_body!(SynchronizeMessage(SyncMessage));
244impl_from_for_content_body!(CallMessage(CallMessage));
245impl_from_for_content_body!(ReceiptMessage(ReceiptMessage));
246impl_from_for_content_body!(TypingMessage(TypingMessage));
247impl_from_for_content_body!(StoryMessage(StoryMessage));
252impl_from_for_content_body!(PniSignatureMessage(PniSignatureMessage));
253impl_from_for_content_body!(EditMessage(EditMessage));