mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-05 17:15:12 +00:00
move watch command from folder to envelope
This commit is contained in:
parent
7fccdd822a
commit
d6bf407653
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1246,7 +1246,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "email-lib"
|
name = "email-lib"
|
||||||
version = "0.17.1"
|
version = "0.17.1"
|
||||||
source = "git+https://git.sr.ht/~soywod/pimalaya#8fb9b5ecc417a34a824a6decc3c0cda01af98ffe"
|
source = "git+https://git.sr.ht/~soywod/pimalaya#29d6c73d444e78d667d3d4d70d3ec2ffc032be6d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"advisory-lock",
|
"advisory-lock",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
|
@ -41,16 +41,19 @@ envelope.list.datetime-local-tz = true
|
||||||
# Override the backend used for listing envelopes.
|
# Override the backend used for listing envelopes.
|
||||||
envelope.list.backend = "imap"
|
envelope.list.backend = "imap"
|
||||||
|
|
||||||
|
# Send notification on receiving new envelopes
|
||||||
|
envelope.watch.received.notify.summary = "📬 New message from {sender}"
|
||||||
|
|
||||||
|
# Available placeholders: id, subject, sender, sender.name,
|
||||||
|
# sender.address, recipient, recipient.name, recipient.address.
|
||||||
|
envelope.watch.received.notify.body = "{subject}"
|
||||||
|
|
||||||
|
# Shell commands can also be executed when envelopes change
|
||||||
|
# envelope.watch.any.cmd = "mbsync -a"
|
||||||
|
|
||||||
# Override the backend used for sending messages.
|
# Override the backend used for sending messages.
|
||||||
message.send.backend = "smtp"
|
message.send.backend = "smtp"
|
||||||
|
|
||||||
# Send notification when receiving new messages
|
|
||||||
message.watch.received.notify.summary = "📬 New message from {sender}"
|
|
||||||
message.watch.received.notify.body = "{subject}"
|
|
||||||
|
|
||||||
# Shell commands can also be executed
|
|
||||||
# message.watch.received.cmd = "mbsync -a"
|
|
||||||
|
|
||||||
# IMAP config
|
# IMAP config
|
||||||
imap.host = "localhost"
|
imap.host = "localhost"
|
||||||
imap.port = 3143
|
imap.port = 3143
|
||||||
|
|
|
@ -192,9 +192,9 @@ impl TomlAccountConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_watch_message_kind(&self) -> Option<&BackendKind> {
|
pub fn get_watch_message_kind(&self) -> Option<&BackendKind> {
|
||||||
self.message
|
self.envelope
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|msg| msg.watch.as_ref())
|
.and_then(|envelope| envelope.watch.as_ref())
|
||||||
.and_then(|watch| watch.backend.as_ref())
|
.and_then(|watch| watch.backend.as_ref())
|
||||||
.or_else(|| self.backend.as_ref())
|
.or_else(|| self.backend.as_ref())
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,10 @@ use email::imap::{ImapSessionBuilder, ImapSessionSync};
|
||||||
use email::smtp::{SmtpClientBuilder, SmtpClientSync};
|
use email::smtp::{SmtpClientBuilder, SmtpClientSync};
|
||||||
use email::{
|
use email::{
|
||||||
account::config::AccountConfig,
|
account::config::AccountConfig,
|
||||||
email::watch::{imap::WatchImapEmails, maildir::WatchMaildirEmails},
|
|
||||||
envelope::{
|
envelope::{
|
||||||
get::{imap::GetEnvelopeImap, maildir::GetEnvelopeMaildir},
|
get::{imap::GetEnvelopeImap, maildir::GetEnvelopeMaildir},
|
||||||
list::{imap::ListEnvelopesImap, maildir::ListEnvelopesMaildir},
|
list::{imap::ListEnvelopesImap, maildir::ListEnvelopesMaildir},
|
||||||
|
watch::{imap::WatchImapEnvelopes, maildir::WatchMaildirEnvelopes},
|
||||||
Id, SingleId,
|
Id, SingleId,
|
||||||
},
|
},
|
||||||
flag::{
|
flag::{
|
||||||
|
@ -358,26 +358,27 @@ impl BackendBuilder {
|
||||||
|
|
||||||
match toml_account_config.backend {
|
match toml_account_config.backend {
|
||||||
Some(BackendKind::Maildir) => {
|
Some(BackendKind::Maildir) => {
|
||||||
backend_builder = backend_builder.with_watch_emails(|ctx| {
|
backend_builder = backend_builder.with_watch_envelopes(|ctx| {
|
||||||
ctx.maildir.as_ref().and_then(WatchMaildirEmails::new)
|
ctx.maildir.as_ref().and_then(WatchMaildirEnvelopes::new)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(BackendKind::MaildirForSync) => {
|
Some(BackendKind::MaildirForSync) => {
|
||||||
backend_builder = backend_builder.with_watch_emails(|ctx| {
|
backend_builder = backend_builder.with_watch_envelopes(|ctx| {
|
||||||
ctx.maildir_for_sync
|
ctx.maildir_for_sync
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(WatchMaildirEmails::new)
|
.and_then(WatchMaildirEnvelopes::new)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(feature = "imap")]
|
#[cfg(feature = "imap")]
|
||||||
Some(BackendKind::Imap) => {
|
Some(BackendKind::Imap) => {
|
||||||
backend_builder = backend_builder
|
backend_builder = backend_builder.with_watch_envelopes(|ctx| {
|
||||||
.with_watch_emails(|ctx| ctx.imap.as_ref().and_then(WatchImapEmails::new));
|
ctx.imap.as_ref().and_then(WatchImapEnvelopes::new)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
#[cfg(feature = "notmuch")]
|
#[cfg(feature = "notmuch")]
|
||||||
Some(BackendKind::Notmuch) => {
|
Some(BackendKind::Notmuch) => {
|
||||||
backend_builder = backend_builder.with_watch_emails(|ctx| {
|
backend_builder = backend_builder.with_watch_envelopes(|ctx| {
|
||||||
ctx.notmuch.as_ref().and_then(WatchNotmuchEmails::new)
|
ctx.notmuch.as_ref().and_then(WatchNotmuchEnvelopes::new)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -206,12 +206,12 @@ impl TomlConfig {
|
||||||
}),
|
}),
|
||||||
envelope: config.envelope.map(|c| EnvelopeConfig {
|
envelope: config.envelope.map(|c| EnvelopeConfig {
|
||||||
list: c.list.map(|c| c.remote),
|
list: c.list.map(|c| c.remote),
|
||||||
|
watch: c.watch.map(|c| c.remote),
|
||||||
}),
|
}),
|
||||||
message: config.message.map(|c| MessageConfig {
|
message: config.message.map(|c| MessageConfig {
|
||||||
read: c.read.map(|c| c.remote),
|
read: c.read.map(|c| c.remote),
|
||||||
write: c.write.map(|c| c.remote),
|
write: c.write.map(|c| c.remote),
|
||||||
send: c.send.map(|c| c.remote),
|
send: c.send.map(|c| c.remote),
|
||||||
watch: c.watch.map(|c| c.remote),
|
|
||||||
}),
|
}),
|
||||||
sync: config.sync,
|
sync: config.sync,
|
||||||
#[cfg(feature = "pgp")]
|
#[cfg(feature = "pgp")]
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
/// This command allows you to list all envelopes included in the
|
/// This command allows you to list all envelopes included in the
|
||||||
/// given folder.
|
/// given folder.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct EnvelopeListCommand {
|
pub struct ListEnvelopesCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameOptionalArg,
|
pub folder: FolderNameOptionalArg,
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ pub struct EnvelopeListCommand {
|
||||||
pub account: AccountNameFlag,
|
pub account: AccountNameFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnvelopeListCommand {
|
impl ListEnvelopesCommand {
|
||||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||||
info!("executing envelope list command");
|
info!("executing envelope list command");
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
pub mod list;
|
pub mod list;
|
||||||
|
pub mod watch;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
|
|
||||||
use crate::{config::TomlConfig, printer::Printer};
|
use crate::{config::TomlConfig, printer::Printer};
|
||||||
|
|
||||||
use self::list::EnvelopeListCommand;
|
use self::{list::ListEnvelopesCommand, watch::WatchEnvelopesCommand};
|
||||||
|
|
||||||
/// Manage envelopes.
|
/// Manage envelopes.
|
||||||
///
|
///
|
||||||
|
@ -16,13 +17,17 @@ use self::list::EnvelopeListCommand;
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum EnvelopeSubcommand {
|
pub enum EnvelopeSubcommand {
|
||||||
#[command(alias = "lst")]
|
#[command(alias = "lst")]
|
||||||
List(EnvelopeListCommand),
|
List(ListEnvelopesCommand),
|
||||||
|
|
||||||
|
#[command()]
|
||||||
|
Watch(WatchEnvelopesCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnvelopeSubcommand {
|
impl EnvelopeSubcommand {
|
||||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Self::List(cmd) => cmd.execute(printer, config).await,
|
Self::List(cmd) => cmd.execute(printer, config).await,
|
||||||
|
Self::Watch(cmd) => cmd.execute(printer, config).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,17 @@ use log::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::CacheDisableFlag,
|
||||||
config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer,
|
config::TomlConfig, folder::arg::name::FolderNameOptionalArg, printer::Printer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Watch a folder for changes.
|
/// Watch envelopes for changes.
|
||||||
///
|
///
|
||||||
/// This command allows you to watch a new folder using the given
|
/// This command allows you to watch a folder and execute hooks when
|
||||||
/// name.
|
/// changes occur on envelopes.
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct FolderWatchCommand {
|
pub struct WatchEnvelopesCommand {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub folder: FolderNameArg,
|
pub folder: FolderNameOptionalArg,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub cache: CacheDisableFlag,
|
pub cache: CacheDisableFlag,
|
||||||
|
@ -23,9 +23,9 @@ pub struct FolderWatchCommand {
|
||||||
pub account: AccountNameFlag,
|
pub account: AccountNameFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FolderWatchCommand {
|
impl WatchEnvelopesCommand {
|
||||||
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> {
|
||||||
info!("executing folder watch command");
|
info!("executing envelopes watch command");
|
||||||
|
|
||||||
let folder = &self.folder.name;
|
let folder = &self.folder.name;
|
||||||
|
|
||||||
|
@ -35,8 +35,10 @@ impl FolderWatchCommand {
|
||||||
.into_account_configs(some_account_name, self.cache.disable)?;
|
.into_account_configs(some_account_name, self.cache.disable)?;
|
||||||
let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
let backend = Backend::new(toml_account_config, account_config.clone(), false).await?;
|
||||||
|
|
||||||
printer.print_log(format!("Start watching folder {folder} for changes…"))?;
|
printer.print_log(format!(
|
||||||
|
"Start watching folder {folder} for envelopes changes…"
|
||||||
|
))?;
|
||||||
|
|
||||||
backend.watch_emails(&folder).await
|
backend.watch_envelopes(&folder).await
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,8 +5,9 @@ use crate::backend::BackendKind;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct EnvelopeConfig {
|
pub struct EnvelopeConfig {
|
||||||
pub list: Option<EnvelopeListConfig>,
|
pub list: Option<ListEnvelopesConfig>,
|
||||||
pub get: Option<EnvelopeGetConfig>,
|
pub watch: Option<WatchEnvelopesConfig>,
|
||||||
|
pub get: Option<GetEnvelopeConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnvelopeConfig {
|
impl EnvelopeConfig {
|
||||||
|
@ -21,19 +22,23 @@ impl EnvelopeConfig {
|
||||||
kinds.extend(get.get_used_backends());
|
kinds.extend(get.get_used_backends());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(watch) = &self.watch {
|
||||||
|
kinds.extend(watch.get_used_backends());
|
||||||
|
}
|
||||||
|
|
||||||
kinds
|
kinds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct EnvelopeListConfig {
|
pub struct ListEnvelopesConfig {
|
||||||
pub backend: Option<BackendKind>,
|
pub backend: Option<BackendKind>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub remote: email::envelope::list::config::EnvelopeListConfig,
|
pub remote: email::envelope::list::config::EnvelopeListConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnvelopeListConfig {
|
impl ListEnvelopesConfig {
|
||||||
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
|
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
|
||||||
let mut kinds = HashSet::default();
|
let mut kinds = HashSet::default();
|
||||||
|
|
||||||
|
@ -46,11 +51,31 @@ impl EnvelopeListConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct EnvelopeGetConfig {
|
pub struct WatchEnvelopesConfig {
|
||||||
pub backend: Option<BackendKind>,
|
pub backend: Option<BackendKind>,
|
||||||
|
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub remote: email::envelope::watch::config::WatchEnvelopeConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnvelopeGetConfig {
|
impl WatchEnvelopesConfig {
|
||||||
|
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
|
||||||
|
let mut kinds = HashSet::default();
|
||||||
|
|
||||||
|
if let Some(kind) = &self.backend {
|
||||||
|
kinds.insert(kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
kinds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct GetEnvelopeConfig {
|
||||||
|
pub backend: Option<BackendKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetEnvelopeConfig {
|
||||||
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
|
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
|
||||||
let mut kinds = HashSet::default();
|
let mut kinds = HashSet::default();
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ pub struct MessageConfig {
|
||||||
pub copy: Option<MessageCopyConfig>,
|
pub copy: Option<MessageCopyConfig>,
|
||||||
#[serde(rename = "move")]
|
#[serde(rename = "move")]
|
||||||
pub move_: Option<MessageMoveConfig>,
|
pub move_: Option<MessageMoveConfig>,
|
||||||
|
|
||||||
pub watch: Option<WatchMessageConfig>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageConfig {
|
impl MessageConfig {
|
||||||
|
@ -44,10 +42,6 @@ impl MessageConfig {
|
||||||
kinds.extend(move_.get_used_backends());
|
kinds.extend(move_.get_used_backends());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(watch) = &self.watch {
|
|
||||||
kinds.extend(watch.get_used_backends());
|
|
||||||
}
|
|
||||||
|
|
||||||
kinds
|
kinds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,23 +156,3 @@ impl MessageMoveConfig {
|
||||||
kinds
|
kinds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
|
||||||
pub struct WatchMessageConfig {
|
|
||||||
pub backend: Option<BackendKind>,
|
|
||||||
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub remote: email::message::watch::config::WatchMessageConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WatchMessageConfig {
|
|
||||||
pub fn get_used_backends(&self) -> HashSet<&BackendKind> {
|
|
||||||
let mut kinds = HashSet::default();
|
|
||||||
|
|
||||||
if let Some(kind) = &self.backend {
|
|
||||||
kinds.insert(kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
kinds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ mod delete;
|
||||||
mod expunge;
|
mod expunge;
|
||||||
mod list;
|
mod list;
|
||||||
mod purge;
|
mod purge;
|
||||||
mod watch;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
|
@ -12,7 +11,7 @@ use crate::{config::TomlConfig, printer::Printer};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
create::FolderCreateCommand, delete::FolderDeleteCommand, expunge::FolderExpungeCommand,
|
create::FolderCreateCommand, delete::FolderDeleteCommand, expunge::FolderExpungeCommand,
|
||||||
list::FolderListCommand, purge::FolderPurgeCommand, watch::FolderWatchCommand,
|
list::FolderListCommand, purge::FolderPurgeCommand,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Manage folders.
|
/// Manage folders.
|
||||||
|
@ -27,9 +26,6 @@ pub enum FolderSubcommand {
|
||||||
#[command(alias = "lst")]
|
#[command(alias = "lst")]
|
||||||
List(FolderListCommand),
|
List(FolderListCommand),
|
||||||
|
|
||||||
#[command()]
|
|
||||||
Watch(FolderWatchCommand),
|
|
||||||
|
|
||||||
#[command()]
|
#[command()]
|
||||||
Expunge(FolderExpungeCommand),
|
Expunge(FolderExpungeCommand),
|
||||||
|
|
||||||
|
@ -45,7 +41,6 @@ impl FolderSubcommand {
|
||||||
match self {
|
match self {
|
||||||
Self::Create(cmd) => cmd.execute(printer, config).await,
|
Self::Create(cmd) => cmd.execute(printer, config).await,
|
||||||
Self::List(cmd) => cmd.execute(printer, config).await,
|
Self::List(cmd) => cmd.execute(printer, config).await,
|
||||||
Self::Watch(cmd) => cmd.execute(printer, config).await,
|
|
||||||
Self::Expunge(cmd) => cmd.execute(printer, config).await,
|
Self::Expunge(cmd) => cmd.execute(printer, config).await,
|
||||||
Self::Purge(cmd) => cmd.execute(printer, config).await,
|
Self::Purge(cmd) => cmd.execute(printer, config).await,
|
||||||
Self::Delete(cmd) => cmd.execute(printer, config).await,
|
Self::Delete(cmd) => cmd.execute(printer, config).await,
|
||||||
|
|
Loading…
Reference in a new issue