rust_rcs_client/messaging/cpm/
mod.rs1pub mod session;
16pub mod session_invitation;
17pub mod sip;
18pub mod standalone_messaging;
19
20use std::sync::Arc;
21
22use base64::{engine::general_purpose, Engine as _};
23use chrono::{DateTime, Local, SecondsFormat};
24use rust_rcs_core::{
25 internet::{body::message_body::MessageBody, Body, Header},
26 sip::sip_session::SipSession,
27};
28use uuid::Uuid;
29
30use self::session::CPMSession;
31
32use super::ffi::RecipientType;
33
34pub struct MessagingSessionHandle {
35 pub(crate) inner: Arc<SipSession<CPMSession>>,
36}
37
38pub struct CPMMessageParam {
39 message_type: String,
40 message_content: String,
41 recipient: String,
42 recipient_type: RecipientType,
43 recipient_uri: String,
44 message_result_callback: Arc<dyn Fn(u16, String) + Send + Sync>, }
46
47impl CPMMessageParam {
48 pub fn new<F>(
49 message_type: String,
50 message_content: String,
51 recipient: &str,
52 recipient_type: &RecipientType,
53 recipient_uri: &str,
54 message_result_callback: F,
55 ) -> CPMMessageParam
56 where
57 F: Fn(u16, String) + Send + Sync + 'static,
58 {
59 CPMMessageParam {
60 message_type,
61 message_content,
62 recipient: String::from(recipient),
63 recipient_type: RecipientType::from(recipient_type),
64 recipient_uri: String::from(recipient_uri),
65 message_result_callback: Arc::new(message_result_callback),
66 }
67 }
68}
69
70pub fn make_cpim_message_content_body(
71 message_type: &str,
72 message_content: &str,
73 recipient_type: &RecipientType,
74 recipient_uri: &str,
75 message_imdn_id: Uuid,
76 public_user_identity: &str,
77) -> Body {
78 let encoded = general_purpose::STANDARD.encode(message_content);
79
80 let content_body = Vec::from(encoded);
81 let content_body_length = content_body.len();
82
83 let mut content_headers = Vec::new();
84
85 content_headers.push(Header::new("Content-Type", String::from(message_type)));
86
87 content_headers.push(Header::new("Content-Transfer-Encoding", "base64"));
88
89 content_headers.push(Header::new(
90 "Content-Length",
91 format!("{}", content_body_length),
92 ));
93
94 let cpim_content_body = Body::Message(MessageBody {
95 headers: content_headers,
96 body: Arc::new(Body::Raw(content_body)),
97 });
98
99 let mut cpim_headers = Vec::new();
100
101 if message_type.eq("message/imdn") {
102 cpim_headers.push(Header::new("From", "<sip:anonymous@anonymous.invalid>"));
103 cpim_headers.push(Header::new("To", "<sip:anonymous@anonymous.invalid>"));
104 } else {
105 cpim_headers.push(Header::new("From", format!("<{}>", public_user_identity)));
106 cpim_headers.push(Header::new("To", format!("<{}>", recipient_uri)));
107 }
108
109 let utc: DateTime<Local> = Local::now();
110
111 cpim_headers.push(Header::new(
112 "DateTime",
113 utc.to_rfc3339_opts(SecondsFormat::Millis, false),
114 ));
115
116 cpim_headers.push(Header::new("NS", "imdn <urn:ietf:params:imdn>"));
117
118 cpim_headers.push(Header::new(
119 "imdn.Message-ID",
120 String::from(
121 message_imdn_id
122 .as_hyphenated()
123 .encode_lower(&mut Uuid::encode_buffer()),
124 ),
125 ));
126
127 cpim_headers.push(Header::new(
135 "NS",
136 "cpm <http://www.openmobilealliance.org/cpm/>",
137 ));
138
139 cpim_headers.push(Header::new(b"cpm.Payload-Type", String::from(message_type)));
140
141 if let RecipientType::Chatbot = recipient_type {
147 cpim_headers.push(Header::new("NS", "maap <http://www.gsma.com/rcs/maap/>"));
148 }
149
150 Body::Message(MessageBody {
151 headers: cpim_headers,
152 body: Arc::new(cpim_content_body),
153 })
154}