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