mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-20 07:01:12 +00:00
replace xxx-folder
config props by mailboxes
This commit is contained in:
parent
34ab0f4fa5
commit
b855c44508
|
@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- No tilde expansion in `maildir-dir` [#305]
|
- No tilde expansion in `maildir-dir` [#305]
|
||||||
- Unknown command SORT [#308]
|
- Unknown command SORT [#308]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- [**BREAKING**] Replace `inbox-folder`, `sent-folder` and `draft-folder` by a generic hashmap `mailboxes`
|
||||||
|
|
||||||
## [0.5.6] - 2022-02-22
|
## [0.5.6] - 2022-02-22
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::{convert::TryInto, fs, path::PathBuf};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::{Backend, MaildirEnvelopes, MaildirFlags, MaildirMboxes},
|
backends::{Backend, MaildirEnvelopes, MaildirFlags, MaildirMboxes},
|
||||||
config::{AccountConfig, MaildirBackendConfig},
|
config::{AccountConfig, MaildirBackendConfig, DEFAULT_INBOX_FOLDER},
|
||||||
mbox::Mboxes,
|
mbox::Mboxes,
|
||||||
msg::{Envelopes, Msg},
|
msg::{Envelopes, Msg},
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,14 @@ impl<'a> MaildirBackend<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mdir_from_name(&self, mdir: &str) -> Result<maildir::Maildir> {
|
fn get_mdir_from_name(&self, mdir: &str) -> Result<maildir::Maildir> {
|
||||||
if mdir == self.account_config.inbox_folder {
|
let inbox_folder = self
|
||||||
|
.account_config
|
||||||
|
.mailboxes
|
||||||
|
.get("inbox")
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||||
|
|
||||||
|
if mdir == inbox_folder {
|
||||||
self.validate_mdir_path(self.mdir.path().to_owned())
|
self.validate_mdir_path(self.mdir.path().to_owned())
|
||||||
.map(maildir::Maildir::from)
|
.map(maildir::Maildir::from)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{anyhow, Context, Result};
|
||||||
use lettre::transport::smtp::authentication::Credentials as SmtpCredentials;
|
use lettre::transport::smtp::authentication::Credentials as SmtpCredentials;
|
||||||
use log::{debug, info, trace};
|
use log::{debug, info, trace};
|
||||||
use mailparse::MailAddr;
|
use mailparse::MailAddr;
|
||||||
use std::{env, ffi::OsStr, fs, path::PathBuf};
|
use std::{collections::HashMap, env, ffi::OsStr, fs, path::PathBuf};
|
||||||
|
|
||||||
use crate::{config::*, output::run_cmd};
|
use crate::{config::*, output::run_cmd};
|
||||||
|
|
||||||
|
@ -23,12 +23,6 @@ pub struct AccountConfig {
|
||||||
pub sig: Option<String>,
|
pub sig: Option<String>,
|
||||||
/// Represents the default page size for listings.
|
/// Represents the default page size for listings.
|
||||||
pub default_page_size: usize,
|
pub default_page_size: usize,
|
||||||
/// Represents the inbox folder name for this account.
|
|
||||||
pub inbox_folder: String,
|
|
||||||
/// Represents the sent folder name for this account.
|
|
||||||
pub sent_folder: String,
|
|
||||||
/// Represents the draft folder name for this account.
|
|
||||||
pub draft_folder: String,
|
|
||||||
/// Represents the notify command.
|
/// Represents the notify command.
|
||||||
pub notify_cmd: Option<String>,
|
pub notify_cmd: Option<String>,
|
||||||
/// Overrides the default IMAP query "NEW" used to fetch new messages
|
/// Overrides the default IMAP query "NEW" used to fetch new messages
|
||||||
|
@ -36,6 +30,9 @@ pub struct AccountConfig {
|
||||||
/// Represents the watch commands.
|
/// Represents the watch commands.
|
||||||
pub watch_cmds: Vec<String>,
|
pub watch_cmds: Vec<String>,
|
||||||
|
|
||||||
|
/// Represents mailbox aliases.
|
||||||
|
pub mailboxes: HashMap<String, String>,
|
||||||
|
|
||||||
/// Represents the SMTP host.
|
/// Represents the SMTP host.
|
||||||
pub smtp_host: String,
|
pub smtp_host: String,
|
||||||
/// Represents the SMTP port.
|
/// Represents the SMTP port.
|
||||||
|
@ -137,24 +134,6 @@ impl<'a> AccountConfig {
|
||||||
downloads_dir,
|
downloads_dir,
|
||||||
sig,
|
sig,
|
||||||
default_page_size,
|
default_page_size,
|
||||||
inbox_folder: base_account
|
|
||||||
.inbox_folder
|
|
||||||
.as_deref()
|
|
||||||
.or_else(|| config.inbox_folder.as_deref())
|
|
||||||
.unwrap_or(DEFAULT_INBOX_FOLDER)
|
|
||||||
.to_string(),
|
|
||||||
sent_folder: base_account
|
|
||||||
.sent_folder
|
|
||||||
.as_deref()
|
|
||||||
.or_else(|| config.sent_folder.as_deref())
|
|
||||||
.unwrap_or(DEFAULT_SENT_FOLDER)
|
|
||||||
.to_string(),
|
|
||||||
draft_folder: base_account
|
|
||||||
.draft_folder
|
|
||||||
.as_deref()
|
|
||||||
.or_else(|| config.draft_folder.as_deref())
|
|
||||||
.unwrap_or(DEFAULT_DRAFT_FOLDER)
|
|
||||||
.to_string(),
|
|
||||||
notify_cmd: base_account.notify_cmd.clone(),
|
notify_cmd: base_account.notify_cmd.clone(),
|
||||||
notify_query: base_account
|
notify_query: base_account
|
||||||
.notify_query
|
.notify_query
|
||||||
|
@ -168,6 +147,7 @@ impl<'a> AccountConfig {
|
||||||
.or_else(|| config.watch_cmds.as_ref())
|
.or_else(|| config.watch_cmds.as_ref())
|
||||||
.unwrap_or(&vec![])
|
.unwrap_or(&vec![])
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
|
mailboxes: base_account.mailboxes.clone(),
|
||||||
default: base_account.default.unwrap_or_default(),
|
default: base_account.default.unwrap_or_default(),
|
||||||
email: base_account.email.to_owned(),
|
email: base_account.email.to_owned(),
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::path::PathBuf;
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
pub trait ToDeserializedBaseAccountConfig {
|
pub trait ToDeserializedBaseAccountConfig {
|
||||||
fn to_base(&self) -> DeserializedBaseAccountConfig;
|
fn to_base(&self) -> DeserializedBaseAccountConfig;
|
||||||
|
@ -39,12 +39,6 @@ macro_rules! make_account_config {
|
||||||
pub signature_delimiter: Option<String>,
|
pub signature_delimiter: Option<String>,
|
||||||
/// Overrides the default page size for this account.
|
/// Overrides the default page size for this account.
|
||||||
pub default_page_size: Option<usize>,
|
pub default_page_size: Option<usize>,
|
||||||
/// Overrides the inbox folder name for this account.
|
|
||||||
pub inbox_folder: Option<String>,
|
|
||||||
/// Overrides the sent folder name for this account.
|
|
||||||
pub sent_folder: Option<String>,
|
|
||||||
/// Overrides the draft folder name for this account.
|
|
||||||
pub draft_folder: Option<String>,
|
|
||||||
/// Overrides the notify command for this account.
|
/// Overrides the notify command for this account.
|
||||||
pub notify_cmd: Option<String>,
|
pub notify_cmd: Option<String>,
|
||||||
/// Overrides the IMAP query used to fetch new messages for this account.
|
/// Overrides the IMAP query used to fetch new messages for this account.
|
||||||
|
@ -75,6 +69,10 @@ macro_rules! make_account_config {
|
||||||
/// Represents the command used to decrypt a message.
|
/// Represents the command used to decrypt a message.
|
||||||
pub pgp_decrypt_cmd: Option<String>,
|
pub pgp_decrypt_cmd: Option<String>,
|
||||||
|
|
||||||
|
/// Represents mailbox aliases.
|
||||||
|
#[serde(default)]
|
||||||
|
pub mailboxes: HashMap<String, String>,
|
||||||
|
|
||||||
$(pub $element: $ty),*
|
$(pub $element: $ty),*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,9 +84,6 @@ macro_rules! make_account_config {
|
||||||
signature: self.signature.clone(),
|
signature: self.signature.clone(),
|
||||||
signature_delimiter: self.signature_delimiter.clone(),
|
signature_delimiter: self.signature_delimiter.clone(),
|
||||||
default_page_size: self.default_page_size.clone(),
|
default_page_size: self.default_page_size.clone(),
|
||||||
inbox_folder: self.inbox_folder.clone(),
|
|
||||||
sent_folder: self.sent_folder.clone(),
|
|
||||||
draft_folder: self.draft_folder.clone(),
|
|
||||||
notify_cmd: self.notify_cmd.clone(),
|
notify_cmd: self.notify_cmd.clone(),
|
||||||
notify_query: self.notify_query.clone(),
|
notify_query: self.notify_query.clone(),
|
||||||
watch_cmds: self.watch_cmds.clone(),
|
watch_cmds: self.watch_cmds.clone(),
|
||||||
|
@ -105,6 +100,8 @@ macro_rules! make_account_config {
|
||||||
|
|
||||||
pgp_encrypt_cmd: self.pgp_encrypt_cmd.clone(),
|
pgp_encrypt_cmd: self.pgp_encrypt_cmd.clone(),
|
||||||
pgp_decrypt_cmd: self.pgp_decrypt_cmd.clone(),
|
pgp_decrypt_cmd: self.pgp_decrypt_cmd.clone(),
|
||||||
|
|
||||||
|
mailboxes: self.mailboxes.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,6 @@ pub struct DeserializedConfig {
|
||||||
pub signature_delimiter: Option<String>,
|
pub signature_delimiter: Option<String>,
|
||||||
/// Represents the default page size for listings.
|
/// Represents the default page size for listings.
|
||||||
pub default_page_size: Option<usize>,
|
pub default_page_size: Option<usize>,
|
||||||
/// Overrides the default inbox folder name "INBOX".
|
|
||||||
pub inbox_folder: Option<String>,
|
|
||||||
/// Overrides the default sent folder name "Sent".
|
|
||||||
pub sent_folder: Option<String>,
|
|
||||||
/// Overrides the default draft folder name "Drafts".
|
|
||||||
pub draft_folder: Option<String>,
|
|
||||||
/// Represents the notify command.
|
/// Represents the notify command.
|
||||||
pub notify_cmd: Option<String>,
|
pub notify_cmd: Option<String>,
|
||||||
/// Overrides the default IMAP query "NEW" used to fetch new messages
|
/// Overrides the default IMAP query "NEW" used to fetch new messages
|
||||||
|
@ -48,12 +42,12 @@ pub struct DeserializedConfig {
|
||||||
impl DeserializedConfig {
|
impl DeserializedConfig {
|
||||||
/// Tries to create a config from an optional path.
|
/// Tries to create a config from an optional path.
|
||||||
pub fn from_opt_path(path: Option<&str>) -> Result<Self> {
|
pub fn from_opt_path(path: Option<&str>) -> Result<Self> {
|
||||||
info!("begin: trying to parse config from path");
|
info!("begin: try to parse config from path");
|
||||||
debug!("path: {:?}", path);
|
debug!("path: {:?}", path);
|
||||||
let path = path.map(|s| s.into()).unwrap_or(Self::path()?);
|
let path = path.map(|s| s.into()).unwrap_or(Self::path()?);
|
||||||
let content = fs::read_to_string(path).context("cannot read config file")?;
|
let content = fs::read_to_string(path).context("cannot read config file")?;
|
||||||
let config = toml::from_str(&content).context("cannot parse config file")?;
|
let config = toml::from_str(&content).context("cannot parse config file")?;
|
||||||
info!("end: trying to parse config from path");
|
info!("end: try to parse config from path");
|
||||||
trace!("config: {:?}", config);
|
trace!("config: {:?}", config);
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,10 @@ use url::Url;
|
||||||
use himalaya::{
|
use himalaya::{
|
||||||
backends::{imap_arg, imap_handler, Backend, ImapBackend, MaildirBackend, NotmuchBackend},
|
backends::{imap_arg, imap_handler, Backend, ImapBackend, MaildirBackend, NotmuchBackend},
|
||||||
compl::{compl_arg, compl_handler},
|
compl::{compl_arg, compl_handler},
|
||||||
config::{account_args, config_args, AccountConfig, BackendConfig, DeserializedConfig},
|
config::{
|
||||||
|
account_args, config_args, AccountConfig, BackendConfig, DeserializedConfig,
|
||||||
|
DEFAULT_INBOX_FOLDER,
|
||||||
|
},
|
||||||
mbox::{mbox_arg, mbox_handler},
|
mbox::{mbox_arg, mbox_handler},
|
||||||
msg::{flag_arg, flag_handler, msg_arg, msg_handler, tpl_arg, tpl_handler},
|
msg::{flag_arg, flag_handler, msg_arg, msg_handler, tpl_arg, tpl_handler},
|
||||||
output::{output_arg, OutputFmt, StdoutPrinter},
|
output::{output_arg, OutputFmt, StdoutPrinter},
|
||||||
|
@ -82,7 +85,8 @@ fn main() -> Result<()> {
|
||||||
AccountConfig::from_config_and_opt_account_name(&config, m.value_of("account"))?;
|
AccountConfig::from_config_and_opt_account_name(&config, m.value_of("account"))?;
|
||||||
let mbox = m
|
let mbox = m
|
||||||
.value_of("mbox-source")
|
.value_of("mbox-source")
|
||||||
.unwrap_or(&account_config.inbox_folder);
|
.or_else(|| account_config.mailboxes.get("inbox").map(|s| s.as_str()))
|
||||||
|
.unwrap_or(DEFAULT_INBOX_FOLDER);
|
||||||
let mut printer = StdoutPrinter::try_from(m.value_of("output"))?;
|
let mut printer = StdoutPrinter::try_from(m.value_of("output"))?;
|
||||||
let mut imap;
|
let mut imap;
|
||||||
let mut maildir;
|
let mut maildir;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::Backend,
|
backends::Backend,
|
||||||
config::{AccountConfig, DEFAULT_SIG_DELIM},
|
config::{AccountConfig, DEFAULT_DRAFT_FOLDER, DEFAULT_SENT_FOLDER, DEFAULT_SIG_DELIM},
|
||||||
msg::{
|
msg::{
|
||||||
from_addrs_to_sendable_addrs, from_addrs_to_sendable_mbox, from_slice_to_addrs, msg_utils,
|
from_addrs_to_sendable_addrs, from_addrs_to_sendable_mbox, from_slice_to_addrs, msg_utils,
|
||||||
Addrs, BinaryPart, Part, Parts, TextPlainPart, TplOverride,
|
Addrs, BinaryPart, Part, Parts, TextPlainPart, TplOverride,
|
||||||
|
@ -340,7 +340,12 @@ impl Msg {
|
||||||
match choice::post_edit() {
|
match choice::post_edit() {
|
||||||
Ok(PostEditChoice::Send) => {
|
Ok(PostEditChoice::Send) => {
|
||||||
let sent_msg = smtp.send_msg(account, &self)?;
|
let sent_msg = smtp.send_msg(account, &self)?;
|
||||||
backend.add_msg(&account.sent_folder, &sent_msg.formatted(), "seen")?;
|
let sent_folder = account
|
||||||
|
.mailboxes
|
||||||
|
.get("sent")
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
.unwrap_or(DEFAULT_SENT_FOLDER);
|
||||||
|
backend.add_msg(&sent_folder, &sent_msg.formatted(), "seen")?;
|
||||||
msg_utils::remove_local_draft()?;
|
msg_utils::remove_local_draft()?;
|
||||||
printer.print("Message successfully sent")?;
|
printer.print("Message successfully sent")?;
|
||||||
break;
|
break;
|
||||||
|
@ -355,12 +360,14 @@ impl Msg {
|
||||||
}
|
}
|
||||||
Ok(PostEditChoice::RemoteDraft) => {
|
Ok(PostEditChoice::RemoteDraft) => {
|
||||||
let tpl = self.to_tpl(TplOverride::default(), account)?;
|
let tpl = self.to_tpl(TplOverride::default(), account)?;
|
||||||
backend.add_msg(&account.draft_folder, tpl.as_bytes(), "seen draft")?;
|
let draft_folder = account
|
||||||
|
.mailboxes
|
||||||
|
.get("draft")
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
.unwrap_or(DEFAULT_DRAFT_FOLDER);
|
||||||
|
backend.add_msg(&draft_folder, tpl.as_bytes(), "seen draft")?;
|
||||||
msg_utils::remove_local_draft()?;
|
msg_utils::remove_local_draft()?;
|
||||||
printer.print(format!(
|
printer.print(format!("Message successfully saved to {}", draft_folder))?;
|
||||||
"Message successfully saved to {}",
|
|
||||||
account.draft_folder
|
|
||||||
))?;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(PostEditChoice::Discard) => {
|
Ok(PostEditChoice::Discard) => {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::Backend,
|
backends::Backend,
|
||||||
config::AccountConfig,
|
config::{AccountConfig, DEFAULT_SENT_FOLDER},
|
||||||
msg::{Msg, Part, Parts, TextPlainPart},
|
msg::{Msg, Part, Parts, TextPlainPart},
|
||||||
output::{PrintTableOpts, PrinterService},
|
output::{PrintTableOpts, PrinterService},
|
||||||
smtp::SmtpService,
|
smtp::SmtpService,
|
||||||
|
@ -312,6 +312,13 @@ pub fn send<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
||||||
let is_json = printer.is_json();
|
let is_json = printer.is_json();
|
||||||
debug!("is json: {}", is_json);
|
debug!("is json: {}", is_json);
|
||||||
|
|
||||||
|
let sent_folder = config
|
||||||
|
.mailboxes
|
||||||
|
.get("sent")
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
.unwrap_or(DEFAULT_SENT_FOLDER);
|
||||||
|
debug!("sent folder: {:?}", sent_folder);
|
||||||
|
|
||||||
let raw_msg = if is_tty || is_json {
|
let raw_msg = if is_tty || is_json {
|
||||||
raw_msg.replace("\r", "").replace("\n", "\r\n")
|
raw_msg.replace("\r", "").replace("\n", "\r\n")
|
||||||
} else {
|
} else {
|
||||||
|
@ -325,9 +332,8 @@ pub fn send<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
|
||||||
trace!("raw message: {:?}", raw_msg);
|
trace!("raw message: {:?}", raw_msg);
|
||||||
let envelope: lettre::address::Envelope = Msg::from_tpl(&raw_msg)?.try_into()?;
|
let envelope: lettre::address::Envelope = Msg::from_tpl(&raw_msg)?.try_into()?;
|
||||||
trace!("envelope: {:?}", envelope);
|
trace!("envelope: {:?}", envelope);
|
||||||
|
|
||||||
smtp.send_raw_msg(&envelope, raw_msg.as_bytes())?;
|
smtp.send_raw_msg(&envelope, raw_msg.as_bytes())?;
|
||||||
backend.add_msg(&config.sent_folder, raw_msg.as_bytes(), "seen")?;
|
backend.add_msg(&sent_folder, raw_msg.as_bytes(), "seen")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue