replace xxx-folder config props by mailboxes

This commit is contained in:
Clément DOUIN 2022-02-25 21:56:48 +01:00
parent 34ab0f4fa5
commit b855c44508
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
8 changed files with 56 additions and 57 deletions

View file

@ -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]
- 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
### Added

View file

@ -3,7 +3,7 @@ use std::{convert::TryInto, fs, path::PathBuf};
use crate::{
backends::{Backend, MaildirEnvelopes, MaildirFlags, MaildirMboxes},
config::{AccountConfig, MaildirBackendConfig},
config::{AccountConfig, MaildirBackendConfig, DEFAULT_INBOX_FOLDER},
mbox::Mboxes,
msg::{Envelopes, Msg},
};
@ -36,7 +36,14 @@ impl<'a> MaildirBackend<'a> {
}
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())
.map(maildir::Maildir::from)
} else {

View file

@ -2,7 +2,7 @@ use anyhow::{anyhow, Context, Result};
use lettre::transport::smtp::authentication::Credentials as SmtpCredentials;
use log::{debug, info, trace};
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};
@ -23,12 +23,6 @@ pub struct AccountConfig {
pub sig: Option<String>,
/// Represents the default page size for listings.
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.
pub notify_cmd: Option<String>,
/// Overrides the default IMAP query "NEW" used to fetch new messages
@ -36,6 +30,9 @@ pub struct AccountConfig {
/// Represents the watch commands.
pub watch_cmds: Vec<String>,
/// Represents mailbox aliases.
pub mailboxes: HashMap<String, String>,
/// Represents the SMTP host.
pub smtp_host: String,
/// Represents the SMTP port.
@ -137,24 +134,6 @@ impl<'a> AccountConfig {
downloads_dir,
sig,
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_query: base_account
.notify_query
@ -168,6 +147,7 @@ impl<'a> AccountConfig {
.or_else(|| config.watch_cmds.as_ref())
.unwrap_or(&vec![])
.to_owned(),
mailboxes: base_account.mailboxes.clone(),
default: base_account.default.unwrap_or_default(),
email: base_account.email.to_owned(),

View file

@ -1,5 +1,5 @@
use serde::Deserialize;
use std::path::PathBuf;
use std::{collections::HashMap, path::PathBuf};
pub trait ToDeserializedBaseAccountConfig {
fn to_base(&self) -> DeserializedBaseAccountConfig;
@ -39,12 +39,6 @@ macro_rules! make_account_config {
pub signature_delimiter: Option<String>,
/// Overrides the default page size for this account.
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.
pub notify_cmd: Option<String>,
/// 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.
pub pgp_decrypt_cmd: Option<String>,
/// Represents mailbox aliases.
#[serde(default)]
pub mailboxes: HashMap<String, String>,
$(pub $element: $ty),*
}
@ -86,9 +84,6 @@ macro_rules! make_account_config {
signature: self.signature.clone(),
signature_delimiter: self.signature_delimiter.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_query: self.notify_query.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_decrypt_cmd: self.pgp_decrypt_cmd.clone(),
mailboxes: self.mailboxes.clone(),
}
}
}

View file

@ -27,12 +27,6 @@ pub struct DeserializedConfig {
pub signature_delimiter: Option<String>,
/// Represents the default page size for listings.
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.
pub notify_cmd: Option<String>,
/// Overrides the default IMAP query "NEW" used to fetch new messages
@ -48,12 +42,12 @@ pub struct DeserializedConfig {
impl DeserializedConfig {
/// Tries to create a config from an optional path.
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);
let path = path.map(|s| s.into()).unwrap_or(Self::path()?);
let content = fs::read_to_string(path).context("cannot read 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);
Ok(config)
}

View file

@ -5,7 +5,10 @@ use url::Url;
use himalaya::{
backends::{imap_arg, imap_handler, Backend, ImapBackend, MaildirBackend, NotmuchBackend},
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},
msg::{flag_arg, flag_handler, msg_arg, msg_handler, tpl_arg, tpl_handler},
output::{output_arg, OutputFmt, StdoutPrinter},
@ -82,7 +85,8 @@ fn main() -> Result<()> {
AccountConfig::from_config_and_opt_account_name(&config, m.value_of("account"))?;
let mbox = m
.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 imap;
let mut maildir;

View file

@ -10,7 +10,7 @@ use uuid::Uuid;
use crate::{
backends::Backend,
config::{AccountConfig, DEFAULT_SIG_DELIM},
config::{AccountConfig, DEFAULT_DRAFT_FOLDER, DEFAULT_SENT_FOLDER, DEFAULT_SIG_DELIM},
msg::{
from_addrs_to_sendable_addrs, from_addrs_to_sendable_mbox, from_slice_to_addrs, msg_utils,
Addrs, BinaryPart, Part, Parts, TextPlainPart, TplOverride,
@ -340,7 +340,12 @@ impl Msg {
match choice::post_edit() {
Ok(PostEditChoice::Send) => {
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()?;
printer.print("Message successfully sent")?;
break;
@ -355,12 +360,14 @@ impl Msg {
}
Ok(PostEditChoice::RemoteDraft) => {
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()?;
printer.print(format!(
"Message successfully saved to {}",
account.draft_folder
))?;
printer.print(format!("Message successfully saved to {}", draft_folder))?;
break;
}
Ok(PostEditChoice::Discard) => {

View file

@ -16,7 +16,7 @@ use url::Url;
use crate::{
backends::Backend,
config::AccountConfig,
config::{AccountConfig, DEFAULT_SENT_FOLDER},
msg::{Msg, Part, Parts, TextPlainPart},
output::{PrintTableOpts, PrinterService},
smtp::SmtpService,
@ -312,6 +312,13 @@ pub fn send<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
let is_json = printer.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 {
raw_msg.replace("\r", "").replace("\n", "\r\n")
} else {
@ -325,9 +332,8 @@ pub fn send<'a, P: PrinterService, B: Backend<'a> + ?Sized, S: SmtpService>(
trace!("raw message: {:?}", raw_msg);
let envelope: lettre::address::Envelope = Msg::from_tpl(&raw_msg)?.try_into()?;
trace!("envelope: {:?}", envelope);
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(())
}