1extern crate libc;
16
17use std::net::Ipv4Addr;
18use std::net::Ipv6Addr;
19#[cfg(not(any(
20 all(feature = "android", target_os = "android"),
21 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
22)))]
23use std::net::{SocketAddrV4, SocketAddrV6};
24use std::sync::Arc;
25use std::sync::Mutex;
26
27use futures::StreamExt;
28
29#[cfg(all(feature = "ohos", all(target_os = "linux", target_env = "ohos")))]
30use libc::{AF_INET, AF_INET6};
31use rust_rcs_core::ffi::log::platform_log;
32use rust_rcs_core::http::HttpClient;
33#[cfg(all(feature = "android", target_os = "android"))]
34use rust_rcs_core::io::network::android_socket::AndroidTcpStream;
35#[cfg(all(feature = "ohos", all(target_os = "linux", target_env = "ohos")))]
36use rust_rcs_core::io::network::ohos_socket::OhosTcpStream;
37use rust_rcs_core::io::network::stream::ClientSocket;
38use rust_rcs_core::io::network::stream::ClientStream;
39
40use rust_rcs_core::msrp::info::MsrpInfo;
41use rust_rcs_core::msrp::info::MsrpInterfaceType;
42use rust_rcs_core::msrp::info::MsrpSetupMethod;
43use rust_rcs_core::security::gba::GbaContext;
44use rust_rcs_core::security::SecurityContext;
45use rust_rcs_core::sip::SipCore;
46use rust_rcs_core::sip::SipTransactionManager;
47
48use rust_rcs_core::sip::sip_subscription::SubscriptionManager;
49use rust_rcs_core::sip::sip_transport::setup_sip_transport;
50use rust_rcs_core::sip::SipTransport;
51use rust_rcs_core::sip::TransactionHandler;
52use rust_rcs_core::sip::ACK;
53use rust_rcs_core::sip::BYE;
54use rust_rcs_core::sip::CANCEL;
55use rust_rcs_core::sip::INVITE;
56use rust_rcs_core::sip::MESSAGE;
57use rust_rcs_core::sip::NOTIFY;
58use rust_rcs_core::sip::OPTIONS;
59use rust_rcs_core::sip::UPDATE;
60
61#[cfg(not(any(
62 all(feature = "android", target_os = "android"),
63 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
64)))]
65use tokio::net::TcpSocket;
66use tokio::runtime::Runtime;
67
68use tokio::sync::mpsc;
69use tokio_stream::wrappers::ReceiverStream;
70
71use url::Url;
72use uuid::Uuid;
73
74use crate::chat_bot;
75use crate::chat_bot::chatbot_config::ChatbotConfig;
76use crate::chat_bot::chatbot_sip_uri::AsChatbotSipUri;
77use crate::chat_bot::RetrieveChatbotInfoSuccess;
78use crate::chat_bot::RetrieveSpecificChatbotsSuccess;
79use crate::conference::ffi::MultiConferenceEventListener;
80use crate::conference::ffi::MultiConferenceEventListenerContextWrapper;
81use crate::conference::MultiConferenceServiceV1;
82use crate::conference::MultiConferenceServiceV1Wrapper;
83use crate::conference::MultiConferenceV1;
84use crate::conference::MultiConferenceV1InviteResponseReceiver;
85use crate::connection::msrp_connection_config::MsrpConnectionConfig;
86use crate::connection::p_cscf_connection_config::PCscfConnectionConfig;
87use crate::connection::p_cscf_connection_config::ServiceType;
88use crate::connectivity::authentication_type::AuthenticationType;
89use crate::connectivity::registration::deregister;
90use crate::connectivity::registration::start_register;
91use crate::connectivity::registration::RegistrationEvent;
92use crate::connectivity::{flow::FlowManager, registration::Registration};
93use crate::context::Context;
94use crate::messaging::config::MessagingConfigs;
95use crate::messaging::cpm::session::CPMSessionService;
96use crate::messaging::cpm::session::CPMSessionServiceWrapper;
97use crate::messaging::cpm::standalone_messaging::StandaloneMessagingServiceWrapper;
98use crate::messaging::cpm::standalone_messaging::{self, StandaloneMessagingService};
99use crate::messaging::cpm::MessagingSessionHandle;
100use crate::messaging::ffi::RecipientType;
101use crate::messaging::ft_http::config::FileTransferOverHTTPConfigs;
102use crate::messaging::ft_http::download_file;
103use crate::messaging::ft_http::upload_file;
104use crate::messaging::ft_http::FileInfo;
105use crate::messaging::ft_http::FileTransferOverHTTPService;
106
107use super::provisioning::characteristic::Characteristic;
108use super::provisioning::ims_application::ImsApplication;
109use super::provisioning::rcs_application::RcsApplication;
110
111const LOG_TAG: &str = "librust_rcs_client";
112
113pub enum RcsEngineConnectionState {
114 IDLE,
115 CONNECTING,
116 CONNECTED(Arc<SipTransport>, String),
117}
118
119pub enum RcsEngineRegistrationState {
120 NONE,
121 AUTHENTICATED(String),
122 MAINTAINED(String),
123}
124
125pub struct RcsEngine {
126 state: Arc<Mutex<(RcsEngineConnectionState, RcsEngineRegistrationState)>>,
127
128 state_callback: Arc<Box<dyn Fn(RcsEngineRegistrationState) + Send + Sync + 'static>>,
129
130 tm: Arc<SipTransactionManager>,
131
132 subscription_id: i32,
133
134 impi: Option<String>,
135 impu: Option<String>,
136
137 home_domain: Option<String>,
138
139 authentication_type: Option<AuthenticationType>,
140
141 sip_instance_id: Uuid,
142
143 p_cscf_connection_config: PCscfConnectionConfig,
144
145 registration_id_counter: u32,
146
147 flow_manager: Arc<FlowManager>,
148
149 standalone_messaging_service: Arc<StandaloneMessagingService>,
150
151 cpm_session_service: Arc<CPMSessionService>,
152
153 ft_http_service: Arc<FileTransferOverHTTPService>,
154
155 chatbot_config: ChatbotConfig,
156
157 msrp_connection_config: Arc<Mutex<MsrpConnectionConfig>>,
158
159 messaging_config: Arc<Mutex<MessagingConfigs>>,
160
161 ft_http_configs: FileTransferOverHTTPConfigs,
162
163 conference_service_v1: Arc<MultiConferenceServiceV1>,
164
165 core: Arc<SipCore>,
167 context: Arc<Context>,
168}
169
170impl RcsEngine {
171 pub fn new<SCF, MCF, MCIHF>(
172 subscription_id: i32,
173 rt: Arc<Runtime>,
174 context: Arc<Context>,
175 state_callback: SCF,
176 message_callback: MCF,
177 multi_conference_v1_invite_handler_function: MCIHF,
178 ) -> RcsEngine
179 where
180 SCF: Fn(RcsEngineRegistrationState) + Send + Sync + 'static,
181 MCF: Fn(i32, Option<MessagingSessionHandle>, &str, &str, &str, &str, &str, Option<&str>)
182 + Send
183 + Sync
184 + 'static,
185 MCIHF: Fn(MultiConferenceV1, String, MultiConferenceV1InviteResponseReceiver)
186 + Send
187 + Sync
188 + 'static,
189 {
190 let state = Arc::new(Mutex::new((
191 RcsEngineConnectionState::IDLE,
192 RcsEngineRegistrationState::NONE,
193 )));
194
195 let state_callback: Arc<Box<dyn Fn(RcsEngineRegistrationState) + Send + Sync + 'static>> =
196 Arc::new(Box::new(state_callback));
197 let state_callback_ = Arc::clone(&state_callback);
198
199 let sm = SubscriptionManager::new(500);
200 let (tm, tm_event_itf) = SipTransactionManager::new(&rt);
202
203 #[cfg(not(all(feature = "android", target_os = "android")))]
204 let tls_client_config = context.get_tls_client_config();
205
206 let msrp_connection_config = MsrpConnectionConfig::new();
207 let msrp_connection_config = Arc::new(Mutex::new(msrp_connection_config));
208 let msrp_connection_config_ = Arc::clone(&msrp_connection_config);
209
210 let messaging_config = Arc::new(Mutex::new(MessagingConfigs::new()));
211
212 let messaging_config_1 = Arc::clone(&messaging_config);
213 let messaging_config_2 = Arc::clone(&messaging_config);
214
215 let msrp_socket_allocator_function_impl = move |msrp_info: Option<&MsrpInfo>| {
216 if let Some((dns_config, mut tls)) = msrp_connection_config_
217 .lock()
218 .unwrap()
219 .get_transport_config()
220 {
221 match msrp_info {
222 Some(msrp_info) => {
223 if tls && msrp_info.protocol.eq_ignore_ascii_case(b"TCP/MSRP") {
224 return Err((480, "Temporarily Unavailable"));
225 }
226
227 if msrp_info.protocol.eq_ignore_ascii_case(b"TCP/TLS/MSRP") {
228 tls = true; }
230
231 match msrp_info.setup_method {
232 MsrpSetupMethod::Passive => match msrp_info.interface_type {
233 MsrpInterfaceType::IPv4 => {
234 #[cfg(all(feature = "android", target_os = "android"))]
235 if let Ok(sock) = AndroidTcpStream::create() {
236 if let Ok(_) =
238 sock.bind(&Ipv4Addr::UNSPECIFIED.to_string(), 0)
239 {
240 if let Ok((ip, port)) = sock.get_local_addr() {
241 return Ok((
242 ClientSocket(sock),
243 ip,
244 port,
245 tls,
246 true,
247 false,
248 ));
249 }
250 }
251 }
252
253 #[cfg(all(
254 feature = "ohos",
255 all(target_os = "linux", target_env = "ohos")
256 ))]
257 if let Ok(sock) = OhosTcpStream::create() {
258 if let Ok(_) = sock.bind(
259 AF_INET,
260 &Ipv4Addr::UNSPECIFIED.to_string(),
261 0,
262 ) {
263 if let Ok((ip, port)) = sock.get_local_addr() {
264 return Ok((
265 ClientSocket(sock),
266 ip,
267 port,
268 tls,
269 true,
270 false,
271 ));
272 }
273 }
274 }
275
276 #[cfg(not(any(
277 all(feature = "android", target_os = "android"),
278 all(
279 feature = "ohos",
280 all(target_os = "linux", target_env = "ohos")
281 )
282 )))]
283 if let Ok(sock) = TcpSocket::new_v4() {
284 if let Ok(()) = sock.bind(std::net::SocketAddr::V4(
285 SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0),
286 )) {
287 if let Ok(addr) = sock.local_addr() {
288 let ip = match addr.ip() {
289 std::net::IpAddr::V4(v4) => format!("{}", v4),
290 std::net::IpAddr::V6(v6) => format!("{}", v6),
291 };
292 return Ok((
293 ClientSocket(sock),
294 ip,
295 addr.port(),
296 tls,
297 true,
298 false,
299 ));
300 }
301 }
302 }
303 }
304
305 MsrpInterfaceType::IPv6 => {
306 #[cfg(all(feature = "android", target_os = "android"))]
307 if let Ok(sock) = AndroidTcpStream::create() {
308 if let Ok(_) =
309 sock.bind(&Ipv6Addr::UNSPECIFIED.to_string(), 0)
310 {
311 if let Ok((ip, port)) = sock.get_local_addr() {
312 return Ok((
313 ClientSocket(sock),
314 ip,
315 port,
316 tls,
317 true,
318 false,
319 ));
320 }
321 }
322 }
323
324 #[cfg(all(
325 feature = "ohos",
326 all(target_os = "linux", target_env = "ohos")
327 ))]
328 if let Ok(sock) = OhosTcpStream::create() {
329 if let Ok(_) = sock.bind(
330 AF_INET6,
331 &Ipv6Addr::UNSPECIFIED.to_string(),
332 0,
333 ) {
334 if let Ok((ip, port)) = sock.get_local_addr() {
335 return Ok((
336 ClientSocket(sock),
337 ip,
338 port,
339 tls,
340 true,
341 false,
342 ));
343 }
344 }
345 }
346
347 #[cfg(not(any(
348 all(feature = "android", target_os = "android"),
349 all(
350 feature = "ohos",
351 all(target_os = "linux", target_env = "ohos")
352 )
353 )))]
354 if let Ok(sock) = TcpSocket::new_v6() {
355 if let Ok(()) = sock.bind(std::net::SocketAddr::V6(
356 SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0),
357 )) {
358 if let Ok(addr) = sock.local_addr() {
359 let ip = match addr.ip() {
360 std::net::IpAddr::V4(v4) => format!("{}", v4),
361 std::net::IpAddr::V6(v6) => format!("{}", v6),
362 };
363 return Ok((
364 ClientSocket(sock),
365 ip,
366 addr.port(),
367 tls,
368 true,
369 false,
370 ));
371 }
372 }
373 }
374 }
375 },
376
377 MsrpSetupMethod::Active => {
378 }
380 }
381 }
382
383 None => {
384 #[cfg(all(feature = "android", target_os = "android"))]
385 if let Ok(sock) = AndroidTcpStream::create() {
386 if let Ok(_) = sock.bind(&Ipv4Addr::UNSPECIFIED.to_string(), 0) {
387 if let Ok((ip, port)) = sock.get_local_addr() {
388 return Ok((ClientSocket(sock), ip, port, tls, true, false));
389 }
390 }
391 }
392
393 #[cfg(all(
394 feature = "ohos",
395 all(target_os = "linux", target_env = "ohos")
396 ))]
397 if let Ok(sock) = OhosTcpStream::create() {
398 if let Ok(_) = sock.bind(AF_INET, &Ipv4Addr::UNSPECIFIED.to_string(), 0)
399 {
400 if let Ok((ip, port)) = sock.get_local_addr() {
401 return Ok((ClientSocket(sock), ip, port, tls, true, false));
402 }
403 }
404 }
405
406 #[cfg(not(any(
407 all(feature = "android", target_os = "android"),
408 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
409 )))]
410 if let Ok(sock) = TcpSocket::new_v4() {
411 if let Ok(()) = sock.bind(std::net::SocketAddr::V4(SocketAddrV4::new(
412 Ipv4Addr::UNSPECIFIED,
413 0,
414 ))) {
415 if let Ok(addr) = sock.local_addr() {
416 let ip = match addr.ip() {
417 std::net::IpAddr::V4(v4) => format!("{}", v4),
418 std::net::IpAddr::V6(v6) => format!("{}", v6),
419 };
420 return Ok((
421 ClientSocket(sock),
422 ip,
423 addr.port(),
424 tls,
425 true,
426 false,
427 ));
428 }
429 }
430 }
431
432 }
434 }
435 }
436
437 return Err((480, "Temporarily Unavailable"));
438 };
439
440 let msrp_socket_allocator_function_impl_1 = Arc::new(msrp_socket_allocator_function_impl);
441 let msrp_socket_allocator_function_impl_2 =
442 Arc::clone(&msrp_socket_allocator_function_impl_1);
443
444 let msrp_socket_connect_function_impl =
445 move |sock: ClientSocket, raddr: String, rport: u16, tls: bool| {
446 #[cfg(not(all(feature = "android", target_os = "android")))]
447 let tls_client_config_ = Arc::clone(&tls_client_config);
448 return Box::pin(async move {
449 #[cfg(all(feature = "android", target_os = "android"))]
450 if let Ok(ip) = raddr.parse() {
451 if tls {
452 match sock.configure_tls(&raddr) {
453 Ok(sock) => {
454 if let Ok(cs) = sock.connect(ip, rport).await {
455 return Ok(cs);
456 }
457 }
458 Err(_) => return Err((500, "")),
459 }
460 } else {
461 if let Ok(cs) = sock.connect(ip, rport).await {
462 return Ok(cs);
463 }
464 }
465 }
466
467 #[cfg(all(feature = "ohos", all(target_os = "linux", target_env = "ohos")))]
468 if let Ok(ip) = raddr.parse() {
469 if tls {
470 match sock.configure_tls(tls_client_config_, &raddr) {
471 Ok(cc) => {
472 if let Ok(cs) = sock.connect(ip, rport, Some(cc)).await {
473 return Ok(cs);
474 }
475 }
476 Err(_) => return Err((500, "")),
477 }
478 } else {
479 if let Ok(cs) = sock.connect(ip, rport, None).await {
480 return Ok(cs);
481 }
482 }
483 }
484
485 #[cfg(not(any(
486 all(feature = "android", target_os = "android"),
487 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
488 )))]
489 if let Ok(ip) = raddr.parse() {
490 if tls {
491 match sock.configure_tls(tls_client_config_, &raddr) {
492 Ok(cc) => {
493 if let Ok(cs) = sock.connect(ip, rport, Some(cc)).await {
494 return Ok(cs);
495 }
496 }
497 Err(_) => return Err((500, "")),
498 }
499 } else {
500 if let Ok(cs) = sock.connect(ip, rport, None).await {
501 return Ok(cs);
502 }
503 }
504 }
505
506 Err((500, "Server Internal Error"))
507 });
508 };
509
510 let message_callback_impl_1 = Arc::new(message_callback);
511 let message_callback_impl_2 = Arc::clone(&message_callback_impl_1);
512
513 let msrp_socket_connect_function_impl_1 = Arc::new(msrp_socket_connect_function_impl);
514 let msrp_socket_connect_function_impl_2 = Arc::clone(&msrp_socket_connect_function_impl_1);
515
516 let standalone_messaging_service = StandaloneMessagingService::new(
517 move |contact_uri, cpim_info, content_type, message_body| {
518 if let (Ok(contact_uri), Ok(content_type), Ok(message_body)) = (
519 std::str::from_utf8(contact_uri),
520 std::str::from_utf8(content_type),
521 std::str::from_utf8(message_body),
522 ) {
523 if let (Ok(imdn_message_id), Ok(cpim_date)) = (
524 std::str::from_utf8(cpim_info.imdn_message_id),
525 std::str::from_utf8(cpim_info.date),
526 ) {
527 let cpim_from = if let Some(uri) = &cpim_info.from_uri {
528 let uri = uri.string_representation_without_query_and_fragment();
529 if let Ok(uri) = String::from_utf8(uri) {
530 Some(uri)
531 } else {
532 None
533 }
534 } else {
535 None
536 };
537 message_callback_impl_1(
538 1,
539 None,
540 contact_uri,
541 content_type,
542 message_body,
543 imdn_message_id,
544 cpim_date,
545 cpim_from.as_deref(),
546 );
547 } else {
548 platform_log(LOG_TAG, "failed to decode cpim info as utf-8 string");
549 }
550 } else {
551 platform_log(LOG_TAG, "failed to decode message data as utf-8 string");
552 }
553 },
554 move |msrp_info| msrp_socket_allocator_function_impl_1(msrp_info),
555 move |sock, raddr, rport, tls| {
556 let raddr = String::from(raddr);
557 msrp_socket_connect_function_impl_1(sock, raddr, rport, tls)
558 },
559 );
560 let standalone_messaging_service = Arc::new(standalone_messaging_service);
561 let cpm_session_service = CPMSessionService::new(
562 move |session, contact_uri, cpim_info, content_type, message_body| {
563 if let (Ok(contact_uri), Ok(content_type), Ok(message_body)) = (
564 std::str::from_utf8(contact_uri),
565 std::str::from_utf8(content_type),
566 std::str::from_utf8(message_body),
567 ) {
568 if let (Ok(imdn_message_id), Ok(cpim_date)) = (
569 std::str::from_utf8(cpim_info.imdn_message_id),
570 std::str::from_utf8(cpim_info.date),
571 ) {
572 let cpim_from = if let Some(uri) = &cpim_info.from_uri {
573 let uri = uri.string_representation_without_query_and_fragment();
574 if let Ok(uri) = String::from_utf8(uri) {
575 Some(uri)
576 } else {
577 None
578 }
579 } else {
580 None
581 };
582 message_callback_impl_2(
583 0,
584 Some(MessagingSessionHandle {
585 inner: Arc::clone(session),
587 }),
588 contact_uri,
589 content_type,
590 message_body,
591 imdn_message_id,
592 cpim_date,
593 cpim_from.as_deref(),
594 );
595 } else {
596 platform_log(LOG_TAG, "failed to decode cpim info as utf-8 string");
597 }
598 } else {
599 platform_log(LOG_TAG, "failed to decode message data as utf-8 string");
600 }
601 },
602 move |msrp_info| msrp_socket_allocator_function_impl_2(msrp_info),
603 move |sock, raddr, rport, tls| {
604 let raddr = String::from(raddr);
605 msrp_socket_connect_function_impl_2(sock, raddr, rport, tls)
606 },
607 move |is_deferred_session, contact_uri, conversation_id, contribution_id, rx| {
608 let messaging_config = &*messaging_config_1.lock().unwrap();
609 if messaging_config.chat_auth == 1 {
610 if is_deferred_session {
611 return 200;
612 }
613 if messaging_config.im_session_auto_accept == 1 {
614 return 200;
615 }
616 }
617 180
618 },
619 move |contact_uri,
620 conversation_id,
621 contribution_id,
622 subject,
623 referred_by_name,
624 referred_by_uri,
625 rx| {
626 let messaging_config = &*messaging_config_2.lock().unwrap();
627 if messaging_config.group_chat_auth == 1 {
628 if messaging_config.im_session_auto_accept_group_chat == 1 {
629 return 200;
630 }
631 }
632 180
633 },
634 move |ev| {},
635 );
636 let cpm_session_service = Arc::new(cpm_session_service);
637 let multi_conference_service_v1 =
638 MultiConferenceServiceV1::new(multi_conference_v1_invite_handler_function);
639 let multi_conference_service_v1 = Arc::new(multi_conference_service_v1);
640 let sm = Arc::new(sm);
641 let tm = Arc::new(tm);
642 let allowed_methods: Vec<&'static [u8]> =
643 [ACK, BYE, CANCEL, INVITE, MESSAGE, NOTIFY, OPTIONS, UPDATE].to_vec();
644
645 let mut transaction_handlers: Vec<Box<dyn TransactionHandler + Send + Sync>> = Vec::new();
646 transaction_handlers.push(Box::new(StandaloneMessagingServiceWrapper {
647 service: Arc::clone(&standalone_messaging_service),
648 tm: Arc::clone(&tm),
649 }));
650 transaction_handlers.push(Box::new(CPMSessionServiceWrapper {
651 service: Arc::clone(&cpm_session_service),
652 tm: Arc::clone(&tm),
653 }));
654 transaction_handlers.push(Box::new(MultiConferenceServiceV1Wrapper {
655 service: Arc::clone(&multi_conference_service_v1),
656 tm: Arc::clone(&tm),
657 }));
658
659 let core = Arc::new(SipCore::new(
660 &sm,
661 &tm,
662 tm_event_itf,
663 allowed_methods,
664 transaction_handlers,
665 &rt,
666 ));
667
668 let core_ = Arc::clone(&core);
669 let rt_ = Arc::clone(&rt);
670
671 RcsEngine {
672 state: Arc::clone(&state),
673
674 state_callback,
675
676 tm: Arc::clone(&tm),
677
678 subscription_id,
679
680 impi: None,
681 impu: None,
682
683 home_domain: None,
684
685 authentication_type: None,
686
687 sip_instance_id: Uuid::new_v4(),
688
689 p_cscf_connection_config: PCscfConnectionConfig::new(),
690
691 registration_id_counter: 0,
692
693 flow_manager: Arc::new(FlowManager::new(
694 &sm,
695 &tm,
696 move |is_registered, transport, public_user_id, registration| {
697 platform_log(
698 LOG_TAG,
699 format!(
700 "flow_manager state_callback: is_registered={:?}, public_user_id={:?}",
701 is_registered, &public_user_id
702 ),
703 );
704
705 let mut guard = state.lock().unwrap();
706 match &guard.0 {
707 RcsEngineConnectionState::CONNECTED(transport_, _) => {
708 if Arc::ptr_eq(&transport, transport_) {
709 match (is_registered, public_user_id) {
710 (true, Some(public_user_id)) => {
711 let public_user_id_ = public_user_id.clone();
712 guard.1 =
713 RcsEngineRegistrationState::MAINTAINED(public_user_id_);
714 state_callback_(RcsEngineRegistrationState::MAINTAINED(
715 public_user_id,
716 ));
717 }
718 _ => {
719 guard.0 = RcsEngineConnectionState::IDLE;
720 guard.1 = RcsEngineRegistrationState::NONE;
721 state_callback_(RcsEngineRegistrationState::NONE);
722 }
723 }
724
725 return;
726 }
727
728 platform_log(LOG_TAG, "already registered on another socket");
729 }
730 _ => {
731 platform_log(LOG_TAG, "already abandonned");
732 }
733 }
734
735 if is_registered {
736 deregister(®istration, &core_, &rt_);
737 }
738 },
739 )),
740
741 standalone_messaging_service,
742
743 cpm_session_service,
744
745 ft_http_service: Arc::new(FileTransferOverHTTPService::new()),
746
747 chatbot_config: ChatbotConfig::new(),
748
749 msrp_connection_config,
750
751 messaging_config,
752
753 ft_http_configs: FileTransferOverHTTPConfigs::new(),
754
755 conference_service_v1: multi_conference_service_v1,
756
757 core,
759 context,
760 }
762 }
763
764 pub fn configure(&mut self, ims_config: String, rcs_config: String) {
765 if let (Ok(ims_app), Ok(rcs_app)) = (
766 ims_config.parse::<Characteristic>(),
767 rcs_config.parse::<Characteristic>(),
768 ) {
769 let ims_app = ImsApplication::new(&ims_app);
770 let rcs_app = RcsApplication::new(&rcs_app);
771
772 self.impi.take();
773
774 if let Some(pvui) = ims_app.get_private_user_identity() {
775 self.impi.replace(String::from(pvui));
776 }
777
778 self.impu.take();
779
780 let mut pbui_priority = 0;
781
782 for pbui in ims_app.get_public_user_identity_list() {
783 if pbui.starts_with("sip:") {
784 if pbui.starts_with("sip:+") {
785 if pbui_priority < 3 {
786 pbui_priority = 3;
787 self.impu = Some(String::from(pbui));
788 }
789 } else {
790 if pbui_priority < 2 {
791 pbui_priority = 2;
792 self.impu = Some(String::from(pbui));
793 }
794 }
795 } else if pbui.starts_with("tel:") {
796 if pbui_priority < 1 {
797 pbui_priority = 1;
798 self.impu = Some(String::from(pbui));
799 }
800 } else {
801 if self.impu.is_none() {
802 self.impu.replace(String::from(pbui));
803 }
804 }
805 }
806
807 platform_log(
808 LOG_TAG,
809 format!(
810 "rcs engine configured with IMPI: {:?}, IMPU: {:?}",
811 &self.impi, &self.impu
812 ),
813 );
814
815 self.home_domain = None;
816
817 if let Some(home_domain) = ims_app.get_home_domain() {
818 self.home_domain = Some(String::from(home_domain));
819 }
820
821 self.authentication_type = None;
822
823 if let Some(gsma_ext) = ims_app.get_ims_gsma_extension() {
824 let ext_info = gsma_ext.get_info();
825
826 if let Some(auth_type) = ext_info.auth_type {
827 if auth_type.eq_ignore_ascii_case("AKA") {
828 if let (Some(realm), Some(username)) = (&self.home_domain, &self.impi) {
829 self.authentication_type = Some(AuthenticationType::Aka(
830 String::from("AKAv1-MD5"),
831 realm.clone(),
832 username.clone(),
833 ));
834 }
835 } else if auth_type.eq_ignore_ascii_case("Digest") {
836 if let (Some(realm), Some(username), Some(password)) =
837 (ext_info.realm, ext_info.user_name, ext_info.user_password)
838 {
839 self.authentication_type = Some(AuthenticationType::Digest(
840 String::from("SHA-256"),
841 String::from(realm),
842 String::from(username),
843 String::from(password),
844 ))
845 }
846 }
847 }
848
849 if let Some(uuid_value) = ext_info.uuid_value {
850 if let Ok(uuid) = Uuid::parse_str(uuid_value) {
851 self.sip_instance_id = uuid;
852 }
853 }
854 }
855
856 self.p_cscf_connection_config.update_configuration(&ims_app);
857
858 self.chatbot_config.update_configuration(&rcs_app);
859
860 self.msrp_connection_config
861 .lock()
862 .unwrap()
863 .update_configuration(&ims_app);
864
865 self.messaging_config
866 .lock()
867 .unwrap()
868 .update_configuration(&rcs_app);
869
870 self.ft_http_configs.update_configuration(&rcs_app)
871 }
872 }
873
874 pub fn connect(&mut self, rt: Arc<Runtime>) {
875 platform_log(LOG_TAG, "calling engine->connect()");
876
877 if let (Some(impi), Some(impu), Some(home_domain), Some(authentication_type)) = (
878 &self.impi,
879 &self.impu,
880 &self.home_domain,
881 &self.authentication_type,
882 ) {
883 if let Some((dns_config, service_type, address, known_host, known_ip, known_port)) =
884 self.p_cscf_connection_config.get_next()
885 {
886 platform_log(
887 LOG_TAG,
888 format!(
889 "connect(): configured with: {}, known as {:?}, {:?}:{:?}",
890 &address, &known_host, &known_ip, &known_port
891 ),
892 );
893
894 let state = Arc::clone(&self.state);
895
896 let mut guard = state.lock().unwrap();
897
898 match &guard.0 {
899 RcsEngineConnectionState::IDLE => {
900 guard.0 = RcsEngineConnectionState::CONNECTING;
901 }
902
903 _ => {
904 return;
905 }
906 }
907
908 let impi = impi.clone();
909 let impu = impu.clone();
910 let home_domain = home_domain.clone();
911 let authentication_type = authentication_type.clone();
912
913 let state_ = Arc::clone(&state);
914 let state_callback_ = Arc::clone(&self.state_callback);
915
916 let tm = Arc::clone(&self.tm);
917 let tm_control_itf = tm.get_ctrl_itf();
919 let context = Arc::clone(&self.context);
920 let rt_ = Arc::clone(&rt);
921
922 let subscription_id = self.subscription_id;
923 let sip_instance_id = self.sip_instance_id;
924
925 self.registration_id_counter += 1;
926 let registration_id = self.registration_id_counter;
927
928 let flow_manager = Arc::clone(&self.flow_manager);
929
930 let cpm_session_service = Arc::clone(&self.cpm_session_service);
931
932 let conference_service_v1 = Arc::clone(&self.conference_service_v1);
933
934 let core = Arc::clone(&self.core);
935
936 rt.spawn(async move {
937 let dns_client = context.get_dns_client();
938 let dns_config_ = dns_config.clone();
939
940 let service_name = service_type.get_string_repr();
941
942 #[cfg(not(all(feature = "android", target_os = "android")))]
943 let tls_client_config = context.get_tls_client_config();
944
945 if let Ok(mut stream) = if let Some(port) = known_port {
946 let (tx, rx) = mpsc::channel(1);
947 rt_.spawn(async move {
948 match tx.send((address.clone(), port)).await {
949 Ok(()) => {}
950 Err(_) => {}
951 }
952 });
953 Ok(ReceiverStream::from(rx))
954 } else {
955 dns_client
956 .resolve_service(dns_config_, address.clone(), service_name)
957 .await
958 } {
959 while let Some((target, port)) = stream.next().await {
960 platform_log(
961 LOG_TAG,
962 format!(
963 "connect(): sip service resolved with {}:{}",
964 &target, port
965 ),
966 );
967
968 let dns_config_ = dns_config.clone();
969
970 if let Ok(mut stream) = if let Some(addr) = known_ip {
971 let (tx, rx) = mpsc::channel(1);
972 rt_.spawn(async move {
973 match tx.send(addr).await {
974 Ok(()) => {}
975 Err(_) => {}
976 }
977 });
978 Ok(ReceiverStream::from(rx))
979 } else {
980 dns_client
981 .resolve(
982 dns_config_,
983 if let Some(host) = &known_host {
984 String::from(host)
985 } else {
986 target.clone()
987 },
988 )
989 .await
990 } {
991 while let Some(addr) = stream.next().await {
992 if let std::net::IpAddr::V6(_) = addr {
993 platform_log(LOG_TAG, "IPv6 not supported for sip connection under most Carrier network now");
994 continue;
995 }
996 if let Some(cs) = match service_type {
997 ServiceType::SipD2T => {
998 #[cfg(all(feature = "android", target_os = "android"))]
999 let r = ClientStream::new_android(addr, port).await;
1000
1001 #[cfg(all(feature = "ohos", all(target_os = "linux", target_env = "ohos")))]
1002 let r = ClientStream::new_ohos(addr, port).await;
1003
1004 #[cfg(not(any(
1005 all(feature = "android", target_os = "android"),
1006 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
1007 )))]
1008 let r = ClientStream::new_tokio(addr, port).await;
1009
1010 match r {
1011 Ok(cs) => Some(cs),
1012 Err(e) => {
1013 platform_log(LOG_TAG, format!("error creating client stream: {:?}", e));
1014 None
1015 },
1016 }
1017 }
1018 ServiceType::SipsD2T => {
1019 #[cfg(all(feature = "android", target_os = "android"))]
1020 let r = ClientStream::new_android_ssl(
1021 addr,
1022 port,
1023 if let Some(host) = &known_host {
1024 host
1025 } else {
1026 &target
1027 },
1028 )
1029 .await;
1030
1031 #[cfg(all(feature = "ohos", all(target_os = "linux", target_env = "ohos")))]
1032 let r = ClientStream::new_ohos_ssl(
1033 Arc::clone(&tls_client_config),
1034 addr,
1035 port,
1036 if let Some(host) = &known_host {
1037 host
1038 } else {
1039 &target
1040 },
1041 )
1042 .await;
1043
1044 #[cfg(not(any(
1045 all(feature = "android", target_os = "android"),
1046 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
1047 )))]
1048 let r = ClientStream::new_tokio_ssl(
1049 Arc::clone(&tls_client_config),
1050 addr,
1051 port,
1052 if let Some(host) = &known_host {
1053 host
1054 } else {
1055 &target
1056 },
1057 )
1058 .await;
1059
1060 match r
1061 {
1062 Ok(cs) => match cs.do_handshake().await {
1063 Ok((cs, _)) => {
1064 platform_log(LOG_TAG, format!("ssl do_handshake success"));
1065 Some(cs)
1066 },
1067 Err(e) => {
1068 platform_log(
1069 LOG_TAG,
1070 format!("ssl do_handshake failed with error {:?}", e),
1071 );
1072 None
1073 },
1074 }
1075,
1076 Err(e) => {
1077 platform_log(LOG_TAG, format!("error creating ssl client stream: {:?}", e));
1078 None
1079 },
1080 }
1081 }
1082 ServiceType::SipD2U => None,
1083 } {
1084 let transport_address = cs.get_local_transport_address();
1085
1086 let t = SipTransport::new::<ClientStream>(
1087 transport_address.clone(),
1088 cs.get_sip_transport_type(),
1089 );
1090
1091 let state_ec = Arc::clone(&state_);
1092 let flow_manager_ec = Arc::clone(&flow_manager);
1093 let tm_ec = Arc::clone(&tm);
1094 let rt_ec = Arc::clone(&rt_);
1095 let state_callback_ec = Arc::clone(&state_callback_);
1096
1097 let transport = Arc::new(t);
1098 let transport_ec = Arc::clone(&transport);
1099 let transport_tx = setup_sip_transport(&transport, cs, tm_control_itf.clone(), Arc::clone(&rt_), move || {
1100
1101 platform_log(
1102 LOG_TAG,
1103 "on sip transport exit",
1104 );
1105
1106 let mut guard = state_ec.lock().unwrap();
1107 guard.0 = RcsEngineConnectionState::IDLE;
1108 guard.1 = RcsEngineRegistrationState::NONE;
1109 state_callback_ec(RcsEngineRegistrationState::NONE);
1110 let _ = flow_manager_ec.stop_observation(&transport_ec);
1111 tm_ec.unregister_sip_transport(&transport_ec, &rt_ec);
1112 });
1113
1114 {
1115 let mut guard = state_.lock().unwrap();
1116
1117 match guard.0 {
1118 RcsEngineConnectionState::CONNECTING => {
1119 guard.0 = RcsEngineConnectionState::CONNECTED(
1120 Arc::clone(&transport),
1121 transport_address.clone(),
1122 );
1123
1124 tm.register_sip_transport(Arc::clone(&transport), transport_tx);
1125 },
1126
1127 _ => return,
1128 }
1129 }
1130
1131 let state = Arc::clone(&state_);
1132
1133 let flow_manager_ = Arc::clone(&flow_manager);
1134
1135 let cpm_session_service_ = Arc::clone(&cpm_session_service);
1136
1137 let conference_service_v1_ =
1138 Arc::clone(&conference_service_v1);
1139
1140 let transport_ = Arc::clone(&transport);
1141 let core_ = Arc::clone(&core);
1144
1145 let rt = Arc::clone(&rt_);
1146
1147 let registration = Registration::new(
1148 subscription_id,
1149 impi,
1150 impu,
1151 home_domain,
1152 authentication_type,
1153 Arc::clone(&transport),
1154 transport_address.clone(),
1155 registration_id,
1156 sip_instance_id,
1157 );
1158
1159 let registration = Arc::new(registration);
1160
1161 flow_manager.observe_registration(
1162 &transport,
1163 transport_address,
1164 ®istration,
1165 &core_,
1166 &rt_,
1167 );
1168
1169 start_register(®istration, &flow_manager, &core, &rt_, move |ev| {
1170 let transport = Arc::clone(&transport_);
1171 match ev {
1173 RegistrationEvent::Registered(
1174 unbarred_impu,
1175 ) => {
1176 platform_log(
1177 LOG_TAG,
1178 "on RegistrationEvent::Registered",
1179 );
1180
1181 let sip_instance_id = format!(
1182 "<urn:uuid:{}>",
1183 sip_instance_id
1184 .as_hyphenated()
1185 .encode_lower(
1186 &mut Uuid::encode_buffer()
1187 )
1188 );
1189
1190 core_.set_default_public_identity(
1191 unbarred_impu.clone(),
1192 sip_instance_id.clone(),
1193 Arc::clone(&transport),
1194 ); cpm_session_service_
1197 .set_registered_public_identity(
1198 unbarred_impu.clone(),
1199 sip_instance_id.clone(),
1200 Arc::clone(&transport),
1201 );
1202
1203 conference_service_v1_
1204 .set_registered_public_identity(
1205 unbarred_impu.clone(),
1206 sip_instance_id.clone(),
1207 Arc::clone(&transport),
1208 );
1209
1210 let mut guard = state.lock().unwrap();
1211 let default_public_identity =
1212 unbarred_impu.clone();
1213 guard.1 = RcsEngineRegistrationState::AUTHENTICATED(default_public_identity); state_callback_(RcsEngineRegistrationState::AUTHENTICATED(unbarred_impu));
1215 },
1216 RegistrationEvent::Refreshed => {
1217 platform_log(
1218 LOG_TAG,
1219 "on RegistrationEvent::Refreshed",
1220 );
1221 },
1222 RegistrationEvent::Released => {
1223 platform_log(
1224 LOG_TAG,
1225 "on RegistrationEvent::Released",
1226 );
1227
1228 let mut guard = state.lock().unwrap();
1229 guard.0 = RcsEngineConnectionState::IDLE;
1230 guard.1 = RcsEngineRegistrationState::NONE;
1231 state_callback_(RcsEngineRegistrationState::NONE);
1232 let _ = flow_manager_.stop_observation(&transport);
1233 tm.unregister_sip_transport(&transport, &rt);
1234 },
1235 }
1236 });
1237
1238 return;
1239 }
1240 }
1241 }
1242 }
1243 }
1244
1245 let mut guard = state_.lock().unwrap();
1246
1247 guard.0 = RcsEngineConnectionState::IDLE;
1248 });
1249 }
1250 }
1251 }
1252
1253 pub fn disconnect(&self, rt: Arc<Runtime>) {
1254 let mut guard = self.state.lock().unwrap();
1255 match &mut guard.0 {
1256 RcsEngineConnectionState::IDLE => {}
1257 RcsEngineConnectionState::CONNECTING => {}
1258 RcsEngineConnectionState::CONNECTED(transport, _) => {
1259 let transport = Arc::clone(transport);
1260 match &mut guard.1 {
1261 RcsEngineRegistrationState::NONE => {}
1262 RcsEngineRegistrationState::AUTHENTICATED(_)
1263 | RcsEngineRegistrationState::MAINTAINED(_) => {
1264 if let Some(registration) = self.flow_manager.stop_observation(&transport) {
1265 deregister(®istration, &self.core, &rt);
1266 }
1267 }
1268 }
1269 }
1270 }
1271
1272 guard.0 = RcsEngineConnectionState::IDLE;
1273 guard.1 = RcsEngineRegistrationState::NONE;
1274 (self.state_callback)(RcsEngineRegistrationState::NONE);
1275 }
1276
1277 pub fn send_message<F>(
1278 &self,
1279 message_type: &str,
1280 message_content: &str,
1281 recipient: &str,
1282 recipient_type: RecipientType,
1283 message_result_callback: F,
1284 rt: &Arc<Runtime>,
1285 ) where
1286 F: FnOnce(u16, String) + Send + Sync + 'static,
1287 {
1288 let core = Arc::clone(&self.core);
1289
1290 let guard = self.state.lock().unwrap();
1293
1294 match &*guard {
1295 (
1296 RcsEngineConnectionState::CONNECTED(transport, _),
1297 RcsEngineRegistrationState::MAINTAINED(public_user_identity),
1298 ) => {
1299 let mut send_through_one_to_one_chat_service = false;
1300 let mut send_through_group_chat_service = false;
1301 let mut send_through_standalone_message_service = false;
1302
1303 let recipient_supports_one_to_one = false;
1307
1308 let recipient_supports_standalone = true;
1310
1311 let messaging_config = &*self.messaging_config.lock().unwrap();
1315 let mut recipient_uri = String::from(recipient);
1316
1317 if let RecipientType::Chatbot = recipient_type {
1318 if messaging_config.chatbot_msg_tech == 1
1319 && messaging_config.chat_auth == 1
1320 && recipient_supports_one_to_one
1321 {
1322 send_through_one_to_one_chat_service = true;
1323 } else if messaging_config.chatbot_msg_tech == 2 {
1324 if messaging_config.chat_auth == 1 && recipient_supports_one_to_one {
1325 send_through_one_to_one_chat_service = true;
1326 }
1327
1328 if messaging_config.standalone_msg_auth == 1
1329 && recipient_supports_standalone
1330 {
1331 send_through_standalone_message_service = true;
1332 }
1333 } else if messaging_config.chatbot_msg_tech == 3
1334 && messaging_config.standalone_msg_auth == 1
1335 && recipient_supports_standalone
1336 {
1337 send_through_standalone_message_service = true;
1338 }
1339 } else if let RecipientType::Group = recipient_type {
1340 if messaging_config.group_chat_auth == 1 {
1341 send_through_group_chat_service = true;
1342 }
1343 } else if let RecipientType::ResourceList = recipient_type {
1344 if messaging_config.standalone_msg_auth == 1 {
1345 if let Some(exploder_uri) = &messaging_config.exploder_uri {
1347 recipient_uri = String::from(exploder_uri);
1348 } else {
1349 recipient_uri = String::from("exploder@conf-factory");
1350 }
1351 send_through_standalone_message_service = true;
1352 }
1353 } else {
1354 if messaging_config.chat_auth == 1 && recipient_supports_one_to_one {
1355 send_through_one_to_one_chat_service = true;
1356 }
1357
1358 if messaging_config.standalone_msg_auth == 1 && recipient_supports_standalone {
1359 send_through_standalone_message_service = true;
1360 }
1361 }
1362
1363 if send_through_one_to_one_chat_service || send_through_group_chat_service {
1364 let core = &self.core;
1365 self.cpm_session_service.send_message(
1366 message_type,
1367 message_content,
1368 recipient,
1369 &recipient_type,
1370 &recipient_uri,
1371 message_result_callback,
1372 core,
1373 rt,
1374 );
1375
1376 return;
1377 } else if send_through_standalone_message_service {
1378 if messaging_config.standalone_msg_max_size >= message_content.len() {
1379 if messaging_config.standalone_msg_switch_over_size < message_content.len()
1380 {
1381 let core = &self.core;
1382 self.standalone_messaging_service.send_large_mode_message(
1383 message_type,
1384 message_content,
1385 recipient,
1386 &recipient_type,
1387 &recipient_uri,
1388 message_result_callback,
1389 core,
1390 rt,
1391 );
1392 } else {
1393 standalone_messaging::send_message(
1394 message_type,
1395 message_content,
1396 recipient,
1397 &recipient_type,
1398 &recipient_uri,
1399 message_result_callback,
1400 core,
1401 transport,
1402 public_user_identity,
1403 &rt,
1404 );
1405 }
1406
1407 return;
1408 }
1409 }
1410 }
1411
1412 _ => {}
1413 }
1414
1415 message_result_callback(403, String::from("Forbidden"))
1416 }
1417
1418 pub fn send_imdn_report<F>(
1419 &self,
1420 imdn_content: &str,
1421 sender_uri: &str,
1422 sender_service_type: i32,
1423 sender_session_handle: *mut MessagingSessionHandle,
1424 rt: Arc<Runtime>,
1425 send_imdn_report_result_callback: F,
1426 ) where
1427 F: FnOnce(u16, String) + Send + Sync + 'static,
1428 {
1429 let guard = self.state.lock().unwrap();
1430
1431 match &*guard {
1432 (
1433 RcsEngineConnectionState::CONNECTED(transport, _),
1434 RcsEngineRegistrationState::MAINTAINED(public_user_identity),
1435 ) => {
1436 if sender_service_type == 1 {
1437 let core = Arc::clone(&self.core);
1438
1439 let recipient_type = RecipientType::Contact;
1440
1441 standalone_messaging::send_message(
1442 "message/imdn",
1443 imdn_content,
1444 sender_uri,
1445 &recipient_type, sender_uri,
1447 move |status_code, reason_phrase| {
1448 send_imdn_report_result_callback(status_code, reason_phrase);
1449 },
1450 core,
1451 transport,
1452 public_user_identity,
1453 &rt,
1454 );
1455
1456 return;
1457 }
1458 }
1459
1460 _ => {}
1461 }
1462
1463 send_imdn_report_result_callback(403, String::from("Forbidden"));
1464 }
1465
1466 pub fn upload_file<PF, RF>(
1467 &self,
1468 tid: &str,
1469 file_path: &str,
1470 file_name: &str,
1471 file_mime: &str,
1472 file_hash: Option<&str>,
1473 thumbnail_path: Option<&str>,
1474 thumbnail_name: Option<&str>,
1475 thumbnail_mime: Option<&str>,
1476 thumbnail_hash: Option<&str>,
1477 msisdn: Option<&str>,
1478 http_client: Arc<HttpClient>,
1479 gba_context: Arc<GbaContext>,
1480 security_context: Arc<SecurityContext>,
1481 rt: Arc<Runtime>,
1482 upload_file_progress_callback: PF,
1483 upload_file_result_callback: RF,
1484 ) where
1485 PF: Fn(u32, i32) + Send + Sync + 'static,
1486 RF: FnOnce(u16, String, Option<String>) + Send + Sync + 'static,
1487 {
1488 match Uuid::parse_str(tid) {
1489 Ok(tid) => {
1490 let ft_auth = self.ft_http_configs.ft_auth;
1491
1492 if ft_auth == 1 {
1493 if let Some(ft_http_cs_uri) = &self.ft_http_configs.ft_http_cs_uri {
1494 let ft_http_service = Arc::clone(&self.ft_http_service);
1495
1496 let ft_http_cs_uri = String::from(ft_http_cs_uri);
1497 let msisdn = match msisdn {
1498 Some(msisdn) => Some(String::from(msisdn)),
1499 None => None,
1500 };
1501
1502 let file_path = String::from(file_path);
1503 let file_name = String::from(file_name);
1504 let file_mime = String::from(file_mime);
1505 let file_hash = match file_hash {
1506 Some(file_hash) => Some(String::from(file_hash)),
1507 None => None,
1508 };
1509
1510 let thumbnail_path = match thumbnail_path {
1511 Some(thumbnail_path) => Some(String::from(thumbnail_path)),
1512 None => None,
1513 };
1514
1515 let thumbnail_name = match thumbnail_name {
1516 Some(thumbnail_name) => Some(String::from(thumbnail_name)),
1517 None => None,
1518 };
1519
1520 let thumbnail_mime = match thumbnail_mime {
1521 Some(thumbnail_mime) => Some(String::from(thumbnail_mime)),
1522 None => None,
1523 };
1524
1525 let thumbnail_hash = match thumbnail_hash {
1526 Some(thumbnail_hash) => Some(String::from(thumbnail_hash)),
1527 None => None,
1528 };
1529
1530 rt.spawn(async move {
1531 let file: FileInfo<'_> = FileInfo {
1532 path: &file_path,
1533 name: &file_name,
1534 mime: &file_mime,
1535 hash: file_hash.as_deref(),
1536 };
1537
1538 let thumbnail = match (
1539 thumbnail_path.as_deref(),
1540 thumbnail_name.as_deref(),
1541 thumbnail_mime.as_deref(),
1542 ) {
1543 (
1544 Some(thumbnail_path),
1545 Some(thumbnail_name),
1546 Some(thumbnail_mime),
1547 ) => Some(FileInfo {
1548 path: thumbnail_path,
1549 name: thumbnail_name,
1550 mime: thumbnail_mime,
1551 hash: thumbnail_hash.as_deref(),
1552 }),
1553 _ => None,
1554 };
1555
1556 let progress_callback: Box<dyn Fn(u32, i32) + Send + Sync> =
1557 Box::new(upload_file_progress_callback);
1558 let progress_callback = Arc::new(progress_callback);
1559
1560 match upload_file(
1561 &ft_http_service,
1562 &ft_http_cs_uri,
1563 tid,
1564 file,
1565 thumbnail,
1566 msisdn.as_deref(),
1567 &http_client,
1568 &gba_context,
1569 &security_context,
1570 &progress_callback,
1571 )
1572 .await
1573 {
1574 Ok(result_xml) => {
1575 upload_file_result_callback(
1576 200,
1577 String::from("Ok"),
1578 Some(result_xml),
1579 );
1580 }
1581
1582 Err(e) => {
1583 let status_code = e.error_code();
1584 let reason_phrase = e.error_string();
1585 upload_file_result_callback(status_code, reason_phrase, None);
1586 }
1587 }
1588 });
1589
1590 return;
1591 }
1592 }
1593
1594 upload_file_result_callback(403, String::from("Forbidden"), None);
1595 }
1596
1597 Err(e) => upload_file_result_callback(400, format!("{}", e), None),
1598 }
1599 }
1600
1601 pub fn download_file<PF, RF>(
1602 &self,
1603 file_uri: &str,
1604 download_path: &str,
1605 start: usize,
1606 total: Option<usize>,
1607 msisdn: Option<&str>,
1608 http_client: Arc<HttpClient>,
1609 gba_context: Arc<GbaContext>,
1610 security_context: Arc<SecurityContext>,
1611 rt: Arc<Runtime>,
1612 download_file_progress_callback: PF,
1613 download_file_result_callback: RF,
1614 ) where
1615 PF: Fn(u32, i32) + Send + Sync + 'static,
1616 RF: FnOnce(u16, String) + Send + Sync + 'static,
1617 {
1618 let ft_auth = self.ft_http_configs.ft_auth;
1619
1620 if ft_auth == 1 {
1621 let file_uri = match &self.ft_http_configs.ft_http_dl_uri {
1622 Some(ft_http_dl_uri) => match Url::parse(ft_http_dl_uri) {
1623 Ok(mut url) => {
1624 let query = if let Some(query) = url.query() {
1625 format!("{}&url={}", query, file_uri) } else {
1627 format!("url={}", file_uri) };
1629
1630 url.set_query(Some(&query));
1631
1632 url.to_string()
1633 }
1634 Err(_) => String::from(file_uri),
1635 },
1636 None => String::from(file_uri),
1637 };
1638
1639 let download_path = String::from(download_path);
1640
1641 let msisdn = match msisdn {
1642 Some(msisdn) => Some(String::from(msisdn)),
1643 None => None,
1644 };
1645
1646 rt.spawn(async move {
1647 match download_file(
1648 &file_uri,
1649 &download_path,
1650 start,
1651 total,
1652 msisdn.as_deref(),
1653 &http_client,
1654 &gba_context,
1655 &security_context,
1656 None,
1657 download_file_progress_callback,
1658 )
1659 .await
1660 {
1661 Ok(()) => {
1662 download_file_result_callback(200, String::from("Ok"));
1663 }
1664
1665 Err(e) => {
1666 let status_code = e.error_code();
1667 let reason_phrase = e.error_string();
1668 download_file_result_callback(status_code, reason_phrase);
1669 }
1670 }
1671 });
1672
1673 return;
1674 }
1675
1676 download_file_result_callback(403, String::from("Forbidden"));
1677 }
1678
1679 pub fn create_conference_v1<F>(
1680 &self,
1681 recipients: &str,
1682 offer_sdp: &str,
1683 event_cb: Option<MultiConferenceEventListener>,
1684 event_cb_context: MultiConferenceEventListenerContextWrapper,
1685 rt: &Arc<Runtime>,
1686 callback: F,
1687 ) where
1688 F: FnOnce(Option<(MultiConferenceV1, String)>) + Send + Sync + 'static,
1689 {
1690 let core = Arc::clone(&self.core);
1691
1692 self.conference_service_v1.create_conference(
1695 recipients,
1696 offer_sdp,
1697 event_cb,
1698 event_cb_context,
1699 &core,
1700 rt,
1701 callback,
1702 )
1703 }
1704
1705 pub fn retrieve_specific_chatbots<F>(
1706 &self,
1707 local_etag: Option<&str>,
1708 msisdn: Option<&str>,
1709 http_client: Arc<HttpClient>,
1710 gba_context: Arc<GbaContext>,
1711 security_context: Arc<SecurityContext>,
1712 rt: Arc<Runtime>,
1713 retrieve_specific_chatbots_result_callback: F,
1714 ) where
1715 F: FnOnce(u16, String, Option<String>, Option<String>, u32) + Send + Sync + 'static,
1716 {
1717 platform_log(LOG_TAG, "calling retrieve_specific_chatbots()");
1718
1719 if let Some(specific_chatbots_lists_url) = &self.chatbot_config.specific_chatbots_lists {
1720 let specific_chatbots_lists_url = String::from(specific_chatbots_lists_url);
1721
1722 let local_etag: Option<String> = match local_etag {
1723 Some(local_etag) => Some(String::from(local_etag)),
1724 None => None,
1725 };
1726
1727 let msisdn = match msisdn {
1728 Some(msisdn) => Some(String::from(msisdn)),
1729 None => None,
1730 };
1731
1732 rt.spawn(async move {
1733 match chat_bot::retrieve_specific_chatbots(
1734 &specific_chatbots_lists_url,
1735 local_etag.as_deref(),
1736 msisdn.as_deref(),
1737 &http_client,
1738 &gba_context,
1739 &security_context,
1740 None,
1741 )
1742 .await
1743 {
1744 Ok(result) => match result {
1745 RetrieveSpecificChatbotsSuccess::Ok(
1746 specific_chatbots,
1747 response_etag,
1748 expiry,
1749 ) => {
1750 retrieve_specific_chatbots_result_callback(
1751 200,
1752 String::from("Ok"),
1753 Some(specific_chatbots),
1754 response_etag,
1755 expiry,
1756 );
1757 }
1758 RetrieveSpecificChatbotsSuccess::NotModified(response_etag, expiry) => {
1759 retrieve_specific_chatbots_result_callback(
1760 304,
1761 String::from("Not Modified"),
1762 None,
1763 response_etag,
1764 expiry,
1765 );
1766 }
1767 },
1768 Err(e) => {
1769 platform_log(
1770 LOG_TAG,
1771 format!("retrieve_specific_chatbots error: {:?}", &e),
1772 );
1773 let status_code = e.error_code();
1774 let reason_phrase = e.error_string();
1775 retrieve_specific_chatbots_result_callback(
1776 status_code,
1777 reason_phrase,
1778 None,
1779 None,
1780 0,
1781 );
1782 }
1783 }
1784 });
1785 } else {
1786 retrieve_specific_chatbots_result_callback(
1787 404,
1788 String::from("Not Found"),
1789 None,
1790 None,
1791 0,
1792 );
1793 }
1794 }
1795
1796 pub fn search_chatbot<F>(
1797 &self,
1798 query: &str,
1799 start: u32,
1800 num: u32,
1801 home_operator: &str,
1802 msisdn: Option<&str>,
1803 http_client: Arc<HttpClient>,
1804 gba_context: Arc<GbaContext>,
1805 security_context: Arc<SecurityContext>,
1806 rt: Arc<Runtime>,
1807 chatbot_search_result_callback: F,
1808 ) where
1809 F: FnOnce(u16, String, Option<String>) + Send + Sync + 'static,
1810 {
1811 platform_log(LOG_TAG, "calling search_chatbot()");
1812
1813 if let Some(chatbot_directory) = &self.chatbot_config.chatbot_directory {
1814 let chatbot_directory = String::from(chatbot_directory);
1815 let query = String::from(query);
1816 let home_operator = String::from(home_operator);
1817 let msisdn = match msisdn {
1818 Some(msisdn) => Some(String::from(msisdn)),
1819 None => None,
1820 };
1821
1822 rt.spawn(async move {
1823 match chat_bot::search_chatbot_directory(
1824 &chatbot_directory,
1825 &query,
1826 start,
1827 num,
1828 &home_operator,
1829 msisdn.as_deref(),
1830 &http_client,
1831 &gba_context,
1832 &security_context,
1833 None,
1834 )
1835 .await
1836 {
1837 Ok(json) => {
1838 chatbot_search_result_callback(200, String::from("Ok"), Some(json));
1839 }
1840 Err(e) => {
1841 platform_log(LOG_TAG, format!("search_chatbot_directory error: {:?}", &e));
1842 let status_code = e.error_code();
1843 let reason_phrase = e.error_string();
1844 chatbot_search_result_callback(status_code, reason_phrase, None);
1845 }
1846 }
1847 });
1848
1849 return;
1850 }
1851
1852 chatbot_search_result_callback(403, String::from("Forbidden"), None);
1853 }
1854
1855 pub fn retrieve_chatbot_info<F>(
1856 &self,
1857 chatbot_sip_uri: &str,
1858 local_etag: Option<&str>,
1859 home_operator: &str,
1860 home_language: &str,
1861 msisdn: Option<&str>,
1862 http_client: Arc<HttpClient>,
1863 gba_context: Arc<GbaContext>,
1864 security_context: Arc<SecurityContext>,
1865 rt: Arc<Runtime>,
1866 retrieve_chatbot_info_result_callback: F,
1867 ) where
1868 F: FnOnce(u16, String, Option<String>, Option<String>, u32) + Send + Sync + 'static,
1869 {
1870 platform_log(LOG_TAG, "calling retrieve_chatbot_info()");
1871
1872 let host = match &self.chatbot_config.bot_info_fqdn {
1873 Some(bot_info_fqdn) => String::from(bot_info_fqdn),
1874
1875 None => {
1876 if let Some(chatbot_sip_uri) = chatbot_sip_uri.as_chatbot_sip_uri() {
1877 format!(
1878 "{}.{}",
1879 chatbot_sip_uri.bot_platform, chatbot_sip_uri.bot_platform_domain
1880 )
1881 } else {
1882 retrieve_chatbot_info_result_callback(
1883 403,
1884 String::from("Forbidden"),
1885 None,
1886 None,
1887 0,
1888 );
1889 return;
1890 }
1891 }
1892 };
1893
1894 let chatbot_sip_uri = String::from(chatbot_sip_uri);
1895
1896 let local_etag: Option<String> = match local_etag {
1897 Some(local_etag) => Some(String::from(local_etag)),
1898 None => None,
1899 };
1900
1901 let home_operator = String::from(home_operator);
1902 let home_language = String::from(home_language);
1903
1904 let msisdn = match msisdn {
1905 Some(msisdn) => Some(String::from(msisdn)),
1906 None => None,
1907 };
1908
1909 rt.spawn(async move {
1910 match chat_bot::retrieve_chatbot_info(
1911 &host,
1912 &chatbot_sip_uri,
1913 local_etag.as_deref(),
1914 &home_operator,
1915 &home_language,
1916 msisdn.as_deref(),
1917 &http_client,
1918 &gba_context,
1919 &security_context,
1920 None,
1921 )
1922 .await
1923 {
1924 Ok(result) => match result {
1925 RetrieveChatbotInfoSuccess::Ok(chatbot_info, response_etag, expiry) => {
1926 retrieve_chatbot_info_result_callback(
1927 200,
1928 String::from("Ok"),
1929 Some(chatbot_info),
1930 response_etag,
1931 expiry,
1932 );
1933 }
1934 RetrieveChatbotInfoSuccess::NotModified(response_etag, expiry) => {
1935 retrieve_chatbot_info_result_callback(
1936 304,
1937 String::from("Not Modified"),
1938 None,
1939 response_etag,
1940 expiry,
1941 );
1942 }
1943 },
1944 Err(e) => {
1945 platform_log(LOG_TAG, format!("retrieve_chatbot_info error: {:?}", &e));
1946 let status_code = e.error_code();
1947 let reason_phrase = e.error_string();
1948 retrieve_chatbot_info_result_callback(
1949 status_code,
1950 reason_phrase,
1951 None,
1952 None,
1953 0,
1954 );
1955 }
1956 }
1957 });
1958 }
1959}