diff --git a/Cargo.toml b/Cargo.toml index 6f7122b..215df23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ documentation = "https://docs.rs/libcwtch/0.1.0/libcwtch/" libc = "0.2" serde_json = "1.0" serde = { version = "1.0.127", features = ["derive"] } -serde_with = { version = "1.10.0" } +serde_with = { version = "1.10.0" } \ No newline at end of file diff --git a/README.md b/README.md index 81f3f5f..02df330 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Example echobot in examples/echobot.rs (`cargo run --example echobot` -- assumes ### Updating libCwtch and bingings.rs with Bindgen -``` +```sh cargo install bindgen ``` @@ -16,7 +16,7 @@ libCwtch.so version is specified in build.rs. If updating, also download the cor the 'preamble from import "C"' section as it imports headers required for the C lib to compile but that we don't want to create rust bindings for (like importing stdlib.h). Then: -``` +```sh bindgen libCwtch.h -o src/cwtchlib_go/bindings.rs ``` diff --git a/examples/echobot.rs b/examples/echobot.rs index d137566..d2fc292 100644 --- a/examples/echobot.rs +++ b/examples/echobot.rs @@ -6,7 +6,9 @@ use libcwtch::CwtchLib; fn main() { let bot_home = "example_cwtch_dir"; - std::fs::remove_dir_all(&bot_home).expect("Error removing previous bot_home directory"); + match std::fs::remove_dir_all(&bot_home) { + _ => () + } std::fs::create_dir_all(&bot_home).expect("Error creating bot_home directory"); let cwtch = libcwtch::new_cwtchlib_go(); @@ -45,14 +47,14 @@ fn main() { } "NewMessageFromPeer" => { let to = &event.data["ProfileOnion"]; - let conversation = &event.data["RemotePeer"]; + let conversation_id = event.data["ConversationID"].parse::().unwrap(); let message: Message = serde_json::from_str(&event.data["Data"]).expect("Error parsing message"); let response = Message { o: 1, d: message.d }; let response_json = serde_json::to_string(&response).expect("Error parsing json response"); - cwtch.send_message(&to, &conversation, &response_json); + cwtch.send_message(&to, conversation_id, &response_json); } _ => eprintln!("unhandled event!"), }; diff --git a/src/bindings_go.rs b/src/bindings_go.rs index 79b966b..af3239c 100644 --- a/src/bindings_go.rs +++ b/src/bindings_go.rs @@ -30,29 +30,31 @@ impl c_str_wrap { impl Drop for c_str_wrap { fn drop(&mut self) { unsafe { - CString::from_raw(self.raw); + drop(CString::from_raw(self.raw)); } } } // c_bind handles setting up c string arguments and freeing them -// c_bind!( $fn_name ( [ $string_args ]* ; [ $non_string_args : $type ]* ) $c_function -> $return_type? ) +// c_bind!( $fn_name ( [ $string_args: &str],* [ $non_string_args : $type ],* ) $c_function -> $return_type? ) macro_rules! c_bind { - // macro for returnless fns - ($func_name:ident ($($str:ident),* ; $($arg:ident: $t:ty),*) $bind_fn:ident) => { - fn $func_name(&self, $($str: &str, )* $($arg: $t, )*) { - $(let $str = c_str_wrap::new($str);)* + // No return + ($func_name:ident ($($str1:ident: &str),* ; $($args:ident: $t:ty),* ; $($str2:ident: &str),*) $bind_fn:ident) => { + fn $func_name(&self, $($str1: &str, )* $($args: $t, )* $($str2: &str, )*) { + $(let $str1 = c_str_wrap::new($str1);)* + $(let $str2 = c_str_wrap::new($str2);)* unsafe { - bindings::$bind_fn($( $str.raw, $str.len, )* $($arg,)* ); + bindings::$bind_fn($( $str1.raw, $str1.len, )* $($args,)* $( $str2.raw, $str2.len, )*); } } }; - // macro for str returning fns - ($func_name:ident ($($str:ident),* ; $($arg:ident: $t:ty),* ) $bind_fn:ident -> String) => { - fn $func_name(&self, $($str: &str, )* $($arg: $t, )*) -> String { - $(let $str = c_str_wrap::new($str);)* + // String return + ($func_name:ident ($($str1:ident: &str),* ; $($args:ident: $t:ty),* ; $($str2:ident: &str),*) $bind_fn:ident -> String) => { + fn $func_name(&self, $($str1: &str, )* $($args: $t, )* $($str2: &str, )*) -> String { + $(let $str1 = c_str_wrap::new($str1);)* + $(let $str2 = c_str_wrap::new($str2);)* unsafe { - let result_ptr = bindings::$bind_fn($( $str.raw, $str.len, )* $($arg,)* ); + let result_ptr = bindings::$bind_fn($( $str1.raw, $str1.len, )* $($args,)* $( $str2.raw, $str2.len, )*); let result = match CStr::from_ptr(result_ptr).to_str() { Ok(s) => s.to_owned(), Err(_) => "".to_string() @@ -63,12 +65,13 @@ macro_rules! c_bind { } } }; - // macro for value returning fns - ($func_name:ident ($($str:ident),* ; $($arg:ident: $t:ty),* ) $bind_fn:ident -> $bind_fn_ty:ty) => { - fn $func_name(&self, $($str: &str, )* $($arg: $t, )*) -> $bind_fn_ty { - $(let $str = c_str_wrap::new($str);)* + // Non String return + ($func_name:ident ($($str1:ident: &str),* ; $($args:ident: $t:ty),* ; $($str2:ident: &str),*) $bind_fn:ident -> $bind_fn_ty:ty) => { + fn $func_name(&self, $($str1: &str, )* $($args: t, )* $($str2: &str, )*) -> $bind_fn_ty { + $(let $str1 = c_str_wrap::new($str1);)* + $(let $str2 = c_str_wrap::new($str2);)* unsafe { - let result = bindings::$bind_fn($( $str.raw, $str.len, )* $($arg,)* ); + let result = bindings::$bind_fn($( $str1.raw, $str1.len, )* $($args,)* $( $str2.raw, $str2.len, )*); result } } @@ -77,41 +80,54 @@ macro_rules! c_bind { pub struct CwtchLibGo {} -impl CwtchLibGo { - c_bind!(send_profile_event(profile, event_json;) c_SendProfileEvent); -} - -impl CwtchLib for CwtchLibGo { - c_bind!(start_cwtch(app_dir, tor_path;) c_StartCwtch -> i32); - c_bind!(send_app_event(event_json;) c_SendAppEvent); - c_bind!(get_appbus_event(;) c_GetAppBusEvent -> String); - c_bind!(create_profile(nick, pass;) c_CreateProfile); - c_bind!(load_profiles(pass;) c_LoadProfiles); - c_bind!(accept_contact(profile, contact;) c_AcceptContact); - c_bind!(reject_invite(profile, contact;) c_RejectInvite); - c_bind!(block_contact(profile, contact;) c_BlockContact); - c_bind!(update_message_flags(profile, contact; message_id: i32, message_flags: u64) c_UpdateMessageFlags); - c_bind!(get_message(profile, contact; message_index: i32) c_GetMessage -> String); - c_bind!(get_message_by_content_hash(profile, contact, hash;) c_GetMessagesByContentHash -> String); - c_bind!(send_message(profile, contact, msg;) c_SendMessage); - c_bind!(send_invitation(profile, contact, target;) c_SendInvitation); +impl CwtchLib for CwtchLibGo { + c_bind!(start_cwtch(app_dir: &str, tor_path: &str;;) c_StartCwtch -> i32); + c_bind!(send_app_event(event_json: &str;;) c_SendAppEvent); + c_bind!(send_profile_event(profile: &str, event_jason: &str;;) c_SendProfileEvent); + c_bind!(get_appbus_event(;;) c_GetAppBusEvent -> String); + c_bind!(create_profile(nick: &str, pass: &str;;) c_CreateProfile); + c_bind!(load_profiles(pass: &str;;) c_LoadProfiles); + c_bind!(accept_conversation(profile: &str ; conversation_id: i32 ;) c_AcceptConversation); + c_bind!(block_contact(profile: &str ; conversation_id: i32; ) c_BlockContact); + // todo 1.5.3 + //c_bind!(unblock_contact(profile: &str ; conversation_id: i32; ) c_UnblockContact); + c_bind!(get_message(profile: &str; conversation_id: i32, message_index: i32 ;) c_GetMessage -> String); + c_bind!(get_message_by_id(profile: &str ; conversation_id: i32, message_id: i32 ;) c_GetMessageByID -> String); + c_bind!(get_message_by_content_hash(profile: &str ; conversation_id: i32 ; hash: &str) c_GetMessagesByContentHash -> String); + c_bind!(send_message(profile: &str; conversation_id: i32; msg: &str) c_SendMessage); + c_bind!(send_invitation(profile: &str; conversation_id: i32, target_id: i32;) c_SendInvitation); + c_bind!(share_file(profile: &str; conversation_id: i32; file_path: &str) c_ShareFile); + c_bind!(download_file(profile: &str; conversation_id: i32; file_path: &str, manifest_path: &str, file_key: &str) c_DownloadFile); + c_bind!(check_download_status(profile: &str, file_key: &str;;) c_CheckDownloadStatus); + c_bind!(verify_or_resume_download(profile: &str; conversation_id: i32; file_key: &str) c_VerifyOrResumeDownload); fn reset_tor(&self) { unsafe { bindings::c_ResetTor(); } } - c_bind!(create_group(profile, server, name;) c_CreateGroup); - c_bind!(delete_profile(profile, pass;) c_DeleteProfile); - c_bind!(archive_conversation(profile, contact;) c_ArchiveConversation); - c_bind!(delete_contact(profile, group;) c_DeleteContact); - c_bind!(import_bundle(profile, bundle;) c_ImportBundle); - c_bind!(set_profile_attribute(profile, key, val;) c_SetProfileAttribute); - c_bind!(set_contact_attribute(profile, contact, key, val;) c_SetContactAttribute); - c_bind!(set_group_attribute(profile, group, key, val;) c_SetGroupAttribute); + c_bind!(create_group(profile: &str, server: &str, name: &str;;) c_CreateGroup); + c_bind!(delete_profile(profile: &str, pass: &str;;) c_DeleteProfile); + c_bind!(archive_conversation(profile: &str; conversation_id: i32;) c_ArchiveConversation); + c_bind!(delete_contact(profile: &str; conversation_id: i32;) c_DeleteContact); + c_bind!(import_bundle(profile: &str, bundle: &str;;) c_ImportBundle); + c_bind!(set_profile_attribute(profile: &str, key: &str, val: &str;;) c_SetProfileAttribute); + c_bind!(set_conversation_attribute(profile: &str; conversation_id: i32; key: &str, val: &str) c_SetConversationAttribute); + c_bind!(set_message_attribute(profile: &str; conversation_id: i32, channel_id: i32, message_id: i32; key: &str, val: &str) c_SetMessageAttribute); + c_bind!(change_password(profile: &str, old_pass: &str, new_pass: &str, new_pass_again: &str;;) c_ChangePassword); fn shutdown_cwtch(&self) { unsafe { bindings::c_ShutdownCwtch(); } } + + c_bind!(load_servers(password: &str;;) c_LoadServers); + c_bind!(create_server(password: &str, description: &str; autostart: i8;) c_CreateServer); + c_bind!(delete_server(onion: &str, current_password: &str;;) c_DeleteServer); + c_bind!(launch_servers(;;) c_LaunchServers); + c_bind!(launch_server(onion: &str;;) c_LaunchServer); + c_bind!(stop_server(onion: &str;;) c_StopServer); + c_bind!(stop_servers(;;) c_StopServers); + c_bind!(destroy_servers(;;) c_DestroyServers); + c_bind!(set_server_attribute(onion: &str, key: &str, val: &str;;) c_SetServerAttribute); } diff --git a/src/cwtchlib_go/mod.rs b/src/cwtchlib_go/mod.rs index b11653b..52fb393 100644 --- a/src/cwtchlib_go/mod.rs +++ b/src/cwtchlib_go/mod.rs @@ -2,5 +2,6 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(dead_code)] +#![allow(deref_nullptr)] pub mod bindings; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index c8c2016..70f5da0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,9 @@ pub trait CwtchLib { /// Send json of a structs::CwtchEvent to the cwtch app bus fn send_app_event(&self, event_json: &str); + /// Send json of a structs::CwtchEvent to a cwtch profile + fn send_profile_event(&self, profile: &str, event_json: &str); + /// Pull json of a structs::CwtchEvent off the appbus for responding to fn get_appbus_event(&self) -> String; @@ -26,35 +29,42 @@ pub trait CwtchLib { /// Load any profiles encrypted by pass fn load_profiles(&self, pass: &str); - /// Cause profile to accept contact - fn accept_contact(&self, profile: &str, contact: &str); + /// Cause profile to accept conversation + fn accept_conversation(&self, profile: &str, conversation_id: i32); - /// Cause profile to reject contact - fn reject_invite(&self, profile: &str, contact: &str); + /// Cause profile to block conversation + fn block_contact(&self, profile: &str, conversation_id: i32); - /// Cause profile to block contact - fn block_contact(&self, profile: &str, contact: &str); + // TODO 1.5.3 + /// Cause profile to unblock contact + //fn unblock_contact(&self, profile: &str, conversation_id: i32); - /// Cause profile to update contact's message to have it's flags updated - fn update_message_flags( - &self, - profile: &str, - contact: &str, - message_id: i32, - message_flags: u64, - ); + /// Get a specific message for conversation of profile by index + fn get_message(&self, profile: &str, conversation_id: i32, message_index: i32) -> String; - /// Get a specific message for contact of profile by index - fn get_message(&self, profile: &str, contact: &str, message_index: i32) -> String; + /// Get a specific message for a conversation by its id + fn get_message_by_id(&self, profile: &str, conversation_id: i32, message_id: i32) -> String; - /// Get a specific message for contact of profile by hash - fn get_message_by_content_hash(&self, profile: &str, contact: &str, hash: &str) -> String; + /// Get a specific message for conversation of profile by hash + fn get_message_by_content_hash(&self, profile: &str, conversation_id: i32, hash: &str) -> String; /// Send json of a structs::Message from profile to contact - fn send_message(&self, profile: &str, contact: &str, msg: &str); + fn send_message(&self, profile: &str, conversation_id: i32, msg: &str); /// Send profile's contact an invite for/to target - fn send_invitation(&self, profile: &str, contact: &str, target: &str); + fn send_invitation(&self, profile: &str, conversation_id: i32, target_id: i32); + + /// share a file file_path with a conersation + fn share_file(&self, profile: &str, conversation_id: i32, file_path: &str); + + /// download a file from a conversation to the file_path + fn download_file(&self, profile: &str, conversation_id: i32, file_path: &str, manifest_path: &str, file_key: &str); + + /// Query the status of a download + fn check_download_status(&self, profile: &str, file_key: &str); + + /// Verufy a download is done, and if not, resume it + fn verify_or_resume_download(&self, profile: &str, conversation_id: i32, file_key: &str); /// Ask the ACN inside the Cwtch app to restart the tor connection fn reset_tor(&self); @@ -66,10 +76,10 @@ pub trait CwtchLib { fn delete_profile(&self, profile: &str, pass: &str); /// Cause profile to archive conversation with contact - fn archive_conversation(&self, profile: &str, contact: &str); + fn archive_conversation(&self, profile: &str, conversation_id: i32); /// Cause profile to delete contact/group identified by handle - fn delete_contact(&self, profile: &str, handle: &str); + fn delete_contact(&self, profile: &str, conversation_id: i32); /// Cuase profile to attempt to import a contact/group/keybundle identified by bundle fn import_bundle(&self, profile: &str, bundle: &str); @@ -78,13 +88,45 @@ pub trait CwtchLib { fn set_profile_attribute(&self, profile: &str, key: &str, val: &str); /// Set a profile's contact's attribute of key to val - fn set_contact_attribute(&self, profile: &str, contact: &str, key: &str, val: &str); + fn set_conversation_attribute(&self, profile: &str, conversation_id: i32, key: &str, val: &str); - /// Set a profile's group's attribute of key to val - fn set_group_attribute(&self, profile: &str, group: &str, key: &str, val: &str); + /// Set an attribute on a message in a conversation + fn set_message_attribute(&self, profile: &str, conversation_id: i32, channel_id: i32, message_id: i32, attribute_key: &str, attribute_value: &str); + + /// Change a profile's password to new_pass if old_pass is correct + fn change_password(&self, profile: &str, old_pass: &str, new_pass: &str, new_pass_again: &str); /// Shutdown the cwtch app and associated ACN fn shutdown_cwtch(&self); + + /// Server functions require server experiment to be enabled + + /// Load all servers encrypted by password + fn load_servers(&self, password: &str); + + /// Create a new server, encrypted with password, autostart i8 used as bool + fn create_server(&self, password: &str, description: &str, autostart: i8); + + /// Delete the specified server (if password is correct) + fn delete_server(&self, onion: &str, current_password: &str); + + /// Launch all loaded servers + fn launch_servers(&self); + + /// Launch the specified server + fn launch_server(&self, onion: &str); + + /// Stop the specified server + fn stop_server(&self, onion: &str); + + /// Stop all running servers + fn stop_servers(&self); + + /// Destroy all servers leaving htem un-re-runnable. call only on shutdown + fn destroy_servers(&self); + + /// Set the specified server's attribute of key to val + fn set_server_attribute(&self, onion: &str, key: &str, val: &str); } /// Create a new CwtchLib that is backed by bindings to libcwtch-go