-use clap::{crate_version, Parser, Subcommand, ValueEnum};
use std::{ffi::OsString, net::SocketAddr};
+use clap::{crate_version, Parser, Subcommand, ValueEnum};
+
/// JSON-RPC client for signal-cli
#[derive(Parser, Debug)]
-#[command(rename_all = "kebab-case", version=crate_version!())]
+#[command(rename_all = "kebab-case", version = crate_version!())]
pub struct Cli {
/// Account to use (for daemon in multi-account mode)
#[arg(short = 'a', long)]
#[arg(long, conflicts_with = "json_rpc_socket")]
pub json_rpc_http: Option<Option<String>>,
- #[arg(value_enum, long, default_value_t = OutputTypes::Json)]
- pub output: OutputTypes,
-
#[arg(long)]
pub verbose: bool,
pub command: CliCommands,
}
-#[derive(ValueEnum, Clone, Debug)]
-#[value(rename_all = "kebab-case")]
-pub enum OutputTypes {
- PlainText,
- Json,
-}
-
#[allow(clippy::large_enum_variant)]
#[derive(Subcommand, Debug)]
-#[command(rename_all = "camelCase", version=crate_version!())]
+#[command(rename_all = "camelCase", version = crate_version!())]
pub enum CliCommands {
AddDevice {
#[arg(long)]
uri: String,
},
+ AddStickerPack {
+ #[arg(long)]
+ uri: String,
+ },
#[command(rename_all = "kebab-case")]
Block {
recipient: Vec<String>,
#[arg(long = "ignore-registered")]
ignore_registered: Option<bool>,
},
+ FinishChangeNumber {
+ number: String,
+ #[arg(short = 'v', long = "verification-code")]
+ verification_code: String,
+
+ #[arg(short = 'p', long)]
+ pin: Option<String>,
+ },
+ GetAttachment {
+ #[arg(long)]
+ id: String,
+ #[arg(long)]
+ recipient: Option<String>,
+ #[arg(short = 'g', long = "group-id")]
+ group_id: Option<String>,
+ },
GetUserStatus {
recipient: Vec<String>,
},
recipient: String,
#[arg(long)]
forget: bool,
+ #[arg(long)]
+ hide: bool,
},
RemoveDevice {
#[arg(short = 'd', long = "device-id")]
#[arg(long)]
mention: Vec<String>,
+ #[arg(long)]
+ text_style: Vec<String>,
+
#[arg(long)]
quote_timestamp: Option<u64>,
#[arg(long)]
quote_mention: Vec<String>,
+ #[arg(long)]
+ quote_text_style: Vec<String>,
+
#[arg(long)]
quote_attachment: Vec<String>,
+ #[arg(long)]
+ preview_url: Option<String>,
+
+ #[arg(long)]
+ preview_title: Option<String>,
+
+ #[arg(long)]
+ preview_description: Option<String>,
+
+ #[arg(long)]
+ preview_image: Option<String>,
+
#[arg(long)]
sticker: Option<String>,
#[arg(long)]
story_author: Option<String>,
+
+ #[arg(long)]
+ edit_timestamp: Option<u64>,
},
SendContacts,
SendPaymentNotification {
SetPin {
pin: String,
},
+ StartChangeNumber {
+ number: String,
+ #[arg(short = 'v', long)]
+ voice: bool,
+ #[arg(long)]
+ captcha: Option<String>,
+ },
SubmitRateLimitChallenge {
challenge: String,
captcha: String,
UpdateAccount {
#[arg(short = 'n', long = "device-name")]
device_name: Option<String>,
+ #[arg(long = "unrestricted-unidentified-sender")]
+ unrestricted_unidentified_sender: Option<bool>,
},
UpdateConfiguration {
#[arg(long = "read-receipts")]
uri: String,
) -> Result<Value, ErrorObjectOwned>;
+ #[method(name = "addStickerPack", param_kind = map)]
+ async fn add_sticker_pack(
+ &self,
+ account: Option<String>,
+ uri: String,
+ ) -> Result<Value, ErrorObjectOwned>;
+
#[method(name = "block", param_kind = map)]
fn block(
&self,
#[allow(non_snake_case)] ignoreRegistered: Option<bool>,
) -> Result<Value, ErrorObjectOwned>;
+ #[method(name = "getAttachment", param_kind = map)]
+ fn get_attachment(
+ &self,
+ account: Option<String>,
+ id: String,
+ recipient: Option<String>,
+ group_id: Option<String>,
+ ) -> Result<Value, ErrorObjectOwned>;
+
#[method(name = "getUserStatus", param_kind = map)]
fn get_user_status(
&self,
#[method(name = "joinGroup", param_kind = map)]
fn join_group(&self, account: Option<String>, uri: String) -> Result<Value, ErrorObjectOwned>;
+ #[allow(non_snake_case)]
+ #[method(name = "finishChangeNumber", param_kind = map)]
+ fn finish_change_number(
+ &self,
+ account: Option<String>,
+ number: String,
+ verificationCode: String,
+ pin: Option<String>,
+ ) -> Result<Value, ErrorObjectOwned>;
+
#[method(name = "finishLink", param_kind = map)]
fn finish_link(
&self,
account: Option<String>,
recipient: String,
forget: bool,
+ hide: bool,
) -> Result<Value, ErrorObjectOwned>;
#[method(name = "removeDevice", param_kind = map)]
#[allow(non_snake_case)] noteToSelf: bool,
) -> Result<Value, ErrorObjectOwned>;
+ #[allow(non_snake_case)]
#[method(name = "send", param_kind = map)]
fn send(
&self,
account: Option<String>,
recipients: Vec<String>,
- #[allow(non_snake_case)] groupIds: Vec<String>,
- #[allow(non_snake_case)] noteToSelf: bool,
- #[allow(non_snake_case)] endSession: bool,
+ groupIds: Vec<String>,
+ noteToSelf: bool,
+ endSession: bool,
message: String,
attachments: Vec<String>,
mentions: Vec<String>,
- #[allow(non_snake_case)] quoteTimestamp: Option<u64>,
- #[allow(non_snake_case)] quoteAuthor: Option<String>,
- #[allow(non_snake_case)] quoteMessage: Option<String>,
- #[allow(non_snake_case)] quoteMention: Vec<String>,
- #[allow(non_snake_case)] quoteAttachment: Vec<String>,
+ textStyle: Vec<String>,
+ quoteTimestamp: Option<u64>,
+ quoteAuthor: Option<String>,
+ quoteMessage: Option<String>,
+ quoteMention: Vec<String>,
+ quoteTextStyle: Vec<String>,
+ quoteAttachment: Vec<String>,
+ preview_url: Option<String>,
+ preview_title: Option<String>,
+ preview_description: Option<String>,
+ preview_image: Option<String>,
sticker: Option<String>,
- #[allow(non_snake_case)] storyTimestamp: Option<u64>,
- #[allow(non_snake_case)] storyAuthor: Option<String>,
+ storyTimestamp: Option<u64>,
+ storyAuthor: Option<String>,
+ editTimestamp: Option<u64>,
) -> Result<Value, ErrorObjectOwned>;
#[method(name = "sendContacts", param_kind = map)]
captcha: String,
) -> Result<Value, ErrorObjectOwned>;
+ #[method(name = "startChangeNumber", param_kind = map)]
+ fn start_change_number(
+ &self,
+ account: Option<String>,
+ number: String,
+ voice: bool,
+ captcha: Option<String>,
+ ) -> Result<Value, ErrorObjectOwned>;
+
#[method(name = "startLink", param_kind = map)]
fn start_link(&self, account: Option<String>) -> Result<JsonLink, ErrorObjectOwned>;
#[allow(non_snake_case)] deleteAccount: bool,
) -> Result<Value, ErrorObjectOwned>;
+ #[allow(non_snake_case)]
#[method(name = "updateAccount", param_kind = map)]
fn update_account(
&self,
account: Option<String>,
- #[allow(non_snake_case)] deviceName: Option<String>,
+ deviceName: Option<String>,
+ unrestrictedUnidentifiedSender: Option<bool>,
) -> Result<Value, ErrorObjectOwned>;
#[method(name = "updateConfiguration", param_kind = map)]
fn update_configuration(
&self,
account: Option<String>,
- #[allow(non_snake_case)] readReceiptes: Option<bool>,
+ #[allow(non_snake_case)] readReceipts: Option<bool>,
#[allow(non_snake_case)] unidentifiedDeliveryIndicators: Option<bool>,
#[allow(non_snake_case)] typingIndicators: Option<bool>,
#[allow(non_snake_case)] linkPreviews: Option<bool>,
use std::{path::PathBuf, time::Duration};
use clap::Parser;
-use cli::Cli;
use jsonrpsee::core::client::{Subscription, SubscriptionClientT};
use jsonrpsee::core::Error as RpcError;
use serde_json::Value;
use tokio::{select, time::sleep};
-use crate::cli::{GroupPermission, LinkState};
+use cli::Cli;
+
+use crate::cli::{CliCommands, GroupPermission, LinkState};
use crate::jsonrpc::RpcClient;
mod cli;
client: impl SubscriptionClientT + Sync,
) -> Result<Value, RpcError> {
match cli.command {
- cli::CliCommands::Receive { timeout } => {
+ CliCommands::Receive { timeout } => {
let mut stream = client.subscribe_receive(cli.account).await?;
{
stream.unsubscribe().await?;
Ok(Value::Null)
}
- cli::CliCommands::AddDevice { uri } => client.add_device(cli.account, uri).await,
- cli::CliCommands::Block {
+ CliCommands::AddDevice { uri } => client.add_device(cli.account, uri).await,
+ CliCommands::Block {
recipient,
group_id,
} => client.block(cli.account, recipient, group_id).await,
- cli::CliCommands::DeleteLocalAccountData { ignore_registered } => {
+ CliCommands::DeleteLocalAccountData { ignore_registered } => {
client
.delete_local_account_data(cli.account, ignore_registered)
.await
}
- cli::CliCommands::GetUserStatus { recipient } => {
+ CliCommands::GetUserStatus { recipient } => {
client.get_user_status(cli.account, recipient).await
}
- cli::CliCommands::JoinGroup { uri } => client.join_group(cli.account, uri).await,
- cli::CliCommands::Link { name } => {
+ CliCommands::JoinGroup { uri } => client.join_group(cli.account, uri).await,
+ CliCommands::Link { name } => {
let url = client
.start_link(cli.account)
.await
println!("{}", url);
client.finish_link(url, name).await
}
- cli::CliCommands::ListAccounts => client.list_accounts().await,
- cli::CliCommands::ListContacts {
+ CliCommands::ListAccounts => client.list_accounts().await,
+ CliCommands::ListContacts {
recipient,
all_recipients,
blocked,
.list_contacts(cli.account, recipient, all_recipients, blocked, name)
.await
}
- cli::CliCommands::ListDevices => client.list_devices(cli.account).await,
- cli::CliCommands::ListGroups {
+ CliCommands::ListDevices => client.list_devices(cli.account).await,
+ CliCommands::ListGroups {
detailed: _,
group_id,
} => client.list_groups(cli.account, group_id).await,
- cli::CliCommands::ListIdentities { number } => {
- client.list_identities(cli.account, number).await
- }
- cli::CliCommands::ListStickerPacks => client.list_sticker_packs(cli.account).await,
- cli::CliCommands::QuitGroup {
+ CliCommands::ListIdentities { number } => client.list_identities(cli.account, number).await,
+ CliCommands::ListStickerPacks => client.list_sticker_packs(cli.account).await,
+ CliCommands::QuitGroup {
group_id,
delete,
admin,
.quit_group(cli.account, group_id, delete, admin)
.await
}
- cli::CliCommands::Register { voice, captcha } => {
+ CliCommands::Register { voice, captcha } => {
client.register(cli.account, voice, captcha).await
}
- cli::CliCommands::RemoveContact { recipient, forget } => {
- client.remove_contact(cli.account, recipient, forget).await
+ CliCommands::RemoveContact {
+ recipient,
+ forget,
+ hide,
+ } => {
+ client
+ .remove_contact(cli.account, recipient, forget, hide)
+ .await
}
- cli::CliCommands::RemoveDevice { device_id } => {
+ CliCommands::RemoveDevice { device_id } => {
client.remove_device(cli.account, device_id).await
}
- cli::CliCommands::RemovePin => client.remove_pin(cli.account).await,
- cli::CliCommands::RemoteDelete {
+ CliCommands::RemovePin => client.remove_pin(cli.account).await,
+ CliCommands::RemoteDelete {
target_timestamp,
recipient,
group_id,
)
.await
}
- cli::CliCommands::Send {
+ CliCommands::Send {
recipient,
group_id,
note_to_self,
message,
attachment,
mention,
+ text_style,
quote_timestamp,
quote_author,
quote_message,
quote_mention,
+ quote_text_style,
quote_attachment,
+ preview_url,
+ preview_title,
+ preview_description,
+ preview_image,
sticker,
story_timestamp,
story_author,
+ edit_timestamp,
} => {
client
.send(
message.unwrap_or_default(),
attachment,
mention,
+ text_style,
quote_timestamp,
quote_author,
quote_message,
quote_mention,
+ quote_text_style,
quote_attachment,
+ preview_url,
+ preview_title,
+ preview_description,
+ preview_image,
sticker,
story_timestamp,
story_author,
+ edit_timestamp,
)
.await
}
- cli::CliCommands::SendContacts => client.send_contacts(cli.account).await,
- cli::CliCommands::SendPaymentNotification {
+ CliCommands::SendContacts => client.send_contacts(cli.account).await,
+ CliCommands::SendPaymentNotification {
recipient,
receipt,
note,
.send_payment_notification(cli.account, recipient, receipt, note)
.await
}
- cli::CliCommands::SendReaction {
+ CliCommands::SendReaction {
recipient,
group_id,
note_to_self,
)
.await
}
- cli::CliCommands::SendReceipt {
+ CliCommands::SendReceipt {
recipient,
target_timestamp,
r#type,
)
.await
}
- cli::CliCommands::SendSyncRequest => client.send_sync_request(cli.account).await,
- cli::CliCommands::SendTyping {
+ CliCommands::SendSyncRequest => client.send_sync_request(cli.account).await,
+ CliCommands::SendTyping {
recipient,
group_id,
stop,
.send_typing(cli.account, recipient, group_id, stop)
.await
}
- cli::CliCommands::SetPin { pin } => client.set_pin(cli.account, pin).await,
- cli::CliCommands::SubmitRateLimitChallenge { challenge, captcha } => {
+ CliCommands::SetPin { pin } => client.set_pin(cli.account, pin).await,
+ CliCommands::SubmitRateLimitChallenge { challenge, captcha } => {
client
.submit_rate_limit_challenge(cli.account, challenge, captcha)
.await
}
- cli::CliCommands::Trust {
+ CliCommands::Trust {
recipient,
trust_all_known_keys,
verified_safety_number,
)
.await
}
- cli::CliCommands::Unblock {
+ CliCommands::Unblock {
recipient,
group_id,
} => client.unblock(cli.account, recipient, group_id).await,
- cli::CliCommands::Unregister { delete_account } => {
+ CliCommands::Unregister { delete_account } => {
client.unregister(cli.account, delete_account).await
}
- cli::CliCommands::UpdateAccount { device_name } => {
- client.update_account(cli.account, device_name).await
+ CliCommands::UpdateAccount {
+ device_name,
+ unrestricted_unidentified_sender,
+ } => {
+ client
+ .update_account(cli.account, device_name, unrestricted_unidentified_sender)
+ .await
}
- cli::CliCommands::UpdateConfiguration {
+ CliCommands::UpdateConfiguration {
read_receipts,
unidentified_delivery_indicators,
typing_indicators,
)
.await
}
- cli::CliCommands::UpdateContact {
+ CliCommands::UpdateContact {
recipient,
expiration,
name,
.update_contact(cli.account, recipient, name, expiration)
.await
}
- cli::CliCommands::UpdateGroup {
+ CliCommands::UpdateGroup {
group_id,
name,
description,
)
.await
}
- cli::CliCommands::UpdateProfile {
+ CliCommands::UpdateProfile {
given_name,
family_name,
about,
)
.await
}
- cli::CliCommands::UploadStickerPack { path } => {
+ CliCommands::UploadStickerPack { path } => {
client.upload_sticker_pack(cli.account, path).await
}
- cli::CliCommands::Verify {
+ CliCommands::Verify {
verification_code,
pin,
} => client.verify(cli.account, verification_code, pin).await,
- cli::CliCommands::Version => client.version().await,
+ CliCommands::Version => client.version().await,
+ CliCommands::AddStickerPack { uri } => client.add_sticker_pack(cli.account, uri).await,
+ CliCommands::FinishChangeNumber {
+ number,
+ verification_code,
+ pin,
+ } => {
+ client
+ .finish_change_number(cli.account, number, verification_code, pin)
+ .await
+ }
+ CliCommands::GetAttachment {
+ id,
+ recipient,
+ group_id,
+ } => {
+ client
+ .get_attachment(cli.account, id, recipient, group_id)
+ .await
+ }
+ CliCommands::StartChangeNumber {
+ number,
+ voice,
+ captcha,
+ } => {
+ client
+ .start_change_number(cli.account, number, voice, captcha)
+ .await
+ }
}
}