mirror of
https://github.com/pimalaya/himalaya.git
synced 2026-06-17 13:17:55 +08:00
clean part 1
This commit is contained in:
@@ -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
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
|
||||
@@ -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() })
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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,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,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,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"))
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,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"))
|
||||
|
||||
@@ -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,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,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,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"))
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -1,5 +1,5 @@
|
||||
pub mod account;
|
||||
pub mod cli;
|
||||
pub mod client;
|
||||
pub mod envelope;
|
||||
pub mod flag;
|
||||
pub mod id;
|
||||
|
||||
+4
-2
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user