Skip to main content

jami_rs/
lib.rs

1/**
2 * Copyright (c) 2018-2021, Sébastien Blin <sebastien.blin@enconn.fr>
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * * Redistributions of source code must retain the above copyright
8 *  notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 *  notice, this list of conditions and the following disclaimer in the
11 *  documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 *  names of its contributors may be used to endorse or promote products
14 *  derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 **/
27pub mod account;
28pub mod profile;
29pub mod profilemanager;
30pub mod transfermanager;
31
32pub use profile::Profile;
33pub use profilemanager::ProfileManager;
34pub use transfermanager::TransferManager;
35
36use account::Account;
37
38use dbus::blocking::Connection;
39use dbus::message::MatchRule;
40use dbus_tokio::connection;
41use log::info;
42use std::collections::HashMap;
43use std::sync::atomic::{AtomicBool, Ordering};
44use std::sync::Arc;
45use std::time::Duration;
46use std::{thread, time};
47
48/**
49 * Connect to the jami daemon
50 */
51pub struct Jami {}
52
53#[derive(Debug)]
54pub enum Event<I> {
55    Input(I),
56    Message {
57        account_id: String,
58        conversation_id: String,
59        payloads: HashMap<String, String>,
60    },
61    ConversationReady(String, String),
62    ConversationRemoved(String, String),
63    ConversationRequest(String, String),
64    RegistrationStateChanged(String, String),
65    ProfileReceived(String, String, String),
66    RegisteredNameFound(String, u64, String, String),
67    AccountsChanged(),
68    ConversationLoaded(u32, String, String, Vec<HashMap<String, String>>),
69    DataTransferEvent(String, String, u64, i32),
70    IncomingTrustRequest(String, String, Vec<u8>, u64),
71    MemberPresenceChanged(String, String, bool),
72    Resize,
73}
74
75#[derive(PartialEq)]
76pub enum ImportType {
77    None,
78    BACKUP,
79    NETWORK,
80}
81
82pub struct DataTransferInfo {
83    pub account_id: String,
84    pub last_event: u32,
85    pub flags: u32,
86    pub total: i64,
87    pub bytes_progress: i64,
88    pub author: String,
89    pub peer: String,
90    pub conv_id: String,
91    pub display_name: String,
92    pub path: String,
93    pub mimetype: String,
94}
95
96impl DataTransferInfo {
97    pub fn tuple(&self) -> (String, u32, u32, i64, i64, String, String, String, String, String, String) {
98        (self.account_id.clone(), self.last_event, self.flags, self.total, self.bytes_progress, self.author.clone(), self.peer.clone(), self.conv_id.clone(), self.display_name.clone(), self.path.clone(), self.mimetype.clone())
99    }
100
101    pub fn from_tuple(info: (String, u32, u32, i64, i64, String, String, String, String, String, String)) -> Self {
102        Self {
103            account_id: info.0,
104            last_event: info.1,
105            flags: info.2,
106            total: info.3,
107            bytes_progress: info.4,
108            author: info.5,
109            peer: info.6,
110            conv_id: info.7,
111            display_name: info.8,
112            path: info.9,
113            mimetype: info.10,
114        }
115    }
116}
117
118impl Jami {
119    /**
120     * Retrieve account or create one if necessary.
121     * @param   create_if_not   Create if no account found
122     * @return the account
123     */
124    pub fn select_jami_account(create_if_not: bool) -> Account {
125        let accounts = Jami::get_account_list();
126        // Select first enabled account
127        for account in &accounts {
128            if account.enabled {
129                return account.clone();
130            }
131        }
132        if create_if_not {
133            // No valid account found, generate a new one
134            Jami::add_account("", "", ImportType::None);
135        }
136        return Account::null();
137    }
138
139    /**
140     * Listen to daemon's signals
141     */
142    pub async fn handle_events<T: 'static + std::fmt::Debug + std::marker::Send>(
143        tx: tokio::sync::mpsc::Sender<Event<T>>,
144        stop: Arc<AtomicBool>,
145    ) -> Result<(), std::io::Error> {
146        let (resource, conn) = connection::new_session_sync()
147            .ok()
148            .expect("Lost connection");
149        tokio::spawn(async {
150            let err = resource.await;
151            panic!("Lost connection to D-Bus: {}", err);
152        });
153
154        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "accountsChanged");
155        let txs = tx.clone();
156        let _ic = conn
157            .add_match(mr)
158            .await
159            .ok()
160            .expect("Lost connection")
161            .cb(move |_, (): ()| {
162                let mut txs = txs.clone();
163                tokio::spawn(async move { txs.send(Event::AccountsChanged()).await });
164                true
165            });
166
167        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "messageReceived");
168        let txs = tx.clone();
169        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
170            move |_,
171                  (account_id, conversation_id, payloads): (
172                String,
173                String,
174                HashMap<String, String>,
175            )| {
176                let mut txs = txs.clone();
177                tokio::spawn(async move {
178                    txs.send(Event::Message {
179                        account_id,
180                        conversation_id,
181                        payloads,
182                    })
183                    .await
184                });
185                true
186            },
187        );
188
189        let mr = MatchRule::new_signal(
190            "cx.ring.Ring.ConfigurationManager",
191            "registrationStateChanged",
192        );
193        let txs = tx.clone();
194        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
195            move |_, (account_id, registration_state, _, _): (String, String, u64, String)| {
196                let mut txs = txs.clone();
197                tokio::spawn(async move {
198                    txs.send(Event::RegistrationStateChanged(
199                        account_id,
200                        registration_state,
201                    ))
202                    .await
203                });
204                true
205            },
206        );
207
208        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "conversationReady");
209        let txs = tx.clone();
210        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
211            move |_, (account_id, conversation_id): (String, String)| {
212                let mut txs = txs.clone();
213                tokio::spawn(async move {
214                    txs.send(Event::ConversationReady(account_id, conversation_id))
215                        .await
216                });
217                true
218            },
219        );
220
221        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "conversationRemoved");
222        let txs = tx.clone();
223        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
224            move |_, (account_id, conversation_id): (String, String)| {
225                let mut txs = txs.clone();
226                tokio::spawn(async move {
227                    txs.send(Event::ConversationRemoved(account_id, conversation_id))
228                        .await
229                });
230                true
231            },
232        );
233
234        let mr = MatchRule::new_signal(
235            "cx.ring.Ring.ConfigurationManager",
236            "conversationRequestReceived",
237        );
238        let txs = tx.clone();
239        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
240            move |_, (account_id, conversation_id): (String, String)| {
241                let mut txs = txs.clone();
242                tokio::spawn(async move {
243                    txs.send(Event::ConversationRequest(account_id, conversation_id))
244                        .await
245                });
246                true
247            },
248        );
249
250        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "registeredNameFound");
251        let txs = tx.clone();
252        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
253            move |_, (account_id, status, address, name): (String, i32, String, String)| {
254                let mut txs = txs.clone();
255                tokio::spawn(async move {
256                    txs.send(Event::RegisteredNameFound(
257                        account_id,
258                        status as u64,
259                        address,
260                        name,
261                    ))
262                    .await
263                });
264                true
265            },
266        );
267
268        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "profileReceived");
269        let txs = tx.clone();
270        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
271            move |_, (account_id, from, path): (String, String, String)| {
272                let mut txs = txs.clone();
273                tokio::spawn(async move {
274                    txs.send(Event::ProfileReceived(account_id, from, path))
275                        .await
276                });
277                true
278            },
279        );
280
281        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "incomingTrustRequest");
282        let txs = tx.clone();
283        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
284            move |_, (account_id, from, payloads, receive_time): (String, String, Vec<u8>, u64)| {
285                let mut txs = txs.clone();
286                tokio::spawn(async move {
287                    txs.send(Event::IncomingTrustRequest(
288                        account_id,
289                        from,
290                        payloads,
291                        receive_time,
292                    ))
293                    .await
294                });
295                true
296            },
297        );
298
299        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "conversationLoaded");
300        let txs = tx.clone();
301        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
302            move |_,
303                  (id, account_id, conversation_id, messages): (
304                u32,
305                String,
306                String,
307                Vec<HashMap<String, String>>,
308            )| {
309                let mut txs = txs.clone();
310                tokio::spawn(async move {
311                    txs.send(Event::ConversationLoaded(
312                        id,
313                        account_id,
314                        conversation_id,
315                        messages,
316                    ))
317                    .await
318                });
319                true
320            },
321        );
322
323        let mr = MatchRule::new_signal("cx.ring.Ring.ConfigurationManager", "dataTransferEvent");
324        let txs = tx.clone();
325        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
326            move |_,
327                  (account_id, conversation_id, id, code): (
328                String,
329                String,
330                u64,
331                i32,
332            )| {
333                let mut txs = txs.clone();
334                tokio::spawn(async move {
335                    txs.send(Event::DataTransferEvent(
336                        account_id,
337                        conversation_id,
338                        id,
339                        code,
340                    ))
341                    .await
342                });
343                true
344            },
345        );
346
347        let mr = MatchRule::new_signal("cx.ring.Ring.PresenceManager", "newBuddyNotification");
348        let txs = tx.clone();
349        let _ic = conn.add_match(mr).await.ok().expect("Lost connection").cb(
350            move |_, (account_id, uri, flag, _): (String, String, bool, String)| {
351                let mut txs = txs.clone();
352                tokio::spawn(async move {
353                    txs.send(Event::MemberPresenceChanged(
354                        account_id,
355                        uri,
356                        flag,
357                    ))
358                    .await
359                });
360                true
361            },
362        );
363
364        let ten_millis = time::Duration::from_millis(10);
365        loop {
366            thread::sleep(ten_millis);
367            if stop.load(Ordering::Relaxed) {
368                break;
369            }
370        }
371
372        Ok(())
373    }
374
375    /**
376     * Asynchronously lookup a name
377     * @param account
378     * @param name_service
379     * @param name
380     * @return if dbus is ok
381     */
382    pub fn lookup_name(account: &String, name_service: &String, name: &String) -> bool {
383        let conn = Connection::new_session().unwrap();
384        let proxy = conn.with_proxy(
385            "cx.ring.Ring",
386            "/cx/ring/Ring/ConfigurationManager",
387            Duration::from_millis(5000),
388        );
389        let result: Result<(bool,), _> = proxy.method_call(
390            "cx.ring.Ring.ConfigurationManager",
391            "lookupName",
392            (account, name_service, name),
393        );
394        if result.is_ok() {
395            let result = result.unwrap().0;
396            return result;
397        }
398        false
399    }
400
401    /**
402     * Asynchronously lookup an address
403     * @param account
404     * @param name_service
405     * @param address
406     * @return if dbus is ok
407     */
408    pub fn lookup_address(account: &String, name_service: &String, address: &String) -> bool {
409        let conn = Connection::new_session().unwrap();
410        let proxy = conn.with_proxy(
411            "cx.ring.Ring",
412            "/cx/ring/Ring/ConfigurationManager",
413            Duration::from_millis(5000),
414        );
415        let result: Result<(bool,), _> = proxy.method_call(
416            "cx.ring.Ring.ConfigurationManager",
417            "lookupAddress",
418            (account, name_service, address),
419        );
420        if result.is_ok() {
421            let result = result.unwrap().0;
422            return result;
423        }
424        false
425    }
426
427    // Helpers
428
429    pub fn is_hash(string: &String) -> bool {
430        if string.len() != 40 {
431            return false;
432        }
433        for i in 0..string.len() {
434            if "0123456789abcdef".find(string.as_bytes()[i] as char) == None {
435                return false;
436            }
437        }
438        true
439    }
440
441    /**
442     * Add a new account
443     * @param main_info path or alias
444     * @param password
445     * @param from_archive if main_info is a path
446     */
447    pub fn add_account(main_info: &str, password: &str, import_type: ImportType) -> String {
448        let mut details: HashMap<&str, &str> = HashMap::new();
449        if import_type == ImportType::BACKUP {
450            details.insert("Account.archivePath", main_info);
451        } else if import_type == ImportType::NETWORK {
452            details.insert("Account.archivePin", main_info);
453        } else {
454            details.insert("Account.alias", main_info);
455        }
456        details.insert("Account.type", "RING");
457        details.insert("Account.archivePassword", password);
458        let conn = Connection::new_session().unwrap();
459        let proxy = conn.with_proxy(
460            "cx.ring.Ring",
461            "/cx/ring/Ring/ConfigurationManager",
462            Duration::from_millis(5000),
463        );
464        let result: Result<(String,), _> = proxy.method_call(
465            "cx.ring.Ring.ConfigurationManager",
466            "addAccount",
467            (details,),
468        );
469        if result.is_ok() {
470            let result = result.unwrap().0;
471            info!("New account: {:?}", result);
472            return result;
473        }
474
475        String::new()
476    }
477
478    /**
479     * Get current ring accounts
480     * @return current accounts
481     */
482    pub fn get_account_list() -> Vec<Account> {
483        let mut account_list: Vec<Account> = Vec::new();
484        let conn = Connection::new_session().unwrap();
485        let proxy = conn.with_proxy(
486            "cx.ring.Ring",
487            "/cx/ring/Ring/ConfigurationManager",
488            Duration::from_millis(5000),
489        );
490        let result: Result<(Vec<String>,), _> =
491            proxy.method_call("cx.ring.Ring.ConfigurationManager", "getAccountList", ());
492        if result.is_err() {
493            return account_list;
494        }
495        let accounts = result.unwrap().0;
496        for account in accounts {
497            account_list.push(Jami::get_account(&*account));
498        }
499        account_list
500    }
501
502    /**
503     * Build a new account with an id from the daemon
504     * @param id the account id to build
505     * @return the account retrieven
506     */
507    pub fn get_account(id: &str) -> Account {
508        let conn = Connection::new_session().unwrap();
509        let proxy = conn.with_proxy(
510            "cx.ring.Ring",
511            "/cx/ring/Ring/ConfigurationManager",
512            Duration::from_millis(5000),
513        );
514        let result: Result<(HashMap<String, String>,), _> = proxy.method_call(
515            "cx.ring.Ring.ConfigurationManager",
516            "getAccountDetails",
517            (id,),
518        );
519        if result.is_err() {
520            return Account::null();
521        }
522        let details = result.unwrap().0;
523
524        let mut account = Account::null();
525        account.id = id.to_owned();
526        for detail in details {
527            match detail {
528                (key, value) => {
529                    if key == "Account.enable" {
530                        account.enabled = value == "true";
531                    }
532                    if key == "Account.alias" {
533                        account.alias = value.clone();
534                    }
535                    if key == "Account.username" {
536                        account.hash = value.clone().replace("ring:", "");
537                    }
538                    if key == "Account.registeredName" {
539                        account.registered_name = value.clone();
540                    }
541                }
542            }
543        }
544        account
545    }
546
547    /**
548     * Remove an account
549     * @param id the account id to remove
550     */
551    pub fn rm_account(id: &str) {
552        let conn = Connection::new_session().unwrap();
553        let proxy = conn.with_proxy(
554            "cx.ring.Ring",
555            "/cx/ring/Ring/ConfigurationManager",
556            Duration::from_millis(5000),
557        );
558        let _: Result<(), _> =
559            proxy.method_call("cx.ring.Ring.ConfigurationManager", "removeAccount", (id,));
560    }
561
562    /**
563     * Get account details
564     * @param id the account id to build
565     * @return the account details
566     */
567    pub fn get_account_details(id: &str) -> HashMap<String, String> {
568        let conn = Connection::new_session().unwrap();
569        let proxy = conn.with_proxy(
570            "cx.ring.Ring",
571            "/cx/ring/Ring/ConfigurationManager",
572            Duration::from_millis(5000),
573        );
574        let result: Result<(HashMap<String, String>,), _> = proxy.method_call(
575            "cx.ring.Ring.ConfigurationManager",
576            "getAccountDetails",
577            (id,),
578        );
579        if result.is_ok() {
580            let result = result.unwrap().0;
581            return result;
582        }
583
584        HashMap::new()
585    }
586
587    /**
588     * Get account details
589     * @param id the account id to build
590     */
591    pub fn set_account_details(id: &str, details: HashMap<String, String>) {
592        let conn = Connection::new_session().unwrap();
593        let proxy = conn.with_proxy(
594            "cx.ring.Ring",
595            "/cx/ring/Ring/ConfigurationManager",
596            Duration::from_millis(5000),
597        );
598        let _: Result<(), _> = proxy.method_call(
599            "cx.ring.Ring.ConfigurationManager",
600            "setAccountDetails",
601            (id, details),
602        );
603    }
604
605    /**
606     * Subscribe to a member presence
607     * @param id the account id to build
608     * @param uri to subscribe
609     * @param flag true to subscribe else stop
610     */
611    pub fn subscribe_presence(id: &str, uri: &str, flag: bool) {
612        let conn = Connection::new_session().unwrap();
613        let proxy = conn.with_proxy(
614            "cx.ring.Ring",
615            "/cx/ring/Ring/PresenceManager",
616            Duration::from_millis(5000),
617        );
618        let _: Result<(), _> = proxy.method_call(
619            "cx.ring.Ring.PresenceManager",
620            "subscribeBuddy",
621            (id, uri, flag),
622        );
623    }
624
625    /**
626     * Add a new contact
627     * @param id        Account id
628     * @param uri       Uri of the contact
629     */
630    pub fn add_contact(id: &String, uri: &String) {
631        let conn = Connection::new_session().unwrap();
632        let proxy = conn.with_proxy(
633            "cx.ring.Ring",
634            "/cx/ring/Ring/ConfigurationManager",
635            Duration::from_millis(5000),
636        );
637        let _: Result<(), _> =
638            proxy.method_call("cx.ring.Ring.ConfigurationManager", "addContact", (id, uri));
639    }
640
641    /**
642     * Get trusts requests from an account
643     * @param id        Account id
644     * @return the list of trusts requests senders
645     */
646    pub fn get_trust_requests(id: &String) -> Vec<String> {
647        let mut res = Vec::new();
648        let conn = Connection::new_session().unwrap();
649        let proxy = conn.with_proxy(
650            "cx.ring.Ring",
651            "/cx/ring/Ring/ConfigurationManager",
652            Duration::from_millis(5000),
653        );
654        let result: Result<(Vec<HashMap<String, String>>,), _> = proxy.method_call(
655            "cx.ring.Ring.ConfigurationManager",
656            "getTrustRequests",
657            (id,),
658        );
659        if result.is_ok() {
660            let result = result.unwrap().0;
661            for tr in result {
662                if tr.contains_key("from") {
663                    res.push(tr.get("from").unwrap().clone());
664                }
665            }
666        }
667        return res;
668    }
669
670    /**
671     * Send a trust request to someone
672     * @param id        Account id
673     * @param to        Contact uri
674     * @param payloads  VCard
675     */
676    pub fn send_trust_request(id: &String, to: &String, payloads: Vec<u8>) {
677        let conn = Connection::new_session().unwrap();
678        let proxy = conn.with_proxy(
679            "cx.ring.Ring",
680            "/cx/ring/Ring/ConfigurationManager",
681            Duration::from_millis(5000),
682        );
683        let _: Result<(), _> = proxy.method_call(
684            "cx.ring.Ring.ConfigurationManager",
685            "sendTrustRequest",
686            (id, to, payloads),
687        );
688    }
689
690    /**
691     * Accept a trust request
692     * @param id        Account id
693     * @param from      Contact uri
694     * @return if successful
695     */
696    pub fn accept_trust_request(id: &String, from: &String) -> bool {
697        let conn = Connection::new_session().unwrap();
698        let proxy = conn.with_proxy(
699            "cx.ring.Ring",
700            "/cx/ring/Ring/ConfigurationManager",
701            Duration::from_millis(5000),
702        );
703        let result: Result<(bool,), _> = proxy.method_call(
704            "cx.ring.Ring.ConfigurationManager",
705            "acceptTrustRequest",
706            (id, from),
707        );
708        if result.is_ok() {
709            let result = result.unwrap().0;
710            return result;
711        }
712        false
713    }
714
715    /**
716     * Discard a trust request
717     * @param id        Account id
718     * @param from      Contact uri
719     * @return if successful
720     */
721    pub fn discard_trust_request(id: &String, from: &String) -> bool {
722        let conn = Connection::new_session().unwrap();
723        let proxy = conn.with_proxy(
724            "cx.ring.Ring",
725            "/cx/ring/Ring/ConfigurationManager",
726            Duration::from_millis(5000),
727        );
728        let result: Result<(bool,), _> = proxy.method_call(
729            "cx.ring.Ring.ConfigurationManager",
730            "discardTrustRequest",
731            (id, from),
732        );
733        if result.is_ok() {
734            let result = result.unwrap().0;
735            return result;
736        }
737        false
738    }
739
740    /**
741     * Get current members for a conversation
742     * @param id        Id of the account
743     * @param convid    Id of the conversation
744     * @return current members
745     */
746    pub fn get_members(id: &String, convid: &String) -> Vec<HashMap<String, String>> {
747        let conn = Connection::new_session().unwrap();
748        let proxy = conn.with_proxy(
749            "cx.ring.Ring",
750            "/cx/ring/Ring/ConfigurationManager",
751            Duration::from_millis(5000),
752        );
753        let result: Result<(Vec<HashMap<String, String>>,), _> = proxy.method_call(
754            "cx.ring.Ring.ConfigurationManager",
755            "getConversationMembers",
756            (id, convid),
757        );
758        if result.is_ok() {
759            let result = result.unwrap().0;
760            return result;
761        }
762
763        Vec::new()
764    }
765
766    /**
767     * Get conversation's infos
768     * @param id        Id of the account
769     * @param convid    Id of the conversation
770     * @return current infos
771     */
772    pub fn get_conversation_infos(id: &String, convid: &String) -> HashMap<String, String> {
773        let conn = Connection::new_session().unwrap();
774        let proxy = conn.with_proxy(
775            "cx.ring.Ring",
776            "/cx/ring/Ring/ConfigurationManager",
777            Duration::from_millis(5000),
778        );
779        let result: Result<(HashMap<String, String>,), _> = proxy.method_call(
780            "cx.ring.Ring.ConfigurationManager",
781            "conversationInfos",
782            (id, convid),
783        );
784        if result.is_ok() {
785            let result = result.unwrap().0;
786            return result;
787        }
788
789        HashMap::new()
790    }
791
792    /**
793     * Update conversation's i nfos
794     * @param id        Id of the account
795     * @param convid    Id of the conversation
796     * @param infos     New infos
797     */
798    pub fn update_conversation_infos(id: &String, convid: &String, infos: HashMap<String, String>) {
799        let conn = Connection::new_session().unwrap();
800        let proxy = conn.with_proxy(
801            "cx.ring.Ring",
802            "/cx/ring/Ring/ConfigurationManager",
803            Duration::from_millis(5000),
804        );
805        let _: Result<(), _> = proxy.method_call(
806            "cx.ring.Ring.ConfigurationManager",
807            "updateConversationInfos",
808            (id, convid, infos),
809        );
810    }
811
812    /**
813     * Start conversation
814     * @param id        Id of the account
815     */
816    pub fn start_conversation(id: &String) -> String {
817        let conn = Connection::new_session().unwrap();
818        let proxy = conn.with_proxy(
819            "cx.ring.Ring",
820            "/cx/ring/Ring/ConfigurationManager",
821            Duration::from_millis(5000),
822        );
823        let result: Result<(String,), _> = proxy.method_call(
824            "cx.ring.Ring.ConfigurationManager",
825            "startConversation",
826            (id,),
827        );
828        if result.is_ok() {
829            let result = result.unwrap().0;
830            return result;
831        }
832
833        String::new()
834    }
835
836    /**
837     * Get current conversations for account
838     * @param id        Id of the account
839     * @return current conversations
840     */
841    pub fn get_conversations(id: &String) -> Vec<String> {
842        let conn = Connection::new_session().unwrap();
843        let proxy = conn.with_proxy(
844            "cx.ring.Ring",
845            "/cx/ring/Ring/ConfigurationManager",
846            Duration::from_millis(5000),
847        );
848        let result: Result<(Vec<String>,), _> = proxy.method_call(
849            "cx.ring.Ring.ConfigurationManager",
850            "getConversations",
851            (id,),
852        );
853        if result.is_ok() {
854            let result = result.unwrap().0;
855            return result;
856        }
857
858        Vec::new()
859    }
860
861    /**
862     * Get current conversations requests for account
863     * @param id        Id of the account
864     * @return current conversations requests
865     */
866    pub fn get_conversations_requests(id: &String) -> Vec<HashMap<String, String>> {
867        let conn = Connection::new_session().unwrap();
868        let proxy = conn.with_proxy(
869            "cx.ring.Ring",
870            "/cx/ring/Ring/ConfigurationManager",
871            Duration::from_millis(5000),
872        );
873        let result: Result<(Vec<HashMap<String, String>>,), _> = proxy.method_call(
874            "cx.ring.Ring.ConfigurationManager",
875            "getConversationRequests",
876            (id,),
877        );
878        if result.is_ok() {
879            let result = result.unwrap().0;
880            return result;
881        }
882
883        Vec::new()
884    }
885
886    /**
887     * Decline a conversation request
888     * @param id        Id of the account
889     * @param conv_id   Id of the conversation
890     */
891    pub fn decline_request(id: &String, conv_id: &String) {
892        let conn = Connection::new_session().unwrap();
893        let proxy = conn.with_proxy(
894            "cx.ring.Ring",
895            "/cx/ring/Ring/ConfigurationManager",
896            Duration::from_millis(5000),
897        );
898        let _: Result<(), _> = proxy.method_call(
899            "cx.ring.Ring.ConfigurationManager",
900            "declineConversationRequest",
901            (id, conv_id),
902        );
903    }
904
905    /**
906     * Accept a conversation request
907     * @param id        Id of the account
908     * @param conv_id   Id of the conversation
909     */
910    pub fn accept_request(id: &String, conv_id: &String) {
911        let conn = Connection::new_session().unwrap();
912        let proxy = conn.with_proxy(
913            "cx.ring.Ring",
914            "/cx/ring/Ring/ConfigurationManager",
915            Duration::from_millis(5000),
916        );
917        let _: Result<(), _> = proxy.method_call(
918            "cx.ring.Ring.ConfigurationManager",
919            "acceptConversationRequest",
920            (id, conv_id),
921        );
922    }
923
924    /**
925     * Asynchronously load a conversation
926     * @param account
927     * @param conversation
928     * @param from              "" if latest else the commit id
929     * @param size              0 if all else max number of messages to get
930     * @return the id of the request
931     */
932    pub fn load_conversation(
933        account: &String,
934        conversation: &String,
935        from: &String,
936        size: u32,
937    ) -> u32 {
938        let conn = Connection::new_session().unwrap();
939        let proxy = conn.with_proxy(
940            "cx.ring.Ring",
941            "/cx/ring/Ring/ConfigurationManager",
942            Duration::from_millis(5000),
943        );
944        let result: Result<(u32,), _> = proxy.method_call(
945            "cx.ring.Ring.ConfigurationManager",
946            "loadConversationMessages",
947            (account, conversation, from, size),
948        );
949        if result.is_ok() {
950            let result = result.unwrap().0;
951            return result;
952        }
953        0
954    }
955
956    /**
957     * Remove a conversation for an account
958     * @param id        Id of the account
959     * @param conv_id   Id of the conversation
960     * @return if the conversation is removed
961     */
962    pub fn rm_conversation(id: &String, conv_id: &String) -> bool {
963        let conn = Connection::new_session().unwrap();
964        let proxy = conn.with_proxy(
965            "cx.ring.Ring",
966            "/cx/ring/Ring/ConfigurationManager",
967            Duration::from_millis(5000),
968        );
969        let result: Result<(bool,), _> = proxy.method_call(
970            "cx.ring.Ring.ConfigurationManager",
971            "removeConversation",
972            (id, conv_id),
973        );
974        if result.is_ok() {
975            let result = result.unwrap().0;
976            return result;
977        }
978        false
979    }
980
981    /**
982     * Invite a member to a conversation
983     * @param id        Id of the account
984     * @param conv_id   Id of the conversation
985     * @param hash      Id of the member to invite
986     */
987    pub fn add_conversation_member(id: &String, conv_id: &String, hash: &String) {
988        let conn = Connection::new_session().unwrap();
989        let proxy = conn.with_proxy(
990            "cx.ring.Ring",
991            "/cx/ring/Ring/ConfigurationManager",
992            Duration::from_millis(5000),
993        );
994        let _: Result<(), _> = proxy.method_call(
995            "cx.ring.Ring.ConfigurationManager",
996            "addConversationMember",
997            (id, conv_id, hash),
998        );
999    }
1000
1001    /**
1002     * Remove a member from a conversation
1003     * @param id        Id of the account
1004     * @param conv_id   Id of the conversation
1005     * @param hash      Id of the member to invite
1006     */
1007    pub fn rm_conversation_member(id: &String, conv_id: &String, hash: &String) {
1008        let conn = Connection::new_session().unwrap();
1009        let proxy = conn.with_proxy(
1010            "cx.ring.Ring",
1011            "/cx/ring/Ring/ConfigurationManager",
1012            Duration::from_millis(5000),
1013        );
1014        let _: Result<(), _> = proxy.method_call(
1015            "cx.ring.Ring.ConfigurationManager",
1016            "rmConversationMember",
1017            (id, conv_id, hash),
1018        );
1019    }
1020
1021    /**
1022     * Remove a conversation for an account
1023     * @param id        Id of the account
1024     * @param conv_id   Id of the conversation
1025     * @param hash      Id of the member to invite
1026     * @param hash      Id of the member to invite
1027     */
1028    pub fn send_conversation_message(
1029        id: &String,
1030        conv_id: &String,
1031        message: &String,
1032        parent: &String,
1033    ) -> u64 {
1034        let conn = Connection::new_session().unwrap();
1035        let proxy = conn.with_proxy(
1036            "cx.ring.Ring",
1037            "/cx/ring/Ring/ConfigurationManager",
1038            Duration::from_millis(5000),
1039        );
1040        let result: Result<(u64,), _> = proxy.method_call(
1041            "cx.ring.Ring.ConfigurationManager",
1042            "sendMessage",
1043            (id, conv_id, message, parent),
1044        );
1045        if result.is_ok() {
1046            return result.unwrap().0;
1047        }
1048        0
1049    }
1050
1051    /**
1052     * Send a file to a conversation
1053     * @param account_id        Related account
1054     * @param conv_id           Related conversation
1055     * @param path              Path of the file to send
1056     * @return id of the transfer
1057     */
1058    pub fn send_file(account_id: String, conv_id: String, path: String) -> u64 {
1059        let conn = Connection::new_session().unwrap();
1060        let proxy = conn.with_proxy(
1061            "cx.ring.Ring",
1062            "/cx/ring/Ring/ConfigurationManager",
1063            Duration::from_millis(5000),
1064        );
1065        let info = DataTransferInfo {
1066            account_id,
1067            last_event: 0,
1068            flags: 0,
1069            total: 0,
1070            bytes_progress: 0,
1071            author: String::new(),
1072            peer: String::new(),
1073            conv_id,
1074            display_name: String::new(),
1075            path,
1076            mimetype: String::new()
1077        };
1078        let id = 0 as u64;
1079        let _: Result<(), _> = proxy.method_call(
1080            "cx.ring.Ring.ConfigurationManager",
1081            "sendFile",
1082            (info.tuple(), id),
1083        );
1084        id
1085    }
1086
1087    /**
1088     * Accepts a file transfer
1089     * @param account_id        Related account
1090     * @param conv_id           Related conversation
1091     * @param tid               File transfer to accepts
1092     * @param path              Path of the file to send
1093     * @return if an error occurs
1094     */
1095    pub fn accept_file_transfer(
1096        id: &String,
1097        conv_id: &String,
1098        tid: u64,
1099        path: &String,
1100    ) -> u32 {
1101        let conn = Connection::new_session().unwrap();
1102        let proxy = conn.with_proxy(
1103            "cx.ring.Ring",
1104            "/cx/ring/Ring/ConfigurationManager",
1105            Duration::from_millis(5000),
1106        );
1107        let result: Result<(u32,), _> = proxy.method_call(
1108            "cx.ring.Ring.ConfigurationManager",
1109            "acceptFileTransfer",
1110            (id, conv_id, tid, path, 0 as i64),
1111        );
1112        if result.is_ok() {
1113            return result.unwrap().0;
1114        }
1115        0
1116    }
1117
1118    /**
1119     * Cancel a file transfer
1120     * @param account_id        Related account
1121     * @param conv_id           Related conversation
1122     * @param tid               File transfer to accepts
1123     * @return if an error occurs
1124     */
1125    pub fn cancel_file_transfer(
1126        id: &String,
1127        conv_id: &String,
1128        tid: u64,
1129    ) -> u32 {
1130        let conn = Connection::new_session().unwrap();
1131        let proxy = conn.with_proxy(
1132            "cx.ring.Ring",
1133            "/cx/ring/Ring/ConfigurationManager",
1134            Duration::from_millis(5000),
1135        );
1136        let result: Result<(u32,), _> = proxy.method_call(
1137            "cx.ring.Ring.ConfigurationManager",
1138            "cancelDataTransfer",
1139            (id, conv_id, tid),
1140        );
1141        if result.is_ok() {
1142            return result.unwrap().0;
1143        }
1144        0
1145    }
1146
1147    /**
1148     * Get DataTransferInfo
1149     * @param account_id        Related account
1150     * @param conv_id           Related conversation
1151     * @param tid               File transfer to accepts
1152     * @return if an error occurs or the info
1153     */
1154    pub fn data_transfer_info(
1155        account_id: String,
1156        conv_id: String,
1157        tid: u64,
1158    ) -> Option<DataTransferInfo> {
1159        let conn = Connection::new_session().unwrap();
1160        let proxy = conn.with_proxy(
1161            "cx.ring.Ring",
1162            "/cx/ring/Ring/ConfigurationManager",
1163            Duration::from_millis(5000),
1164        );
1165
1166        let info = DataTransferInfo {
1167            account_id: String::new(),
1168            last_event: 0,
1169            flags: 0,
1170            total: 0,
1171            bytes_progress: 0,
1172            author: String::new(),
1173            peer: String::new(),
1174            conv_id: String::new(),
1175            display_name: String::new(),
1176            path: String::new(),
1177            mimetype: String::new()
1178        };
1179        let result: Result<(u32, (String, u32, u32, i64, i64, String, String, String, String, String, String),), _> = proxy.method_call(
1180            "cx.ring.Ring.ConfigurationManager",
1181            "dataTransferInfo",
1182            (account_id, conv_id, tid, info.tuple()),
1183        );
1184        if result.is_ok() {
1185            return Some(DataTransferInfo::from_tuple(result.unwrap().1));
1186        }
1187        None
1188    }
1189
1190
1191}