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 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}