chatwith/
chatwith.rs

1use tokio;
2use std::convert::TryFrom;
3
4use threema_client::directory_api;
5use threema_client::messaging_client;
6use threema_client::transport::{ThreemaServer, SERVER, Envelope};
7use threema_client::naclbox;
8use threema_client::{ThreemaID, Credentials, Peer};
9
10use tokio::io::AsyncBufReadExt;
11
12use std::sync::Arc;
13
14async fn handle_message(envelope: &Envelope, content: &[u8]) -> bool{
15    let msg_type = content[0];
16    let msg = &content[1..];
17    use threema_client::msg_types::*;
18    match (msg_type, msg.len()) {
19        (TEXT, _) => {
20            println!("{:?} ({}) => {:?}: {}", envelope.sender, envelope.nickname, &envelope.recipient, String::from_utf8_lossy(msg));
21            true
22        }
23        (TYPING_INDICATOR, 1) => {
24            let x = if msg[0] == 1 {"is"} else {"has stopped"};
25            println!("{} ({:?}) {} typing", envelope.nickname, envelope.sender, x);
26            false
27        }
28        (CONTACT_SET_PHOTO, 52) => {
29            let blobref = threema_client::blob_api::BlobRef::from_slice(msg);
30            println!("CONTACT_SET_PHOTO, blob {:?}, {}", blobref, blobref.hex());
31            //let res = blob_api::Client::new().download(&blobref).await;
32            //println!(":) {:?}", res);
33            false
34        }
35        (unknown_type, unknown_length) => {
36            eprintln!("Message with unknown type {} or length {}: {:?}", unknown_type, unknown_length, msg);
37            false
38        }
39    }
40}
41async fn recv_print(c: Arc<messaging_client::Client>, peer: Peer, creds: Credentials){
42    while let Some(e) =  c.event().await {
43        match e {
44            threema_client::messaging_client::Event::BoxedMessage(m) => {
45                if m.envelope.sender != peer.id {
46                    println!("new message from {} ({})", m.envelope.nickname, m.envelope.sender);
47                }
48                else {
49                    match m.open(&peer.pk, &creds.sk) {
50                        Ok(plain) => {
51                            let ackit = handle_message(&m.envelope, &plain).await;
52                            if ackit {
53                                let _ = c.send_ack(&m.envelope.sender_ack()).await;
54                            }
55                        }
56                        Err(e) => {
57                            log::warn!("invalid message: {}", e);
58                        }
59                    }
60                }
61            }
62            unhandled => {
63                println!("Unhandled Event: {:?}", unhandled);
64            }
65        }
66    }
67}
68
69#[tokio::main]
70async fn main(){
71    env_logger::init();
72    let argv: Vec<_> = std::env::args().collect();
73    if argv.len() != 3 {
74        eprintln!("usage: {} CREDENTIALS-FILE CONTACT", argv[0]);
75        std::process::exit(1);
76    }
77    let creds = threema_client::import::json_file::from_file(&argv[1]).expect("could not read credentials json");
78    let contact = ThreemaID::try_from(argv[2].as_str()).expect("invalid ID");
79    let contact_pubkey = directory_api::Client::default().get_pubkey(&contact).await.expect("could not get public key");
80    let peer = threema_client::Peer{id: contact, pk: contact_pubkey};
81
82    let server = ThreemaServer {addr: SERVER.to_string(), pk: naclbox::PublicKey::from_slice(b"E\x0b\x97W5'\x9f\xde\xcb3\x13d\x8f_\xc6\xee\x9f\xf46\x0e\xa9*\x8c\x17Q\xc6a\xe4\xc0\xd8\xc9\t").unwrap()};
83    let messenger = Arc::new(messaging_client::Client::new(server, creds.clone()));
84
85    let recver = tokio::spawn(recv_print(Arc::clone(&messenger), peer.clone(), creds.clone()));
86    let mut stdin = tokio::io::BufReader::new(tokio::io::stdin());
87    loop {
88        let mut line = String::new();
89        match stdin.read_line(&mut line).await {
90            Err(e) => {
91                eprintln!("{}", e);
92                break;
93            }
94            Ok(0) => { break; }
95            Ok(_) => {
96                let mut plain = threema_client::msg_types::TEXT.to_le_bytes().to_vec();
97                plain.extend_from_slice(&line.trim_end().as_bytes());
98                let m = threema_client::transport::BoxedMessage::encrypt(&creds, "hi", &peer, plain, 0);
99                let sent = messenger.send_message(m).await;
100                if let Err(c) = sent {
101                    println!("{:?}", c);
102                    break;
103                }
104            }
105        }
106    }
107    messenger.shutdown();
108    eprintln!("waiting for receiver to quit...");
109    recver.await.unwrap();
110}