mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-24 20:10:23 +00:00
move id mapper from lib to CLI
This commit is contained in:
parent
53538e36f9
commit
0ff77b5179
13 changed files with 429 additions and 168 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -1110,11 +1110,13 @@ dependencies = [
|
|||
"erased-serde",
|
||||
"indicatif",
|
||||
"log",
|
||||
"md5",
|
||||
"once_cell",
|
||||
"pimalaya-email",
|
||||
"pimalaya-keyring",
|
||||
"pimalaya-process",
|
||||
"pimalaya-secret",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
|
@ -2066,7 +2068,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pimalaya-email"
|
||||
version = "0.7.1"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#4fc9ef469ddb89728c42b13bbff928266307ed9b"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#715546fabf7246a7f4bff8371aff77f116ae9b9a"
|
||||
dependencies = [
|
||||
"advisory-lock",
|
||||
"ammonia",
|
||||
|
@ -2108,7 +2110,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pimalaya-keyring"
|
||||
version = "0.0.1"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#4fc9ef469ddb89728c42b13bbff928266307ed9b"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#715546fabf7246a7f4bff8371aff77f116ae9b9a"
|
||||
dependencies = [
|
||||
"keyring",
|
||||
"log",
|
||||
|
@ -2118,7 +2120,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pimalaya-oauth2"
|
||||
version = "0.0.1"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#4fc9ef469ddb89728c42b13bbff928266307ed9b"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#715546fabf7246a7f4bff8371aff77f116ae9b9a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"oauth2",
|
||||
|
@ -2130,7 +2132,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pimalaya-process"
|
||||
version = "0.0.1"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#4fc9ef469ddb89728c42b13bbff928266307ed9b"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#715546fabf7246a7f4bff8371aff77f116ae9b9a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"thiserror",
|
||||
|
@ -2139,7 +2141,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pimalaya-secret"
|
||||
version = "0.0.1"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#4fc9ef469ddb89728c42b13bbff928266307ed9b"
|
||||
source = "git+https://git.sr.ht/~soywod/pimalaya#715546fabf7246a7f4bff8371aff77f116ae9b9a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pimalaya-keyring",
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -50,11 +50,16 @@ env_logger = "0.8"
|
|||
erased-serde = "0.3"
|
||||
indicatif = "0.17"
|
||||
log = "0.4"
|
||||
md5 = "0.7.0"
|
||||
once_cell = "1.16.0"
|
||||
pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
pimalaya-keyring = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
pimalaya-process = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
pimalaya-secret = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||
# pimalaya-email = { path = "/home/soywod/sourcehut/pimalaya/email" }
|
||||
# pimalaya-keyring = { path = "/home/soywod/sourcehut/pimalaya/keyring" }
|
||||
# pimalaya-process = { path = "/home/soywod/sourcehut/pimalaya/process" }
|
||||
# pimalaya-secret = { path = "/home/soywod/sourcehut/pimalaya/secret" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
shellexpand = "2.1"
|
||||
|
@ -64,3 +69,8 @@ toml = "0.7.2"
|
|||
unicode-width = "0.1"
|
||||
url = "2.2"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
|
||||
[target.'cfg(target_env = "musl")'.dependencies]
|
||||
rusqlite = { version = "0.29", features = [] }
|
||||
[target.'cfg(not(target_env = "musl"))'.dependencies]
|
||||
rusqlite = { version = "0.29", features = ["bundled"] }
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "stable"
|
||||
profile = "default"
|
||||
components = [
|
||||
"cargo",
|
||||
"clippy",
|
||||
"rust-analyzer",
|
||||
"rust-std",
|
||||
"rustc",
|
||||
"rustfmt",
|
||||
]
|
||||
components = [ "rust-src", "rust-analyzer" ]
|
||||
|
|
187
src/cache/id_mapper.rs
vendored
Normal file
187
src/cache/id_mapper.rs
vendored
Normal file
|
@ -0,0 +1,187 @@
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
use log::{debug, trace};
|
||||
#[cfg(feature = "imap-backend")]
|
||||
use pimalaya_email::ImapBackend;
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
use pimalaya_email::NotmuchBackend;
|
||||
use pimalaya_email::{Backend, MaildirBackend};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const ID_MAPPER_DB_FILE_NAME: &str = ".id-mapper.sqlite";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IdMapper {
|
||||
Dummy,
|
||||
Mapper(String, rusqlite::Connection),
|
||||
}
|
||||
|
||||
impl IdMapper {
|
||||
fn find_closest_db_path<D>(dir: D) -> PathBuf
|
||||
where
|
||||
D: AsRef<Path>,
|
||||
{
|
||||
let mut db_path = dir.as_ref().join(ID_MAPPER_DB_FILE_NAME);
|
||||
let mut db_parent_dir = dir.as_ref().parent();
|
||||
|
||||
while !db_path.is_file() {
|
||||
match db_parent_dir {
|
||||
Some(dir) => {
|
||||
db_path = dir.join(ID_MAPPER_DB_FILE_NAME);
|
||||
db_parent_dir = dir.parent();
|
||||
}
|
||||
None => {
|
||||
db_path = dir.as_ref().join(ID_MAPPER_DB_FILE_NAME);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db_path
|
||||
}
|
||||
|
||||
pub fn new(backend: &dyn Backend, account: &str, folder: &str) -> Result<Self> {
|
||||
let mut db_path = PathBuf::default();
|
||||
|
||||
if let Some(backend) = backend.as_any().downcast_ref::<MaildirBackend>() {
|
||||
db_path = Self::find_closest_db_path(&backend.path());
|
||||
}
|
||||
|
||||
#[cfg(feature = "imap-backend")]
|
||||
if backend.as_any().is::<ImapBackend>() {
|
||||
return Ok(Self::Dummy);
|
||||
}
|
||||
|
||||
#[cfg(feature = "notmuch-backend")]
|
||||
if let Some(backend) = backend.as_any().downcast_ref::<NotmuchBackend>() {
|
||||
db_path = Self::find_closest_db_path(&backend.path());
|
||||
}
|
||||
|
||||
let digest = md5::compute(account.to_string() + folder);
|
||||
let table = format!("id_mapper_{digest:x}");
|
||||
debug!("creating id mapper table {table} at {db_path:?}…");
|
||||
|
||||
let conn = rusqlite::Connection::open(&db_path)
|
||||
.with_context(|| format!("cannot open id mapper database at {db_path:?}"))?;
|
||||
|
||||
let query = format!(
|
||||
"CREATE TABLE IF NOT EXISTS {table} (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
internal_id TEXT UNIQUE
|
||||
)",
|
||||
);
|
||||
trace!("create table query: {query:#?}");
|
||||
|
||||
conn.execute(&query, [])
|
||||
.context("cannot create id mapper table")?;
|
||||
|
||||
Ok(Self::Mapper(table, conn))
|
||||
}
|
||||
|
||||
pub fn create_alias<I>(&self, id: I) -> Result<String>
|
||||
where
|
||||
I: AsRef<str>,
|
||||
{
|
||||
let id = id.as_ref();
|
||||
match self {
|
||||
Self::Dummy => Ok(id.to_owned()),
|
||||
Self::Mapper(table, conn) => {
|
||||
debug!("creating alias for id {id}…");
|
||||
|
||||
let query = format!("INSERT OR IGNORE INTO {} (internal_id) VALUES (?)", table);
|
||||
trace!("insert query: {query:#?}");
|
||||
|
||||
conn.execute(&query, [id])
|
||||
.with_context(|| format!("cannot create id alias for id {id}"))?;
|
||||
|
||||
let alias = conn.last_insert_rowid().to_string();
|
||||
debug!("created alias {alias} for id {id}");
|
||||
|
||||
Ok(alias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_create_alias<I>(&self, id: I) -> Result<String>
|
||||
where
|
||||
I: AsRef<str>,
|
||||
{
|
||||
let id = id.as_ref();
|
||||
match self {
|
||||
Self::Dummy => Ok(id.to_owned()),
|
||||
Self::Mapper(table, conn) => {
|
||||
debug!("getting alias for id {id}…");
|
||||
|
||||
let query = format!("SELECT id FROM {} WHERE internal_id = ?", table);
|
||||
trace!("select query: {query:#?}");
|
||||
|
||||
let mut stmt = conn
|
||||
.prepare(&query)
|
||||
.with_context(|| format!("cannot get alias for id {id}"))?;
|
||||
let aliases: Vec<i64> = stmt
|
||||
.query_map([id], |row| row.get(0))
|
||||
.with_context(|| format!("cannot get alias for id {id}"))?
|
||||
.collect::<rusqlite::Result<_>>()
|
||||
.with_context(|| format!("cannot get alias for id {id}"))?;
|
||||
let alias = match aliases.first() {
|
||||
Some(alias) => {
|
||||
debug!("found alias {alias} for id {id}");
|
||||
alias.to_string()
|
||||
}
|
||||
None => {
|
||||
debug!("alias not found, creating it…");
|
||||
self.create_alias(id)?
|
||||
}
|
||||
};
|
||||
|
||||
Ok(alias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id<A>(&self, alias: A) -> Result<String>
|
||||
where
|
||||
A: AsRef<str>,
|
||||
{
|
||||
let alias = alias.as_ref();
|
||||
let alias = alias
|
||||
.parse::<i64>()
|
||||
.context(format!("cannot parse id mapper alias {alias}"))?;
|
||||
|
||||
match self {
|
||||
Self::Dummy => Ok(alias.to_string()),
|
||||
Self::Mapper(table, conn) => {
|
||||
debug!("getting id from alias {alias}…");
|
||||
|
||||
let query = format!("SELECT internal_id FROM {} WHERE id = ?", table);
|
||||
trace!("select query: {query:#?}");
|
||||
|
||||
let mut stmt = conn
|
||||
.prepare(&query)
|
||||
.with_context(|| format!("cannot get id from alias {alias}"))?;
|
||||
let ids: Vec<String> = stmt
|
||||
.query_map([alias], |row| row.get(0))
|
||||
.with_context(|| format!("cannot get id from alias {alias}"))?
|
||||
.collect::<rusqlite::Result<_>>()
|
||||
.with_context(|| format!("cannot get id from alias {alias}"))?;
|
||||
let id = ids
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot get id from alias {alias}"))?
|
||||
.to_owned();
|
||||
debug!("found id {id} from alias {alias}");
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ids<A, I>(&self, aliases: I) -> Result<Vec<String>>
|
||||
where
|
||||
A: AsRef<str>,
|
||||
I: IntoIterator<Item = A>,
|
||||
{
|
||||
aliases
|
||||
.into_iter()
|
||||
.map(|alias| self.get_id(alias))
|
||||
.collect()
|
||||
}
|
||||
}
|
3
src/cache/mod.rs
vendored
3
src/cache/mod.rs
vendored
|
@ -1 +1,4 @@
|
|||
pub mod args;
|
||||
mod id_mapper;
|
||||
|
||||
pub use id_mapper::IdMapper;
|
||||
|
|
|
@ -14,17 +14,20 @@ use uuid::Uuid;
|
|||
use crate::{
|
||||
printer::{PrintTableOpts, Printer},
|
||||
ui::editor,
|
||||
Envelopes,
|
||||
Envelopes, IdMapper,
|
||||
};
|
||||
|
||||
pub fn attachments<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn attachments<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
ids: Vec<&str>,
|
||||
) -> Result<()> {
|
||||
let folder = config.folder_alias(folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let emails = backend.get_emails(&folder, ids.clone())?;
|
||||
let mut index = 0;
|
||||
|
||||
|
@ -71,45 +74,54 @@ pub fn attachments<P: Printer, B: Backend + ?Sized>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn copy<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn copy<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
from_folder: &str,
|
||||
to_folder: &str,
|
||||
ids: Vec<&str>,
|
||||
) -> Result<()> {
|
||||
let from_folder = config.folder_alias(from_folder)?;
|
||||
let to_folder = config.folder_alias(to_folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.copy_emails(&from_folder, &to_folder, ids)?;
|
||||
printer.print("Email(s) successfully copied!")
|
||||
}
|
||||
|
||||
pub fn delete<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn delete<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
ids: Vec<&str>,
|
||||
) -> Result<()> {
|
||||
let folder = config.folder_alias(folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.delete_emails(&folder, ids)?;
|
||||
printer.print("Email(s) successfully deleted!")
|
||||
}
|
||||
|
||||
pub fn forward<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
||||
pub fn forward<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
sender: &mut S,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
sender: &mut dyn Sender,
|
||||
folder: &str,
|
||||
id: &str,
|
||||
headers: Option<Vec<&str>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let folder = config.folder_alias(folder)?;
|
||||
let ids = id_mapper.get_ids([id])?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let tpl = backend
|
||||
.get_emails(&folder, vec![id])?
|
||||
.get_emails(&folder, ids)?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_forward_tpl_builder(config)?
|
||||
|
@ -121,10 +133,11 @@ pub fn forward<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn list<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
max_width: Option<usize>,
|
||||
page_size: Option<usize>,
|
||||
|
@ -133,8 +146,11 @@ pub fn list<P: Printer, B: Backend + ?Sized>(
|
|||
let folder = config.folder_alias(folder)?;
|
||||
let page_size = page_size.unwrap_or(config.email_listing_page_size());
|
||||
debug!("page size: {}", page_size);
|
||||
let envelopes: Envelopes = backend.list_envelopes(&folder, page_size, page)?.into();
|
||||
|
||||
let mut envelopes: Envelopes = backend.list_envelopes(&folder, page_size, page)?.into();
|
||||
envelopes.remap_ids(id_mapper)?;
|
||||
trace!("envelopes: {:?}", envelopes);
|
||||
|
||||
printer.print_table(
|
||||
Box::new(envelopes),
|
||||
PrintTableOpts {
|
||||
|
@ -147,11 +163,11 @@ pub fn list<P: Printer, B: Backend + ?Sized>(
|
|||
/// Parses and edits a message from a [mailto] URL string.
|
||||
///
|
||||
/// [mailto]: https://en.wikipedia.org/wiki/Mailto
|
||||
pub fn mailto<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
||||
pub fn mailto<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
sender: &mut S,
|
||||
backend: &mut dyn Backend,
|
||||
sender: &mut dyn Sender,
|
||||
url: &Url,
|
||||
) -> Result<()> {
|
||||
let mut tpl = TplBuilder::default().to(url.path());
|
||||
|
@ -169,24 +185,28 @@ pub fn mailto<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
|||
editor::edit_tpl_with_editor(config, printer, backend, sender, tpl.build())
|
||||
}
|
||||
|
||||
pub fn move_<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn move_<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
from_folder: &str,
|
||||
to_folder: &str,
|
||||
ids: Vec<&str>,
|
||||
) -> Result<()> {
|
||||
let from_folder = config.folder_alias(from_folder)?;
|
||||
let to_folder = config.folder_alias(to_folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.move_emails(&from_folder, &to_folder, ids)?;
|
||||
printer.print("Email(s) successfully moved!")
|
||||
}
|
||||
|
||||
pub fn read<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn read<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
ids: Vec<&str>,
|
||||
text_mime: &str,
|
||||
|
@ -195,6 +215,8 @@ pub fn read<P: Printer, B: Backend + ?Sized>(
|
|||
headers: Vec<&str>,
|
||||
) -> Result<()> {
|
||||
let folder = config.folder_alias(folder)?;
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let emails = backend.get_emails(&folder, ids)?;
|
||||
|
||||
let mut glue = "";
|
||||
|
@ -230,11 +252,12 @@ pub fn read<P: Printer, B: Backend + ?Sized>(
|
|||
printer.print(bodies)
|
||||
}
|
||||
|
||||
pub fn reply<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
||||
pub fn reply<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
sender: &mut S,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
sender: &mut dyn Sender,
|
||||
folder: &str,
|
||||
id: &str,
|
||||
all: bool,
|
||||
|
@ -242,8 +265,10 @@ pub fn reply<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
|||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let folder = config.folder_alias(folder)?;
|
||||
let ids = id_mapper.get_ids([id])?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let tpl = backend
|
||||
.get_emails(&folder, vec![id])?
|
||||
.get_emails(&folder, ids)?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_reply_tpl_builder(config, all)?
|
||||
|
@ -256,10 +281,11 @@ pub fn reply<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn save<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
raw_email: String,
|
||||
) -> Result<()> {
|
||||
|
@ -276,14 +302,18 @@ pub fn save<P: Printer, B: Backend + ?Sized>(
|
|||
.collect::<Vec<String>>()
|
||||
.join("\r\n")
|
||||
};
|
||||
backend.add_email(&folder, raw_email.as_bytes(), &Flags::default())?;
|
||||
|
||||
let id = backend.add_email(&folder, raw_email.as_bytes(), &Flags::default())?;
|
||||
id_mapper.create_alias(id)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn search<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn search<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
query: String,
|
||||
max_width: Option<usize>,
|
||||
|
@ -292,9 +322,10 @@ pub fn search<P: Printer, B: Backend + ?Sized>(
|
|||
) -> Result<()> {
|
||||
let folder = config.folder_alias(folder)?;
|
||||
let page_size = page_size.unwrap_or(config.email_listing_page_size());
|
||||
let envelopes: Envelopes = backend
|
||||
let mut envelopes: Envelopes = backend
|
||||
.search_envelopes(&folder, &query, "", page_size, page)?
|
||||
.into();
|
||||
envelopes.remap_ids(id_mapper)?;
|
||||
let opts = PrintTableOpts {
|
||||
format: &config.email_reading_format,
|
||||
max_width,
|
||||
|
@ -303,10 +334,11 @@ pub fn search<P: Printer, B: Backend + ?Sized>(
|
|||
printer.print_table(Box::new(envelopes), opts)
|
||||
}
|
||||
|
||||
pub fn sort<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn sort<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
sort: String,
|
||||
query: String,
|
||||
|
@ -316,9 +348,10 @@ pub fn sort<P: Printer, B: Backend + ?Sized>(
|
|||
) -> Result<()> {
|
||||
let folder = config.folder_alias(folder)?;
|
||||
let page_size = page_size.unwrap_or(config.email_listing_page_size());
|
||||
let envelopes: Envelopes = backend
|
||||
let mut envelopes: Envelopes = backend
|
||||
.search_envelopes(&folder, &query, &sort, page_size, page)?
|
||||
.into();
|
||||
envelopes.remap_ids(id_mapper)?;
|
||||
let opts = PrintTableOpts {
|
||||
format: &config.email_reading_format,
|
||||
max_width,
|
||||
|
@ -327,11 +360,11 @@ pub fn sort<P: Printer, B: Backend + ?Sized>(
|
|||
printer.print_table(Box::new(envelopes), opts)
|
||||
}
|
||||
|
||||
pub fn send<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
||||
pub fn send<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
sender: &mut S,
|
||||
backend: &mut dyn Backend,
|
||||
sender: &mut dyn Sender,
|
||||
raw_email: String,
|
||||
) -> Result<()> {
|
||||
let folder = config.sent_folder_alias()?;
|
||||
|
@ -357,11 +390,11 @@ pub fn send<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
||||
pub fn write<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
sender: &mut S,
|
||||
backend: &mut dyn Backend,
|
||||
sender: &mut dyn Sender,
|
||||
headers: Option<Vec<&str>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
use std::ops;
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
use std::ops;
|
||||
|
||||
use crate::{
|
||||
printer::{PrintTable, PrintTableOpts, WriteColor},
|
||||
ui::Table,
|
||||
Envelope,
|
||||
Envelope, IdMapper,
|
||||
};
|
||||
|
||||
/// Represents the list of envelopes.
|
||||
#[derive(Clone, Debug, Default, Serialize)]
|
||||
pub struct Envelopes(Vec<Envelope>);
|
||||
|
||||
impl Envelopes {
|
||||
pub fn remap_ids(&mut self, id_mapper: &IdMapper) -> Result<()> {
|
||||
for envelope in &mut self.0 {
|
||||
envelope.id = id_mapper.get_or_create_alias(&envelope.id)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for Envelopes {
|
||||
type Target = Vec<Envelope>;
|
||||
|
||||
|
|
|
@ -1,37 +1,46 @@
|
|||
use anyhow::Result;
|
||||
use pimalaya_email::{Backend, Flags};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::{printer::Printer, IdMapper};
|
||||
|
||||
pub fn add<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn add<P: Printer>(
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
ids: Vec<&str>,
|
||||
flags: &Flags,
|
||||
) -> Result<()> {
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.add_flags(folder, ids, flags)?;
|
||||
printer.print("Flag(s) successfully added!")
|
||||
}
|
||||
|
||||
pub fn set<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn set<P: Printer>(
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
ids: Vec<&str>,
|
||||
flags: &Flags,
|
||||
) -> Result<()> {
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.set_flags(folder, ids, flags)?;
|
||||
printer.print("Flag(s) successfully set!")
|
||||
}
|
||||
|
||||
pub fn remove<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn remove<P: Printer>(
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
ids: Vec<&str>,
|
||||
flags: &Flags,
|
||||
) -> Result<()> {
|
||||
let ids = id_mapper.get_ids(ids)?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
backend.remove_flags(folder, ids, flags)?;
|
||||
printer.print("Flag(s) successfully removed!")
|
||||
}
|
||||
|
|
|
@ -12,19 +12,15 @@ use crate::{
|
|||
Folders,
|
||||
};
|
||||
|
||||
pub fn expunge<P: Printer, B: Backend + ?Sized>(
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
folder: &str,
|
||||
) -> Result<()> {
|
||||
pub fn expunge<P: Printer>(printer: &mut P, backend: &mut dyn Backend, folder: &str) -> Result<()> {
|
||||
backend.expunge_folder(folder)?;
|
||||
printer.print(format!("Folder {folder} successfully expunged!"))
|
||||
}
|
||||
|
||||
pub fn list<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn list<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
backend: &mut dyn Backend,
|
||||
max_width: Option<usize>,
|
||||
) -> Result<()> {
|
||||
let folders: Folders = backend.list_folders()?.into();
|
||||
|
@ -38,20 +34,12 @@ pub fn list<P: Printer, B: Backend + ?Sized>(
|
|||
)
|
||||
}
|
||||
|
||||
pub fn create<P: Printer, B: Backend + ?Sized>(
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
folder: &str,
|
||||
) -> Result<()> {
|
||||
pub fn create<P: Printer>(printer: &mut P, backend: &mut dyn Backend, folder: &str) -> Result<()> {
|
||||
backend.add_folder(folder)?;
|
||||
printer.print("Folder successfully created!")
|
||||
}
|
||||
|
||||
pub fn delete<P: Printer, B: Backend + ?Sized>(
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
folder: &str,
|
||||
) -> Result<()> {
|
||||
pub fn delete<P: Printer>(printer: &mut P, backend: &mut dyn Backend, folder: &str) -> Result<()> {
|
||||
if let Some(false) | None = Confirm::new()
|
||||
.with_prompt(format!("Confirm deletion of folder {folder}?"))
|
||||
.default(false)
|
||||
|
@ -176,9 +164,6 @@ mod tests {
|
|||
fn get_envelope(&self, _: &str, _: &str) -> backend::Result<Envelope> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn get_envelope_internal(&self, _: &str, _: &str) -> backend::Result<Envelope> {
|
||||
unimplemented!();
|
||||
}
|
||||
fn list_envelopes(&self, _: &str, _: usize, _: usize) -> backend::Result<Envelopes> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -195,60 +180,31 @@ mod tests {
|
|||
fn add_email(&self, _: &str, _: &[u8], _: &Flags) -> backend::Result<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn add_email_internal(&self, _: &str, _: &[u8], _: &Flags) -> backend::Result<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_emails(&self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn preview_emails(&self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_emails_internal(&self, _: &str, _: Vec<&str>) -> backend::Result<Emails> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn copy_emails(&self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn copy_emails_internal(&self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn move_emails(&self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn move_emails_internal(&self, _: &str, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn delete_emails(&self, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn delete_emails_internal(&self, _: &str, _: Vec<&str>) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn add_flags(&self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn add_flags_internal(&self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_flags(&self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_flags_internal(&self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn remove_flags(&self, _: &str, _: Vec<&str>, _: &Flags) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn remove_flags_internal(
|
||||
&self,
|
||||
_: &str,
|
||||
_: Vec<&str>,
|
||||
_: &Flags,
|
||||
) -> backend::Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn as_any(&'static self) -> &(dyn Any) {
|
||||
fn as_any(&self) -> &(dyn Any) {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,19 +3,22 @@ use atty::Stream;
|
|||
use pimalaya_email::{AccountConfig, Backend, CompilerBuilder, Email, Flags, Sender, Tpl};
|
||||
use std::io::{stdin, BufRead};
|
||||
|
||||
use crate::printer::Printer;
|
||||
use crate::{printer::Printer, IdMapper};
|
||||
|
||||
pub fn forward<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn forward<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
id: &str,
|
||||
headers: Option<Vec<&str>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let ids = id_mapper.get_ids([id])?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let tpl = backend
|
||||
.get_emails(folder, vec![id])?
|
||||
.get_emails(folder, ids)?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_forward_tpl_builder(config)?
|
||||
|
@ -26,18 +29,21 @@ pub fn forward<P: Printer, B: Backend + ?Sized>(
|
|||
printer.print(<Tpl as Into<String>>::into(tpl))
|
||||
}
|
||||
|
||||
pub fn reply<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn reply<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
id: &str,
|
||||
all: bool,
|
||||
headers: Option<Vec<&str>>,
|
||||
body: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let ids = id_mapper.get_ids([id])?;
|
||||
let ids = ids.iter().map(String::as_str).collect::<Vec<_>>();
|
||||
let tpl = backend
|
||||
.get_emails(folder, vec![id])?
|
||||
.get_emails(folder, ids)?
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("cannot find email {}", id))?
|
||||
.to_reply_tpl_builder(config, all)?
|
||||
|
@ -48,10 +54,11 @@ pub fn reply<P: Printer, B: Backend + ?Sized>(
|
|||
printer.print(<Tpl as Into<String>>::into(tpl))
|
||||
}
|
||||
|
||||
pub fn save<P: Printer, B: Backend + ?Sized>(
|
||||
pub fn save<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
id_mapper: &IdMapper,
|
||||
backend: &mut dyn Backend,
|
||||
folder: &str,
|
||||
tpl: String,
|
||||
) -> Result<()> {
|
||||
|
@ -71,15 +78,17 @@ pub fn save<P: Printer, B: Backend + ?Sized>(
|
|||
.some_pgp_encrypt_cmd(config.email_writing_encrypt_cmd.as_ref()),
|
||||
)?;
|
||||
|
||||
backend.add_email(folder, &email, &Flags::default())?;
|
||||
let id = backend.add_email(folder, &email, &Flags::default())?;
|
||||
id_mapper.create_alias(id)?;
|
||||
|
||||
printer.print("Template successfully saved!")
|
||||
}
|
||||
|
||||
pub fn send<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
||||
pub fn send<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
sender: &mut S,
|
||||
backend: &mut dyn Backend,
|
||||
sender: &mut dyn Sender,
|
||||
folder: &str,
|
||||
tpl: String,
|
||||
) -> Result<()> {
|
||||
|
@ -114,6 +123,5 @@ pub fn write<'a, P: Printer>(
|
|||
.set_some_raw_headers(headers)
|
||||
.some_text_plain_part(body)
|
||||
.build();
|
||||
|
||||
printer.print(<Tpl as Into<String>>::into(tpl))
|
||||
}
|
||||
|
|
|
@ -7,4 +7,5 @@ pub mod output;
|
|||
pub mod printer;
|
||||
pub mod ui;
|
||||
|
||||
pub use cache::*;
|
||||
pub use domain::*;
|
||||
|
|
127
src/main.rs
127
src/main.rs
|
@ -1,6 +1,9 @@
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
use clap::Command;
|
||||
use std::{borrow::Cow, env};
|
||||
use pimalaya_email::{
|
||||
BackendBuilder, BackendConfig, ImapBackend, SenderBuilder, DEFAULT_INBOX_FOLDER,
|
||||
};
|
||||
use std::env;
|
||||
use url::Url;
|
||||
|
||||
use himalaya::{
|
||||
|
@ -8,10 +11,7 @@ use himalaya::{
|
|||
config::{self, DeserializedConfig},
|
||||
email, flag, folder, man, output,
|
||||
printer::StdoutPrinter,
|
||||
tpl,
|
||||
};
|
||||
use pimalaya_email::{
|
||||
BackendBuilder, BackendConfig, ImapBackend, SenderBuilder, DEFAULT_INBOX_FOLDER,
|
||||
tpl, IdMapper,
|
||||
};
|
||||
|
||||
#[cfg(feature = "imap-backend")]
|
||||
|
@ -52,7 +52,8 @@ fn main() -> Result<()> {
|
|||
let url = Url::parse(&raw_args[1])?;
|
||||
let config = DeserializedConfig::from_opt_path(None)?;
|
||||
let (account_config, backend_config) = config.to_configs(None)?;
|
||||
let mut backend = BackendBuilder::new().build(&account_config, &backend_config)?;
|
||||
let mut backend =
|
||||
BackendBuilder::new().build(account_config.clone(), backend_config.clone())?;
|
||||
let mut sender = SenderBuilder::build(&account_config)?;
|
||||
let mut printer = StdoutPrinter::default();
|
||||
|
||||
|
@ -99,13 +100,11 @@ fn main() -> Result<()> {
|
|||
// recreating an instance.
|
||||
match imap::args::matches(&m)? {
|
||||
Some(imap::args::Cmd::Notify(keepalive)) => {
|
||||
let imap =
|
||||
ImapBackend::new(Cow::Borrowed(&account_config), Cow::Borrowed(&imap_config))?;
|
||||
let imap = ImapBackend::new(account_config.clone(), imap_config.clone())?;
|
||||
return imap::handlers::notify(&imap, &folder, keepalive);
|
||||
}
|
||||
Some(imap::args::Cmd::Watch(keepalive)) => {
|
||||
let imap =
|
||||
ImapBackend::new(Cow::Borrowed(&account_config), Cow::Borrowed(&imap_config))?;
|
||||
let imap = ImapBackend::new(account_config.clone(), imap_config.clone())?;
|
||||
return imap::handlers::watch(&imap, &folder, keepalive);
|
||||
}
|
||||
_ => (),
|
||||
|
@ -126,7 +125,7 @@ fn main() -> Result<()> {
|
|||
let backend = BackendBuilder::new()
|
||||
.sessions_pool_size(8)
|
||||
.disable_cache(true)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
account::handlers::sync(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
|
@ -152,13 +151,13 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder)?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
return folder::handlers::create(&mut printer, backend.as_mut(), &folder);
|
||||
}
|
||||
Some(folder::args::Cmd::List(max_width)) => {
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
return folder::handlers::list(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
|
@ -170,7 +169,7 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
return folder::handlers::expunge(&mut printer, backend.as_mut(), &folder);
|
||||
}
|
||||
Some(folder::args::Cmd::Delete) => {
|
||||
|
@ -180,7 +179,7 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder)?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
return folder::handlers::delete(&mut printer, backend.as_mut(), &folder);
|
||||
}
|
||||
_ => (),
|
||||
|
@ -192,10 +191,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::attachments(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
|
@ -205,10 +206,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::copy(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
to_folder,
|
||||
|
@ -219,10 +222,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::delete(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
|
@ -232,10 +237,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::forward(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
sender.as_mut(),
|
||||
&folder,
|
||||
|
@ -248,10 +255,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::list(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
max_width,
|
||||
|
@ -263,10 +272,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::move_(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
to_folder,
|
||||
|
@ -277,10 +288,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::read(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
|
@ -294,10 +307,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::reply(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
sender.as_mut(),
|
||||
&folder,
|
||||
|
@ -311,10 +326,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::save(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
raw_email,
|
||||
|
@ -324,10 +341,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::search(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
query,
|
||||
|
@ -340,10 +359,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return email::handlers::sort(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
criteria,
|
||||
|
@ -356,7 +377,7 @@ fn main() -> Result<()> {
|
|||
Some(email::args::Cmd::Send(raw_email)) => {
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
return email::handlers::send(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
|
@ -370,22 +391,46 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
return flag::handlers::set(&mut printer, backend.as_mut(), &folder, ids, flags);
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return flag::handlers::set(
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
flags,
|
||||
);
|
||||
}
|
||||
Some(flag::args::Cmd::Add(ids, ref flags)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
return flag::handlers::add(&mut printer, backend.as_mut(), &folder, ids, flags);
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return flag::handlers::add(
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
flags,
|
||||
);
|
||||
}
|
||||
Some(flag::args::Cmd::Remove(ids, ref flags)) => {
|
||||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
return flag::handlers::remove(&mut printer, backend.as_mut(), &folder, ids, flags);
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return flag::handlers::remove(
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
ids,
|
||||
flags,
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
|
@ -394,10 +439,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return tpl::handlers::forward(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
id,
|
||||
|
@ -412,10 +459,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return tpl::handlers::reply(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
id,
|
||||
|
@ -428,10 +477,12 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
let id_mapper = IdMapper::new(backend.as_ref(), &account_config.name, &folder)?;
|
||||
return tpl::handlers::save(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
&id_mapper,
|
||||
backend.as_mut(),
|
||||
&folder,
|
||||
tpl,
|
||||
|
@ -441,7 +492,7 @@ fn main() -> Result<()> {
|
|||
let folder = account_config.folder_alias(folder.unwrap_or(DEFAULT_INBOX_FOLDER))?;
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
return tpl::handlers::send(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
|
@ -456,7 +507,7 @@ fn main() -> Result<()> {
|
|||
Some(email::args::Cmd::Write(headers, body)) => {
|
||||
let mut backend = BackendBuilder::new()
|
||||
.disable_cache(disable_cache)
|
||||
.build(&account_config, &backend_config)?;
|
||||
.build(account_config.clone(), backend_config.clone())?;
|
||||
return email::handlers::write(
|
||||
&account_config,
|
||||
&mut printer,
|
||||
|
|
|
@ -37,11 +37,11 @@ pub fn open_with_local_draft() -> Result<Tpl> {
|
|||
open_with_tpl(Tpl::from(content))
|
||||
}
|
||||
|
||||
pub fn edit_tpl_with_editor<P: Printer, B: Backend + ?Sized, S: Sender + ?Sized>(
|
||||
pub fn edit_tpl_with_editor<P: Printer>(
|
||||
config: &AccountConfig,
|
||||
printer: &mut P,
|
||||
backend: &mut B,
|
||||
sender: &mut S,
|
||||
backend: &mut dyn Backend,
|
||||
sender: &mut dyn Sender,
|
||||
mut tpl: Tpl,
|
||||
) -> Result<()> {
|
||||
let draft = local_draft_path();
|
||||
|
|
Loading…
Reference in a new issue