clean doc

This commit is contained in:
Clément DOUIN 2023-12-08 12:18:18 +01:00
parent fff11fbe20
commit ef3214f36f
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
52 changed files with 452 additions and 318 deletions

View file

@ -1,26 +1,24 @@
use clap::Parser;
/// The account name argument parser
/// The account name argument parser.
#[derive(Debug, Parser)]
pub struct AccountNameArg {
/// The name of the account
/// The name of the account.
///
/// The account names are taken from the table at the root level
/// of your TOML configuration file.
#[arg(value_name = "ACCOUNT")]
/// An account name corresponds to an entry in the table at the
/// root level of your TOML configuration file.
#[arg(name = "account_name", value_name = "ACCOUNT")]
pub name: String,
}
/// The account name flag parser
/// The account name flag parser.
#[derive(Debug, Parser)]
pub struct AccountNameFlag {
/// Override the default account
#[arg(
long = "account",
short = 'a',
name = "account-name",
value_name = "NAME",
global = true
)]
/// Override the default account.
///
/// An account name corresponds to an entry in the table at the
/// root level of your TOML configuration file.
#[arg(long = "account", short = 'a', global = true)]
#[arg(name = "account_name", value_name = "NAME")]
pub name: Option<String>,
}

View file

@ -15,26 +15,32 @@ use crate::{
printer::Printer,
};
/// Configure the given account
/// Configure an account.
///
/// This command is mostly used to define or reset passwords managed
/// by your global keyring. If you do not use the keyring system, you
/// can skip this command.
#[derive(Debug, Parser)]
pub struct AccountConfigureCommand {
#[command(flatten)]
pub account: AccountNameArg,
/// Force the account to reconfigure, even if it has already been
/// configured
/// Reset keyring passwords.
///
/// This argument will force passwords to be prompted again, then
/// saved to your global keyring.
#[arg(long, short)]
pub force: bool,
pub reset: bool,
}
impl AccountConfigureCommand {
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
info!("executing account configure command");
let (_, account_config) =
config.into_toml_account_config(Some(self.account.name.as_str()))?;
let account = &self.account.name;
let (_, account_config) = config.into_toml_account_config(Some(account))?;
if self.force {
if self.reset {
#[cfg(feature = "imap")]
if let Some(ref config) = account_config.imap {
let reset = match &config.auth {
@ -102,11 +108,8 @@ impl AccountConfigureCommand {
}
printer.print(format!(
"Account {} successfully {}configured!",
self.account.name,
if self.force { "re" } else { "" }
))?;
Ok(())
"Account {account} successfully {}configured!",
if self.reset { "re" } else { "" }
))
}
}

View file

@ -6,14 +6,17 @@ use crate::{
account::Accounts,
config::TomlConfig,
printer::{PrintTableOpts, Printer},
ui::arg::max_width::MaxTableWidthFlag,
ui::arg::max_width::TableMaxWidthFlag,
};
/// List all accounts
/// List all accounts.
///
/// This command lists all accounts defined in your TOML configuration
/// file.
#[derive(Debug, Parser)]
pub struct AccountListCommand {
#[command(flatten)]
pub table: MaxTableWidthFlag,
pub table: TableMaxWidthFlag,
}
impl AccountListCommand {
@ -31,9 +34,7 @@ impl AccountListCommand {
.unwrap_or(&Default::default()),
max_width: self.table.max_width,
},
)?;
Ok(())
)
}
}

View file

@ -11,18 +11,19 @@ use self::{
configure::AccountConfigureCommand, list::AccountListCommand, sync::AccountSyncCommand,
};
/// Subcommand to manage accounts
/// Manage accounts.
///
/// An account is a set of settings, identified by an account
/// name. Settings are directly taken from your TOML configuration
/// file.
#[derive(Debug, Subcommand)]
pub enum AccountSubcommand {
/// Configure an account
#[command(alias = "cfg")]
Configure(AccountConfigureCommand),
/// List all accounts
#[command(alias = "lst")]
List(AccountListCommand),
/// Synchronize an account locally
#[command()]
Sync(AccountSyncCommand),
}

View file

@ -32,30 +32,49 @@ const SUB_PROGRESS_DONE_STYLE: Lazy<ProgressStyle> = Lazy::new(|| {
ProgressStyle::with_template(" {prefix:.bold} \n {wide_bar:.green} {percent}% ").unwrap()
});
/// Synchronize an account.
///
/// This command allows you to synchronize all folders and emails
/// (including envelopes and messages) of an account into a local
/// Maildir folder.
#[derive(Debug, Parser)]
pub struct AccountSyncCommand {
#[command(flatten)]
pub account: AccountNameArg,
/// Run the synchronization without applying changes
/// Run the synchronization without applying any changes.
///
/// Instead, a report will be printed to stdout containing all the
/// changes the synchronization plan to do.
#[arg(long, short)]
pub dry_run: bool,
#[arg(long, short = 'f', value_name = "FOLDER", action = ArgAction::Append, conflicts_with = "exclude_folder", conflicts_with = "all_folders")]
/// Synchronize only specific folders.
///
/// Only the given folders will be synchronized (including
/// associated envelopes and messages). Useful when you need to
/// speed up the synchronization process. A good usecase is to
/// synchronize only the INBOX in order to quickly check for new
/// messages.
#[arg(long, short = 'f')]
#[arg(value_name = "FOLDER", action = ArgAction::Append)]
#[arg(conflicts_with = "exclude_folder", conflicts_with = "all_folders")]
pub include_folder: Vec<String>,
#[arg(long, short = 'x', value_name = "FOLDER", action = ArgAction::Append, conflicts_with = "include_folder", conflicts_with = "all_folders")]
/// Omit specific folders from the synchronization.
///
/// The given folders will be excluded from the synchronization
/// (including associated envelopes and messages). Useful when you
/// have heavy folders that you do not want to take care of, or to
/// speed up the synchronization process.
#[arg(long, short = 'x')]
#[arg(value_name = "FOLDER", action = ArgAction::Append)]
#[arg(conflicts_with = "include_folder", conflicts_with = "all_folders")]
pub exclude_folder: Vec<String>,
#[arg(
long,
short = 'A',
conflicts_with = "include_folder",
conflicts_with = "exclude_folder"
)]
/// Synchronize all exsting folders.
#[arg(long, short = 'A')]
#[arg(conflicts_with = "include_folder", conflicts_with = "exclude_folder")]
pub all_folders: bool,
}

