diff --git a/Cargo.toml b/Cargo.toml index b9b73f8..77d3f11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ name = "ffsend" path = "src/main.rs" [features] -default = ["archive", "clipboard", "history", "send2", "send3", "qrcode", "urlshorten"] +default = ["archive", "clipboard", "history", "infer-command", "qrcode", "send2", "send3", "urlshorten"] # Compile with file archiving support archive = ["tar"] @@ -58,9 +58,6 @@ archive = ["tar"] # Compile with file history support history = [] -# Compile without colored output support -no-color = ["colored/no-color"] - # Support for Firefox Send v2 send2 = ["ffsend-api/send2"] @@ -73,6 +70,12 @@ qrcode = ["qr2term"] # Support for shortening share URLs urlshorten = ["urlshortener"] +# Support for inferring subcommand when linking binary +infer-command = [] + +# Compile without colored output support +no-color = ["colored/no-color"] + [dependencies] chbs = "0.0.8" chrono = "0.4" diff --git a/README.md b/README.md index c86c0eb..2acd6a6 100644 --- a/README.md +++ b/README.md @@ -388,16 +388,17 @@ Different use flags are available for `ffsend` to toggle whether to include various features. The following features are available, some of which are enabled by default: -| Feature | Enabled | Description | -| :---------: | :-----: | :--------------------------------------------------------- | -| `send2` | Default | Support for Firefox Send v2 servers | -| `send3` | Default | Support for Firefox Send v3 servers | -| `clipboard` | Default | Support for copying links to the clipboard | -| `history` | Default | Support for tracking files in history | -| `archive` | Default | Support for archiving and extracting uploads and downloads | -| `qrcode` | Default | Support for rendering a QR code for a share URL | -| `urlshorten`| Default | Support for shortening share URLs | -| `no-color` | | Compile without color support in error and help messages | +| Feature | Enabled | Description | +| :------------: | :-----: | :--------------------------------------------------------- | +| `send2` | Default | Support for Firefox Send v2 servers | +| `send3` | Default | Support for Firefox Send v3 servers | +| `clipboard` | Default | Support for copying links to the clipboard | +| `history` | Default | Support for tracking files in history | +| `archive` | Default | Support for archiving and extracting uploads and downloads | +| `qrcode` | Default | Support for rendering a QR code for a share URL | +| `urlshorten` | Default | Support for shortening share URLs | +| `infer-command`| Default | Support for inferring subcommand based on binary name | +| `no-color` | | Compile without color support in error and help messages | To enable features during building or installation, specify them with `--features ` when using `cargo`. @@ -454,6 +455,37 @@ empty. At this time, no configuration or _dotfile_ file support is available. This will be something added in a later release. +### Binary for each subcommand: `ffput`, `ffget` +`ffsend` supports having a separate binary for a single subcommand, such as +having `ffput` and `ffget` just for uploading and downloading through `ffsend`. +This allows simple commands like: +```bash +ffput my-file.txt +ffget https://send.firefox.com/#sample-share-url +``` + +This works for a predefined list of binary names: +* `ffput` -> `ffsend upload ...` +* `ffget` -> `ffsend download ...` +* `ffdel` -> `ffsend delete ...` +* _This list is defined in [`src/config.rs`](./src/config.rs) as `INFER_COMMANDS`_ + +Symbolic or hard links may be created having these names for this functionality +(similar to [`busybox`](https://en.wikipedia.org/wiki/BusyBox#Single_binary)), +so you don't have to clone the `ffsend` binary for each subcommand. +On Linux and macOS you can use the following commands for setting up these +symbolic links in the current directory: +```bash +ln -s $(which ffsend) ./ffput +ln -s $(which ffsend) ./ffget +``` + +Support for this feature is only available when `ffsend` is compiled with the +[`infer-command`](#compile-features--use-flags) feature flag. +This is usually enabled by default. +To verify support is available with an existing installation, make sure the +feature is listed when invoking `ffsend debug`. + ## Security In short; the `ffsend` tool and the [Send][send] service can be considered secure, and may be used to share sensitive files. Note though that the diff --git a/src/cmd/handler.rs b/src/cmd/handler.rs index 56a81ab..0e84e0d 100644 --- a/src/cmd/handler.rs +++ b/src/cmd/handler.rs @@ -1,5 +1,8 @@ extern crate directories; +#[cfg(feature = "infer-command")] +use std::ffi::OsString; + use clap::{App, AppSettings, Arg, ArgMatches}; use super::arg::{ArgApi, CmdArg}; @@ -15,9 +18,13 @@ use super::subcmd::{ CmdDebug, CmdDelete, CmdDownload, CmdExists, CmdInfo, CmdParams, CmdPassword, CmdUpload, CmdVersion, }; +#[cfg(feature = "infer-command")] +use crate::config::INFER_COMMANDS; use crate::config::{CLIENT_TIMEOUT, CLIENT_TRANSFER_TIMEOUT}; #[cfg(feature = "history")] use crate::util::app_history_file_path_string; +#[cfg(feature = "infer-command")] +use crate::util::bin_name; #[cfg(feature = "history")] lazy_static! { @@ -188,9 +195,40 @@ impl<'a: 'b, 'b> Handler<'a> { /// Parse CLI arguments. pub fn parse() -> Handler<'a> { + // Obtain the program arguments + #[allow(unused_mut)] + let mut args: Vec<_> = ::std::env::args_os().collect(); + + // Infer subcommand based on binary name + #[cfg(feature = "infer-command")] + Self::infer_subcommand(&mut args); + // Build the application CLI definition, get the matches Handler { - matches: Handler::build().get_matches(), + matches: Handler::build().get_matches_from(args), + } + } + + /// Infer subcommand when the binary has a predefined name, + /// modifying the given program arguments. + /// + /// If no subcommand could be inferred, the `args` list leaves unchanged. + /// See `crate::config::INFER_COMMANDS` for a list of commands. + /// + /// When the `ffsend` binary is called with such a name, the corresponding subcommand is + /// automatically inserted as argument. This also works when calling binaries through symbolic + /// or hard links. + #[cfg(feature = "infer-command")] + fn infer_subcommand(args: &mut Vec) { + // Get the name of the called binary + let name = bin_name(); + + // Infer subcommands + for (bin, subcmd) in INFER_COMMANDS.iter() { + if &name == bin { + args.insert(1, subcmd.into()); + break; + } } } diff --git a/src/config.rs b/src/config.rs index 8789968..9775596 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "infer-command")] +use std::collections::HashMap; + use ffsend_api::api::{DesiredVersion, Version}; /// The timeout for the Send client for generic requests, `0` to disable. @@ -15,3 +18,19 @@ pub const API_VERSION_DESIRED_DEFAULT: DesiredVersion = DesiredVersion::Assume(A pub const API_VERSION_ASSUME: Version = Version::V3; #[cfg(not(feature = "send3"))] pub const API_VERSION_ASSUME: Version = Version::V2; + +#[cfg(feature = "infer-command")] +lazy_static! { + /// Hashmap holding binary names to infer subcommands for. + /// + /// When the `ffsend` binary is called with such a name, the corresponding subcommand is + /// automatically inserted as argument. This also works when calling binaries through symbolic + /// or hard links. + pub static ref INFER_COMMANDS: HashMap<&'static str, &'static str> = { + let mut m = HashMap::new(); + m.insert("ffput", "upload"); + m.insert("ffget", "download"); + m.insert("ffdel", "delete"); + m + }; +} diff --git a/src/util.rs b/src/util.rs index a4835ce..471d8f9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -849,6 +849,8 @@ pub fn features_list() -> Vec<&'static str> { features.push("qrcode"); #[cfg(feature = "urlshorten")] features.push("urlshorten"); + #[cfg(feature = "infer-command")] + features.push("infer-command"); #[cfg(feature = "no-qcolor")] features.push("no-color"); #[cfg(feature = "send2")]