clean part 1

This commit is contained in:
Clément DOUIN
2026-05-06 23:02:11 +02:00
parent 8416a41f99
commit cd27969e14
179 changed files with 5244 additions and 3357 deletions
-21
View File
@@ -1,21 +0,0 @@
use anyhow::Result;
use io_imap::client::ImapClient;
use crate::{account::Account, config::ImapConfig, imap::session::ImapSession};
pub type ImapAccount = Account<ImapConfig>;
impl ImapAccount {
/// Opens the IMAP connection (TCP/TLS/STARTTLS, greeting, SASL),
/// then hands the established stream and context off to a fresh
/// [`ImapClient`].
pub fn new_imap_client(&self) -> Result<ImapClient> {
let session = ImapSession::new(
self.backend.url.clone(),
self.backend.tls.clone().try_into()?,
self.backend.starttls,
self.backend.sasl.clone().try_into()?,
)?;
Ok(ImapClient::from_parts(session.stream, session.context))
}
}
+8 -8
View File
@@ -3,11 +3,11 @@ use clap::Subcommand;
use pimalaya_cli::printer::Printer;
use crate::imap::{
account::ImapAccount, envelope::cli::ImapEnvelopeCommand, flag::cli::ImapFlagCommand,
client::ImapClient, envelope::cli::ImapEnvelopeCommand, flag::cli::ImapFlagCommand,
id::ImapIdCommand, mailbox::cli::ImapMailboxCommand, message::cli::ImapMessageCommand,
};
/// IMAP CLI (requires the `imap` cargo feature).
/// IMAP CLI.
///
/// This command gives you access to the IMAP CLI API, and allows you
/// to manage IMAP mailboxes, envelopes, flags, messages etc.
@@ -29,14 +29,14 @@ pub enum ImapCommand {
}
impl ImapCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
pub fn execute(self, printer: &mut impl Printer, client: ImapClient) -> Result<()> {
match self {
Self::Id(cmd) => cmd.execute(printer, account),
Self::Id(cmd) => cmd.execute(printer, client),
Self::Envelopes(cmd) => cmd.execute(printer, account),
Self::Flags(cmd) => cmd.execute(printer, account),
Self::Mailboxes(cmd) => cmd.execute(printer, account),
Self::Messages(cmd) => cmd.execute(printer, account),
Self::Envelopes(cmd) => cmd.execute(printer, client),
Self::Flags(cmd) => cmd.execute(printer, client),
Self::Mailboxes(cmd) => cmd.execute(printer, client),
Self::Messages(cmd) => cmd.execute(printer, client),
}
}
}
+73
View File
@@ -0,0 +1,73 @@
//! Himalaya wrapper around [`io_imap::client::ImapClient`] that
//! bundles the merged [`Account`] alongside the live IMAP client.
//!
//! This is what every IMAP-specific subcommand receives: the dispatch
//! layer (`crate::cli`) opens the session up front via
//! [`build_imap_client`] and hands the ready-to-use wrapper down.
use std::{
ops::{Deref, DerefMut},
path::PathBuf,
};
use anyhow::{anyhow, Result};
use io_imap::client::ImapClient as Inner;
use pimalaya_config::toml::TomlConfig;
use crate::{
account::context::Account, cli::load_or_wizard, config::ImapConfig, imap::session::ImapSession,
};
pub struct ImapClient {
inner: Inner,
pub account: Account,
}
impl ImapClient {
/// Opens the IMAP connection (TCP/TLS/STARTTLS, greeting, SASL)
/// then wraps the resulting stream + context in an
/// [`io_imap::client::ImapClient`] alongside `account`.
pub fn new(config: ImapConfig, account: Account) -> Result<Self> {
let session = ImapSession::new(
config.url,
config.tls.try_into()?,
config.starttls,
config.sasl.try_into()?,
)?;
let inner = Inner::from_parts(session.stream, session.context);
Ok(Self { inner, account })
}
}
impl Deref for ImapClient {
type Target = Inner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for ImapClient {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
/// Loads the configuration, picks the active account, builds the
/// merged [`Account`] then opens the IMAP session. Bails when the
/// account has no `[imap]` block.
pub fn build_imap_client(
config_paths: &[PathBuf],
account_name: Option<&str>,
) -> Result<ImapClient> {
let mut config = load_or_wizard(config_paths)?;
let (name, mut ac) = config
.take_account(account_name)?
.ok_or_else(|| anyhow!("Cannot find account"))?;
let imap_config = ac
.imap
.take()
.ok_or_else(|| anyhow!("IMAP config is missing for account `{name}`"))?;
let account = Account::from(config).merge(Account::from(ac));
ImapClient::new(imap_config, account)
}
+7 -7
View File
@@ -3,7 +3,7 @@ use clap::Subcommand;
use pimalaya_cli::printer::Printer;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
envelope::{
get::ImapEnvelopeGetCommand, list::ImapEnvelopeListCommand,
search::ImapEnvelopeSearchCommand, sort::ImapEnvelopeSortCommand,
@@ -26,13 +26,13 @@ pub enum ImapEnvelopeCommand {
}
impl ImapEnvelopeCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
pub fn execute(self, printer: &mut impl Printer, client: ImapClient) -> Result<()> {
match self {
Self::Get(cmd) => cmd.execute(printer, account),
Self::List(cmd) => cmd.execute(printer, account),
Self::Search(cmd) => cmd.execute(printer, account),
Self::Sort(cmd) => cmd.execute(printer, account),
Self::Thread(cmd) => cmd.execute(printer, account),
Self::Get(cmd) => cmd.execute(printer, client),
Self::List(cmd) => cmd.execute(printer, client),
Self::Search(cmd) => cmd.execute(printer, client),
Self::Sort(cmd) => cmd.execute(printer, client),
Self::Thread(cmd) => cmd.execute(printer, client),
}
}
}
+3 -4
View File
@@ -11,7 +11,7 @@ use pimalaya_cli::printer::Printer;
use serde::Serialize;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
envelope::list::{decode_mime, format_address},
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -37,8 +37,7 @@ pub struct ImapEnvelopeGetCommand {
}
impl ImapEnvelopeGetCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
@@ -60,7 +59,7 @@ impl ImapEnvelopeGetCommand {
};
let table = EnvelopeTable {
preset: account.table_preset,
preset: client.account.table_preset().to_string(),
envelope: items.into(),
};
+4 -5
View File
@@ -16,7 +16,7 @@ use rfc2047_decoder::{Decoder, RecoverStrategy};
use serde::Serialize;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -50,8 +50,7 @@ pub struct ImapEnvelopeListCommand {
}
impl ImapEnvelopeListCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
let exists = if self.mailbox_no_select.inner {
@@ -84,8 +83,8 @@ impl ImapEnvelopeListCommand {
let data = client.fetch(sequence_set, item_names, !self.sequence && has_sequence)?;
let table = EnvelopesTable {
preset: account.table_preset,
arrangement: account.table_arrangement,
preset: client.account.table_preset().to_string(),
arrangement: client.account.table_arrangement(),
envelopes: map_envelopes_table_entries(data),
};
+4 -5
View File
@@ -12,7 +12,7 @@ use pimalaya_cli::printer::Printer;
use serde::Serialize;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -58,8 +58,7 @@ pub struct ImapEnvelopeSearchCommand {
}
impl ImapEnvelopeSearchCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
@@ -70,8 +69,8 @@ impl ImapEnvelopeSearchCommand {
let ids = client.search(criteria, !self.seq)?;
let table = SearchTable {
preset: account.table_preset,
arrangement: account.table_arrangement,
preset: client.account.table_preset().to_string(),
arrangement: client.account.table_arrangement(),
ids: ids
.into_iter()
.map(|id| SearchResult { id: id.get() })
+2 -3
View File
@@ -11,7 +11,7 @@ use pimalaya_cli::printer::Printer;
use serde::Serialize;
use crate::imap::{
account::ImapAccount, envelope::search::parse_query, mailbox::arg::MailboxNameOptionalArg,
client::ImapClient, envelope::search::parse_query, mailbox::arg::MailboxNameOptionalArg,
};
/// Sort messages by criteria.
@@ -51,8 +51,7 @@ pub struct ImapEnvelopeSortCommand {
}
impl ImapEnvelopeSortCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
client.select(mailbox)?;
+6 -10
View File
@@ -2,19 +2,16 @@ use std::{collections::HashMap, fmt, num::NonZeroU32};
use anyhow::{bail, Result};
use clap::Parser;
use io_imap::{
client::ImapClient,
types::{
extensions::thread::{Thread, ThreadingAlgorithm},
fetch::{MacroOrMessageDataItemNames, MessageDataItem, MessageDataItemName},
sequence::SequenceSet,
},
use io_imap::types::{
extensions::thread::{Thread, ThreadingAlgorithm},
fetch::{MacroOrMessageDataItemNames, MessageDataItem, MessageDataItemName},
sequence::SequenceSet,
};
use pimalaya_cli::printer::Printer;
use serde::{ser::SerializeStruct, Serialize, Serializer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
envelope::{list::decode_mime, search::parse_query},
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -48,8 +45,7 @@ pub struct ImapEnvelopeThreadCommand {
}
impl ImapEnvelopeThreadCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+2 -3
View File
@@ -7,7 +7,7 @@ use io_imap::types::{
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -35,8 +35,7 @@ pub struct ImapFlagAddCommand {
}
impl ImapFlagAddCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+6 -6
View File
@@ -3,7 +3,7 @@ use clap::Subcommand;
use pimalaya_cli::printer::Printer;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
flag::{
add::ImapFlagAddCommand, list::ImapFlagListCommand, remove::ImapFlagRemoveCommand,
set::ImapFlagSetCommand,
@@ -23,12 +23,12 @@ pub enum ImapFlagCommand {
}
impl ImapFlagCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
pub fn execute(self, printer: &mut impl Printer, client: ImapClient) -> Result<()> {
match self {
Self::List(cmd) => cmd.execute(printer, account),
Self::Add(cmd) => cmd.execute(printer, account),
Self::Set(cmd) => cmd.execute(printer, account),
Self::Remove(cmd) => cmd.execute(printer, account),
Self::List(cmd) => cmd.execute(printer, client),
Self::Add(cmd) => cmd.execute(printer, client),
Self::Set(cmd) => cmd.execute(printer, client),
Self::Remove(cmd) => cmd.execute(printer, client),
}
}
}
+4 -5
View File
@@ -7,7 +7,7 @@ use io_imap::types::flag::{Flag, FlagPerm};
use pimalaya_cli::printer::Printer;
use serde::{Serialize, Serializer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameArg};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameArg};
/// List available IMAP flags for the given mailbox.
///
@@ -21,8 +21,7 @@ pub struct ImapFlagListCommand {
}
impl ImapFlagListCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
let data = client.select(mailbox)?;
@@ -30,8 +29,8 @@ impl ImapFlagListCommand {
let permanent_flags = data.permanent_flags.unwrap_or_default();
let table = FlagsTable {
preset: account.table_preset,
arrangement: account.table_arrangement,
preset: client.account.table_preset().to_string(),
arrangement: client.account.table_arrangement(),
flags,
permanent_flags,
};
+2 -3
View File
@@ -7,7 +7,7 @@ use io_imap::types::{
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -35,8 +35,7 @@ pub struct ImapFlagRemoveCommand {
}
impl ImapFlagRemoveCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+2 -3
View File
@@ -7,7 +7,7 @@ use io_imap::types::{
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -35,8 +35,7 @@ pub struct ImapFlagSetCommand {
}
impl ImapFlagSetCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+3 -4
View File
@@ -10,7 +10,7 @@ use io_imap::types::{
use pimalaya_cli::printer::Printer;
use serde::Serialize;
use crate::imap::account::ImapAccount;
use crate::imap::client::ImapClient;
/// Get information about the IMAP server.
///
@@ -27,8 +27,7 @@ pub struct ImapIdCommand {
}
impl ImapIdCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mut params = HashMap::new();
params.extend([
@@ -57,7 +56,7 @@ impl ImapIdCommand {
let params = client.id(Some(params.into_iter().collect()))?;
let table = ServerIdTable {
preset: account.table_preset,
preset: client.account.table_preset().to_string(),
server_id: params
.unwrap_or_default()
.into_iter()
+14 -14
View File
@@ -3,7 +3,7 @@ use clap::Subcommand;
use pimalaya_cli::printer::Printer;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::{
close::ImapMailboxCloseCommand, create::ImapMailboxCreateCommand,
delete::ImapMailboxDeleteCommand, expunge::ImapMailboxExpungeCommand,
@@ -38,20 +38,20 @@ pub enum ImapMailboxCommand {
}
impl ImapMailboxCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
pub fn execute(self, printer: &mut impl Printer, client: ImapClient) -> Result<()> {
match self {
Self::Close(cmd) => cmd.execute(printer, account),
Self::Create(cmd) => cmd.execute(printer, account),
Self::Delete(cmd) => cmd.execute(printer, account),
Self::Expunge(cmd) => cmd.execute(printer, account),
Self::List(cmd) => cmd.execute(printer, account),
Self::Purge(cmd) => cmd.execute(printer, account),
Self::Rename(cmd) => cmd.execute(printer, account),
Self::Select(cmd) => cmd.execute(printer, account),
Self::Status(cmd) => cmd.execute(printer, account),
Self::Subscribe(cmd) => cmd.execute(printer, account),
Self::Unselect(cmd) => cmd.execute(printer, account),
Self::Unsubscribe(cmd) => cmd.execute(printer, account),
Self::Close(cmd) => cmd.execute(printer, client),
Self::Create(cmd) => cmd.execute(printer, client),
Self::Delete(cmd) => cmd.execute(printer, client),
Self::Expunge(cmd) => cmd.execute(printer, client),
Self::List(cmd) => cmd.execute(printer, client),
Self::Purge(cmd) => cmd.execute(printer, client),
Self::Rename(cmd) => cmd.execute(printer, client),
Self::Select(cmd) => cmd.execute(printer, client),
Self::Status(cmd) => cmd.execute(printer, client),
Self::Subscribe(cmd) => cmd.execute(printer, client),
Self::Unselect(cmd) => cmd.execute(printer, client),
Self::Unsubscribe(cmd) => cmd.execute(printer, client),
}
}
}
+2 -3
View File
@@ -2,7 +2,7 @@ use anyhow::Result;
use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::account::ImapAccount;
use crate::imap::client::ImapClient;
/// Close the current, selected mailbox.
///
@@ -17,8 +17,7 @@ use crate::imap::account::ImapAccount;
pub struct ImapMailboxCloseCommand;
impl ImapMailboxCloseCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
client.close()?;
printer.out(Message::new("Mailbox successfully closed"))
}
+2 -3
View File
@@ -2,7 +2,7 @@ use anyhow::Result;
use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameArg};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameArg};
/// Create the given mailbox.
///
@@ -15,8 +15,7 @@ pub struct ImapMailboxCreateCommand {
}
impl ImapMailboxCreateCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
client.create(mailbox)?;
printer.out(Message::new("Mailbox successfully created"))
+2 -3
View File
@@ -2,7 +2,7 @@ use anyhow::Result;
use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameArg};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameArg};
/// Delete the given mailbox.
///
@@ -15,8 +15,7 @@ pub struct ImapMailboxDeleteCommand {
}
impl ImapMailboxDeleteCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
client.delete(mailbox)?;
printer.out(Message::new("Mailbox successfully deleted"))
+2 -3
View File
@@ -3,7 +3,7 @@ use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameArg, MailboxNoSelectFlag},
};
@@ -20,8 +20,7 @@ pub struct ImapMailboxExpungeCommand {
}
impl ImapMailboxExpungeCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+15 -4
View File
@@ -3,11 +3,12 @@ use std::fmt;
use anyhow::Result;
use clap::Parser;
use comfy_table::{Cell, Row, Table};
use io_email::mailbox::MailboxRole;
use io_imap::types::{core::QuotedChar, flag::FlagNameAttribute, mailbox::Mailbox};
use pimalaya_cli::printer::Printer;
use serde::Serialize;
use crate::imap::account::ImapAccount;
use crate::imap::client::ImapClient;
/// List, search and filter mailboxes.
///
@@ -30,8 +31,7 @@ pub struct ImapMailboxListCommand {
}
impl ImapMailboxListCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let reference = self.reference.try_into()?;
let pattern = self.pattern.try_into()?;
@@ -42,7 +42,7 @@ impl ImapMailboxListCommand {
};
let table = MailboxesTable {
preset: account.table_preset,
preset: client.account.table_preset().to_string(),
mailboxes: mailboxes.into_iter().map(From::from).collect(),
};
@@ -66,14 +66,25 @@ impl fmt::Display for MailboxesTable {
.set_header(Row::from([
Cell::new("NAME"),
Cell::new("DELIMITER"),
Cell::new("ROLE"),
Cell::new("ATTRIBUTES"),
]))
.add_rows(self.mailboxes.iter().map(|mbox| {
let mut row = Row::new();
let role = mbox
.attributes
.iter()
.find_map(|raw| match MailboxRole::parse(raw) {
MailboxRole::Other(_) => None,
role => Some(format!("{role:?}")),
})
.unwrap_or_default();
row.max_height(1)
.add_cell(Cell::new(&mbox.name))
.add_cell(Cell::new(&mbox.delimiter))
.add_cell(Cell::new(role))
.add_cell(Cell::new(mbox.attributes.join(", ")));
row
+2 -3
View File
@@ -4,7 +4,7 @@ use io_imap::types::flag::{Flag, StoreType};
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameArg, MailboxNoSelectFlag},
};
@@ -22,8 +22,7 @@ pub struct ImapMailboxPurgeCommand {
}
impl ImapMailboxPurgeCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+2 -3
View File
@@ -3,7 +3,7 @@ use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameArg, TargetMailboxNameArg},
};
@@ -19,8 +19,7 @@ pub struct ImapMailboxRenameCommand {
}
impl ImapMailboxRenameCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let from = self.mailbox_source_name.inner.try_into()?;
let to = self.mailbox_dest_name.inner.try_into()?;
client.rename(from, to)?;
+2 -3
View File
@@ -2,7 +2,7 @@ use anyhow::Result;
use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameArg};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameArg};
/// Select the given mailbox.
///
@@ -19,8 +19,7 @@ pub struct ImapMailboxSelectCommand {
}
impl ImapMailboxSelectCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
client.select(mailbox)?;
printer.out(Message::new("Mailbox successfully selected"))
+3 -4
View File
@@ -7,7 +7,7 @@ use io_imap::types::status::{StatusDataItem, StatusDataItemName};
use pimalaya_cli::printer::Printer;
use serde::{Serialize, Serializer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameArg};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameArg};
/// Get the status of the given mailbox.
///
@@ -20,8 +20,7 @@ pub struct ImapMailboxStatusCommand {
}
impl ImapMailboxStatusCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
let item_names = vec![
StatusDataItemName::Messages,
@@ -34,7 +33,7 @@ impl ImapMailboxStatusCommand {
let items = client.status(mailbox, item_names)?;
let table = MailboxStatusTable {
preset: account.table_preset,
preset: client.account.table_preset().to_string(),
status: items.into(),
};
+2 -3
View File
@@ -2,7 +2,7 @@ use anyhow::Result;
use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameArg};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameArg};
/// Subscribe to the given mailbox.
///
@@ -15,8 +15,7 @@ pub struct ImapMailboxSubscribeCommand {
}
impl ImapMailboxSubscribeCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
client.subscribe(mailbox)?;
printer.out(Message::new("Mailbox successfully subscribed"))
+2 -3
View File
@@ -2,7 +2,7 @@ use anyhow::Result;
use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::account::ImapAccount;
use crate::imap::client::ImapClient;
/// Unselect a current, selected mailbox.
///
@@ -16,8 +16,7 @@ use crate::imap::account::ImapAccount;
pub struct ImapMailboxUnselectCommand;
impl ImapMailboxUnselectCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
client.unselect()?;
printer.out(Message::new("Mailbox successfully unselected"))
}
+2 -3
View File
@@ -2,7 +2,7 @@ use anyhow::Result;
use clap::Parser;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameArg};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameArg};
/// Unsubscribe from the given mailbox.
///
@@ -15,8 +15,7 @@ pub struct ImapMailboxUnsubscribeCommand {
}
impl ImapMailboxUnsubscribeCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
client.unsubscribe(mailbox)?;
printer.out(Message::new("Mailbox successfully unsubscribed"))
+8 -8
View File
@@ -3,7 +3,7 @@ use clap::Subcommand;
use pimalaya_cli::printer::Printer;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
message::{
copy::ImapMessageCopyCommand, export::ImapMessageExportCommand, get::ImapMessageGetCommand,
r#move::ImapMessageMoveCommand, read::ImapMessageReadCommand, save::ImapMessageSaveCommand,
@@ -26,14 +26,14 @@ pub enum ImapMessageCommand {
}
impl ImapMessageCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
pub fn execute(self, printer: &mut impl Printer, client: ImapClient) -> Result<()> {
match self {
Self::Save(cmd) => cmd.execute(printer, account),
Self::Get(cmd) => cmd.execute(printer, account),
Self::Read(cmd) => cmd.execute(printer, account),
Self::Export(cmd) => cmd.execute(printer, account),
Self::Copy(cmd) => cmd.execute(printer, account),
Self::Move(cmd) => cmd.execute(printer, account),
Self::Save(cmd) => cmd.execute(printer, client),
Self::Get(cmd) => cmd.execute(printer, client),
Self::Read(cmd) => cmd.execute(printer, client),
Self::Export(cmd) => cmd.execute(printer, client),
Self::Copy(cmd) => cmd.execute(printer, client),
Self::Move(cmd) => cmd.execute(printer, client),
}
}
}
+2 -3
View File
@@ -4,7 +4,7 @@ use io_imap::types::mailbox::Mailbox;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag, TargetMailboxNameArg},
};
@@ -31,8 +31,7 @@ pub struct ImapMessageCopyCommand {
}
impl ImapMessageCopyCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+5 -4
View File
@@ -10,7 +10,7 @@ use io_imap::types::fetch::{MacroOrMessageDataItemNames, MessageDataItem, Messag
use mail_parser::{MessageParser, MimeHeaders};
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameOptionalFlag};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameOptionalFlag};
/// Export type for message export.
#[derive(Debug, Clone, clap::ValueEnum)]
@@ -56,8 +56,7 @@ pub struct ImapMessageExportCommand {
}
impl ImapMessageExportCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
client.select(mailbox)?;
@@ -117,7 +116,9 @@ impl ImapMessageExportCommand {
// Generate filename from subject or message-id
let filename = generate_eml_filename(&message, self.id);
let dir = self.directory.unwrap_or(account.downloads_dir);
let dir = self
.directory
.unwrap_or_else(|| client.account.downloads_dir());
if !dir.exists() {
fs::create_dir_all(&dir)?;
+2 -3
View File
@@ -9,7 +9,7 @@ use pimalaya_cli::printer::Printer;
use serde::Serialize;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -32,8 +32,7 @@ pub struct ImapMessageGetCommand {
}
impl ImapMessageGetCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if self.id == 0 {
bail!("ID must be non-zero");
+2 -3
View File
@@ -4,7 +4,7 @@ use io_imap::types::mailbox::Mailbox;
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag, TargetMailboxNameArg},
};
@@ -32,8 +32,7 @@ pub struct ImapMessageMoveCommand {
}
impl ImapMessageMoveCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+2 -3
View File
@@ -8,7 +8,7 @@ use pimalaya_cli::printer::Printer;
use serde::Serialize;
use crate::imap::{
account::ImapAccount,
client::ImapClient,
mailbox::arg::{MailboxNameOptionalFlag, MailboxNoSelectFlag},
};
@@ -37,8 +37,7 @@ pub struct ImapMessageReadCommand {
}
impl ImapMessageReadCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox = self.mailbox_name.inner.try_into()?;
if !self.mailbox_no_select.inner {
+2 -3
View File
@@ -7,7 +7,7 @@ use io_imap::types::{
};
use pimalaya_cli::printer::{Message, Printer};
use crate::imap::{account::ImapAccount, mailbox::arg::MailboxNameArg};
use crate::imap::{client::ImapClient, mailbox::arg::MailboxNameArg};
/// Save a message to a mailbox.
///
@@ -29,8 +29,7 @@ pub struct ImapMessageSaveCommand {
}
impl ImapMessageSaveCommand {
pub fn execute(self, printer: &mut impl Printer, account: ImapAccount) -> Result<()> {
let mut client = account.new_imap_client()?;
pub fn execute(self, printer: &mut impl Printer, mut client: ImapClient) -> Result<()> {
let mailbox: Mailbox<'static> = self.mailbox.inner.try_into()?;
let message = if !self.message.is_empty() || stdin().is_terminal() || printer.is_json() {
self.message
+1 -1
View File
@@ -1,5 +1,5 @@
pub mod account;
pub mod cli;
pub mod client;
pub mod envelope;
pub mod flag;
pub mod id;
+4 -2
View File
@@ -30,8 +30,10 @@ use io_imap::{
use log::info;
use pimalaya_stream::{
sasl::{Sasl, SaslMechanism},
std::stream::Stream,
tls::{upgrade_tls, Tls},
std::{
stream::Stream,
tls::{upgrade_tls, Tls},
},
};
#[cfg(windows)]
use uds_windows::UnixStream;