View file

@ -1,19 +1,15 @@
use clap::Parser;
/// The disable cache flag parser
/// The disable cache flag parser.
#[derive(Debug, Parser)]
pub struct DisableCacheFlag {
/// Disable any sort of cache
pub struct CacheDisableFlag {
/// Disable any sort of cache.
///
/// The action depends on commands it apply on. For example, when
/// listing envelopes using the IMAP backend, this flag will
/// ensure that envelopes are fetched from the IMAP server and not
/// from the synchronized local Maildir.
#[arg(
long = "disable-cache",
alias = "no-cache",
name = "disable-cache",
global = true
)]
/// ensure that envelopes are fetched from the IMAP server rather
/// than the synchronized local Maildir.
#[arg(long = "disable-cache", alias = "no-cache", global = true)]
#[arg(name = "cache_disable")]
pub disable: bool,
}

View file

@ -19,14 +19,8 @@ use crate::{
};
#[derive(Parser, Debug)]
#[command(
name = "himalaya",
author,
version,
about,
propagate_version = true,
infer_subcommands = true
)]
#[command(name = "himalaya", author, version, about)]
#[command(propagate_version = true, infer_subcommands = true)]
pub struct Cli {
#[command(subcommand)]
pub command: HimalayaCommand,
@ -83,46 +77,38 @@ pub struct Cli {
#[derive(Subcommand, Debug)]
pub enum HimalayaCommand {
/// Manage accounts
#[command(subcommand)]
#[command(alias = "accounts")]
Account(AccountSubcommand),
/// Manage folders
#[command(subcommand)]
#[command(alias = "folders")]
Folder(FolderSubcommand),
/// Manage envelopes
#[command(subcommand)]
#[command(alias = "envelopes")]
Envelope(EnvelopeSubcommand),
/// Manage flags
#[command(subcommand)]
#[command(alias = "flags")]
Flag(FlagSubcommand),
/// Manage messages
#[command(subcommand)]
#[command(alias = "messages", alias = "msgs", alias = "msg")]
Message(MessageSubcommand),
/// Manage templates
#[command(subcommand)]
#[command(alias = "attachments")]
Attachment(AttachmentSubcommand),
#[command(subcommand)]
#[command(alias = "templates", alias = "tpls", alias = "tpl")]
Template(TemplateSubcommand),
/// Manage attachments
#[command(subcommand)]
Attachment(AttachmentSubcommand),
/// Generate manual pages to a directory
#[command(arg_required_else_help = true)]
#[command(alias = "manuals", alias = "mans")]
Manual(ManualGenerateCommand),
/// Print completion script for a shell to stdout
#[command(arg_required_else_help = true)]
#[command(alias = "completions")]
Completion(CompletionGenerateCommand),
@ -136,8 +122,8 @@ impl HimalayaCommand {
Self::Envelope(cmd) => cmd.execute(printer, config).await,
Self::Flag(cmd) => cmd.execute(printer, config).await,
Self::Message(cmd) => cmd.execute(printer, config).await,
Self::Template(cmd) => cmd.execute(printer, config).await,
Self::Attachment(cmd) => cmd.execute(printer, config).await,
Self::Template(cmd) => cmd.execute(printer, config).await,
Self::Manual(cmd) => cmd.execute(printer).await,
Self::Completion(cmd) => cmd.execute(printer).await,
}

View file

@ -6,10 +6,14 @@ use std::io;
use crate::{cli::Cli, printer::Printer};
/// Print completion script for a shell to stdout
/// Print completion script for a shell to stdout.
///
/// This command allows you to generate completion script for a given
/// shell. The script is printed to the standard output. If you want
/// to write it to a file, just use unix redirection.
#[derive(Debug, Parser)]
pub struct CompletionGenerateCommand {
/// Shell for which completion script should be generated for
/// Shell for which completion script should be generated for.
#[arg(value_parser = value_parser!(Shell))]
pub shell: Shell,
}

View file

@ -121,10 +121,7 @@ impl TomlConfig {
match path.map(Into::into) {
Some(ref path) if path.exists() => Self::from_path(path),
Some(path) => Self::from_wizard(path).await,
None => match Self::first_valid_default_path() {
Some(path) => Self::from_path(&path),
None => Self::from_wizard(Self::default_path()?).await,
},
None => Self::from_default_paths().await,
}
}

View file

@ -1,17 +1,17 @@
use clap::Parser;
/// The envelope id argument parser
/// The envelope id argument parser.
#[derive(Debug, Parser)]
pub struct EnvelopeIdArg {
/// The envelope id
/// The envelope id.
#[arg(value_name = "ID", required = true)]
pub id: usize,
}
/// The envelopes ids arguments parser
/// The envelopes ids arguments parser.
#[derive(Debug, Parser)]
pub struct EnvelopeIdsArgs {
/// The list of envelopes ids
/// The list of envelopes ids.
#[arg(value_name = "ID", required = true)]
pub ids: Vec<usize>,
}

View file

@ -5,35 +5,43 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::arg::name::FolderNameOptionalArg,
printer::{PrintTableOpts, Printer},
ui::arg::max_width::MaxTableWidthFlag,
ui::arg::max_width::TableMaxWidthFlag,
};
/// List all envelopes from a folder
/// List all envelopes.
///
/// This command allows you to list all envelopes included in the
/// given folder.
#[derive(Debug, Parser)]
pub struct EnvelopeListCommand {
#[command(flatten)]
pub folder: FolderNameOptionalArg,
/// The page number
/// The page number.
///
/// The page number starts from 1 (which is the default). Giving a
/// page number to big will result in a out of bound error.
#[arg(long, short, value_name = "NUMBER", default_value = "1")]
pub page: usize,
/// The page size
/// The page size.
///
/// Determine the amount of envelopes a page should contain.
#[arg(long, short = 's', value_name = "NUMBER")]
pub page_size: Option<usize>,
#[command(flatten)]
pub table: MaxTableWidthFlag,
pub table: TableMaxWidthFlag,
#[command(flatten)]
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
}
impl EnvelopeListCommand {

View file

@ -7,10 +7,14 @@ use crate::{config::TomlConfig, printer::Printer};
use self::list::EnvelopeListCommand;
/// Subcommand to manage envelopes
/// Manage envelopes.
///
/// An envelope is a small representation of a message. It contains an
/// identifier (given by the backend), some flags as well as few
/// headers from the message itself. This subcommand allows you to
/// manage them.
#[derive(Debug, Subcommand)]
pub enum EnvelopeSubcommand {
/// List all envelopes from a folder
#[command(alias = "lst")]
List(EnvelopeListCommand),
}

View file

@ -2,10 +2,10 @@ use clap::Parser;
use email::flag::{Flag, Flags};
use log::debug;
/// The ids and/or flags arguments parser
/// The ids and/or flags arguments parser.
#[derive(Debug, Parser)]
pub struct IdsAndFlagsArgs {
/// The list of ids and/or flags
/// The list of ids and/or flags.
///
/// Every argument that can be parsed as an integer is considered
/// an id, otherwise it is considered as a flag.

View file

@ -5,14 +5,17 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
folder::arg::name::FolderNameArg,
printer::Printer,
};
/// Add flag(s) to an envelope
/// Add flag(s) to an envelope.
///
/// This command allows you to attach the given flag(s) to the given
/// envelope(s).
#[derive(Debug, Parser)]
pub struct FlagAddCommand {
#[command(flatten)]
@ -22,10 +25,10 @@ pub struct FlagAddCommand {
pub args: IdsAndFlagsArgs,
#[command(flatten)]
pub account: AccountNameFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub account: AccountNameFlag,
}
impl FlagAddCommand {

View file

@ -9,20 +9,22 @@ use crate::{config::TomlConfig, printer::Printer};
use self::{add::FlagAddCommand, remove::FlagRemoveCommand, set::FlagSetCommand};
/// Subcommand to manage flags
/// Manage flags.
///
/// A flag is a tag associated to an envelope. Existing flags are
/// seen, answered, flagged, deleted, draft. Other flags are
/// considered custom, which are not always supported (the
/// synchronization does not take care of them yet).
#[derive(Debug, Subcommand)]
pub enum FlagSubcommand {
/// Add flag(s) to an envelope
#[command(arg_required_else_help = true)]
#[command(alias = "create")]
Add(FlagAddCommand),
/// Replace flag(s) of an envelope
#[command(arg_required_else_help = true)]
#[command(aliases = ["update", "change", "replace"])]
Set(FlagSetCommand),
/// Remove flag(s) from an envelope
#[command(arg_required_else_help = true)]
#[command(aliases = ["rm", "delete", "del"])]
Remove(FlagRemoveCommand),

View file

@ -5,14 +5,17 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
folder::arg::name::FolderNameArg,
printer::Printer,
};
/// Remove flag(s) from an envelope
/// Remove flag(s) from an envelope.
///
/// This command allows you to remove the given flag(s) from the given
/// envelope(s).
#[derive(Debug, Parser)]
pub struct FlagRemoveCommand {
#[command(flatten)]
@ -22,10 +25,10 @@ pub struct FlagRemoveCommand {
pub args: IdsAndFlagsArgs,
#[command(flatten)]
pub account: AccountNameFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub account: AccountNameFlag,
}
impl FlagRemoveCommand {

View file

@ -5,14 +5,17 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
flag::arg::ids_and_flags::{into_tuple, IdsAndFlagsArgs},
folder::arg::name::FolderNameArg,
printer::Printer,
};
/// Replace flag(s) of an envelope
/// Replace flag(s) of an envelope.
///
/// This command allows you to replace existing flags of the given
/// envelope(s) with the given flag(s).
#[derive(Debug, Parser)]
pub struct FlagSetCommand {
#[command(flatten)]
@ -22,10 +25,10 @@ pub struct FlagSetCommand {
pub args: IdsAndFlagsArgs,
#[command(flatten)]
pub account: AccountNameFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub account: AccountNameFlag,
}
impl FlagSetCommand {

View file

@ -1,22 +1,22 @@
use clap::Parser;
use std::ops::Deref;
/// The raw message body argument parser
/// The raw message body argument parser.
#[derive(Debug, Parser)]
pub struct BodyRawArg {
/// Prefill the template with a custom body
#[arg(raw = true, required = false)]
#[arg(name = "body-raw", value_delimiter = ' ')]
pub struct MessageRawBodyArg {
/// Prefill the template with a custom body.
#[arg(trailing_var_arg = true)]
#[arg(name = "body-raw")]
pub raw: Vec<String>,
}
impl BodyRawArg {
impl MessageRawBodyArg {
pub fn raw(self) -> String {
self.raw.join(" ").replace("\r", "").replace("\n", "\r\n")
}
}
impl Deref for BodyRawArg {
impl Deref for MessageRawBodyArg {
type Target = Vec<String>;
fn deref(&self) -> &Self::Target {

View file

@ -1,9 +1,9 @@
use clap::Parser;
/// The envelope id argument parser
/// The envelope id argument parser.
#[derive(Debug, Parser)]
pub struct HeaderRawArgs {
/// Prefill the template with custom headers
/// Prefill the template with custom headers.
///
/// A raw header should follow the pattern KEY:VAL.
#[arg(long = "header", short = 'H', required = false)]

View file

@ -1,9 +1,12 @@
use clap::Parser;
/// The reply to all argument parser
/// The reply to all argument parser.
#[derive(Debug, Parser)]
pub struct MessageReplyAllArg {
/// Reply to all recipients
/// Reply to all recipients.
///
/// This argument will add all recipients for the To and Cc
/// headers.
#[arg(long, short = 'A')]
pub all: bool,
}

View file

@ -5,12 +5,15 @@ use std::fs;
use uuid::Uuid;
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg,
printer::Printer,
};
/// Download attachments of a message
/// Download all attachments for the given message.
///
/// This command allows you to download all attachments found for the
/// given message to your downloads directory.
#[derive(Debug, Parser)]
pub struct AttachmentDownloadCommand {
#[command(flatten)]
@ -20,7 +23,7 @@ pub struct AttachmentDownloadCommand {
pub envelopes: EnvelopeIdsArgs,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -7,10 +7,13 @@ use crate::{config::TomlConfig, printer::Printer};
use self::download::AttachmentDownloadCommand;
/// Subcommand dedicated to attachments
/// Manage attachments.
///
/// A message body can be composed of multiple MIME parts. An
/// attachment is the representation of a binary part of a message
/// body.
#[derive(Debug, Subcommand)]
pub enum AttachmentSubcommand {
/// Download all attachments of one or more messages
#[command(arg_required_else_help = true)]
Download(AttachmentDownloadCommand),
}

View file

@ -5,14 +5,14 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdsArgs,
folder::arg::name::{SourceFolderNameArg, TargetFolderNameArg},
printer::Printer,
};
/// Copy a message from a source folder to a target folder
/// Copy a message from a source folder to a target folder.
#[derive(Debug, Parser)]
pub struct MessageCopyCommand {
#[command(flatten)]
@ -25,7 +25,7 @@ pub struct MessageCopyCommand {
pub envelopes: EnvelopeIdsArgs,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -3,12 +3,17 @@ use clap::Parser;
use log::info;
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg,
printer::Printer,
};
/// Delete a message from a folder
/// Mark as deleted a message from a folder.
///
/// This command does not really delete the message: if the given
/// folder points to the trash folder, it adds the "deleted" flag to
/// its envelope, otherwise it moves it to the trash folder. Only the
/// expunge folder command truly deletes messages.
#[derive(Debug, Parser)]
pub struct MessageDeleteCommand {
#[command(flatten)]
@ -18,7 +23,7 @@ pub struct MessageDeleteCommand {
pub envelopes: EnvelopeIdsArgs,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -7,16 +7,21 @@ use std::io::{self, BufRead};
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdArg,
folder::arg::name::FolderNameArg,
message::arg::{body::BodyRawArg, header::HeaderRawArgs},
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs},
printer::Printer,
ui::editor,
};
/// Forward a new message
/// Forward a message.
///
/// This command allows you to forward the given message using the
/// editor defined in your environment variable $EDITOR. When the
/// edition process finishes, you can choose between saving or sending
/// the final message.
#[derive(Debug, Parser)]
pub struct MessageForwardCommand {
#[command(flatten)]
@ -25,18 +30,14 @@ pub struct MessageForwardCommand {
#[command(flatten)]
pub envelope: EnvelopeIdArg,
/// Forward to all recipients
#[arg(long, short = 'A')]
pub all: bool,
#[command(flatten)]
pub headers: HeaderRawArgs,
#[command(flatten)]
pub body: BodyRawArg,
pub body: MessageRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -1,20 +1,30 @@
use anyhow::Result;
use clap::Parser;
use log::info;
use log::{debug, info};
use mail_builder::MessageBuilder;
use url::Url;
use crate::{backend::Backend, config::TomlConfig, printer::Printer, ui::editor};
/// Parse and edit a message from a mailto URL string
/// Parse and edit a message from a mailto URL string.
///
/// This command allows you to edit a message from the mailto format
/// using the editor defined in your environment variable
/// $EDITOR. When the edition process finishes, you can choose between
/// saving or sending the final message.
#[derive(Debug, Parser)]
pub struct MessageMailtoCommand {
/// The mailto url
/// The mailto url.
#[arg()]
pub url: Url,
}
impl MessageMailtoCommand {
pub fn new(url: &str) -> Result<Self> {
let url = Url::parse(url)?;
Ok(Self { url })
}
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
info!("executing message mailto command");
@ -23,17 +33,27 @@ impl MessageMailtoCommand {
let backend = Backend::new(toml_account_config, account_config.clone(), true).await?;
let mut builder = MessageBuilder::new().to(self.url.path());
let mut body = String::new();
for (key, val) in self.url.query_pairs() {
match key.to_lowercase().as_bytes() {
b"cc" => builder = builder.cc(val.to_string()),
b"bcc" => builder = builder.bcc(val.to_string()),
b"subject" => builder = builder.subject(val),
b"body" => builder = builder.text_body(val),
b"body" => body += &val,
_ => (),
}
}
match account_config.signature() {
Ok(Some(ref signature)) => builder = builder.text_body(body + "\n\n" + signature),
Ok(None) => builder = builder.text_body(body),
Err(err) => {
debug!("cannot add signature to mailto message, skipping it: {err}");
debug!("{err:?}");
}
}
let tpl = account_config
.generate_tpl_interpreter()
.with_show_only_headers(account_config.email_writing_headers())

View file

@ -21,47 +21,42 @@ use self::{
write::MessageWriteCommand,
};
/// Subcommand to manage messages
/// Manage messages.
///
/// A message is the content of an email. It is composed of headers
/// (located at the top of the message) and a body (located at the
/// bottom of the message). Both are separated by two new lines. This
/// subcommand allows you to manage them.
#[derive(Debug, Subcommand)]
pub enum MessageSubcommand {
/// Read a message
#[command(arg_required_else_help = true)]
Read(MessageReadCommand),
/// Write a new message
#[command(alias = "new", alias = "compose")]
#[command(alias = "add", alias = "create", alias = "new", alias = "compose")]
Write(MessageWriteCommand),
/// Reply to a message
#[command()]
Reply(MessageReplyCommand),
/// Forward a message
#[command(alias = "fwd")]
Forward(MessageForwardCommand),
/// Parse and edit a message from a mailto URL string
#[command()]
Mailto(MessageMailtoCommand),
/// Save a message to a folder
#[command(arg_required_else_help = true)]
#[command(alias = "add", alias = "create")]
Save(MessageSaveCommand),
/// Send a message
#[command(arg_required_else_help = true)]
Send(MessageSendCommand),
/// Copy a message from a source folder to a target folder
#[command(arg_required_else_help = true)]
Copy(MessageCopyCommand),
/// Move a message from a source folder to a target folder
#[command(arg_required_else_help = true)]
Move(MessageMoveCommand),
/// Delete a message from a folder
#[command(arg_required_else_help = true)]
Delete(MessageDeleteCommand),
}

View file

@ -5,14 +5,14 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdsArgs,
folder::arg::name::{SourceFolderNameArg, TargetFolderNameArg},
printer::Printer,
};
/// Move a message from a source folder to a target folder
/// Move a message from a source folder to a target folder.
#[derive(Debug, Parser)]
pub struct MessageMoveCommand {
#[command(flatten)]
@ -25,7 +25,7 @@ pub struct MessageMoveCommand {
pub envelopes: EnvelopeIdsArgs,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -4,12 +4,14 @@ use log::info;
use mml::message::FilterParts;
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, envelope::arg::ids::EnvelopeIdsArgs, folder::arg::name::FolderNameArg,
printer::Printer,
};
/// Read a message from a folder
/// Read a message.
///
/// This command allows you to read a message.
#[derive(Debug, Parser)]
pub struct MessageReadCommand {
#[command(flatten)]
@ -18,18 +20,18 @@ pub struct MessageReadCommand {
#[command(flatten)]
pub envelopes: EnvelopeIdsArgs,
/// Read the raw version of the message
/// Read the raw version of the given message.
///
/// The raw message represents the message as it is on the
/// backend, unedited: not decoded nor decrypted. This is useful
/// for debugging faulty messages, but also for
/// The raw message represents the headers and the body as it is
/// on the backend, unedited: not decoded nor decrypted. This is
/// useful for debugging faulty messages, but also for
/// saving/sending/transfering messages.
#[arg(long, short)]
#[arg(conflicts_with = "no_headers")]
#[arg(conflicts_with = "headers")]
pub raw: bool,
/// Read only body of text/html parts
/// Read only body of text/html parts.
///
/// This argument is useful when you need to read the HTML version
/// of a message. Combined with --no-headers, you can write it to
@ -38,7 +40,7 @@ pub struct MessageReadCommand {
#[arg(conflicts_with = "raw")]
pub html: bool,
/// Read only the body of the message
/// Read only the body of the message.
///
/// All headers will be removed from the message.
#[arg(long)]
@ -47,7 +49,7 @@ pub struct MessageReadCommand {
pub no_headers: bool,
/// List of headers that should be visible at the top of the
/// message
/// message.
///
/// If a given header is not found in the message, it will not be
/// visible. If no header is given, defaults to the one set up in
@ -58,7 +60,7 @@ pub struct MessageReadCommand {
pub headers: Vec<String>,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -8,16 +8,21 @@ use std::io::{self, BufRead};
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdArg,
folder::arg::name::FolderNameArg,
message::arg::{body::BodyRawArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
printer::Printer,
ui::editor,
};
/// Reply a new message
/// Reply to a message.
///
/// This command allows you to reply to the given message using the
/// editor defined in your environment variable $EDITOR. When the
/// edition process finishes, you can choose between saving or sending
/// the final message.
#[derive(Debug, Parser)]
pub struct MessageReplyCommand {
#[command(flatten)]
@ -33,10 +38,10 @@ pub struct MessageReplyCommand {
pub headers: HeaderRawArgs,
#[command(flatten)]
pub body: BodyRawArg,
pub body: MessageRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -5,22 +5,24 @@ use log::info;
use std::io::{self, BufRead};
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, folder::arg::name::FolderNameArg, message::arg::body::MessageRawBodyArg,
printer::Printer,
};
/// Save a message to a folder
/// Save a message to a folder.
///
/// This command allows you to add a raw message to the given folder.
#[derive(Debug, Parser)]
pub struct MessageSaveCommand {
#[command(flatten)]
pub folder: FolderNameArg,
/// The raw message to save
#[arg(value_name = "MESSAGE", raw = true)]
pub raw: String,
#[command(flatten)]
pub body: MessageRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,
@ -33,7 +35,6 @@ impl MessageSaveCommand {
let folder = &self.folder.name;
let account = self.account.name.as_ref().map(String::as_str);
let cache = self.cache.disable;
let raw_msg = &self.raw;
let (toml_account_config, account_config) =
config.clone().into_account_configs(account, cache)?;
@ -41,8 +42,8 @@ impl MessageSaveCommand {
let is_tty = atty::is(Stream::Stdin);
let is_json = printer.is_json();
let raw_email = if is_tty || is_json {
raw_msg.replace("\r", "").replace("\n", "\r\n")
let msg = if is_tty || is_json {
self.body.raw()
} else {
io::stdin()
.lock()
@ -52,9 +53,7 @@ impl MessageSaveCommand {
.join("\r\n")
};
backend
.add_raw_message(folder, raw_email.as_bytes())
.await?;
backend.add_raw_message(folder, msg.as_bytes()).await?;
printer.print(format!("Message successfully saved to {folder}!"))
}

View file

@ -6,19 +6,21 @@ use log::info;
use std::io::{self, BufRead};
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
config::TomlConfig, printer::Printer,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, message::arg::body::MessageRawBodyArg, printer::Printer,
};
/// Send a message from a folder
/// Send a message.
///
/// This command allows you to send a raw message and to save a copy
/// to your send folder.
#[derive(Debug, Parser)]
pub struct MessageSendCommand {
/// The raw message to send
#[arg(value_name = "MESSAGE", raw = true)]
pub raw: String,
#[command(flatten)]
pub body: MessageRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,
@ -30,7 +32,6 @@ impl MessageSendCommand {
let account = self.account.name.as_ref().map(String::as_str);
let cache = self.cache.disable;
let raw_msg = &self.raw;
let (toml_account_config, account_config) =
config.clone().into_account_configs(account, cache)?;
@ -39,8 +40,8 @@ impl MessageSendCommand {
let is_tty = atty::is(Stream::Stdin);
let is_json = printer.is_json();
let raw_email = if is_tty || is_json {
raw_msg.replace("\r", "").replace("\n", "\r\n")
let msg = if is_tty || is_json {
self.body.raw()
} else {
io::stdin()
.lock()
@ -50,11 +51,11 @@ impl MessageSendCommand {
.join("\r\n")
};
backend.send_raw_message(raw_email.as_bytes()).await?;
backend.send_raw_message(msg.as_bytes()).await?;
if account_config.email_sending_save_copy.unwrap_or_default() {
backend
.add_raw_message_with_flag(&folder, raw_email.as_bytes(), Flag::Seen)
.add_raw_message_with_flag(&folder, msg.as_bytes(), Flag::Seen)
.await?;
printer.print(format!("Message successfully sent and saved to {folder}!"))

View file

@ -8,24 +8,29 @@ use std::io::{self, BufRead};
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
message::arg::{body::BodyRawArg, header::HeaderRawArgs},
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs},
printer::Printer,
ui::editor,
};
/// Write a new message
/// Write a new message.
///
/// This command allows you to write a new message using the editor
/// defined in your environment variable $EDITOR. When the edition
/// process finishes, you can choose between saving or sending the
/// final message.
#[derive(Debug, Parser)]
pub struct MessageWriteCommand {
#[command(flatten)]
pub headers: HeaderRawArgs,
#[command(flatten)]
pub body: BodyRawArg,
pub body: MessageRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -0,0 +1,25 @@
use clap::Parser;
use std::ops::Deref;
/// The raw template body argument parser.
#[derive(Debug, Parser)]
pub struct TemplateRawBodyArg {
/// Prefill the template with a custom body.
#[arg(trailing_var_arg = true)]
#[arg(name = "body-raw")]
pub raw: Vec<String>,
}
impl TemplateRawBodyArg {
pub fn raw(self) -> String {
self.raw.join(" ").replace("\r", "")
}
}
impl Deref for TemplateRawBodyArg {
type Target = Vec<String>;
fn deref(&self) -> &Self::Target {
&self.raw
}
}

View file

@ -0,0 +1 @@
pub mod body;

View file

@ -5,15 +5,19 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdArg,
folder::arg::name::FolderNameArg,
message::arg::{body::BodyRawArg, header::HeaderRawArgs},
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs},
printer::Printer,
};
/// Generate a forward message template
/// Generate a template for forwarding a message.
///
/// The generated template is prefilled with your email in a From
/// header as well as your signature. The forwarded message is also
/// prefilled in the body of the template, prefixed by a separator.
#[derive(Debug, Parser)]
pub struct TemplateForwardCommand {
#[command(flatten)]
@ -26,10 +30,10 @@ pub struct TemplateForwardCommand {
pub headers: HeaderRawArgs,
#[command(flatten)]
pub body: BodyRawArg,
pub body: MessageRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -14,28 +14,31 @@ use self::{
send::TemplateSendCommand, write::TemplateWriteCommand,
};
/// Subcommand to manage templates
/// Manage templates.
///
/// A template is an editable version of a message (headers +
/// body). It uses a specific language called MML that allows you to
/// attach file or encrypt content. This subcommand allows you manage
/// them.
///
/// You can learn more about MML at
/// <https://crates.io/crates/mml-lib>.
#[derive(Debug, Subcommand)]
pub enum TemplateSubcommand {
/// Write a new template
#[command(alias = "new", alias = "compose")]
#[command(alias = "create", alias = "new", alias = "compose")]
Write(TemplateWriteCommand),
/// Reply to a template
#[command()]
#[command(arg_required_else_help = true)]
Reply(TemplateReplyCommand),
/// Generate a template for forwarding an email
#[command(arg_required_else_help = true)]
#[command(alias = "fwd")]
Forward(TemplateForwardCommand),
/// Save a template to a folder
#[command(arg_required_else_help = true)]
#[command(alias = "add", alias = "create")]
#[command(alias = "add")]
Save(TemplateSaveCommand),
/// Send a template
#[command(arg_required_else_help = true)]
#[command()]
Send(TemplateSendCommand),
}

View file

@ -5,15 +5,20 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
envelope::arg::ids::EnvelopeIdArg,
folder::arg::name::FolderNameArg,
message::arg::{body::BodyRawArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
message::arg::{body::MessageRawBodyArg, header::HeaderRawArgs, reply::MessageReplyAllArg},
printer::Printer,
};
/// Generate a reply message template
/// Generate a template for replying to a message.
///
/// The generated template is prefilled with your email in a From
/// header as well as your signature. The replied message is also
/// prefilled in the body of the template, with all lines prefixed by
/// the symbol greater than ">".
#[derive(Debug, Parser)]
pub struct TemplateReplyCommand {
#[command(flatten)]
@ -29,10 +34,10 @@ pub struct TemplateReplyCommand {
pub headers: HeaderRawArgs,
#[command(flatten)]
pub body: BodyRawArg,
pub body: MessageRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -6,22 +6,27 @@ use mml::MmlCompilerBuilder;
use std::io::{self, BufRead};
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, email::template::arg::body::TemplateRawBodyArg,
folder::arg::name::FolderNameArg, printer::Printer,
};
/// Save a template to a folder
/// Save a template to a folder.
///
/// This command allows you to save a template to the given
/// folder. The template is compiled into a MIME message before being
/// saved to the folder. If you want to save a raw message, use the
/// message save command instead.
#[derive(Debug, Parser)]
pub struct TemplateSaveCommand {
#[command(flatten)]
pub folder: FolderNameArg,
/// The raw template to save
#[arg(raw = true, value_delimiter = ' ')]
pub raw: Vec<String>,
#[command(flatten)]
pub body: TemplateRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,
@ -42,7 +47,7 @@ impl TemplateSaveCommand {
let is_tty = atty::is(Stream::Stdin);
let is_json = printer.is_json();
let tpl = if is_tty || is_json {
self.raw.join(" ").replace("\r", "")
self.body.raw()
} else {
io::stdin()
.lock()

View file

@ -7,19 +7,23 @@ use mml::MmlCompilerBuilder;
use std::io::{self, BufRead};
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
config::TomlConfig, printer::Printer,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, email::template::arg::body::TemplateRawBodyArg, printer::Printer,
};
/// Send a template
/// Send a template.
///
/// This command allows you to send a template and save a copy to the
/// sent folder. The template is compiled into a MIME message before
/// being sent. If you want to send a raw message, use the message
/// send command instead.
#[derive(Debug, Parser)]
pub struct TemplateSendCommand {
/// The raw template to save
#[arg(raw = true, value_delimiter = ' ')]
pub raw: Vec<String>,
#[command(flatten)]
pub body: TemplateRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,
@ -40,7 +44,7 @@ impl TemplateSendCommand {
let is_tty = atty::is(Stream::Stdin);
let is_json = printer.is_json();
let tpl = if is_tty || is_json {
self.raw.join(" ").replace("\r", "")
self.body.raw()
} else {
io::stdin()
.lock()

View file

@ -4,24 +4,25 @@ use email::message::Message;
use log::info;
use crate::{
account::arg::name::AccountNameFlag,
cache::arg::disable::DisableCacheFlag,
config::TomlConfig,
message::arg::{body::BodyRawArg, header::HeaderRawArgs},
account::arg::name::AccountNameFlag, cache::arg::disable::CacheDisableFlag, config::TomlConfig,
email::template::arg::body::TemplateRawBodyArg, message::arg::header::HeaderRawArgs,
printer::Printer,
};
/// Write a new template
/// Generate a template for writing a new message from scratch.
///
/// The generated template is prefilled with your email in a From
/// header as well as your signature.
#[derive(Debug, Parser)]
pub struct TemplateWriteCommand {
#[command(flatten)]
pub headers: HeaderRawArgs,
#[command(flatten)]
pub body: BodyRawArg,
pub body: TemplateRawBodyArg,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,

View file

@ -1 +1,2 @@
pub mod arg;
pub mod command;

View file

@ -1,34 +1,34 @@
use clap::Parser;
use email::account::config::DEFAULT_INBOX_FOLDER;
/// The folder name argument parser
/// The folder name argument parser.
#[derive(Debug, Parser)]
pub struct FolderNameArg {
/// The name of the folder
#[arg(name = "folder-name", value_name = "FOLDER")]
/// The name of the folder.
#[arg(name = "folder_name", value_name = "FOLDER")]
pub name: String,
}
/// The optional folder name argument parser
/// The optional folder name argument parser.
#[derive(Debug, Parser)]
pub struct FolderNameOptionalArg {
/// The name of the folder
#[arg(name = "folder-name", value_name = "FOLDER", default_value = DEFAULT_INBOX_FOLDER)]
/// The name of the folder.
#[arg(name = "folder_name", value_name = "FOLDER", default_value = DEFAULT_INBOX_FOLDER)]
pub name: String,
}
/// The source folder name argument parser
/// The source folder name argument parser.
#[derive(Debug, Parser)]
pub struct SourceFolderNameArg {
/// The name of the source folder
/// The name of the source folder.
#[arg(name = "from-folder-name", value_name = "FROM")]
pub name: String,
}
/// The target folder name argument parser
/// The target folder name argument parser.
#[derive(Debug, Parser)]
pub struct TargetFolderNameArg {
/// The name of the target folder
/// The name of the target folder.
#[arg(name = "to-folder-name", value_name = "TO")]
pub name: String,
}

View file

@ -3,21 +3,24 @@ use clap::Parser;
use log::info;
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer,
};
/// Create a new folder
/// Create a new folder.
///
/// This command allows you to create a new folder using the given
/// name.
#[derive(Debug, Parser)]
pub struct FolderCreateCommand {
#[command(flatten)]
pub folder: FolderNameArg,
#[command(flatten)]
pub account: AccountNameFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub account: AccountNameFlag,
}
impl FolderCreateCommand {

View file

@ -5,24 +5,24 @@ use log::info;
use std::process;
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer,
};
/// Delete a folder
/// Delete a folder.
///
/// All emails from a given folder are definitely deleted. The folder
/// is also deleted after execution of the command.
/// All emails from the given folder are definitely deleted. The
/// folder is also deleted after execution of the command.
#[derive(Debug, Parser)]
pub struct FolderDeleteCommand {
#[command(flatten)]
pub folder: FolderNameArg,
#[command(flatten)]
pub account: AccountNameFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub account: AccountNameFlag,
}
impl FolderDeleteCommand {

View file

@ -3,14 +3,14 @@ use clap::Parser;
use log::info;
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer,
};
/// Expunge a folder
/// Expunge a folder.
///
/// The concept of expunging is similar to the IMAP one: it definitely
/// deletes emails from a given folder that contain the "deleted"
/// deletes emails from the given folder that contain the "deleted"
/// flag.
#[derive(Debug, Parser)]
pub struct FolderExpungeCommand {
@ -18,10 +18,10 @@ pub struct FolderExpungeCommand {
pub folder: FolderNameArg,
#[command(flatten)]
pub account: AccountNameFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub account: AccountNameFlag,
}
impl FolderExpungeCommand {

View file

@ -5,24 +5,26 @@ use log::info;
use crate::{
account::arg::name::AccountNameFlag,
backend::Backend,
cache::arg::disable::DisableCacheFlag,
cache::arg::disable::CacheDisableFlag,
config::TomlConfig,
folder::Folders,
printer::{PrintTableOpts, Printer},
ui::arg::max_width::MaxTableWidthFlag,
ui::arg::max_width::TableMaxWidthFlag,
};
/// List all folders
/// List all folders.
///
/// This command allows you to list all exsting folders.
#[derive(Debug, Parser)]
pub struct FolderListCommand {
#[command(flatten)]
pub table: MaxTableWidthFlag,
pub table: TableMaxWidthFlag,
#[command(flatten)]
pub cache: CacheDisableFlag,
#[command(flatten)]
pub account: AccountNameFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
}
impl FolderListCommand {

View file

@ -14,26 +14,24 @@ use self::{
list::FolderListCommand, purge::FolderPurgeCommand,
};
/// Subcommand to manage accounts
/// Manage folders.
///
/// A folder (AKA mailbox, or directory) contains envelopes and
/// messages. This subcommand allows you to manage them.
#[derive(Debug, Subcommand)]
pub enum FolderSubcommand {
/// Create a new folder
#[command(alias = "add")]
#[command(alias = "add", alias = "new")]
Create(FolderCreateCommand),
/// List all folders
#[command(alias = "lst")]
List(FolderListCommand),
/// Expunge a folder
#[command()]
Expunge(FolderExpungeCommand),
/// Purge a folder
#[command()]
Purge(FolderPurgeCommand),
/// Delete a folder
#[command(alias = "remove", alias = "rm")]
Delete(FolderDeleteCommand),
}

View file

@ -5,24 +5,24 @@ use log::info;
use std::process;
use crate::{
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag,
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer,
};
/// Purge a folder
/// Purge a folder.
///
/// All emails from a given folder are definitely deleted. The purged
/// folder will remain empty after executing of the command.
/// All emails from the given folder are definitely deleted. The
/// purged folder will remain empty after execution of the command.
#[derive(Debug, Parser)]
pub struct FolderPurgeCommand {
#[command(flatten)]
pub folder: FolderNameArg,
#[command(flatten)]
pub account: AccountNameFlag,
pub cache: CacheDisableFlag,
#[command(flatten)]
pub cache: DisableCacheFlag,
pub account: AccountNameFlag,
}
impl FolderPurgeCommand {

View file

@ -1,7 +1,10 @@
use anyhow::Result;
use clap::Parser;
use env_logger::{Builder as LoggerBuilder, Env, DEFAULT_FILTER_ENV};
use himalaya::{cli::Cli, config::TomlConfig, printer::StdoutPrinter};
use himalaya::{
cli::Cli, config::TomlConfig, message::command::mailto::MessageMailtoCommand,
printer::StdoutPrinter,
};
use log::{debug, warn};
use std::env;
@ -9,7 +12,7 @@ use std::env;
async fn main() -> Result<()> {
#[cfg(not(target_os = "windows"))]
if let Err((_, err)) = coredump::register_panic_handler() {
warn!("cannot register custom panic handler: {err}");
warn!("cannot register coredump panic handler: {err}");
debug!("{err:?}");
}
@ -18,15 +21,15 @@ async fn main() -> Result<()> {
.format_timestamp(None)
.init();
let raw_args: Vec<String> = env::args().collect();
if raw_args.len() > 1 && raw_args[1].starts_with("mailto:") {
// TODO
// let cmd = MessageMailtoCommand::command()
// .no_binary_name(true)
// .try_get_matches_from([&raw_args[1]]);
// match cmd {
// Ok(m) => m.exec
// }
// if the first argument starts by "mailto:", execute straight the
// mailto message command
if let Some(ref url) = env::args().nth(1).filter(|arg| arg.starts_with("mailto:")) {
let mut printer = StdoutPrinter::default();
let config = TomlConfig::from_default_paths().await?;
return MessageMailtoCommand::new(url)?
.execute(&mut printer, &config)
.await;
}
let cli = Cli::parse();

View file

@ -7,10 +7,15 @@ use std::{fs, path::PathBuf};
use crate::{cli::Cli, printer::Printer};
/// Generate manual pages to a directory
/// Generate manual pages to a directory.
///
/// This command allows you to generate manual pages (following the
/// man page format) to the given directory. If the directory does not
/// exist, it will be created. Any existing man pages will be
/// overriden.
#[derive(Debug, Parser)]
pub struct ManualGenerateCommand {
/// Directory where man files should be generated in
/// Directory where man files should be generated in.
#[arg(value_parser = dir_parser)]
pub dir: PathBuf,
}

View file

@ -1,9 +1,13 @@
use clap::Parser;
/// The table max width argument parser
/// The table max width argument parser.
#[derive(Debug, Parser)]
pub struct MaxTableWidthFlag {
/// The maximum width the table should not exceed
#[arg(long, short = 'w', value_name = "PIXELS")]
pub struct TableMaxWidthFlag {
/// The maximum width the table should not exceed.
///
/// This argument will force the table not to exceed the given
/// width in pixels. Columns may shrink with ellipsis in order to
/// fit the width.
#[arg(long, short = 'w', name = "table_max_width", value_name = "PIXELS")]
pub max_width: Option<usize>,
}