2017-09-07 23:00:08 +03: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 10:57:36 +02:00
2020-04-04 20:09:51 +03:00
use smallvec ::SmallVec ;
2019-12-08 10:57:36 +02:00
#[ macro_export ]
macro_rules ! tag_hash {
( $tag :ident ) = > { {
2020-02-28 09:04:01 +02:00
use std ::collections ::hash_map ::DefaultHasher ;
use std ::hash ::Hasher ;
2019-12-08 10:57:36 +02:00
let mut hasher = DefaultHasher ::new ( ) ;
hasher . write ( $tag . as_bytes ( ) ) ;
hasher . finish ( )
} } ;
}
2019-09-21 21:23:06 +03:00
#[ cfg(feature = " imap_backend " ) ]
2018-07-27 21:37:56 +03:00
pub mod imap ;
2020-07-30 20:58:53 +03:00
#[ cfg(feature = " imap_backend " ) ]
pub mod nntp ;
2019-11-14 17:55:06 +02:00
#[ cfg(feature = " notmuch_backend " ) ]
pub mod notmuch ;
#[ cfg(feature = " notmuch_backend " ) ]
pub use self ::notmuch ::NotmuchDb ;
2019-12-03 13:25:49 +02:00
#[ cfg(feature = " jmap_backend " ) ]
pub mod jmap ;
2020-07-06 11:12:38 +03:00
#[ cfg(feature = " maildir_backend " ) ]
pub mod maildir ;
#[ cfg(feature = " mbox_backend " ) ]
pub mod mbox ;
2019-09-21 21:23:06 +03:00
#[ cfg(feature = " imap_backend " ) ]
2019-06-28 19:34:40 +03:00
pub use self ::imap ::ImapType ;
2020-08-01 23:40:36 +03:00
#[ cfg(feature = " imap_backend " ) ]
2020-07-30 20:58:53 +03:00
pub use self ::nntp ::NntpType ;
2019-04-04 14:21:52 +03:00
use crate ::conf ::AccountSettings ;
2019-07-18 20:16:51 +03:00
use crate ::error ::{ MeliError , Result } ;
2019-09-21 21:23:06 +03:00
#[ cfg(feature = " maildir_backend " ) ]
2019-04-04 14:21:52 +03:00
use self ::maildir ::MaildirType ;
2019-09-21 21:23:06 +03:00
#[ cfg(feature = " mbox_backend " ) ]
2019-07-11 11:44:27 +03:00
use self ::mbox ::MboxType ;
2019-04-04 14:21:52 +03:00
use super ::email ::{ Envelope , EnvelopeHash , Flag } ;
2019-11-06 14:53:12 +02:00
use std ::any ::Any ;
2020-09-22 14:14:11 +03:00
use std ::collections ::{ BTreeMap , BTreeSet } ;
2017-09-14 18:08:14 +03:00
use std ::fmt ;
2018-08-11 18:00:21 +03:00
use std ::fmt ::Debug ;
2018-09-23 19:55:29 +03:00
use std ::ops ::Deref ;
2019-11-30 17:37:00 +02:00
use std ::sync ::{ Arc , RwLock } ;
2017-09-14 18:08:14 +03:00
2020-06-22 11:29:36 +03:00
pub use futures ::stream ::Stream ;
2020-06-27 21:40:46 +03:00
use std ::future ::Future ;
2020-06-28 19:16:13 +03:00
pub use std ::pin ::Pin ;
2020-06-22 11:29:36 +03:00
2020-05-10 21:14:49 +03:00
use std ::collections ::HashMap ;
2017-09-30 20:53:14 +03:00
2020-02-06 01:49:18 +02:00
#[ macro_export ]
macro_rules ! get_path_hash {
( $path :expr ) = > { {
use std ::collections ::hash_map ::DefaultHasher ;
use std ::hash ::{ Hash , Hasher } ;
let mut hasher = DefaultHasher ::new ( ) ;
$path . hash ( & mut hasher ) ;
hasher . finish ( )
} } ;
}
2019-11-16 00:33:22 +02:00
pub type BackendCreator = Box <
dyn Fn (
& AccountSettings ,
Box < dyn Fn ( & str ) -> bool + Send + Sync > ,
2020-08-20 01:55:24 +03:00
BackendEventConsumer ,
2019-11-16 00:33:22 +02:00
) -> Result < Box < dyn MailBackend > > ,
> ;
2018-08-11 18:00:21 +03:00
2017-09-30 20:53:14 +03:00
/// A hashmap containing all available mail backends.
2018-07-10 11:18:11 +03:00
/// An abstraction over any available backends.
2017-09-30 20:02:22 +03:00
pub struct Backends {
2020-05-10 21:14:49 +03:00
map : HashMap < std ::string ::String , Backend > ,
2019-11-27 14:22:53 +02:00
}
pub struct Backend {
pub create_fn : Box < dyn Fn ( ) -> BackendCreator > ,
pub validate_conf_fn : Box < dyn Fn ( & AccountSettings ) -> Result < ( ) > > ,
2017-09-30 20:02:22 +03:00
}
2018-08-23 15:36:52 +03:00
impl Default for Backends {
fn default ( ) -> Self {
Backends ::new ( )
}
}
2020-02-26 14:18:00 +02:00
#[ cfg(feature = " notmuch_backend " ) ]
2020-07-05 15:28:55 +03:00
pub const NOTMUCH_ERROR_MSG : & str =
2020-02-26 14:18:00 +02:00
" libnotmuch5 was not found in your system. Make sure it is installed and in the library paths. \n " ;
#[ cfg(not(feature = " notmuch_backend " )) ]
2020-07-05 15:28:55 +03: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 14:18:00 +02:00
2017-09-30 20:02:22 +03:00
impl Backends {
pub fn new ( ) -> Self {
2017-09-30 20:53:14 +03:00
let mut b = Backends {
2020-05-10 21:14:49 +03:00
map : HashMap ::with_capacity_and_hasher ( 1 , Default ::default ( ) ) ,
2017-09-30 20:53:14 +03:00
} ;
2019-09-21 21:23:06 +03:00
#[ cfg(feature = " maildir_backend " ) ]
{
b . register (
" maildir " . to_string ( ) ,
2019-11-27 14:22:53 +02:00
Backend {
2020-08-20 01:55:24 +03:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | MaildirType ::new ( f , i , ev ) ) ) ,
2019-11-27 14:22:53 +02:00
validate_conf_fn : Box ::new ( MaildirType ::validate_config ) ,
} ,
2019-09-21 21:23:06 +03:00
) ;
}
#[ cfg(feature = " mbox_backend " ) ]
{
b . register (
" mbox " . to_string ( ) ,
2019-11-27 14:22:53 +02:00
Backend {
2020-08-20 01:55:24 +03:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | MboxType ::new ( f , i , ev ) ) ) ,
2019-11-27 14:22:53 +02:00
validate_conf_fn : Box ::new ( MboxType ::validate_config ) ,
} ,
2019-09-21 21:23:06 +03:00
) ;
}
#[ cfg(feature = " imap_backend " ) ]
{
b . register (
" imap " . to_string ( ) ,
2019-11-27 14:22:53 +02:00
Backend {
2020-08-20 01:55:24 +03:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | imap ::ImapType ::new ( f , i , ev ) ) ) ,
2020-07-06 11:12:38 +03:00
validate_conf_fn : Box ::new ( imap ::ImapType ::validate_config ) ,
2020-06-27 21:40:46 +03:00
} ,
) ;
2020-07-30 20:58:53 +03:00
b . register (
" nntp " . to_string ( ) ,
Backend {
2020-08-20 01:55:24 +03:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | nntp ::NntpType ::new ( f , i , ev ) ) ) ,
2020-07-30 20:58:53 +03:00
validate_conf_fn : Box ::new ( nntp ::NntpType ::validate_config ) ,
} ,
) ;
2019-09-21 21:23:06 +03:00
}
2019-11-14 17:55:06 +02:00
#[ cfg(feature = " notmuch_backend " ) ]
{
2020-02-26 14:18:00 +02:00
if libloading ::Library ::new ( " libnotmuch.so.5 " ) . is_ok ( ) {
b . register (
" notmuch " . to_string ( ) ,
Backend {
2020-08-20 01:55:24 +03:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | NotmuchDb ::new ( f , i , ev ) ) ) ,
2020-02-26 14:18:00 +02:00
validate_conf_fn : Box ::new ( NotmuchDb ::validate_config ) ,
} ,
) ;
}
2019-11-14 17:55:06 +02:00
}
2019-12-03 13:25:49 +02:00
#[ cfg(feature = " jmap_backend " ) ]
{
b . register (
" jmap " . to_string ( ) ,
Backend {
2020-08-20 01:55:24 +03:00
create_fn : Box ::new ( | | Box ::new ( | f , i , ev | jmap ::JmapType ::new ( f , i , ev ) ) ) ,
2020-08-07 13:51:44 +03:00
validate_conf_fn : Box ::new ( jmap ::JmapType ::validate_config ) ,
2019-12-03 13:25:49 +02:00
} ,
) ;
}
2017-09-30 20:53:14 +03:00
b
2017-09-30 20:02:22 +03:00
}
2018-08-11 18:00:21 +03:00
pub fn get ( & self , key : & str ) -> BackendCreator {
2017-09-30 20:02:22 +03:00
if ! self . map . contains_key ( key ) {
2020-02-26 14:18:00 +02:00
if key = = " notmuch " {
eprint! ( " {} " , NOTMUCH_ERROR_MSG ) ;
}
2017-09-30 20:53:14 +03:00
panic! ( " {} is not a valid mail backend " , key ) ;
2017-09-30 20:02:22 +03:00
}
2019-11-27 14:22:53 +02:00
( self . map [ key ] . create_fn ) ( )
2017-09-30 20:02:22 +03:00
}
2018-08-13 09:25:48 +03:00
2019-11-27 14:22:53 +02:00
pub fn register ( & mut self , key : String , backend : Backend ) {
2017-09-30 20:02:22 +03:00
if self . map . contains_key ( & key ) {
2017-09-30 20:53:14 +03:00
panic! ( " {} is an already registered backend " , key ) ;
2017-09-30 20:02:22 +03:00
}
self . map . insert ( key , backend ) ;
}
2019-11-27 14:22:53 +02:00
pub fn validate_config ( & self , key : & str , s : & AccountSettings ) -> Result < ( ) > {
( self
. map
. get ( key )
2020-02-26 14:18:00 +02:00
. ok_or_else ( | | {
MeliError ::new ( format! (
" {}{} is not a valid mail backend " ,
if key = = " notmuch " {
NOTMUCH_ERROR_MSG
} else {
" "
} ,
key
) )
} ) ?
2019-11-27 14:22:53 +02:00
. validate_conf_fn ) ( s )
}
2017-09-30 20:02:22 +03:00
}
2020-08-20 01:55:24 +03:00
#[ derive(Debug, Clone) ]
pub enum BackendEvent {
Notice {
description : Option < String > ,
content : String ,
level : crate ::LoggingLevel ,
} ,
Refresh ( RefreshEvent ) ,
//Job(Box<Future<Output = Result<()>> + Send + 'static>)
}
2020-08-28 00:24:43 +03:00
impl From < MeliError > for BackendEvent {
fn from ( val : MeliError ) -> BackendEvent {
BackendEvent ::Notice {
description : val . summary . as_ref ( ) . map ( | s | s . to_string ( ) ) ,
content : val . to_string ( ) ,
level : crate ::LoggingLevel ::ERROR ,
}
}
}
2020-05-10 22:05:04 +03:00
#[ derive(Debug, Clone) ]
2018-09-05 16:08:11 +03:00
pub enum RefreshEventKind {
2018-09-12 15:10:19 +03:00
Update ( EnvelopeHash , Box < Envelope > ) ,
2018-10-14 19:49:16 +03:00
/// Rename(old_hash, new_hash)
Rename ( EnvelopeHash , EnvelopeHash ) ,
2018-09-12 15:10:19 +03:00
Create ( Box < Envelope > ) ,
2019-10-24 20:30:17 +03:00
Remove ( EnvelopeHash ) ,
2020-02-28 09:09:43 +02:00
NewFlags ( EnvelopeHash , ( Flag , Vec < String > ) ) ,
2018-09-05 16:08:11 +03:00
Rescan ,
2019-08-14 22:59:46 +03:00
Failure ( MeliError ) ,
2018-09-05 16:08:11 +03:00
}
2020-05-10 22:05:04 +03:00
#[ derive(Debug, Clone) ]
2017-09-28 18:06:35 +03:00
pub struct RefreshEvent {
2020-08-26 19:13:18 +03:00
pub mailbox_hash : MailboxHash ,
pub account_hash : AccountHash ,
pub kind : RefreshEventKind ,
2017-09-05 16:41:29 +03:00
}
2017-09-14 18:08:14 +03:00
2020-08-20 01:55:24 +03:00
#[ derive(Clone) ]
2020-08-25 16:39:12 +03:00
pub struct BackendEventConsumer ( Arc < dyn Fn ( AccountHash , BackendEvent ) + Send + Sync > ) ;
2020-08-20 01:55:24 +03:00
impl BackendEventConsumer {
2020-08-25 16:39:12 +03:00
pub fn new ( b : Arc < dyn Fn ( AccountHash , BackendEvent ) + Send + Sync > ) -> Self {
2020-08-20 01:55:24 +03:00
BackendEventConsumer ( b )
2017-09-28 18:06:35 +03:00
}
}
2018-09-07 15:36:42 +03:00
2020-08-20 01:55:24 +03:00
impl fmt ::Debug for BackendEventConsumer {
2018-09-07 15:36:42 +03:00
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
2020-08-20 01:55:24 +03:00
write! ( f , " BackendEventConsumer " )
2018-09-07 15:36:42 +03:00
}
}
2020-08-20 01:55:24 +03:00
impl Deref for BackendEventConsumer {
2020-08-25 16:39:12 +03:00
type Target = dyn Fn ( AccountHash , BackendEvent ) + Send + Sync ;
2018-09-07 15:36:42 +03:00
2020-08-20 01:55:24 +03:00
fn deref ( & self ) -> & Self ::Target {
& ( * self . 0 )
2018-09-07 15:36:42 +03:00
}
}
2019-08-26 19:44:05 +03:00
2020-08-01 12:36:47 +03:00
#[ derive(Debug, Clone) ]
2020-07-25 17:53:04 +03:00
pub struct MailBackendCapabilities {
pub is_async : bool ,
pub is_remote : bool ,
2020-08-01 12:36:47 +03:00
pub extensions : Option < Vec < ( String , MailBackendExtensionStatus ) > > ,
2020-07-25 17:53:04 +03:00
pub supports_search : bool ,
pub supports_tags : bool ,
2020-08-09 14:56:34 +03:00
pub supports_submission : bool ,
2020-07-25 17:53:04 +03:00
}
2020-08-01 12:36:47 +03: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 11:40:26 +03:00
pub type ResultFuture < T > = Result < Pin < Box < dyn Future < Output = Result < T > > + Send + 'static > > > ;
2019-11-03 13:12:28 +02:00
pub trait MailBackend : ::std ::fmt ::Debug + Send + Sync {
2020-07-25 17:53:04 +03:00
fn capabilities ( & self ) -> MailBackendCapabilities ;
2020-08-20 17:37:19 +03:00
fn is_online ( & self ) -> ResultFuture < ( ) > {
2020-08-20 21:25:12 +03:00
Ok ( Box ::pin ( async { Ok ( ( ) ) } ) )
2020-07-05 19:56:17 +03:00
}
2020-08-20 21:25:12 +03:00
2020-08-20 17:37:19 +03:00
fn fetch (
2020-06-22 11:29:36 +03:00
& mut self ,
2020-08-20 21:25:12 +03: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 17:21:50 +03:00
fn operation ( & self , hash : EnvelopeHash ) -> Result < Box < dyn BackendOp > > ;
2019-02-16 16:37:14 +02:00
2020-06-30 11:40:26 +03:00
fn save (
& self ,
bytes : Vec < u8 > ,
mailbox_hash : MailboxHash ,
flags : Option < Flag > ,
) -> ResultFuture < ( ) > ;
2020-09-11 16:58:56 +03:00
2020-07-24 20:17:06 +03:00
fn copy_messages (
& mut self ,
2020-09-11 16:58:56 +03:00
env_hashes : EnvelopeHashBatch ,
source_mailbox_hash : MailboxHash ,
destination_mailbox_hash : MailboxHash ,
move_ : bool ,
) -> ResultFuture < ( ) > ;
2020-07-24 20:17:06 +03:00
fn set_flags (
& mut self ,
2020-09-11 16:58:56 +03:00
env_hashes : EnvelopeHashBatch ,
mailbox_hash : MailboxHash ,
flags : SmallVec < [ ( std ::result ::Result < Flag , String > , bool ) ; 8 ] > ,
) -> ResultFuture < ( ) > ;
2020-07-24 20:17:06 +03:00
fn delete_messages (
2020-10-13 13:57:04 +03:00
& mut self ,
env_hashes : EnvelopeHashBatch ,
mailbox_hash : MailboxHash ,
) -> ResultFuture < ( ) > ;
2019-11-30 17:37:00 +02:00
fn tags ( & self ) -> Option < Arc < RwLock < BTreeMap < u64 , String > > > > {
None
}
2019-11-06 14:53:12 +02:00
fn as_any ( & self ) -> & dyn Any ;
2020-08-20 21:25:12 +03:00
fn as_any_mut ( & mut self ) -> & mut dyn Any ;
2020-02-06 01:49:18 +02:00
2020-02-26 10:54:10 +02:00
fn create_mailbox (
2020-02-22 10:57:59 +02:00
& mut self ,
_path : String ,
2020-06-30 11:40:26 +03:00
) -> ResultFuture < ( MailboxHash , HashMap < MailboxHash , Mailbox > ) > {
2020-02-06 01:49:18 +02:00
Err ( MeliError ::new ( " Unimplemented. " ) )
}
2020-02-26 10:54:10 +02:00
fn delete_mailbox (
2020-02-22 10:57:59 +02:00
& mut self ,
2020-02-26 10:54:10 +02:00
_mailbox_hash : MailboxHash ,
2020-06-30 11:40:26 +03:00
) -> ResultFuture < HashMap < MailboxHash , Mailbox > > {
2020-02-06 01:49:18 +02:00
Err ( MeliError ::new ( " Unimplemented. " ) )
}
2020-06-30 11:40:26 +03:00
fn set_mailbox_subscription (
& mut self ,
_mailbox_hash : MailboxHash ,
_val : bool ,
) -> ResultFuture < ( ) > {
2020-02-06 01:49:18 +02:00
Err ( MeliError ::new ( " Unimplemented. " ) )
}
2020-06-30 11:40:26 +03:00
fn rename_mailbox (
& mut self ,
_mailbox_hash : MailboxHash ,
_new_path : String ,
) -> ResultFuture < Mailbox > {
2020-02-06 01:49:18 +02:00
Err ( MeliError ::new ( " Unimplemented. " ) )
}
2020-02-26 10:54:10 +02:00
fn set_mailbox_permissions (
2020-02-06 01:49:18 +02:00
& mut self ,
2020-02-26 10:54:10 +02:00
_mailbox_hash : MailboxHash ,
_val : MailboxPermissions ,
2020-06-30 11:40:26 +03:00
) -> ResultFuture < ( ) > {
2020-02-06 01:49:18 +02:00
Err ( MeliError ::new ( " Unimplemented. " ) )
2020-04-04 20:09:51 +03:00
}
fn search (
& self ,
_query : crate ::search ::Query ,
_mailbox_hash : Option < MailboxHash > ,
2020-06-30 11:40:26 +03:00
) -> ResultFuture < SmallVec < [ EnvelopeHash ; 512 ] > > {
2020-04-04 20:09:51 +03:00
Err ( MeliError ::new ( " Unimplemented. " ) )
2020-02-06 01:49:18 +02:00
}
2017-09-28 18:06:35 +03:00
}
2017-09-14 18:08:14 +03:00
2017-09-16 14:14:08 +03:00
/// A `BackendOp` manages common operations for the various mail backends. They only live for the
2019-07-18 20:14:14 +03:00
/// duration of the operation. They are generated by the `operation` method of `Mailbackend` trait.
2017-09-16 13:32:56 +03:00
///
/// # Motivation
///
/// We need a way to do various operations on individual mails regardless of what backend they come
/// from (eg local or imap).
///
2019-03-26 15:27:02 +02:00
/// # Creation
2019-12-11 16:07:08 +02:00
/// ```ignore
2019-03-26 15:27:02 +02:00
/// /* Create operation from Backend */
///
2020-02-26 10:54:10 +02:00
/// let op = backend.operation(message.hash(), mailbox.hash());
2019-03-26 15:27:02 +02:00
/// ```
///
2017-09-16 13:32:56 +03:00
/// # Example
2019-12-11 16:07:08 +02:00
/// ```ignore
/// use melib::backends::{BackendOp};
2017-10-01 17:31:20 +03:00
/// use melib::Result;
/// use melib::{Envelope, Flag};
2017-09-16 13:32:56 +03:00
///
/// #[derive(Debug)]
/// struct FooOp {}
///
/// impl BackendOp for FooOp {
/// fn as_bytes(&mut self) -> Result<&[u8]> {
/// unimplemented!()
/// }
2020-06-28 16:53:52 +03:00
/// fn fetch_flags(&self) -> Result<Flag> {
2017-09-16 19:15:51 +03:00
/// unimplemented!()
/// }
2017-09-16 13:32:56 +03:00
/// }
///
2019-07-18 20:14:14 +03:00
/// let operation = Box::new(FooOp {});
2017-09-16 13:32:56 +03:00
/// ```
2017-09-14 18:08:14 +03:00
pub trait BackendOp : ::std ::fmt ::Debug + ::std ::marker ::Send {
2020-07-04 17:38:57 +03:00
fn as_bytes ( & mut self ) -> ResultFuture < Vec < u8 > > ;
2020-06-30 19:36:02 +03:00
fn fetch_flags ( & self ) -> ResultFuture < Flag > ;
2017-09-14 18:08:14 +03:00
}
2019-07-18 20:16:51 +03:00
/// Wrapper for BackendOps that are to be set read-only.
///
/// Warning: Backend implementations may still cause side-effects (for example IMAP can set the
/// Seen flag when fetching an envelope)
#[ derive(Debug) ]
pub struct ReadOnlyOp {
2019-09-09 11:54:47 +03:00
op : Box < dyn BackendOp > ,
2019-07-18 20:16:51 +03:00
}
impl ReadOnlyOp {
2019-09-09 11:54:47 +03:00
pub fn new ( op : Box < dyn BackendOp > ) -> Box < dyn BackendOp > {
2019-07-18 20:16:51 +03:00
Box ::new ( ReadOnlyOp { op } )
}
}
impl BackendOp for ReadOnlyOp {
2020-07-04 17:38:57 +03:00
fn as_bytes ( & mut self ) -> ResultFuture < Vec < u8 > > {
2019-07-18 20:16:51 +03:00
self . op . as_bytes ( )
}
2020-06-30 19:36:02 +03:00
fn fetch_flags ( & self ) -> ResultFuture < Flag > {
2019-07-18 20:16:51 +03:00
self . op . fetch_flags ( )
}
2017-09-14 18:08:14 +03:00
}
2018-08-11 18:00:21 +03:00
2019-08-25 21:44:19 +03:00
#[ derive(Debug, Copy, Hash, Eq, Clone, Serialize, Deserialize, PartialEq) ]
2019-12-11 00:15:36 +02:00
pub enum SpecialUsageMailbox {
2019-08-23 21:58:41 +03:00
Normal ,
Inbox ,
Archive ,
Drafts ,
Flagged ,
Junk ,
Sent ,
Trash ,
}
2019-12-17 14:12:41 +02: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-11 00:15:36 +02:00
impl Default for SpecialUsageMailbox {
fn default ( ) -> Self {
SpecialUsageMailbox ::Normal
}
}
2019-12-07 14:04:25 +02:00
impl SpecialUsageMailbox {
pub fn detect_usage ( name : & str ) -> Option < SpecialUsageMailbox > {
if name . eq_ignore_ascii_case ( " inbox " ) {
Some ( SpecialUsageMailbox ::Inbox )
} else if name . eq_ignore_ascii_case ( " archive " ) {
Some ( SpecialUsageMailbox ::Archive )
} else if name . eq_ignore_ascii_case ( " drafts " ) {
Some ( SpecialUsageMailbox ::Drafts )
2020-07-05 15:28:55 +03:00
} else if name . eq_ignore_ascii_case ( " junk " ) | | name . eq_ignore_ascii_case ( " spam " ) {
2019-12-07 14:04:25 +02:00
Some ( SpecialUsageMailbox ::Junk )
} else if name . eq_ignore_ascii_case ( " sent " ) {
Some ( SpecialUsageMailbox ::Sent )
} else if name . eq_ignore_ascii_case ( " trash " ) {
Some ( SpecialUsageMailbox ::Trash )
} else {
Some ( SpecialUsageMailbox ::Normal )
}
}
}
2020-02-26 10:54:10 +02:00
pub trait BackendMailbox : Debug {
fn hash ( & self ) -> MailboxHash ;
2018-08-11 18:00:21 +03:00
fn name ( & self ) -> & str ;
2020-02-26 10:54:10 +02:00
/// Path of mailbox within the mailbox hierarchy, with `/` as separator.
2019-08-23 21:32:32 +03:00
fn path ( & self ) -> & str ;
2019-04-04 14:21:52 +03:00
fn change_name ( & mut self , new_name : & str ) ;
2020-02-26 10:54:10 +02:00
fn clone ( & self ) -> Mailbox ;
fn children ( & self ) -> & [ MailboxHash ] ;
fn parent ( & self ) -> Option < MailboxHash > ;
2019-12-17 14:12:41 +02: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-11 00:15:36 +02:00
fn special_usage ( & self ) -> SpecialUsageMailbox ;
2020-02-26 10:54:10 +02:00
fn permissions ( & self ) -> MailboxPermissions ;
2019-12-17 14:12:41 +02:00
fn count ( & self ) -> Result < ( usize , usize ) > ;
2018-08-11 18:00:21 +03:00
}
2020-05-10 22:05:04 +03:00
pub type AccountHash = u64 ;
2020-02-26 10:54:10 +02:00
pub type MailboxHash = u64 ;
pub type Mailbox = Box < dyn BackendMailbox + Send + Sync > ;
2018-09-23 19:55:29 +03:00
2020-02-26 10:54:10 +02:00
impl Clone for Mailbox {
2018-09-23 19:55:29 +03:00
fn clone ( & self ) -> Self {
2020-02-26 10:54:10 +02:00
BackendMailbox ::clone ( self . deref ( ) )
2018-09-23 19:55:29 +03:00
}
}
2019-11-11 00:47:23 +02:00
#[ derive(Debug, PartialEq, Eq, Hash, Clone, Copy) ]
2020-02-26 10:54:10 +02:00
pub struct MailboxPermissions {
2019-11-11 00:47:23 +02: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 10:54:10 +02:00
impl Default for MailboxPermissions {
2019-11-11 00:47:23 +02:00
fn default ( ) -> Self {
2020-02-26 10:54:10 +02:00
MailboxPermissions {
2019-11-11 00:47:23 +02:00
create_messages : false ,
remove_messages : false ,
set_flags : false ,
create_child : false ,
rename_messages : false ,
delete_messages : false ,
2020-02-26 10:54:10 +02:00
delete_mailbox : true ,
2019-11-11 00:47:23 +02:00
change_permissions : false ,
}
}
}
2020-02-06 01:49:18 +02:00
2020-02-26 10:54:10 +02:00
impl std ::fmt ::Display for MailboxPermissions {
2020-02-06 01:49:18 +02:00
fn fmt ( & self , fmt : & mut std ::fmt ::Formatter ) -> std ::fmt ::Result {
write! ( fmt , " {:#?} " , self )
}
}
2020-07-24 20:17:06 +03:00
#[ derive(Debug, Clone, PartialEq) ]
pub struct EnvelopeHashBatch {
pub first : EnvelopeHash ,
pub rest : SmallVec < [ EnvelopeHash ; 64 ] > ,
}
impl From < EnvelopeHash > for EnvelopeHashBatch {
fn from ( value : EnvelopeHash ) -> Self {
EnvelopeHashBatch {
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 ( ( ) ) ;
}
Ok ( EnvelopeHashBatch {
first : value [ 0 ] ,
rest : value [ 1 .. ] . iter ( ) . cloned ( ) . collect ( ) ,
} )
}
}
impl EnvelopeHashBatch {
2020-09-16 13:14:54 +03:00
pub fn iter ( & self ) -> impl std ::iter ::Iterator < Item = EnvelopeHash > + '_ {
2020-07-24 20:17:06 +03:00
std ::iter ::once ( self . first ) . chain ( self . rest . iter ( ) . cloned ( ) )
}
2020-09-16 13:14:54 +03:00
pub fn len ( & self ) -> usize {
1 + self . rest . len ( )
}
2020-07-24 20:17:06 +03:00
}
2020-09-22 14:14:11 +03:00
#[ derive(Debug, Default, Clone) ]
pub struct LazyCountSet {
not_yet_seen : usize ,
set : BTreeSet < EnvelopeHash > ,
}
impl LazyCountSet {
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 {
self . not_yet_seen - = 1 ;
self . set . insert ( new_val ) ;
true
}
}
pub fn insert_existing_set ( & mut self , set : BTreeSet < EnvelopeHash > ) -> bool {
debug! ( " insert_existing_set {:?} " , & set ) ;
if self . not_yet_seen < set . len ( ) {
false
} else {
self . not_yet_seen - = set . len ( ) ;
self . set . extend ( set . into_iter ( ) ) ;
true
}
}
#[ 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 > ) {
debug! ( " insert__set {:?} " , & set ) ;
self . set . extend ( set . into_iter ( ) ) ;
}
pub fn remove ( & mut self , new_val : EnvelopeHash ) -> bool {
self . set . remove ( & new_val )
}
}
#[ test ]
fn test_lazy_count_set ( ) {
let mut new = LazyCountSet ::default ( ) ;
new . set_not_yet_seen ( 10 ) ;
for i in 0 .. 10 {
assert! ( new . insert_existing ( i ) ) ;
}
assert! ( ! new . insert_existing ( 10 ) ) ;
}