From dc2184a9de3ee0aff260d23d07e42dd0bd3755d8 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Mon, 26 Aug 2019 19:44:05 +0300 Subject: [PATCH] melib: add Folder operations in mail backends Add following operations in mail backend: - Create, - Delete, - Subscribe, - Unsubscribe, - Rename --- melib/src/backends.rs | 15 ++++++++ melib/src/error.rs | 7 ++++ ui/src/conf/accounts.rs | 8 +++-- ui/src/execute.rs | 75 ++++++++++++++++++++++++++++++++++++++- ui/src/execute/actions.rs | 5 +++ ui/src/state.rs | 27 ++++++++++++++ 6 files changed, 134 insertions(+), 3 deletions(-) diff --git a/melib/src/backends.rs b/melib/src/backends.rs index 9456a3ac3..49c881c1c 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -143,6 +143,18 @@ impl NotifyFn { self.0(f); } } + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub enum FolderOperation { + Create, + Delete, + Subscribe, + Unsubscribe, + Rename(NewFolderName), +} + +type NewFolderName = String; + pub trait MailBackend: ::std::fmt::Debug { fn get(&mut self, folder: &Folder) -> Async>>; fn watch(&self, sender: RefreshEventConsumer) -> Result<()>; @@ -150,6 +162,9 @@ pub trait MailBackend: ::std::fmt::Debug { fn operation(&self, hash: EnvelopeHash, folder_hash: FolderHash) -> Box; fn save(&self, bytes: &[u8], folder: &str) -> Result<()>; + fn folder_operation(&mut self, path: &str, op: FolderOperation) -> Result<()> { + Ok(()) + } //login function } diff --git a/melib/src/error.rs b/melib/src/error.rs index 8c4b447bb..7b1b2f6dd 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -110,3 +110,10 @@ impl From for MeliError { // MeliError::new(format!("{:?}", kind)) // } //} + +impl From> for MeliError { + #[inline] + fn from(kind: std::sync::PoisonError) -> MeliError { + MeliError::new(format!("{}", kind)) + } +} diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index f82c77e82..925559427 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -27,8 +27,8 @@ use super::AccountConf; use fnv::FnvHashMap; use melib::async_workers::{Async, AsyncBuilder, AsyncStatus}; use melib::backends::{ - BackendOp, Backends, Folder, FolderHash, MailBackend, NotifyFn, ReadOnlyOp, RefreshEvent, - RefreshEventConsumer, RefreshEventKind, SpecialUseMailbox, + BackendOp, Backends, Folder, FolderHash, FolderOperation, MailBackend, NotifyFn, ReadOnlyOp, + RefreshEvent, RefreshEventConsumer, RefreshEventKind, SpecialUseMailbox, }; use melib::error::{MeliError, Result}; use melib::mailbox::*; @@ -601,6 +601,10 @@ impl Account { pub fn thread(&self, h: ThreadHash, f: FolderHash) -> &ThreadNode { &self.collection.threads[&f].thread_nodes()[&h] } + + pub fn folder_operation(&mut self, path: &str, op: FolderOperation) -> Result<()> { + self.backend.folder_operation(path, op) + } } impl Index for Account { diff --git a/ui/src/execute.rs b/ui/src/execute.rs index 0c459a58e..499698c12 100644 --- a/ui/src/execute.rs +++ b/ui/src/execute.rs @@ -21,6 +21,7 @@ /*! A parser module for user commands passed through the Ex mode. */ +use melib::backends::FolderOperation; pub use melib::mailbox::{SortField, SortOrder}; use nom::{digit, not_line_ending}; use std; @@ -211,6 +212,78 @@ define_commands!([ ) ); ) + }, + { tags: ["create-folder "], + desc: "create-folder ACCOUNT FOLDER_PATH", + parser:( + named!( create_folder, + do_parse!( + ws!(tag!("create-folder")) + >> account: map_res!(is_not!(" "), std::str::from_utf8) + >> is_a!(" ") + >> path: map_res!(call!(not_line_ending), std::str::from_utf8) + >> (Folder(account.to_string(), path.to_string(), FolderOperation::Create)) + ) + ); + ) + }, + { tags: ["subscribe-folder "], + desc: "subscribe-folder ACCOUNT FOLDER_PATH", + parser:( + named!( sub_folder, + do_parse!( + ws!(tag!("subscribe-folder")) + >> account: map_res!(is_not!(" "), std::str::from_utf8) + >> is_a!(" ") + >> path: map_res!(call!(not_line_ending), std::str::from_utf8) + >> (Folder(account.to_string(), path.to_string(), FolderOperation::Subscribe)) + ) + ); + ) + }, + { tags: ["unsubscribe-folder "], + desc: "unsubscribe-folder ACCOUNT FOLDER_PATH", + parser:( + named!( unsub_folder, + do_parse!( + ws!(tag!("unsubscribe-folder")) + >> account: map_res!(is_not!(" "), std::str::from_utf8) + >> is_a!(" ") + >> path: map_res!(call!(not_line_ending), std::str::from_utf8) + >> (Folder(account.to_string(), path.to_string(), FolderOperation::Unsubscribe)) + ) + ); + ) + }, + { tags: ["rename-folder "], + desc: "rename-folder ACCOUNT FOLDER_PATH_SRC FOLDER_PATH_DEST", + parser:( + named!( rename_folder, + do_parse!( + ws!(tag!("rename-folder")) + >> account: map_res!(is_not!(" "), std::str::from_utf8) + >> is_a!(" ") + >> src: map_res!(is_not!(" "), std::str::from_utf8) + >> is_a!(" ") + >> dest: map_res!(call!(not_line_ending), std::str::from_utf8) + >> (Folder(account.to_string(), src.to_string(), FolderOperation::Rename(dest.to_string()))) + ) + ); + ) + }, + { tags: ["delete-folder "], + desc: "delete-folder ACCOUNT FOLDER_PATH", + parser:( + named!( delete_folder, + do_parse!( + ws!(tag!("delete-folder")) + >> account: map_res!(is_not!(" "), std::str::from_utf8) + >> is_a!(" ") + >> path: map_res!(call!(not_line_ending), std::str::from_utf8) + >> (Folder(account.to_string(), path.to_string(), FolderOperation::Delete)) + ) + ); + ) } ]); @@ -263,5 +336,5 @@ named!( ); named!(pub parse_command, - alt_complete!( goto | listing_action | sort | subsort | close | mailinglist | setenv | printenv | pipe | compose_action) + alt_complete!( goto | listing_action | sort | subsort | close | mailinglist | setenv | printenv | pipe | compose_action | create_folder | sub_folder | unsub_folder | delete_folder | rename_folder) ); diff --git a/ui/src/execute/actions.rs b/ui/src/execute/actions.rs index 6010afa01..fae20e99b 100644 --- a/ui/src/execute/actions.rs +++ b/ui/src/execute/actions.rs @@ -24,6 +24,7 @@ */ use crate::components::Component; +use melib::backends::FolderOperation; pub use melib::mailbox::{SortField, SortOrder}; use melib::thread::ThreadHash; use melib::{Draft, EnvelopeHash}; @@ -83,4 +84,8 @@ pub enum Action { SetEnv(String, String), PrintEnv(String), Compose(ComposeAction), + Folder(AccountName, FolderPath, FolderOperation), } + +type AccountName = String; +type FolderPath = String; diff --git a/ui/src/state.rs b/ui/src/state.rs index c3479db1d..c0345cfe7 100644 --- a/ui/src/state.rs +++ b/ui/src/state.rs @@ -494,10 +494,37 @@ impl State { ), )); } + Folder(account_name, path, op) => { + if let Some(account) = self + .context + .accounts + .iter_mut() + .find(|a| a.name() == account_name) + { + if let Err(e) = account.folder_operation(&path, op) { + self.context.replies.push_back(UIEvent::StatusEvent( + StatusEvent::DisplayMessage(e.to_string()), + )); + } + } else { + self.context.replies.push_back(UIEvent::StatusEvent( + StatusEvent::DisplayMessage(format!( + "Account with name `{}` not found.", + account_name + )), + )); + } + } v => { self.rcv_event(UIEvent::Action(v)); } } + } else { + self.context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage( + "invalid command".to_string(), + ))); } }