connect/
connect.rs

1use env_logger;
2use tokio;
3use anyhow::Context;
4
5use threema_client::*;
6
7#[derive(Default)]
8pub struct AddressBook{
9    key_cache: std::collections::HashMap<ThreemaID, naclbox::PublicKey>,
10    api: directory_api::Client,
11}
12
13impl AddressBook {
14    pub async fn lookup(&mut self, identity: &ThreemaID) -> anyhow::Result<naclbox::PublicKey>{
15        let e = self.key_cache.get(identity);
16        match e {
17            Some(pk) => Ok(*pk),
18            None => {
19                let pk = self.api.get_pubkey(identity).await?;
20                self.key_cache.insert(*identity, pk);
21                Ok(pk)
22            }
23        }
24    }
25}
26
27pub struct Agent {
28    creds: Credentials,
29    r: transport::ReadHalf,
30    w: transport::WriteHalf,
31    contacts: AddressBook,
32}
33
34impl Agent {
35    pub async fn new(creds: Credentials) -> anyhow::Result<Self>{
36        use transport::{SERVER, ThreemaServer};
37        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()};
38        let (r, w) = transport::connect(&server, &creds).await?;
39        println!("logged in!");
40        let contacts = AddressBook::default();
41
42        Ok(Agent{creds, r, w, contacts})
43    }
44    pub async fn listen(&mut self) -> anyhow::Result<()>{
45        loop {
46            let p = self.r.receive_packet().await?;
47            self.handle_packet(&p).await?;
48        }
49    }
50
51    async fn handle_message(&mut self, envelope: &transport::Envelope, content: Vec<u8>) {
52        let msg_type = content[0];
53        let msg = &content[1..];
54        use msg_types::*;
55        match (msg_type, msg.len()) {
56            (TEXT, _) => {
57                println!("{:?} ({}) => {:?}: {}", envelope.sender, envelope.nickname, &envelope.recipient, String::from_utf8_lossy(msg));
58                let _res = self.w.send_download_ack(envelope).await;
59            }
60            (TYPING_INDICATOR, 1) => {
61                let x = if msg[0] == 1 {"is"} else {"has stopped"};
62                println!("{} ({:?}) {} typing", envelope.nickname, envelope.sender, x);
63            }
64            (CONTACT_SET_PHOTO, 52) => {
65                let blobref = blob_api::BlobRef::from_slice(msg);
66                println!("CONTACT_SET_PHOTO, blob {:?}, {}", blobref, blobref.hex());
67                //let res = blob_api::Client::new().download(&blobref).await;
68                //println!(":) {:?}", res);
69                
70            }
71            (unknown_type, unknown_length) => {
72                eprintln!("Message with unknown type {} or length {}: {:?}", unknown_type, unknown_length, msg)
73            }
74        }
75    }
76    async fn handle_packet(&mut self, packet: &transport::Packet) -> Result<(), ParseError>{
77        match packet {
78            transport::Packet::BoxedMessageDownload(m) => {
79                println!("New Message!");
80                println!("{:?}", &m.envelope);
81                match self.contacts.lookup(&m.envelope.sender).await {
82                    Ok(their_pk) => {
83                        match m.open(&their_pk, &self.creds.sk) {
84                            Ok(msg) => self.handle_message(&m.envelope, msg).await,
85                            Err(e) => eprintln!("Decryption or verification failed: {}", e),
86                        }
87                    }
88                    Err(e) => {
89                        eprintln!("No PublicKey found for sender {:?}: {}", m.envelope.sender, e);
90                    }
91                }
92                println!("");
93            }
94            transport::Packet::QueueSendComplete => {
95                println!("QUEUE_SEND_COMPLETE\n");
96            }
97
98            unknown => {
99                println!("Unknown Payload Type: {:?}", unknown);
100            }
101        }
102
103        Ok(())
104    }
105    
106}
107
108#[tokio::main]
109async fn main() -> anyhow::Result<()>{
110    sodiumoxide::init().expect("failed sodium initialisation");
111    env_logger::init();
112
113    let args = std::env::args().collect::<Vec<_>>();
114    let f = args.get(1).context("missing arg")?;
115    let u = import::json_file::from_file(f)?;
116
117    let mut agent = Agent::new(u).await?;
118    agent.listen().await?;
119
120    Ok(())
121}