mirror of
https://github.com/soywod/himalaya.git
synced 2024-09-05 02:21:17 +00:00
improve imap and mbox arg/handler
This commit is contained in:
parent
248240f52d
commit
bc5f9045ce
|
@ -1,21 +1,12 @@
|
||||||
//! Module related to completion arguments.
|
//! Module related to completion arguments.
|
||||||
//!
|
//!
|
||||||
//! This module provides subcommands and an argument matcher for the completion command.
|
//! This module provides subcommands and an argument matcher related to completion.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{self, App, Arg, ArgMatches, Shell, SubCommand};
|
use clap::{self, App, Arg, ArgMatches, Shell, SubCommand};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
/// Subcommands related to the completion generation.
|
/// Enumeration of all possible matches.
|
||||||
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
|
|
||||||
vec![SubCommand::with_name("completion")
|
|
||||||
.about("Generates the completion script for the given shell")
|
|
||||||
.args(&[Arg::with_name("shell")
|
|
||||||
.possible_values(&Shell::variants()[..])
|
|
||||||
.required(true)])]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enumeration of all possible completion matches.
|
|
||||||
pub enum Match<'a> {
|
pub enum Match<'a> {
|
||||||
/// Generate completion script for the given shell slice.
|
/// Generate completion script for the given shell slice.
|
||||||
Generate(&'a str),
|
Generate(&'a str),
|
||||||
|
@ -32,3 +23,12 @@ pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Match<'a>>> {
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Completion subcommands.
|
||||||
|
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
|
||||||
|
vec![SubCommand::with_name("completion")
|
||||||
|
.about("Generates the completion script for the given shell")
|
||||||
|
.args(&[Arg::with_name("shell")
|
||||||
|
.possible_values(&Shell::variants()[..])
|
||||||
|
.required(true)])]
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,41 @@
|
||||||
|
//! Module related to IMAP arguments.
|
||||||
|
//!
|
||||||
|
//! This module provides subcommands and an argument matcher related to IMAP.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap;
|
use clap::{App, ArgMatches};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::domain::{config::entity::Config, imap::service::ImapServiceInterface};
|
/// Enumeration of all possible matches.
|
||||||
|
pub enum Match {
|
||||||
|
/// Start the IMAP notify mode with the give keepalive duration.
|
||||||
|
Notify(u64),
|
||||||
|
|
||||||
pub fn subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
/// Start the IMAP watch mode with the give keepalive duration.
|
||||||
|
Watch(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IMAP arg matcher.
|
||||||
|
pub fn matches(m: &ArgMatches) -> Result<Option<Match>> {
|
||||||
|
if let Some(m) = m.subcommand_matches("notify") {
|
||||||
|
debug!("notify command matched");
|
||||||
|
let keepalive = clap::value_t_or_exit!(m.value_of("keepalive"), u64);
|
||||||
|
debug!("keepalive: {}", keepalive);
|
||||||
|
return Ok(Some(Match::Notify(keepalive)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(m) = m.subcommand_matches("watch") {
|
||||||
|
debug!("watch command matched");
|
||||||
|
let keepalive = clap::value_t_or_exit!(m.value_of("keepalive"), u64);
|
||||||
|
debug!("keepalive: {}", keepalive);
|
||||||
|
return Ok(Some(Match::Watch(keepalive)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IMAP subcommands.
|
||||||
|
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
|
||||||
vec![
|
vec![
|
||||||
clap::SubCommand::with_name("notify")
|
clap::SubCommand::with_name("notify")
|
||||||
.about("Notifies when new messages arrive in the given mailbox")
|
.about("Notifies when new messages arrive in the given mailbox")
|
||||||
|
@ -29,34 +60,3 @@ pub fn subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches<ImapService: ImapServiceInterface>(
|
|
||||||
arg_matches: &clap::ArgMatches,
|
|
||||||
config: &Config,
|
|
||||||
imap: &mut ImapService,
|
|
||||||
) -> Result<bool> {
|
|
||||||
if let Some(matches) = arg_matches.subcommand_matches("notify") {
|
|
||||||
debug!("notify command matched");
|
|
||||||
|
|
||||||
let keepalive = clap::value_t_or_exit!(matches.value_of("keepalive"), u64);
|
|
||||||
debug!("keepalive: {}", &keepalive);
|
|
||||||
|
|
||||||
imap.notify(&config, keepalive)?;
|
|
||||||
imap.logout()?;
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(matches) = arg_matches.subcommand_matches("watch") {
|
|
||||||
debug!("watch command matched");
|
|
||||||
|
|
||||||
let keepalive = clap::value_t_or_exit!(matches.value_of("keepalive"), u64);
|
|
||||||
debug!("keepalive: {}", &keepalive);
|
|
||||||
|
|
||||||
imap.watch(keepalive)?;
|
|
||||||
imap.logout()?;
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("nothing matched");
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
28
src/domain/imap/handler.rs
Normal file
28
src/domain/imap/handler.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//! Module related to IMAP handling.
|
||||||
|
//!
|
||||||
|
//! This module gathers all IMAP handlers triggered by the CLI.
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::domain::{config::entity::Config, imap::service::ImapServiceInterface};
|
||||||
|
|
||||||
|
/// Notify handler.
|
||||||
|
pub fn notify<ImapService: ImapServiceInterface>(
|
||||||
|
keepalive: u64,
|
||||||
|
config: &Config,
|
||||||
|
imap: &mut ImapService,
|
||||||
|
) -> Result<()> {
|
||||||
|
imap.notify(&config, keepalive)?;
|
||||||
|
imap.logout()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Watch handler.
|
||||||
|
pub fn watch<ImapService: ImapServiceInterface>(
|
||||||
|
keepalive: u64,
|
||||||
|
imap: &mut ImapService,
|
||||||
|
) -> Result<()> {
|
||||||
|
imap.watch(keepalive)?;
|
||||||
|
imap.logout()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
//! Modules related to IMAP.
|
//! Module related to IMAP.
|
||||||
|
|
||||||
pub mod cli;
|
pub mod arg;
|
||||||
|
pub mod handler;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
//! Module related to IMAP servicing.
|
||||||
|
//!
|
||||||
|
//! This module exposes a service that can interact with IMAP servers.
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use imap;
|
use imap;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
|
|
47
src/domain/mbox/arg.rs
Normal file
47
src/domain/mbox/arg.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//! Module related to mailboxes arguments.
|
||||||
|
//!
|
||||||
|
//! This module provides subcommands and an argument matcher related to mailboxes.
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
/// Enumeration of all possible matches.
|
||||||
|
pub enum Match {
|
||||||
|
/// List all available mailboxes.
|
||||||
|
List,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mailboxes arg matcher.
|
||||||
|
pub fn matches(m: &ArgMatches) -> Result<Option<Match>> {
|
||||||
|
if let Some(_) = m.subcommand_matches("mailboxes") {
|
||||||
|
debug!("mailboxes command matched");
|
||||||
|
return Ok(Some(Match::List));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mailboxes subcommands.
|
||||||
|
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
|
||||||
|
vec![SubCommand::with_name("mailboxes")
|
||||||
|
.aliases(&["mailbox", "mboxes", "mbox", "m"])
|
||||||
|
.about("Lists all mailboxes")]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Source mailbox arg.
|
||||||
|
pub fn source_arg<'a>() -> Arg<'a, 'a> {
|
||||||
|
Arg::with_name("mailbox")
|
||||||
|
.short("m")
|
||||||
|
.long("mailbox")
|
||||||
|
.help("Selects a specific mailbox")
|
||||||
|
.value_name("MAILBOX")
|
||||||
|
.default_value("INBOX")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Target mailbox arg.
|
||||||
|
pub fn target_arg<'a>() -> Arg<'a, 'a> {
|
||||||
|
Arg::with_name("target")
|
||||||
|
.help("Specifies the targetted mailbox")
|
||||||
|
.value_name("TARGET")
|
||||||
|
}
|
|
@ -1,48 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
use clap;
|
|
||||||
use log::{debug, trace};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
domain::{imap::service::ImapServiceInterface, mbox::entity::Mboxes},
|
|
||||||
output::service::{OutputService, OutputServiceInterface},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
|
||||||
vec![clap::SubCommand::with_name("mailboxes")
|
|
||||||
.aliases(&["mailbox", "mboxes", "mbox", "m"])
|
|
||||||
.about("Lists all mailboxes")]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn matches<ImapService: ImapServiceInterface>(
|
|
||||||
arg_matches: &clap::ArgMatches,
|
|
||||||
output: &OutputService,
|
|
||||||
imap: &mut ImapService,
|
|
||||||
) -> Result<bool> {
|
|
||||||
if let Some(_) = arg_matches.subcommand_matches("mailboxes") {
|
|
||||||
debug!("mailboxes command matched");
|
|
||||||
let names = imap.list_mboxes()?;
|
|
||||||
let mboxes = Mboxes::from(&names);
|
|
||||||
debug!("mboxes len: {}", mboxes.0.len());
|
|
||||||
trace!("{:#?}", mboxes);
|
|
||||||
output.print(mboxes)?;
|
|
||||||
imap.logout()?;
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn source_arg<'a>() -> clap::Arg<'a, 'a> {
|
|
||||||
clap::Arg::with_name("mailbox")
|
|
||||||
.short("m")
|
|
||||||
.long("mailbox")
|
|
||||||
.help("Selects a specific mailbox")
|
|
||||||
.value_name("MAILBOX")
|
|
||||||
.default_value("INBOX")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mbox_target_arg<'a>() -> clap::Arg<'a, 'a> {
|
|
||||||
clap::Arg::with_name("target")
|
|
||||||
.help("Specifies the targetted mailbox")
|
|
||||||
.value_name("TARGET")
|
|
||||||
}
|
|
25
src/domain/mbox/handler.rs
Normal file
25
src/domain/mbox/handler.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//! Module related to mailboxes handling.
|
||||||
|
//!
|
||||||
|
//! This module gathers all mailboxes actions triggered by the CLI.
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use log::{debug, trace};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
domain::{imap::service::ImapServiceInterface, mbox::entity::Mboxes},
|
||||||
|
output::service::{OutputService, OutputServiceInterface},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// List mailboxes.
|
||||||
|
pub fn list<ImapService: ImapServiceInterface>(
|
||||||
|
output: &OutputService,
|
||||||
|
imap: &mut ImapService,
|
||||||
|
) -> Result<()> {
|
||||||
|
let names = imap.list_mboxes()?;
|
||||||
|
let mboxes = Mboxes::from(&names);
|
||||||
|
debug!("mailboxes len: {}", mboxes.0.len());
|
||||||
|
trace!("mailboxes: {:#?}", mboxes);
|
||||||
|
output.print(mboxes)?;
|
||||||
|
imap.logout()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,2 +1,5 @@
|
||||||
pub mod cli;
|
//! Module related to mailboxes.
|
||||||
|
|
||||||
|
pub mod arg;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
|
pub mod handler;
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
domain::{
|
domain::{
|
||||||
account::entity::Account,
|
account::entity::Account,
|
||||||
imap::service::ImapServiceInterface,
|
imap::service::ImapServiceInterface,
|
||||||
mbox::{cli::mbox_target_arg, entity::Mbox},
|
mbox::{arg::target_arg, entity::Mbox},
|
||||||
smtp::service::SmtpServiceInterface,
|
smtp::service::SmtpServiceInterface,
|
||||||
},
|
},
|
||||||
flag::model::Flags,
|
flag::model::Flags,
|
||||||
|
@ -93,12 +93,12 @@ pub fn subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||||
.aliases(&["cp"])
|
.aliases(&["cp"])
|
||||||
.about("Copies a message to the targetted mailbox")
|
.about("Copies a message to the targetted mailbox")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(mbox_target_arg()),
|
.arg(target_arg()),
|
||||||
clap::SubCommand::with_name("move")
|
clap::SubCommand::with_name("move")
|
||||||
.aliases(&["mv"])
|
.aliases(&["mv"])
|
||||||
.about("Moves a message to the targetted mailbox")
|
.about("Moves a message to the targetted mailbox")
|
||||||
.arg(uid_arg())
|
.arg(uid_arg())
|
||||||
.arg(mbox_target_arg()),
|
.arg(target_arg()),
|
||||||
clap::SubCommand::with_name("delete")
|
clap::SubCommand::with_name("delete")
|
||||||
.aliases(&["remove", "rm"])
|
.aliases(&["remove", "rm"])
|
||||||
.about("Deletes a message")
|
.about("Deletes a message")
|
|
@ -18,7 +18,7 @@
|
||||||
///
|
///
|
||||||
/// Execute `himalaya help <cmd>` where `<cmd>` is one entry of this list above
|
/// Execute `himalaya help <cmd>` where `<cmd>` is one entry of this list above
|
||||||
/// to get more information about them.
|
/// to get more information about them.
|
||||||
pub mod cli;
|
pub mod arg;
|
||||||
|
|
||||||
/// Here are the two **main structs** of this module: `Msg` and `Msgs` which
|
/// Here are the two **main structs** of this module: `Msg` and `Msgs` which
|
||||||
/// represent a *Mail* or *multiple Mails* in this crate.
|
/// represent a *Mail* or *multiple Mails* in this crate.
|
||||||
|
|
|
@ -3,7 +3,7 @@ use clap;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
domain::{imap::service::ImapServiceInterface, msg::cli::uid_arg},
|
domain::{imap::service::ImapServiceInterface, msg::arg::uid_arg},
|
||||||
flag::model::Flags,
|
flag::model::Flags,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
pub mod cli;
|
pub mod arg;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
|
44
src/main.rs
44
src/main.rs
|
@ -23,14 +23,13 @@ fn create_app<'a>() -> clap::App<'a, 'a> {
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
.about(env!("CARGO_PKG_DESCRIPTION"))
|
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||||
.author(env!("CARGO_PKG_AUTHORS"))
|
.author(env!("CARGO_PKG_AUTHORS"))
|
||||||
.setting(clap::AppSettings::InferSubcommands)
|
|
||||||
.args(&output_args())
|
.args(&output_args())
|
||||||
.args(&config_args())
|
.args(&config_args())
|
||||||
.arg(mbox::cli::source_arg())
|
.arg(mbox::arg::source_arg())
|
||||||
.subcommands(flag::cli::subcmds())
|
.subcommands(flag::arg::subcmds())
|
||||||
.subcommands(imap::cli::subcmds())
|
.subcommands(imap::arg::subcmds())
|
||||||
.subcommands(mbox::cli::subcmds())
|
.subcommands(mbox::arg::subcmds())
|
||||||
.subcommands(msg::cli::subcmds())
|
.subcommands(msg::arg::subcmds())
|
||||||
.subcommands(compl::arg::subcmds())
|
.subcommands(compl::arg::subcmds())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,10 +56,14 @@ fn main() -> Result<()> {
|
||||||
let app = create_app();
|
let app = create_app();
|
||||||
let m = app.get_matches();
|
let m = app.get_matches();
|
||||||
|
|
||||||
// Check shell completion BEFORE any entity or service initialization.
|
// Check completion match BEFORE any entity or service initialization.
|
||||||
if let Some(compl::arg::Match::Generate(shell)) = compl::arg::matches(&m)? {
|
// See https://github.com/soywod/himalaya/issues/115.
|
||||||
|
match compl::arg::matches(&m)? {
|
||||||
|
Some(compl::arg::Match::Generate(shell)) => {
|
||||||
return compl::handler::generate(shell, create_app());
|
return compl::handler::generate(shell, create_app());
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
let mbox = Mbox::try_from(m.value_of("mailbox"))?;
|
let mbox = Mbox::try_from(m.value_of("mailbox"))?;
|
||||||
let config = Config::try_from(m.value_of("config"))?;
|
let config = Config::try_from(m.value_of("config"))?;
|
||||||
|
@ -69,11 +72,28 @@ fn main() -> Result<()> {
|
||||||
let mut imap = ImapService::from((&account, &mbox));
|
let mut imap = ImapService::from((&account, &mbox));
|
||||||
let mut smtp = SmtpService::from(&account);
|
let mut smtp = SmtpService::from(&account);
|
||||||
|
|
||||||
|
// Check IMAP matches.
|
||||||
|
match imap::arg::matches(&m)? {
|
||||||
|
Some(imap::arg::Match::Notify(keepalive)) => {
|
||||||
|
return imap::handler::notify(keepalive, &config, &mut imap);
|
||||||
|
}
|
||||||
|
Some(imap::arg::Match::Watch(keepalive)) => {
|
||||||
|
return imap::handler::watch(keepalive, &mut imap);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check mailbox matches.
|
||||||
|
match mbox::arg::matches(&m)? {
|
||||||
|
Some(mbox::arg::Match::List) => {
|
||||||
|
return mbox::handler::list(&output, &mut imap);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: use same system as compl
|
// TODO: use same system as compl
|
||||||
let _matched = mbox::cli::matches(&m, &output, &mut imap)?
|
let _matched = flag::arg::matches(&m, &mut imap)?
|
||||||
|| flag::cli::matches(&m, &mut imap)?
|
|| msg::arg::matches(&m, &mbox, &account, &output, &mut imap, &mut smtp)?;
|
||||||
|| imap::cli::matches(&m, &config, &mut imap)?
|
|
||||||
|| msg::cli::matches(&m, &mbox, &account, &output, &mut imap, &mut smtp)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//!
|
//!
|
||||||
//! [builder design pattern]: https://refactoring.guru/design-patterns/builder
|
//! [builder design pattern]: https://refactoring.guru/design-patterns/builder
|
||||||
|
|
||||||
use log::{debug, trace};
|
use log::trace;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use terminal_size;
|
use terminal_size;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
@ -228,12 +228,12 @@ where
|
||||||
table
|
table
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|row| {
|
.map(|row| {
|
||||||
debug!("processing row: {:?}", row);
|
trace!("processing row: {:?}", row);
|
||||||
row.0
|
row.0
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, cell)| {
|
.map(|(i, cell)| {
|
||||||
debug!("processing cell: {:?}", cell);
|
trace!("processing cell: {:?}", cell);
|
||||||
trace!("table_width: {}", table_width);
|
trace!("table_width: {}", table_width);
|
||||||
trace!("max_width: {}", Self::max_width());
|
trace!("max_width: {}", Self::max_width());
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue