rust_rcs_client/
rcs_engine.rs

1// Copyright 2023 宋昊文
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15extern 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    // msrp_channels: Arc<MsrpChannelManager>,
166    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_control_itf, tm_event_itf) = SipTransactionManager::new(rt);
201        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; // it is okay to use tls transport under cellular IMHO
229                        }
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                                        // to-do: the socket
237                                        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                                // not supported yet
379                            }
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                        // to-do: could use ipv6 sometimes
433                    }
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                                // to-do: it might be deferred session
586                                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(&registration, &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            // msrp_channels,
758            core,
759            context,
760            // gba_context: None,
761        }
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 = engine_itf.tm_control_itf.clone();
918                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 transport_address_ = transport_address.clone();
1142
1143                                        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                                            &registration,
1165                                            &core_,
1166                                            &rt_,
1167                                        );
1168
1169                                        start_register(&registration, &flow_manager, &core, &rt_, move |ev| {
1170                                            let transport = Arc::clone(&transport_);
1171                                            // let transport_address = transport_address_.clone();
1172                                            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                                                    ); // fix-me: contact identities should not be visible for sip core, best we can do is to provide a map between transport and registered impu to each message consumer
1195
1196                                                    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); // to-do: we need to append transport address anyway, why not here?
1214                                                    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(&registration, &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        /* engine_itf: RcsEngineInterface, */ rt: &Arc<Runtime>,
1285    ) where
1286        F: FnOnce(u16, String) + Send + Sync + 'static,
1287    {
1288        let core = Arc::clone(&self.core);
1289
1290        // let tm_control_itf = engine_itf.tm_control_itf;
1291
1292        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                // bool contact_is_chatbot = (options & rcs_send_message_option_contact_is_chatbot) != 0;
1304
1305                // bool contact_supports_one_to_one = (options & rcs_send_message_option_contact_supports_one_to_one) != 0;
1306                let recipient_supports_one_to_one = false;
1307
1308                // bool contact_supports_standalone = (options & rcs_send_message_option_contact_supports_standalone) != 0;
1309                let recipient_supports_standalone = true;
1310
1311                // bool contact_is_group = (options & rcs_send_message_option_send_to_group) != 0;
1312                // let recipient_is_group = false;
1313
1314                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                        // to-do: check max_one_to_many_recipients for limit
1346                        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, // to-do: support IMDN in group chat
1446                        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) // to-do: requires id, op, ci
1626                        } else {
1627                            format!("url={}", file_uri) // to-do: requires id, op, ci
1628                        };
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        // to-do: check RcsEngineRegistrationState
1693
1694        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}