~nicohman/signal-rs

32c5e84b12c02450980fcad26344cb6f9fd8deee — nicohman 3 months ago 9efdf4d
Add basic profile support
6 files changed, 321 insertions(+), 337 deletions(-)

M Cargo.lock
M Cargo.toml
M src/main.rs
M src/presage_manager.rs
M src/signal.rs
M src/util.rs
M Cargo.lock => Cargo.lock +6 -110
@@ 1358,62 1358,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"

[[package]]
name = "glib"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5"
dependencies = [
 "bitflags 1.2.1",
 "futures-channel",
 "futures-core",
 "futures-executor",
 "futures-task",
 "futures-util",
 "glib-macros",
 "glib-sys",
 "gobject-sys",
 "libc",
 "once_cell 1.5.2",
]

[[package]]
name = "glib-macros"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039"
dependencies = [
 "anyhow",
 "heck",
 "itertools",
 "proc-macro-crate",
 "proc-macro-error",
 "proc-macro2",
 "quote 1.0.8",
 "syn 1.0.58",
]

[[package]]
name = "glib-sys"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1"
dependencies = [
 "libc",
 "system-deps",
]

[[package]]
name = "gobject-sys"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c"
dependencies = [
 "glib-sys",
 "libc",
 "system-deps",
]

[[package]]
name = "h2"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1894,7 1838,7 @@ dependencies = [
[[package]]
name = "libsignal-service"
version = "0.1.0"
source = "git+https://github.com/gferon/libsignal-service-rs.git?branch=presage#6f53b81b63feef19b226068593e1315fbb735c75"
source = "git+https://github.com/Michael-F-Bryan/libsignal-service-rs#8ddb9c860afafa3ef4475ce1330420678bb41f43"
dependencies = [
 "aes 0.6.0",
 "aes-ctr",


@@ 1927,7 1871,7 @@ dependencies = [
[[package]]
name = "libsignal-service-hyper"
version = "0.1.0"
source = "git+https://github.com/gferon/libsignal-service-rs.git?branch=presage#6f53b81b63feef19b226068593e1315fbb735c75"
source = "git+https://github.com/Michael-F-Bryan/libsignal-service-rs#8ddb9c860afafa3ef4475ce1330420678bb41f43"
dependencies = [
 "async-trait",
 "async-tungstenite",


@@ 2724,7 2668,7 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "presage"
version = "0.1.0"
source = "git+https://github.com/nicohman/presage#0f85fd4453d0413c8595bf973b330aac0cb77799"
source = "git+https://github.com/whisperfish/presage#1ede250d04ccc700ee89e3c0632bf96c62452e03"
dependencies = [
 "anyhow",
 "base64 0.12.3",


@@ 2750,15 2694,6 @@ dependencies = [
]

[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
 "toml",
]

[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 3477,7 3412,6 @@ dependencies = [
 "futures",
 "futures-util",
 "gettext-rs",
 "glib",
 "home",
 "lazy_static",
 "libsignal-service",


@@ 3485,6 3419,7 @@ dependencies = [
 "notify-rust",
 "once_cell 0.2.4",
 "pallet",
 "phonenumber",
 "presage",
 "qmetaobject",
 "regex",


@@ 3618,12 3553,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca6e4730f517e041e547ffe23d29daab8de6b73af4b6ae2a002108169f5e7da"

[[package]]
name = "strum"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"

[[package]]
name = "strum_macros"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 3634,18 3563,6 @@ dependencies = [
]

[[package]]
name = "strum_macros"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
dependencies = [
 "heck",
 "proc-macro2",
 "quote 1.0.8",
 "syn 1.0.58",
]

[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 3701,21 3618,6 @@ dependencies = [
]

[[package]]
name = "system-deps"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b"
dependencies = [
 "heck",
 "pkg-config",
 "strum 0.18.0",
 "strum_macros 0.18.0",
 "thiserror",
 "toml",
 "version-compare",
]

[[package]]
name = "tantivy"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 4271,12 4173,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"

[[package]]
name = "version-compare"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1"

[[package]]
name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 4495,8 4391,8 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57790eb281688a4682dab44df2a1ba8b78373233bd71cb291c3e75fecb1a01c4"
dependencies = [
 "strum 0.8.0",
 "strum_macros 0.8.0",
 "strum",
 "strum_macros",
 "winapi 0.3.9",
 "winrt",
 "xml-rs",

M Cargo.toml => Cargo.toml +4 -7
@@ 17,13 17,13 @@ serde_json = "1.0.57"
mio = { version = "0.7", features = ["tcp", "os-poll"]}
futures-util = { version = "0.3", default-features = true, features = ["async-await", "sink", "std"] }
tokio = { version = "1",features = ["full"] }
libsignal-service = { git = "https://github.com/gferon/libsignal-service-rs.git", branch = "presage" }
libsignal-service = { git = "https://github.com/Michael-F-Bryan/libsignal-service-rs.git"}
zkgroup = { git = "https://github.com/signalapp/zkgroup" }
phonenumber = "0.3.1"
chrono = "0.4.6"
crossbeam-channel = "0.4.4"
glib = "0.10"
once_cell = "^0"
presage = { git = "https://github.com/nicohman/presage" }
presage = { git = "https://github.com/whisperfish/presage" }
lazy_static = "1.4.0"
regex = "1.4.1"
reqwest = "0.10.8"


@@ 39,7 39,4 @@ base64 = "0.13.0"
cpp_macros = "0.4"
[build-dependencies]
cpp_build = "0.5"
cpp_macros = "0.5"
[patch."https://github.com/Michael-F-Bryan/libsignal-service-rs.git"]
libsignal-service = { git = "https://github.com/gferon/libsignal-service-rs.git", branch = "presage" }
libsignal-service-hyper = { git = "https://github.com/gferon/libsignal-service-rs.git", branch = "presage" }
\ No newline at end of file
cpp_macros = "0.5"
\ No newline at end of file

M src/main.rs => src/main.rs +3 -9
@@ 30,7 30,6 @@ use std::collections::*;
mod config;
mod util;
use config::*;
use futures::StreamExt;
use notify_rust::Notification;
use serde_json::json;
use std::cell::*;


@@ 345,6 344,7 @@ impl SignalUI {
                        slf.update_contacts();
                        slf.show_view("chats".to_string());
                        slf.ready();
                        slf.chats_changed();
                        slf.signalResponse(serde_json::to_string(&res).unwrap());
                    }
                    _ => {}


@@ 352,11 352,10 @@ impl SignalUI {
            });
        });
        let (res_sender, mut res_receiver) = unbounded_channel::<SignalResponse>();
        let l_res_sender = res_sender.clone();
        let (req_sender, req_receiver) = unbounded_channel::<SignalRequest>();

        self.state = Some(
            Presage::new(l_res_sender, config.clone(), req_sender.clone())
            Presage::new(res_sender.clone(), config.clone(), req_sender.clone())
                .expect("Couldn't create Presage"),
        );
        // Spawn a tokio task to receive the SignalResponses and call the Qt callback w/ them


@@ 441,15 440,10 @@ impl SignalUI {
            .into_iter()
            .enumerate()
        {
            println!("{}", gid);
            println!("{:?}", group);
            if let Some(msgs) = self.state.as_ref().unwrap().messages_id(&gid).ok() {
                println!("GROUP2");
                if msgs.len() > 0 {
                    println!("GROUP");
                    let latest = msgs.values().max_by_key(|x| x.sent_at).unwrap();
                    constructed.push(gid.clone());

                    chats.push(Chat {
                        ID: (chats.len() + i) as i32,
                        name: group.name,


@@ 473,7 467,7 @@ impl SignalUI {
            .enumerate()
        {
            if msgs.len() > 0 {
                println!("{}", id);
                println!("not found - {}", id);
                let latest = msgs.values().max_by_key(|x| x.sent_at).unwrap();
                if latest.message.as_str() == "🧝\u{200d}♀\u{fe0f}" {
                    println!("{:?} - {}", latest, id);

M src/presage_manager.rs => src/presage_manager.rs +290 -205
@@ 11,6 11,7 @@ pub struct Presage {
    pub msg_store: Store<SignalMessage>,
    pub contact_store: Store<Contact>,
    pub group_store: Store<Group>,
    pub profile_store: Store<Profile>,
    pub req_sender: UnboundedSender<SignalRequest>,
    pub whoami: Option<Uuid>,
    pub res_sender: UnboundedSender<SignalResponse>,


@@ 22,7 23,6 @@ impl Presage {
        res_sender: UnboundedSender<SignalResponse>,
        mut req_receiver: UnboundedReceiver<SignalRequest>,
    ) {
        let (tx, mut rx) = futures::channel::mpsc::channel::<(Metadata, ContentBody)>(100);
        let mut manager = Manager::with_config_store(config_store, ProtocolContext::default())
            .expect("Couldn't create Manager");
        let whoami = manager


@@ 32,214 32,243 @@ impl Presage {
            .uuid
            .to_string()
            .to_uppercase();
        let cloned_man = manager.clone();
        let x = cloned_man.receive_messages(tx);
        let mut fut = Box::pin(x);
        let self_profile = manager
            .retrieve_profile()
            .await
            .expect("Couldn't fetch own profile");
        let name = self_profile.name.map(|x| x.given_name).unwrap_or(
            manager
                .phone_number()
                .map(|x| x.format().mode(phonenumber::Mode::E164).to_string())
                .unwrap_or_default(),
        );
        res_sender
            .send(SignalResponse::Profile(Profile {
                uuid: whoami.clone(),
                name,
                about_emoji: self_profile.about_emoji.unwrap_or_default(),
                about: self_profile.about.unwrap_or_default(),
            }))
            .expect("Couldn't send own profile");
        let incoming_messages = manager
            .receive_messages_stream()
            .await
            .expect("Couldn't create incoming messages stream");
        let mut pinned_fut = Box::pin(incoming_messages);
        loop {
            tokio::select! {
                    inc = rx.next() => {
                        if let Some(response) = inc {
                            println!("{:?}", response);
                            res_sender.send(SignalResponse::Metadata(response.0.clone())).expect("Couldn't send Metadata");
                inc = pinned_fut.next() => {
                    if let Some(response) = inc {
                        println!("{:?}", response);
                        res_sender.send(SignalResponse::Metadata(response.metadata.clone())).expect("Couldn't send Metadata");
                        match response.body.clone() {
                            ContentBody::DataMessage(dm) => {
                                if let Some(profile_key) = dm.profile_key {
                                    if let Some(uuid) = response.metadata.sender.uuid {
                                        if let Ok(profile) = manager.retrieve_profile_by_uuid(uuid.clone(), make_profile_key(profile_key)).await {
                                            let name = profile.name.map(|x| {
                                                x.given_name
                                            }).unwrap_or_default();
                                            res_sender.send(SignalResponse::Profile(Profile {
                                                name,
                                                about: profile.about.unwrap_or_default(),
                                                about_emoji: profile.about_emoji.unwrap_or_default(),
                                                uuid: response.metadata.sender.identifier().to_uppercase()
                                            })).expect("Couldn't send Profile");
                                        }
                                    }

                            match response.1.clone() {
                ContentBody::DataMessage(dm) => {
                    if let Some(react) = dm.reaction {
                        if react.target_author_uuid.is_some() && react.emoji.is_some() && react.target_sent_timestamp.is_some() {
                            if let Some(remove) = react.remove {
                                if remove {
                                    //Remove reaction
                                    continue;
                                }
                            res_sender.send(SignalResponse::AddReaction{
                                target: react.target_author_uuid.unwrap().clone().to_uppercase(),
                                emoji: react.emoji.unwrap(),
                                target_timestamp: react.target_sent_timestamp.unwrap() as i64,
                                timestamp: response.0.timestamp as i64,
                                from: response.0.sender.identifier().to_uppercase()
                            }).expect("Couldn't send AddReaction");
                            }
                        }
                    }
                    if let Some(body) = dm.body {
                        let mut chat_id = response
                            .0
                            .sender
                            .identifier().to_uppercase();
                        if let Some(gc) = dm.group {
                            chat_id = get_gid(gc.id.unwrap());
                            let g = Group {
                                name: gc.name.unwrap_or_default(),
                                members: gc.members_e164,
                                id: chat_id.clone(),
                                master_key: None
                            };
                            res_sender.send(SignalResponse::SGroup(g)).expect("Couldn't send SGroup");
                        }
                        if let Some(gc2) = dm.group_v2 {
                            let gid = get_gid_v2(gc2.master_key.clone().unwrap());
                            chat_id = gid;
                            res_sender.send(SignalResponse::GroupV2Context(gc2)).expect("Couldn't send GroupV2Context");
                        }
                        let msg = SignalMessage {
                            source: response
                                .0
                                .sender
                                .identifier(),
                            chat_id: chat_id,
                            sent_at: dm.timestamp.unwrap() as i64,
                            ID: 0,
                            message: body,
                            reactions: vec![],
                            attachment: Some(vec![]),
                            outgoing: response.0.sender.identifier().to_uppercase() == whoami,
                        };
                        res_sender.send(SignalResponse::IDLessMessage(msg)).expect("Couldn't send IDLessMessage");
                    } else {
                    }
                }
                ContentBody::SynchronizeMessage(sm) => {
                    if let Some(sent) = sm.sent {
                        if let Some(dm) = sent.message {
                                                if let Some(react) = dm.reaction {
                        if react.target_author_uuid.is_some() && react.emoji.is_some() && react.target_sent_timestamp.is_some() {
                            if let Some(remove) = react.remove {
                                if remove {
                                    //Remove reaction
                                    continue;
                                if let Some(react) = dm.reaction {
                                    if react.target_author_uuid.is_some() && react.emoji.is_some() && react.target_sent_timestamp.is_some() {
                                        if let Some(remove) = react.remove {
                                            if remove {
                                                //Remove reaction
                                                continue;
                                            }
                                        res_sender.send(SignalResponse::AddReaction{
                                            target: react.target_author_uuid.unwrap().clone().to_uppercase(),
                                            emoji: react.emoji.unwrap(),
                                            target_timestamp: react.target_sent_timestamp.unwrap() as i64,
                                            timestamp: response.metadata.timestamp as i64,
                                            from: response.metadata.sender.identifier().to_uppercase()
                                        }).expect("Couldn't send AddReaction");
                                        }
                                    }
                                }
                            res_sender.send(SignalResponse::AddReaction{
                                target: react.target_author_uuid.unwrap().clone().to_uppercase(),
                                emoji: react.emoji.unwrap(),
                                target_timestamp: react.target_sent_timestamp.unwrap() as i64,
                                timestamp: response.0.timestamp as i64,
                                from: response.0.sender.identifier().to_uppercase()
                            }).expect("Couldn't send AddReaction");
                            }


                        }
                    }
                            if let Some(body) = dm.body {
                                let mut chat_id = sent
                                    .destination_uuid.
                                    unwrap_or(sent.destination_e164.unwrap_or_default()).to_uppercase();
                                if let Some(gc) = dm.group {
                                    chat_id = get_gid(gc.id.unwrap());
                                                                let g = Group {
                                name: gc.name.unwrap_or_default(),
                                members: gc.members_e164,
                                id: chat_id.clone(),
                                master_key: None
                            };
                            res_sender.send(SignalResponse::SGroup(g)).expect("Couldn't send SGroup");
                                if let Some(body) = dm.body {
                                    let mut chat_id = response
                                        .metadata
                                        .sender
                                        .identifier().to_uppercase();
                                    if let Some(gc) = dm.group {
                                        chat_id = get_gid(gc.id.unwrap());
                                        let g = Group {
                                            name: gc.name.unwrap_or_default(),
                                            members: gc.members_e164,
                                            id: chat_id.clone(),
                                            master_key: None
                                        };
                                        res_sender.send(SignalResponse::SGroup(g)).expect("Couldn't send SGroup");
                                    }
                                    if let Some(gc2) = dm.group_v2 {
                                        let gid = get_gid_v2(gc2.master_key.clone().unwrap());
                                        chat_id = gid;
                                        res_sender.send(SignalResponse::GroupV2Context(gc2)).expect("Couldn't send GroupV2Context");
                                    }
                                    let msg = SignalMessage {
                                        source: response
                                            .metadata
                                            .sender
                                            .identifier().to_uppercase(),
                                        chat_id: chat_id,
                                        sent_at: dm.timestamp.unwrap() as i64,
                                        ID: 0,
                                        message: body,
                                        reactions: vec![],
                                        attachment: Some(vec![]),
                                        outgoing: response.metadata.sender.identifier().to_uppercase() == whoami,
                                    };
                                    res_sender.send(SignalResponse::IDLessMessage(msg)).expect("Couldn't send IDLessMessage");
                                } else {
                                }
                                if let Some(gc2) = dm.group_v2 {
                                    let gid = get_gid_v2(gc2.master_key.clone().unwrap());
                                    chat_id = gid;
                                    res_sender.send(SignalResponse::GroupV2Context(gc2)).expect("Couldn't send GroupV2Context");
                            }
                            ContentBody::SynchronizeMessage(sm) => {
                                if let Some(sent) = sm.sent {
                                    if let Some(dm) = sent.message {
                                        if let Some(react) = dm.reaction {
                                            if react.target_author_uuid.is_some() && react.emoji.is_some() && react.target_sent_timestamp.is_some() {
                                                if let Some(remove) = react.remove {
                                                    if remove {
                                                        //Remove reaction
                                                        continue;
                                                    }
                                                res_sender.send(SignalResponse::AddReaction{
                                                    target: react.target_author_uuid.unwrap().clone().to_uppercase(),
                                                    emoji: react.emoji.unwrap(),
                                                    target_timestamp: react.target_sent_timestamp.unwrap() as i64,
                                                    timestamp: response.metadata.timestamp as i64,
                                                    from: response.metadata.sender.identifier().to_uppercase()
                                                }).expect("Couldn't send AddReaction");
                                                }
                                            }
                                        }
                                        if let Some(body) = dm.body {
                                            let mut chat_id = sent
                                                .destination_uuid.
                                                unwrap_or(sent.destination_e164.unwrap_or_default()).to_uppercase();
                                            if let Some(gc) = dm.group {
                                                chat_id = get_gid(gc.id.unwrap());
                                                let g = Group {
                                                    name: gc.name.unwrap_or_default(),
                                                    members: gc.members_e164,
                                                    id: chat_id.clone(),
                                                    master_key: None
                                                };
                                                res_sender.send(SignalResponse::SGroup(g)).expect("Couldn't send SGroup");
                                            }
                                            if let Some(gc2) = dm.group_v2 {
                                                let gid = get_gid_v2(gc2.master_key.clone().unwrap());
                                                chat_id = gid;
                                                res_sender.send(SignalResponse::GroupV2Context(gc2)).expect("Couldn't send GroupV2Context");
                                            }
                                            let msg = SignalMessage {
                                                source: response
                                                    .metadata
                                                    .sender.identifier().to_uppercase(),
                                                chat_id: chat_id,
                                                sent_at: dm.timestamp.unwrap() as i64,
                                                ID: 0,
                                                message: body,
                                                reactions: vec![],
                                                attachment: Some(vec![]),
                                                outgoing: response.metadata.sender.identifier().to_uppercase() == whoami,
                                            };
                                            res_sender.send(SignalResponse::IDLessMessage(msg)).expect("Couldn't send IDLessMessage");
                                        }
                                    }
                                }
                                let msg = SignalMessage {
                                    source: response
                                        .0
                                        .sender.identifier().to_uppercase(),
                                    chat_id: chat_id,
                                    sent_at: dm.timestamp.unwrap() as i64,
                                    ID: 0,
                                    message: body,
                                    reactions: vec![],
                                    attachment: Some(vec![]),
                                    outgoing: response.0.sender.identifier().to_uppercase() == whoami,
                                };
                                res_sender.send(SignalResponse::IDLessMessage(msg)).expect("Couldn't send IDLessMessage");
                            }
                        _ => {}
                        }
                    }
                }
                _ => {}
            }

                    }
                    },
                    req = req_receiver.recv() => {
                        println!("{:?}", req);
                        if let Some(req) = req {
                        match req {
                            SignalRequest::SendMessageToGroup { members, message, attachment: _, id, master_key} => {
                                let now = chrono::Utc::now().timestamp_millis() as u64;
                                let msg = DataMessage {
                                    body: Some(message.clone()),
                                    timestamp:Some(now.clone()),
                                    group_v2: Some(GroupContextV2 {
                                        master_key: master_key,
                                        revision: Some(1),
                                        group_change: None
                                    }),
                                    ..Default::default()
                                };
                                manager.send_message_to_group(members.into_iter().map(|x| {
                                    return ServiceAddress::parse(None, Some(&x)).unwrap();
                                }).collect::<Vec<ServiceAddress>>(),  msg, now).await.unwrap();
                                let sm = SignalResponse::IDLessMessage(SignalMessage {
                                    message: message,
                                    source: whoami.clone().to_uppercase(),
                                    chat_id: id,
                                    outgoing: true,
                                    attachment: None,
                                    sent_at: now as i64,
                                    ID: 0,
                                    reactions: vec![]
                                });
                                res_sender.send(sm).expect("Couldn't send IDLessMessage");
                            },
                            SignalRequest::SendMessage { to, message, attachment: _ } => {
                                let tos = ServiceAddress::parse(None, Some(to.as_str())).unwrap_or_else(|_| {ServiceAddress::parse(Some(to.as_str()), None).unwrap()});
                                let now = chrono::Utc::now().timestamp_millis() as u64;
                                let msg = DataMessage {
                                    body: Some(message.clone()),
                                    timestamp:Some(now.clone()),
                                    ..Default::default()
                                };
                                manager.send_message(tos.clone(), msg, now).await.unwrap();
                                let sm = SignalResponse::IDLessMessage(SignalMessage {
                                    message: message,
                                    source: to.clone().to_uppercase(),
                                    chat_id: to.clone().to_uppercase(),
                                    outgoing: true,
                                    attachment: None,
                                    sent_at: now as i64,
                                    ID: 0,
                                    reactions: vec![]
                                });
                                res_sender.send(sm).expect("Couldn't send IDLessMessage");
                            },
                            SignalRequest::EditContact{ name, phone, id } => {
                                res_sender.send(SignalResponse::RmContact(id.clone())).expect("Couldn't send RmContact");
                                res_sender.send(SignalResponse::ContactList(vec![Contact {name, tel: phone, uuid: id}])).expect("Couldn't send ContactList");
                            },
                            SignalRequest::GetGroupCtxV2(ctx) => {
                                let group = manager.get_group_v2(make_gkey(ctx.master_key.clone().unwrap())).await.unwrap();
                                println!("{:?}", group);
                                let gid = get_gid_v2(ctx.master_key.clone().unwrap());
                                res_sender.send(SignalResponse::SGroup(Group {
                                    name: group.title,
                                    id: gid,
                                    master_key: ctx.master_key.clone(),
                                    members: group.members.clone().into_iter().map(|x| {
                                        return Uuid::from_slice(&x.uuid).unwrap().to_string().to_uppercase();
                                    }).collect()
                                })).expect("Couldn't send SGroup");
                            },
                            _ => {
                },
                req = req_receiver.recv() => {
                    println!("{:?}", req);
                    if let Some(req) = req {
                    match req {
                        SignalRequest::SendMessageToGroup { members, message, attachment: _, id, master_key} => {
                            let now = chrono::Utc::now().timestamp_millis() as u64;
                            let msg = DataMessage {
                                body: Some(message.clone()),
                                timestamp:Some(now.clone()),
                                group_v2: Some(GroupContextV2 {
                                    master_key: master_key,
                                    revision: Some(1),
                                    group_change: None
                                }),
                                ..Default::default()
                            };
                            manager.send_message_to_group(members.into_iter().map(|x| {
                                return ServiceAddress::parse(None, Some(&x)).unwrap();
                            }).collect::<Vec<ServiceAddress>>(),  msg, now).await.unwrap();
                            let sm = SignalResponse::IDLessMessage(SignalMessage {
                                message: message,
                                source: whoami.clone().to_uppercase(),
                                chat_id: id,
                                outgoing: true,
                                attachment: None,
                                sent_at: now as i64,
                                ID: 0,
                                reactions: vec![]
                            });
                            res_sender.send(sm).expect("Couldn't send IDLessMessage");
                        },
                        SignalRequest::SendMessage { to, message, attachment: _ } => {
                            let tos = ServiceAddress::parse(None, Some(to.as_str())).unwrap_or_else(|_| {ServiceAddress::parse(Some(to.as_str()), None).unwrap()});
                            let now = chrono::Utc::now().timestamp_millis() as u64;
                            let msg = DataMessage {
                                body: Some(message.clone()),
                                timestamp:Some(now.clone()),
                                ..Default::default()
                            };
                            manager.send_message(tos.clone(), msg, now).await.unwrap();
                            let sm = SignalResponse::IDLessMessage(SignalMessage {
                                message: message,
                                source: to.clone().to_uppercase(),
                                chat_id: to.clone().to_uppercase(),
                                outgoing: true,
                                attachment: None,
                                sent_at: now as i64,
                                ID: 0,
                                reactions: vec![]
                            });
                            res_sender.send(sm).expect("Couldn't send IDLessMessage");
                        },
                        SignalRequest::EditContact{ name, phone, id } => {
                            res_sender.send(SignalResponse::RmContact(id.clone())).expect("Couldn't send RmContact");
                            res_sender.send(SignalResponse::ContactList(vec![Contact {name, tel: phone, uuid: id, state: "real".to_string()}])).expect("Couldn't send ContactList");
                        },
                        SignalRequest::GetGroupCtxV2(ctx) => {
                            let group = manager.get_group_v2(make_gkey(ctx.master_key.clone().unwrap())).await.unwrap();
                            println!("{:?}", group);
                            let gid = get_gid_v2(ctx.master_key.clone().unwrap());
                            res_sender.send(SignalResponse::SGroup(Group {
                                name: group.title,
                                id: gid,
                                master_key: ctx.master_key.clone(),
                                members: group.members.clone().into_iter().map(|x| {
                                    return Uuid::from_slice(&x.uuid).unwrap().to_string().to_uppercase();
                                }).collect()
                            })).expect("Couldn't send SGroup");
                        },
                        _ => {

                            }
                        }
                    }
                    }
                    _ = &mut fut => {

                    }
                }
                }
            }
        }
    }



@@ 259,9 288,12 @@ impl Presage {
        let c_db =
            pallet::ext::sled::open(Path::new(&data_dir).join("contacts").to_str().unwrap())?;
        let g_db = pallet::ext::sled::open(Path::new(&data_dir).join("groups").to_str().unwrap())?;
        let p_db =
            pallet::ext::sled::open(Path::new(&data_dir).join("profiles").to_str().unwrap())?;
        fs::create_dir_all("/tmp/mdb")?;
        fs::create_dir_all("/tmp/cdb")?;
        fs::create_dir_all("/tmp/gdb")?;
        fs::create_dir_all("/tmp/pdb")?;
        let msg_store = pallet::Store::builder()
            .with_db(m_db)
            .with_index_dir("/tmp/mdb")


@@ 277,17 309,23 @@ impl Presage {
            .with_index_dir("/tmp/gdb")
            .finish()?;
        group_store.index_all()?;
        let profile_store = pallet::Store::builder()
            .with_db(p_db)
            .with_index_dir("/tmp/pdb")
            .finish()?;
        let pre = Presage {
            msg_store,
            contact_store,
            group_store,
            profile_store,
            whoami: None,
            res_sender,
            req_sender,
            data_dir,
        };
        // Converts all old messages stored by phone # into uuid. Probably not necessary anymore
        pre.contact_store.all()?.into_iter().for_each(|c| {
        /*pre.contact_store.all()?.into_iter().for_each(|c| {
            println!("{:?}", c);
            if c.uuid == String::new() || c.tel == String::new() {
                return;
            }


@@ 327,6 365,9 @@ impl Presage {
                g.inner.id = g.inner.id.to_uppercase();
                pre.group_store.update(&g).unwrap();
            });
        pre.profile_store.all().unwrap().into_iter().for_each(|p| {
            println!("{:?}", p);
        });*/
        return Ok(pre);
    }



@@ 410,7 451,8 @@ impl Presage {
                        .unwrap_or(meta.sender.uuid.unwrap().to_string().to_uppercase())
                        .to_uppercase();
                    let contact = Contact {
                        name,
                        state: "fake".into(),
                        name: "".to_string(),
                        tel: meta.sender.e164().unwrap_or_default().to_string(),
                        uuid: meta
                            .sender


@@ 482,6 524,20 @@ impl Presage {
                    }
                }
            }
            SignalResponse::Profile(profile) => {
                println!("{:?}", profile);
                if let Ok(mut fetched) = self.profile_doc(profile.uuid.as_str()) {
                    println!("Found profile");
                    fetched.inner = profile;
                    self.profile_store
                        .update(&fetched)
                        .expect("Couldn't update profile");
                } else {
                    self.profile_store
                        .create(&profile)
                        .expect("Couldn't create profile");
                }
            }
            SignalResponse::AddReaction {
                target,
                target_timestamp,


@@ 515,10 571,26 @@ impl Presage {

    // Given a chat id of any kind, resolve a relevant name. E.g. returns a contact's name/group name/etc. Returns the id if no name can be found
    pub fn resolve_name(&mut self, chat_id: &str) -> Result<String> {
        if let Some(contact) = self.contact(chat_id.clone()).ok() {
            return Ok(contact.name);
        let searched_for = self
            .contact_store
            .search(format!("uuid:{} AND state:real", chat_id).as_str())
            .expect("Couldn't search for resolve contact")
            .hits
            .into_iter()
            .next();
        let profile_search = self
            .profile_store
            .all()
            .unwrap()
            .into_iter()
            .filter(|p| p.uuid.as_str() == chat_id)
            .next();
        if let Some(contact) = searched_for {
            return Ok(contact.doc.inner.name);
        } else if let Ok(group) = self.group(chat_id) {
            return Ok(group.name.clone());
        } else if let Some(profile) = profile_search {
            return Ok(profile.name.clone());
        } else {
            return Ok(chat_id.to_string());
        }


@@ 672,10 744,24 @@ impl Presage {
            .clone())
    }

    fn contact_tel<'a>(&'a self, tel: &str) -> Result<Contact> {
    // Returns a contact with the given string as either phone # or uuid. Includes Document
    fn contact_doc(&self, search: &str) -> Result<Document<Contact>, anyhow::Error> {
        Ok(self
            .contact_store
            .search(format!("tel:{}", tel).as_str())?
            .search(format!("tel:{} OR uuid:{}", search, search).as_str())?
            .hits
            .into_iter()
            .next()
            .context("none")?
            .doc
            .clone())
    }

    pub fn profile(&self, uuid: &str) -> Result<Profile> {
        println!("|{}|", uuid);
        Ok(self
            .profile_store
            .search(format!("uuid:{}", uuid).as_str())?
            .hits
            .into_iter()
            .next()


@@ 685,11 771,10 @@ impl Presage {
            .clone())
    }

    // Returns a contact with the given string as either phone # or uuid. Includes Document
    fn contact_doc(&self, search: &str) -> Result<Document<Contact>, anyhow::Error> {
    fn profile_doc(&self, uuid: &str) -> Result<Document<Profile>> {
        Ok(self
            .contact_store
            .search(format!("tel:{} OR uuid:{}", search, search).as_str())?
            .profile_store
            .search(format!("uuid:{}", uuid).as_str())?
            .hits
            .into_iter()
            .next()

M src/signal.rs => src/signal.rs +11 -6
@@ 89,8 89,6 @@ pub struct Reaction {
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SignalResponse {
    #[serde(skip)]
    Whoami(String),
    SGroup(Group),
    #[serde(skip)]
    Metadata(presage::prelude::Metadata),


@@ 100,6 98,7 @@ pub enum SignalResponse {
    Type(String),
    AddHist(SignalMessage, bool),
    IDLessMessage(SignalMessage),
    Profile(Profile),
    RmContact(String),
    Quit,
    DefaultOp,


@@ 216,6 215,15 @@ impl SignalMessage {
        to
    }
}
#[derive(Serialize, Deserialize, Clone, Debug, DocumentLike, Default)]
#[pallet(tree_name = "profiles")]
pub struct Profile {
    pub name: String,
    pub about: String,
    pub about_emoji: String,
    #[pallet(default_search_field, index_field_options = "SignalMessage::id_opts()")]
    pub uuid: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, Default, QGadget, SimpleListItem)]
#[serde(rename_all = "PascalCase")]
pub struct QMLSignalMessage {


@@ 301,8 309,5 @@ pub struct Contact {
    pub name: String,
    #[pallet(default_search_field, index_field_options = "SignalMessage::id_opts()")]
    pub uuid: String,
    //pub color: String,
    //pub avatar: String,
    //pub blocked: bool,
    //pub expire_timer: i32,
    pub state: String,
}

M src/util.rs => src/util.rs +7 -0
@@ 18,3 18,10 @@ pub fn make_gkey(bytes: Vec<u8>) -> GroupMasterKey {
    slice.copy_from_slice(bytes.as_slice());
    GroupMasterKey::new(slice)
}

// Takes a vec of bytes and returns a profilekey slice
pub fn make_profile_key(bytes: Vec<u8>) -> [u8; 32] {
    let mut slice: [u8; 32] = Default::default();
    slice.copy_from_slice(bytes.as_slice());
    slice
}