2017-09-07 20:00:08 +00:00
/*
* meli - backends module
*
* Copyright 2017 Manos Pitsidianakis
*
* This file is part of meli .
*
* meli is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* meli is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with meli . If not , see < http ://www.gnu.org/licenses/>.
* /
2019-12-08 08:57:36 +00:00
2023-04-08 21:03:20 +00:00
pub mod utf7 ;
2020-04-04 17:09:51 +00:00
use smallvec ::SmallVec ;
2019-12-08 08:57:36 +00:00
2023-07-22 17:46:23 +00:00
#[ cfg(feature = " imap " ) ]
2018-07-27 18:37:56 +00:00
pub mod imap ;
2023-07-22 17:46:23 +00:00
#[ cfg(feature = " imap " ) ]
2020-07-30 17:58:53 +00:00
pub mod nntp ;
2023-07-22 17:51:12 +00:00
#[ cfg(feature = " notmuch " ) ]
2019-11-14 15:55:06 +00:00
pub mod notmuch ;
2023-07-22 17:51:12 +00:00
#[ cfg(feature = " notmuch " ) ]
2019-11-14 15:55:06 +00:00
pub use self ::notmuch ::NotmuchDb ;
2023-07-22 17:54:55 +00:00
#[ cfg(feature = " jmap " ) ]
2019-12-03 11:25:49 +00:00
pub mod jmap ;
2023-07-22 17:48:09 +00:00
#[ cfg(feature = " maildir " ) ]
2020-07-06 08:12:38 +00:00
pub mod maildir ;
2023-07-22 17:52:37 +00:00
#[ cfg(feature = " mbox " ) ]
2020-07-06 08:12:38 +00:00
pub mod mbox ;
2023-04-30 16:39:41 +00:00
use std ::{
any ::Any ,
borrow ::Cow ,
collections ::{ BTreeSet , HashMap } ,
fmt ,
fmt ::Debug ,
future ::Future ,
ops ::Deref ,
pin ::Pin ,
sync ::{ Arc , RwLock } ,
} ;
use futures ::stream ::Stream ;
2023-07-22 17:46:23 +00:00
#[ cfg(feature = " imap " ) ]
2019-06-28 16:34:40 +00:00
pub use self ::imap ::ImapType ;
2023-07-22 17:48:09 +00:00
#[ cfg(feature = " maildir " ) ]
2019-04-04 11:21:52 +00:00
use self ::maildir ::MaildirType ;
2023-07-22 17:52:37 +00:00
#[ cfg(feature = " mbox " ) ]
2019-07-11 08:44:27 +00:00
use self ::mbox ::MboxType ;
2023-07-22 17:46:23 +00:00
#[ cfg(feature = " imap " ) ]
2023-04-30 16:39:41 +00:00
pub use self ::nntp ::NntpType ;
2019-04-04 11:21:52 +00:00
use super ::email ::{ Envelope , EnvelopeHash , Flag } ;
2023-04-30 16:39:41 +00:00
use crate ::{
conf ::AccountSettings ,
error ::{ Error , ErrorKind , Result } ,
2023-05-01 13:22:35 +00:00
LogLevel ,
2023-04-30 16:39:41 +00:00
} ;
2017-09-30 17:53:14 +00:00
2020-02-05 23:49:18 +00:00
#[ macro_export ]
macro_rules ! get_path_hash {
( $path :expr ) = > { {
2023-04-30 16:39:41 +00:00
use std ::{
collections ::hash_map ::DefaultHasher ,
hash ::{ Hash , Hasher } ,
} ;
2020-02-05 23:49:18 +00:00
let mut hasher = DefaultHasher ::new ( ) ;
$path . hash ( & mut hasher ) ;
hasher . finish ( )
} } ;
}
2019-11-15 22:33:22 +00:00
pub type BackendCreator = Box <
dyn Fn (
& AccountSettings ,
Box < dyn Fn ( & str ) -> bool + Send + Sync > ,
2020-08-19 22:55:24 +00:00
BackendEventConsumer ,
2019-11-15 22:33:22 +00:00
) -> Result < Box < dyn MailBackend > > ,
> ;
2018-08-11 15:00:21 +00:00
2023-07-01 13:34:06 +00:00
pub type BackendValidateConfigFn = Box < dyn Fn ( & mut AccountSettings ) -> Result < ( ) > > ;
2017-09-30 17:53:14 +00:00
/// A hashmap containing all available mail backends.
2018-07-10 08:18:11 +00:00
/// An abstraction over any available backends.
2017-09-30 17:02:22 +00:00
pub struct Backends {
2020-05-10 18:14:49 +00:00
map : HashMap < std ::string ::String , Backend > ,
2019-11-27 12:22:53 +00:00
}
pub struct Backend {
pub create_fn : Box < dyn Fn ( ) -> BackendCreator > ,
2023-07-01 13:34:06 +00:00
pub validate_conf_fn : BackendValidateConfigFn ,
2017-09-30 17:02:22 +00:00
}
2018-08-23 12:36:52 +00:00
impl Default for Backends {
fn default ( ) -> Self {
2023-07-01 13:34:06 +00:00
Self ::new ( )
2018-08-23 12:36:52 +00:00
}
}
2023-07-22 17:51:12 +00:00
#[ cfg(feature = " notmuch " ) ]
2023-04-30 16:39:41 +00:00
pub const NOTMUCH_ERROR_MSG : & str = " libnotmuch5 was not found in your system. Make sure it is \
installed and in the library paths . For a custom file path , \
use ` library_file_path ` setting in your notmuch account . \ n " ;
2023-07-22 17:51:12 +00:00
#[ cfg(not(feature = " notmuch " )) ]
2023-04-30 16:39:41 +00:00
pub const NOTMUCH_ERROR_MSG : & str = " this version of meli is not compiled with notmuch support. \
Use an appropriate version and make sure libnotmuch5 is \
installed and in the library paths . \ n " ;
2020-02-26 12:18:00 +00:00
2023-07-22 17:51:12 +00:00
#[ cfg(not(feature = " notmuch " )) ]
2022-09-02 10:07:15 +00:00
pub const NOTMUCH_ERROR_DETAILS : & str = " " ;
2023-07-22 17:51:12 +00:00
#[ cfg(all(feature = " notmuch " , target_os = " unix " )) ]
2022-09-02 10:07:15 +00:00
pub const NOTMUCH_ERROR_DETAILS : & str = r #" If you have installed the library manually, try setting the `LD_LIBRARY_PATH` environment variable to its `lib` directory. Otherwise, set it to the location of libnotmuch.5.so. Example:
LD_LIBRARY_PATH = " $LD_LIBRARY_PATH:/path/to/notmuch/lib " meli
or , put this in your shell init script ( . bashenv , . zshenv , . bashrc , . zshrc , . profile ) :
export LD_LIBRARY_PATH = " $LD_LIBRARY_PATH:/path/to/notmuch/lib "
You can also set any location by specifying the library file path with the configuration flag ` library_file_path ` . " #;
2023-07-22 17:51:12 +00:00
#[ cfg(all(feature = " notmuch " , target_os = " macos " )) ]
2022-09-02 10:07:15 +00:00
pub const NOTMUCH_ERROR_DETAILS : & str = r #" If you have installed the library via homebrew, try setting the `DYLD_LIBRARY_PATH` environment variable to its `lib` directory. Otherwise, set it to the location of libnotmuch.5.dylib. Example:
DYLD_LIBRARY_PATH = " $(brew --prefix)/lib " meli
or , put this in your shell init script ( . bashenv , . zshenv , . bashrc , . zshrc , . profile ) :
export DYLD_LIBRARY_PATH = " $(brew --prefix)/lib "
Make sure to append to DYLD_LIBRARY_PATH if it ' s not empty , by prepending a colon to the libnotmuch5 . dylib location :
export DYLD_LIBRARY_PATH = " $DYLD_LIBRARY_PATH:$(brew --prefix)/lib "
You can also set any location by specifying the library file path with the configuration flag ` library_file_path ` . " #;
2023-07-22 17:51:12 +00:00
#[ cfg(all(feature = " notmuch " , not(any(target_os = " unix " , target_os = " macos " )))) ]
2022-09-02 10:07:15 +00:00
pub const NOTMUCH_ERROR_DETAILS : & str = r # "If notmuch is installed but the library isn't found, consult your system's documentation on how to make dynamic libraries discoverable."# ;
2017-09-30 17:02:22 +00:00
impl Backends {
pub fn new ( ) -> Self {
2023-07-01 13:34:06 +00:00
let mut b = Self {
2020-05-10 18:14:49 +00:00
map : HashMap ::with_capacity_and_hasher ( 1 , Default ::default ( ) ) ,
2017-09-30 17:53:14 +00:00
} ;
2023-07-22 17:48:09 +00:00
#[ cfg(feature = " maildir " ) ]
2019-09-21 18:23:06 +00:00
{
b . register (
" maildir " . to_string ( ) ,
2019-11-27 12:22:53 +00:00
Backend {
2020-08-19 22:55:24 +00:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | MaildirType ::new ( f , i , ev ) ) ) ,
2019-11-27 12:22:53 +00:00
validate_conf_fn : Box ::new ( MaildirType ::validate_config ) ,
} ,
2019-09-21 18:23:06 +00:00
) ;
}
2023-07-22 17:52:37 +00:00
#[ cfg(feature = " mbox " ) ]
2019-09-21 18:23:06 +00:00
{
b . register (
" mbox " . to_string ( ) ,
2019-11-27 12:22:53 +00:00
Backend {
2020-08-19 22:55:24 +00:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | MboxType ::new ( f , i , ev ) ) ) ,
2019-11-27 12:22:53 +00:00
validate_conf_fn : Box ::new ( MboxType ::validate_config ) ,
} ,
2019-09-21 18:23:06 +00:00
) ;
}
2023-07-22 17:46:23 +00:00
#[ cfg(feature = " imap " ) ]
2019-09-21 18:23:06 +00:00
{
b . register (
" imap " . to_string ( ) ,
2019-11-27 12:22:53 +00:00
Backend {
2020-08-19 22:55:24 +00:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | imap ::ImapType ::new ( f , i , ev ) ) ) ,
2020-07-06 08:12:38 +00:00
validate_conf_fn : Box ::new ( imap ::ImapType ::validate_config ) ,
2020-06-27 18:40:46 +00:00
} ,
) ;
2020-07-30 17:58:53 +00:00
b . register (
" nntp " . to_string ( ) ,
Backend {
2020-08-19 22:55:24 +00:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | nntp ::NntpType ::new ( f , i , ev ) ) ) ,
2020-07-30 17:58:53 +00:00
validate_conf_fn : Box ::new ( nntp ::NntpType ::validate_config ) ,
} ,
) ;
2019-09-21 18:23:06 +00:00
}
2023-07-22 17:51:12 +00:00
#[ cfg(feature = " notmuch " ) ]
2019-11-14 15:55:06 +00:00
{
2022-09-02 10:07:15 +00:00
b . register (
" notmuch " . to_string ( ) ,
Backend {
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | NotmuchDb ::new ( f , i , ev ) ) ) ,
validate_conf_fn : Box ::new ( NotmuchDb ::validate_config ) ,
} ,
) ;
2019-11-14 15:55:06 +00:00
}
2023-07-22 17:54:55 +00:00
#[ cfg(feature = " jmap " ) ]
2019-12-03 11:25:49 +00:00
{
b . register (
" jmap " . to_string ( ) ,
Backend {
2020-08-19 22:55:24 +00:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | jmap ::JmapType ::new ( f , i , ev ) ) ) ,
2020-08-07 10:51:44 +00:00
validate_conf_fn : Box ::new ( jmap ::JmapType ::validate_config ) ,
2019-12-03 11:25:49 +00:00
} ,
) ;
}
2017-09-30 17:53:14 +00:00
b
2017-09-30 17:02:22 +00:00
}
2018-08-11 15:00:21 +00:00
pub fn get ( & self , key : & str ) -> BackendCreator {
2017-09-30 17:02:22 +00:00
if ! self . map . contains_key ( key ) {
2020-02-26 12:18:00 +00:00
if key = = " notmuch " {
eprint! ( " {} " , NOTMUCH_ERROR_MSG ) ;
2023-07-22 17:51:12 +00:00
#[ cfg(feature = " notmuch " ) ]
2022-09-02 10:07:15 +00:00
{
eprint! ( " {} " , NOTMUCH_ERROR_DETAILS ) ;
}
2020-02-26 12:18:00 +00:00
}
2017-09-30 17:53:14 +00:00
panic! ( " {} is not a valid mail backend " , key ) ;
2017-09-30 17:02:22 +00:00
}
2019-11-27 12:22:53 +00:00
( self . map [ key ] . create_fn ) ( )
2017-09-30 17:02:22 +00:00
}
2018-08-13 06:25:48 +00:00
2019-11-27 12:22:53 +00:00
pub fn register ( & mut self , key : String , backend : Backend ) {
2017-09-30 17:02:22 +00:00
if self . map . contains_key ( & key ) {
2017-09-30 17:53:14 +00:00
panic! ( " {} is an already registered backend " , key ) ;
2017-09-30 17:02:22 +00:00
}
self . map . insert ( key , backend ) ;
}
2019-11-27 12:22:53 +00:00
2022-03-20 14:31:55 +00:00
pub fn validate_config ( & self , key : & str , s : & mut AccountSettings ) -> Result < ( ) > {
2019-11-27 12:22:53 +00:00
( self
. map
. get ( key )
2020-02-26 12:18:00 +00:00
. ok_or_else ( | | {
2022-12-08 20:20:05 +00:00
Error ::new ( format! (
2022-09-02 10:07:15 +00:00
" {}{} is not a valid mail backend. {} " ,
2020-02-26 12:18:00 +00:00
if key = = " notmuch " {
NOTMUCH_ERROR_MSG
} else {
" "
} ,
2022-09-02 10:07:15 +00:00
key ,
2023-07-22 17:51:12 +00:00
if cfg! ( feature = " notmuch " ) & & key = = " notmuch " {
2022-09-02 10:07:15 +00:00
NOTMUCH_ERROR_DETAILS
} else {
" "
} ,
2020-02-26 12:18:00 +00:00
) )
} ) ?
2019-11-27 12:22:53 +00:00
. validate_conf_fn ) ( s )
}
2017-09-30 17:02:22 +00:00
}
2020-08-19 22:55:24 +00:00
#[ derive(Debug, Clone) ]
pub enum BackendEvent {
Notice {
2022-09-02 09:12:12 +00:00
description : String ,
content : Option < String > ,
2023-05-01 13:22:35 +00:00
level : LogLevel ,
2020-08-19 22:55:24 +00:00
} ,
Refresh ( RefreshEvent ) ,
2022-09-11 12:00:30 +00:00
AccountStateChange {
message : Cow < 'static , str > ,
} ,
2020-08-19 22:55:24 +00:00
//Job(Box<Future<Output = Result<()>> + Send + 'static>)
}
2022-12-08 20:20:05 +00:00
impl From < Error > for BackendEvent {
2023-07-01 13:34:06 +00:00
fn from ( val : Error ) -> Self {
Self ::Notice {
2022-09-02 09:12:12 +00:00
description : val . summary . to_string ( ) ,
content : Some ( val . to_string ( ) ) ,
2023-05-01 13:22:35 +00:00
level : LogLevel ::ERROR ,
2020-08-27 21:24:43 +00:00
}
}
}
2020-05-10 19:05:04 +00:00
#[ derive(Debug, Clone) ]
2018-09-05 13:08:11 +00:00
pub enum RefreshEventKind {
2018-09-12 12:10:19 +00:00
Update ( EnvelopeHash , Box < Envelope > ) ,
2018-10-14 16:49:16 +00:00
/// Rename(old_hash, new_hash)
Rename ( EnvelopeHash , EnvelopeHash ) ,
2018-09-12 12:10:19 +00:00
Create ( Box < Envelope > ) ,
2019-10-24 17:30:17 +00:00
Remove ( EnvelopeHash ) ,
2020-02-28 07:09:43 +00:00
NewFlags ( EnvelopeHash , ( Flag , Vec < String > ) ) ,
2018-09-05 13:08:11 +00:00
Rescan ,
2022-12-08 20:20:05 +00:00
Failure ( Error ) ,
2021-01-07 13:48:13 +00:00
MailboxCreate ( Mailbox ) ,
MailboxDelete ( MailboxHash ) ,
MailboxRename {
old_mailbox_hash : MailboxHash ,
new_mailbox : Mailbox ,
} ,
MailboxSubscribe ( MailboxHash ) ,
MailboxUnsubscribe ( MailboxHash ) ,
2018-09-05 13:08:11 +00:00
}
2020-05-10 19:05:04 +00:00
#[ derive(Debug, Clone) ]
2017-09-28 15:06:35 +00:00
pub struct RefreshEvent {
2020-08-26 16:13:18 +00:00
pub mailbox_hash : MailboxHash ,
pub account_hash : AccountHash ,
pub kind : RefreshEventKind ,
2017-09-05 13:41:29 +00:00
}
2017-09-14 15:08:14 +00:00
2020-08-19 22:55:24 +00:00
#[ derive(Clone) ]
2020-08-25 13:39:12 +00:00
pub struct BackendEventConsumer ( Arc < dyn Fn ( AccountHash , BackendEvent ) + Send + Sync > ) ;
2023-07-01 13:34:06 +00:00
2020-08-19 22:55:24 +00:00
impl BackendEventConsumer {
2020-08-25 13:39:12 +00:00
pub fn new ( b : Arc < dyn Fn ( AccountHash , BackendEvent ) + Send + Sync > ) -> Self {
2023-07-01 13:34:06 +00:00
Self ( b )
2017-09-28 15:06:35 +00:00
}
}
2018-09-07 12:36:42 +00:00
2020-08-19 22:55:24 +00:00
impl fmt ::Debug for BackendEventConsumer {
2018-09-07 12:36:42 +00:00
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
2020-08-19 22:55:24 +00:00
write! ( f , " BackendEventConsumer " )
2018-09-07 12:36:42 +00:00
}
}
2020-08-19 22:55:24 +00:00
impl Deref for BackendEventConsumer {
2020-08-25 13:39:12 +00:00
type Target = dyn Fn ( AccountHash , BackendEvent ) + Send + Sync ;
2018-09-07 12:36:42 +00:00
2020-08-19 22:55:24 +00:00
fn deref ( & self ) -> & Self ::Target {
& ( * self . 0 )
2018-09-07 12:36:42 +00:00
}
}
2019-08-26 16:44:05 +00:00
2020-08-01 09:36:47 +00:00
#[ derive(Debug, Clone) ]
2020-07-25 14:53:04 +00:00
pub struct MailBackendCapabilities {
pub is_async : bool ,
pub is_remote : bool ,
2020-08-01 09:36:47 +00:00
pub extensions : Option < Vec < ( String , MailBackendExtensionStatus ) > > ,
2020-07-25 14:53:04 +00:00
pub supports_search : bool ,
pub supports_tags : bool ,
2020-08-09 11:56:34 +00:00
pub supports_submission : bool ,
2020-07-25 14:53:04 +00:00
}
2020-08-01 09:36:47 +00:00
#[ derive(Debug, Copy, Clone) ]
pub enum MailBackendExtensionStatus {
Unsupported { comment : Option < & 'static str > } ,
Supported { comment : Option < & 'static str > } ,
Enabled { comment : Option < & 'static str > } ,
}
2020-06-30 08:40:26 +00:00
pub type ResultFuture < T > = Result < Pin < Box < dyn Future < Output = Result < T > > + Send + 'static > > > ;
2019-11-03 11:12:28 +00:00
pub trait MailBackend : ::std ::fmt ::Debug + Send + Sync {
2020-07-25 14:53:04 +00:00
fn capabilities ( & self ) -> MailBackendCapabilities ;
2020-08-20 14:37:19 +00:00
fn is_online ( & self ) -> ResultFuture < ( ) > {
2020-08-20 18:25:12 +00:00
Ok ( Box ::pin ( async { Ok ( ( ) ) } ) )
2020-07-05 16:56:17 +00:00
}
2020-08-20 18:25:12 +00:00
2023-07-01 13:34:06 +00:00
#[ allow(clippy::type_complexity) ]
2020-08-20 14:37:19 +00:00
fn fetch (
2020-06-22 08:29:36 +00:00
& mut self ,
2020-08-20 18:25:12 +00:00
mailbox_hash : MailboxHash ,
) -> Result < Pin < Box < dyn Stream < Item = Result < Vec < Envelope > > > + Send + 'static > > > ;
fn refresh ( & mut self , mailbox_hash : MailboxHash ) -> ResultFuture < ( ) > ;
fn watch ( & self ) -> ResultFuture < ( ) > ;
fn mailboxes ( & self ) -> ResultFuture < HashMap < MailboxHash , Mailbox > > ;
2020-06-23 14:21:50 +00:00
fn operation ( & self , hash : EnvelopeHash ) -> Result < Box < dyn BackendOp > > ;
2019-02-16 14:37:14 +00:00
2020-06-30 08:40:26 +00:00
fn save (
& self ,
bytes : Vec < u8 > ,
mailbox_hash : MailboxHash ,
flags : Option < Flag > ,
) -> ResultFuture < ( ) > ;
2020-09-11 13:58:56 +00:00
2020-07-24 17:17:06 +00:00
fn copy_messages (
& mut self ,
2020-09-11 13:58:56 +00:00
env_hashes : EnvelopeHashBatch ,
source_mailbox_hash : MailboxHash ,
destination_mailbox_hash : MailboxHash ,
move_ : bool ,
) -> ResultFuture < ( ) > ;
2020-07-24 17:17:06 +00:00
fn set_flags (
& mut self ,
2020-09-11 13:58:56 +00:00
env_hashes : EnvelopeHashBatch ,
mailbox_hash : MailboxHash ,
flags : SmallVec < [ ( std ::result ::Result < Flag , String > , bool ) ; 8 ] > ,
) -> ResultFuture < ( ) > ;
2020-07-24 17:17:06 +00:00
fn delete_messages (
2020-10-13 10:57:04 +00:00
& mut self ,
env_hashes : EnvelopeHashBatch ,
mailbox_hash : MailboxHash ,
) -> ResultFuture < ( ) > ;
2020-08-10 11:24:21 +00:00
fn collection ( & self ) -> crate ::Collection ;
2019-11-06 12:53:12 +00:00
fn as_any ( & self ) -> & dyn Any ;
2020-08-20 18:25:12 +00:00
fn as_any_mut ( & mut self ) -> & mut dyn Any ;
2020-02-05 23:49:18 +00:00
2020-02-26 08:54:10 +00:00
fn create_mailbox (
2020-02-22 08:57:59 +00:00
& mut self ,
2022-11-14 17:14:19 +00:00
path : String ,
) -> ResultFuture < ( MailboxHash , HashMap < MailboxHash , Mailbox > ) > ;
2020-02-05 23:49:18 +00:00
2020-02-26 08:54:10 +00:00
fn delete_mailbox (
2020-02-22 08:57:59 +00:00
& mut self ,
2022-11-14 17:14:19 +00:00
mailbox_hash : MailboxHash ,
) -> ResultFuture < HashMap < MailboxHash , Mailbox > > ;
2020-02-05 23:49:18 +00:00
2020-06-30 08:40:26 +00:00
fn set_mailbox_subscription (
& mut self ,
2022-11-14 17:14:19 +00:00
mailbox_hash : MailboxHash ,
val : bool ,
) -> ResultFuture < ( ) > ;
2020-02-05 23:49:18 +00:00
2020-06-30 08:40:26 +00:00
fn rename_mailbox (
& mut self ,
2022-11-14 17:14:19 +00:00
mailbox_hash : MailboxHash ,
new_path : String ,
) -> ResultFuture < Mailbox > ;
2020-02-05 23:49:18 +00:00
2020-02-26 08:54:10 +00:00
fn set_mailbox_permissions (
2020-02-05 23:49:18 +00:00
& mut self ,
2022-11-14 17:14:19 +00:00
mailbox_hash : MailboxHash ,
val : MailboxPermissions ,
) -> ResultFuture < ( ) > ;
2020-04-04 17:09:51 +00:00
fn search (
& self ,
2022-11-14 17:14:19 +00:00
query : crate ::search ::Query ,
mailbox_hash : Option < MailboxHash > ,
) -> ResultFuture < SmallVec < [ EnvelopeHash ; 512 ] > > ;
2021-09-03 21:32:57 +00:00
fn submit (
& self ,
2021-09-04 13:52:17 +00:00
_bytes : Vec < u8 > ,
_mailbox_hash : Option < MailboxHash > ,
_flags : Option < Flag > ,
2021-09-03 21:32:57 +00:00
) -> ResultFuture < ( ) > {
2022-12-08 20:20:05 +00:00
Err ( Error ::new ( " Submission not supported in this backend. " )
2022-11-14 17:14:19 +00:00
. set_kind ( ErrorKind ::NotSupported ) )
2021-09-03 21:32:57 +00:00
}
2017-09-28 15:06:35 +00:00
}
2017-09-14 15:08:14 +00:00
2023-04-30 16:39:41 +00:00
/// A `BackendOp` manages common operations for the various mail backends. They
/// only live for the duration of the operation. They are generated by the
/// `operation` method of `Mailbackend` trait.
2017-09-16 10:32:56 +00:00
///
/// # Motivation
///
2023-04-30 16:39:41 +00:00
/// We need a way to do various operations on individual mails regardless of
/// what backend they come from (eg local or imap).
2017-09-16 10:32:56 +00:00
///
2019-03-26 13:27:02 +00:00
/// # Creation
2019-12-11 14:07:08 +00:00
/// ```ignore
2019-03-26 13:27:02 +00:00
/// /* Create operation from Backend */
///
2020-02-26 08:54:10 +00:00
/// let op = backend.operation(message.hash(), mailbox.hash());
2019-03-26 13:27:02 +00:00
/// ```
///
2017-09-16 10:32:56 +00:00
/// # Example
2019-12-11 14:07:08 +00:00
/// ```ignore
/// use melib::backends::{BackendOp};
2017-10-01 14:31:20 +00:00
/// use melib::Result;
/// use melib::{Envelope, Flag};
2017-09-16 10:32:56 +00:00
///
/// #[derive(Debug)]
/// struct FooOp {}
///
/// impl BackendOp for FooOp {
/// fn as_bytes(&mut self) -> Result<&[u8]> {
/// unimplemented!()
/// }
/// }
///
2019-07-18 17:14:14 +00:00
/// let operation = Box::new(FooOp {});
2017-09-16 10:32:56 +00:00
/// ```
2017-09-14 15:08:14 +00:00
pub trait BackendOp : ::std ::fmt ::Debug + ::std ::marker ::Send {
2020-07-04 14:38:57 +00:00
fn as_bytes ( & mut self ) -> ResultFuture < Vec < u8 > > ;
2017-09-14 15:08:14 +00:00
}
2019-07-18 17:16:51 +00:00
/// Wrapper for BackendOps that are to be set read-only.
///
2023-04-30 16:39:41 +00:00
/// Warning: Backend implementations may still cause side-effects (for example
/// IMAP can set the Seen flag when fetching an envelope)
2019-07-18 17:16:51 +00:00
#[ derive(Debug) ]
pub struct ReadOnlyOp {
2019-09-09 08:54:47 +00:00
op : Box < dyn BackendOp > ,
2019-07-18 17:16:51 +00:00
}
impl ReadOnlyOp {
2023-07-01 13:34:06 +00:00
#[ allow(clippy::new_ret_no_self) ]
2019-09-09 08:54:47 +00:00
pub fn new ( op : Box < dyn BackendOp > ) -> Box < dyn BackendOp > {
2023-07-01 13:34:06 +00:00
Box ::new ( Self { op } )
2019-07-18 17:16:51 +00:00
}
}
impl BackendOp for ReadOnlyOp {
2020-07-04 14:38:57 +00:00
fn as_bytes ( & mut self ) -> ResultFuture < Vec < u8 > > {
2019-07-18 17:16:51 +00:00
self . op . as_bytes ( )
}
2017-09-14 15:08:14 +00:00
}
2018-08-11 15:00:21 +00:00
2023-07-01 13:34:06 +00:00
#[ derive(Default, Debug, Copy, Hash, Eq, Clone, Serialize, Deserialize, PartialEq) ]
2019-12-10 22:15:36 +00:00
pub enum SpecialUsageMailbox {
2023-07-01 13:34:06 +00:00
#[ default ]
2019-08-23 18:58:41 +00:00
Normal ,
Inbox ,
Archive ,
Drafts ,
Flagged ,
Junk ,
Sent ,
Trash ,
}
2019-12-17 12:12:41 +00:00
impl std ::fmt ::Display for SpecialUsageMailbox {
fn fmt ( & self , f : & mut std ::fmt ::Formatter ) -> std ::fmt ::Result {
use SpecialUsageMailbox ::* ;
write! (
f ,
" {} " ,
match self {
Normal = > " Normal " ,
Inbox = > " Inbox " ,
Archive = > " Archive " ,
Drafts = > " Drafts " ,
Flagged = > " Flagged " ,
Junk = > " Junk " ,
Sent = > " Sent " ,
Trash = > " Trash " ,
}
)
}
}
2019-12-07 12:04:25 +00:00
impl SpecialUsageMailbox {
2023-07-01 13:34:06 +00:00
pub fn detect_usage ( name : & str ) -> Option < Self > {
2019-12-07 12:04:25 +00:00
if name . eq_ignore_ascii_case ( " inbox " ) {
2023-07-01 13:34:06 +00:00
Some ( Self ::Inbox )
2019-12-07 12:04:25 +00:00
} else if name . eq_ignore_ascii_case ( " archive " ) {
2023-07-01 13:34:06 +00:00
Some ( Self ::Archive )
2019-12-07 12:04:25 +00:00
} else if name . eq_ignore_ascii_case ( " drafts " ) {
2023-07-01 13:34:06 +00:00
Some ( Self ::Drafts )
2020-07-05 12:28:55 +00:00
} else if name . eq_ignore_ascii_case ( " junk " ) | | name . eq_ignore_ascii_case ( " spam " ) {
2023-07-01 13:34:06 +00:00
Some ( Self ::Junk )
2019-12-07 12:04:25 +00:00
} else if name . eq_ignore_ascii_case ( " sent " ) {
2023-07-01 13:34:06 +00:00
Some ( Self ::Sent )
2019-12-07 12:04:25 +00:00
} else if name . eq_ignore_ascii_case ( " trash " ) {
2023-07-01 13:34:06 +00:00
Some ( Self ::Trash )
2019-12-07 12:04:25 +00:00
} else {
2023-07-01 13:34:06 +00:00
Some ( Self ::Normal )
2019-12-07 12:04:25 +00:00
}
}
}
2020-02-26 08:54:10 +00:00
pub trait BackendMailbox : Debug {
fn hash ( & self ) -> MailboxHash ;
2023-04-08 21:03:20 +00:00
/// Final component of `path`.
2018-08-11 15:00:21 +00:00
fn name ( & self ) -> & str ;
2020-02-26 08:54:10 +00:00
/// Path of mailbox within the mailbox hierarchy, with `/` as separator.
2019-08-23 18:32:32 +00:00
fn path ( & self ) -> & str ;
2020-02-26 08:54:10 +00:00
fn clone ( & self ) -> Mailbox ;
fn children ( & self ) -> & [ MailboxHash ] ;
fn parent ( & self ) -> Option < MailboxHash > ;
2019-12-17 12:12:41 +00:00
fn is_subscribed ( & self ) -> bool ;
fn set_is_subscribed ( & mut self , new_val : bool ) -> Result < ( ) > ;
fn set_special_usage ( & mut self , new_val : SpecialUsageMailbox ) -> Result < ( ) > ;
2019-12-10 22:15:36 +00:00
fn special_usage ( & self ) -> SpecialUsageMailbox ;
2020-02-26 08:54:10 +00:00
fn permissions ( & self ) -> MailboxPermissions ;
2019-12-17 12:12:41 +00:00
fn count ( & self ) -> Result < ( usize , usize ) > ;
2018-08-11 15:00:21 +00:00
}
2022-12-08 19:34:32 +00:00
crate ::declare_u64_hash! ( AccountHash ) ;
crate ::declare_u64_hash! ( MailboxHash ) ;
crate ::declare_u64_hash! ( TagHash ) ;
2020-02-26 08:54:10 +00:00
pub type Mailbox = Box < dyn BackendMailbox + Send + Sync > ;
2018-09-23 16:55:29 +00:00
2020-02-26 08:54:10 +00:00
impl Clone for Mailbox {
2018-09-23 16:55:29 +00:00
fn clone ( & self ) -> Self {
2020-02-26 08:54:10 +00:00
BackendMailbox ::clone ( self . deref ( ) )
2018-09-23 16:55:29 +00:00
}
}
2019-11-10 22:47:23 +00:00
#[ derive(Debug, PartialEq, Eq, Hash, Clone, Copy) ]
2020-02-26 08:54:10 +00:00
pub struct MailboxPermissions {
2019-11-10 22:47:23 +00:00
pub create_messages : bool ,
pub remove_messages : bool ,
pub set_flags : bool ,
pub create_child : bool ,
pub rename_messages : bool ,
pub delete_messages : bool ,
pub delete_mailbox : bool ,
pub change_permissions : bool ,
}
2020-02-26 08:54:10 +00:00
impl Default for MailboxPermissions {
2019-11-10 22:47:23 +00:00
fn default ( ) -> Self {
2023-07-01 13:34:06 +00:00
Self {
2019-11-10 22:47:23 +00:00
create_messages : false ,
remove_messages : false ,
set_flags : false ,
create_child : false ,
rename_messages : false ,
delete_messages : false ,
2020-02-26 08:54:10 +00:00
delete_mailbox : true ,
2019-11-10 22:47:23 +00:00
change_permissions : false ,
}
}
}
2020-02-05 23:49:18 +00:00
2020-02-26 08:54:10 +00:00
impl std ::fmt ::Display for MailboxPermissions {
2020-02-05 23:49:18 +00:00
fn fmt ( & self , fmt : & mut std ::fmt ::Formatter ) -> std ::fmt ::Result {
write! ( fmt , " {:#?} " , self )
}
}
2020-07-24 17:17:06 +00:00
2022-11-14 17:14:19 +00:00
#[ derive(Debug, Clone, PartialEq, Eq) ]
2020-07-24 17:17:06 +00:00
pub struct EnvelopeHashBatch {
pub first : EnvelopeHash ,
pub rest : SmallVec < [ EnvelopeHash ; 64 ] > ,
}
impl From < EnvelopeHash > for EnvelopeHashBatch {
fn from ( value : EnvelopeHash ) -> Self {
2023-07-01 13:34:06 +00:00
Self {
2020-07-24 17:17:06 +00:00
first : value ,
rest : SmallVec ::new ( ) ,
}
}
}
impl std ::convert ::TryFrom < & [ EnvelopeHash ] > for EnvelopeHashBatch {
type Error = ( ) ;
fn try_from ( value : & [ EnvelopeHash ] ) -> std ::result ::Result < Self , Self ::Error > {
if value . is_empty ( ) {
return Err ( ( ) ) ;
}
2023-07-01 13:34:06 +00:00
Ok ( Self {
2020-07-24 17:17:06 +00:00
first : value [ 0 ] ,
rest : value [ 1 .. ] . iter ( ) . cloned ( ) . collect ( ) ,
} )
}
}
2023-07-01 13:34:06 +00:00
impl From < & EnvelopeHashBatch > for BTreeSet < EnvelopeHash > {
fn from ( val : & EnvelopeHashBatch ) -> Self {
val . iter ( ) . collect ( )
2022-09-17 22:42:45 +00:00
}
}
2020-07-24 17:17:06 +00:00
impl EnvelopeHashBatch {
2020-09-16 10:14:54 +00:00
pub fn iter ( & self ) -> impl std ::iter ::Iterator < Item = EnvelopeHash > + '_ {
2020-07-24 17:17:06 +00:00
std ::iter ::once ( self . first ) . chain ( self . rest . iter ( ) . cloned ( ) )
}
2020-09-16 10:14:54 +00:00
2023-07-01 13:34:06 +00:00
pub fn is_empty ( & self ) -> bool {
self . len ( ) = = 0
}
2020-09-16 10:14:54 +00:00
pub fn len ( & self ) -> usize {
1 + self . rest . len ( )
}
2022-09-17 22:42:45 +00:00
pub fn to_set ( & self ) -> BTreeSet < EnvelopeHash > {
self . into ( )
}
2020-07-24 17:17:06 +00:00
}
2020-09-22 11:14:11 +00:00
2020-11-23 22:23:45 +00:00
#[ derive(Default, Clone) ]
2020-09-22 11:14:11 +00:00
pub struct LazyCountSet {
not_yet_seen : usize ,
set : BTreeSet < EnvelopeHash > ,
}
2020-11-23 22:23:45 +00:00
impl fmt ::Debug for LazyCountSet {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
f . debug_struct ( " LazyCountSet " )
. field ( " not_yet_seen " , & self . not_yet_seen )
. field ( " set " , & self . set . len ( ) )
. field ( " total_len " , & self . len ( ) )
. finish ( )
}
}
2020-09-22 11:14:11 +00:00
impl LazyCountSet {
2023-07-16 08:37:09 +00:00
pub fn new ( ) -> Self {
Self ::default ( )
}
2020-09-22 11:14:11 +00:00
pub fn set_not_yet_seen ( & mut self , new_val : usize ) {
self . not_yet_seen = new_val ;
}
pub fn insert_existing ( & mut self , new_val : EnvelopeHash ) -> bool {
if self . not_yet_seen = = 0 {
false
} else {
2020-11-23 22:23:45 +00:00
if ! self . set . contains ( & new_val ) {
self . not_yet_seen - = 1 ;
}
2020-09-22 11:14:11 +00:00
self . set . insert ( new_val ) ;
true
}
}
2020-11-29 17:33:23 +00:00
pub fn insert_existing_set ( & mut self , set : BTreeSet < EnvelopeHash > ) {
let old_len = self . set . len ( ) ;
self . set . extend ( set . into_iter ( ) ) ;
self . not_yet_seen = self . not_yet_seen . saturating_sub ( self . set . len ( ) - old_len ) ;
2020-09-22 11:14:11 +00:00
}
2023-07-01 13:34:06 +00:00
pub fn is_empty ( & self ) -> bool {
self . len ( ) = = 0
}
2020-09-22 11:14:11 +00:00
#[ inline(always) ]
pub fn len ( & self ) -> usize {
self . set . len ( ) + self . not_yet_seen
}
#[ inline(always) ]
pub fn clear ( & mut self ) {
self . set . clear ( ) ;
self . not_yet_seen = 0 ;
}
pub fn insert_new ( & mut self , new_val : EnvelopeHash ) {
self . set . insert ( new_val ) ;
}
pub fn insert_set ( & mut self , set : BTreeSet < EnvelopeHash > ) {
self . set . extend ( set . into_iter ( ) ) ;
}
2020-11-23 22:23:45 +00:00
pub fn remove ( & mut self , env_hash : EnvelopeHash ) -> bool {
self . set . remove ( & env_hash )
2020-09-22 11:14:11 +00:00
}
}
#[ test ]
fn test_lazy_count_set ( ) {
let mut new = LazyCountSet ::default ( ) ;
2020-11-23 22:23:45 +00:00
assert_eq! ( new . len ( ) , 0 ) ;
2020-09-22 11:14:11 +00:00
new . set_not_yet_seen ( 10 ) ;
2020-11-23 22:23:45 +00:00
assert_eq! ( new . len ( ) , 10 ) ;
2020-09-22 11:14:11 +00:00
for i in 0 .. 10 {
2022-12-08 19:34:32 +00:00
assert! ( new . insert_existing ( EnvelopeHash ( i ) ) ) ;
2020-09-22 11:14:11 +00:00
}
2020-11-23 22:23:45 +00:00
assert_eq! ( new . len ( ) , 10 ) ;
2022-12-08 19:34:32 +00:00
assert! ( ! new . insert_existing ( EnvelopeHash ( 10 ) ) ) ;
2020-11-23 22:23:45 +00:00
assert_eq! ( new . len ( ) , 10 ) ;
2020-09-22 11:14:11 +00:00
}
2020-12-20 18:05:20 +00:00
pub struct IsSubscribedFn ( Box < dyn Fn ( & str ) -> bool + Send + Sync > ) ;
impl std ::fmt ::Debug for IsSubscribedFn {
fn fmt ( & self , f : & mut std ::fmt ::Formatter ) -> std ::fmt ::Result {
write! ( f , " IsSubscribedFn Box " )
}
}
impl std ::ops ::Deref for IsSubscribedFn {
type Target = Box < dyn Fn ( & str ) -> bool + Send + Sync > ;
fn deref ( & self ) -> & Box < dyn Fn ( & str ) -> bool + Send + Sync > {
& self . 0
}
}