email-lib 0.27.0

Cross-platform, asynchronous Rust library to manage emails
Documentation
use std::{collections::BTreeSet, sync::Arc};

#[doc(inline)]
pub use super::{Error, Result};
use super::{SyncDestination, SyncEventHandler};
use crate::{
    backend::{
        context::{BackendContext, BackendContextBuilder},
        Backend, BackendBuilder,
    },
    email::sync::hunk::EmailSyncHunk,
    envelope::sync::config::EnvelopeSyncFilters,
    flag::sync::config::FlagSyncPermissions,
    folder::sync::{
        config::{FolderSyncPermissions, FolderSyncStrategy},
        hunk::FolderSyncHunk,
        patch::FolderSyncPatches,
    },
    maildir::{MaildirContextBuilder, MaildirContextSync},
    message::sync::config::MessageSyncPermissions,
    AnyResult,
};

#[derive(Clone, Default)]
pub struct SyncPoolConfig {
    pub left_folder_permissions: Option<FolderSyncPermissions>,
    pub left_flag_permissions: Option<FlagSyncPermissions>,
    pub left_message_permissions: Option<MessageSyncPermissions>,
    pub right_folder_permissions: Option<FolderSyncPermissions>,
    pub right_flag_permissions: Option<FlagSyncPermissions>,
    pub right_message_permissions: Option<MessageSyncPermissions>,
    pub pool_size: Option<usize>,
    pub folder_filters: Option<FolderSyncStrategy>,
    pub envelope_filters: Option<EnvelopeSyncFilters>,
    pub handler: Option<Arc<SyncEventHandler>>,
    pub dry_run: Option<bool>,
}

#[derive(Clone)]
pub struct SyncPoolContextBuilder<L, R>
where
    L: BackendContextBuilder,
    R: BackendContextBuilder,
{
    config: SyncPoolConfig,
    left_cache_builder: BackendBuilder<MaildirContextBuilder>,
    left_builder: BackendBuilder<L>,
    right_cache_builder: BackendBuilder<MaildirContextBuilder>,
    right_builder: BackendBuilder<R>,
}

impl<L, R> SyncPoolContextBuilder<L, R>
where
    L: BackendContextBuilder,
    R: BackendContextBuilder,
{
    pub fn new(
        config: SyncPoolConfig,
        left_cache_builder: BackendBuilder<MaildirContextBuilder>,
        left_builder: BackendBuilder<L>,
        right_cache_builder: BackendBuilder<MaildirContextBuilder>,
        right_builder: BackendBuilder<R>,
    ) -> Self {
        Self {
            config,
            left_cache_builder,
            left_builder,
            right_cache_builder,
            right_builder,
        }
    }

    pub async fn build(self) -> AnyResult<SyncPoolContext<L::Context, R::Context>> {
        let left_folder_permissions = self
            .config
            .left_folder_permissions
            .clone()
            .or_else(|| {
                self.left_builder
                    .account_config
                    .folder
                    .as_ref()
                    .and_then(|c| c.sync.as_ref())
                    .map(|c| c.permissions.clone())
            })
            .unwrap_or_default();

        let left_flag_permissions = self
            .config
            .left_flag_permissions
            .clone()
            .or_else(|| {
                self.left_builder
                    .account_config
                    .flag
                    .as_ref()
                    .and_then(|c| c.sync.as_ref())
                    .map(|c| c.permissions.clone())
            })
            .unwrap_or_default();

        let left_message_permissions = self
            .config
            .left_message_permissions
            .clone()
            .or_else(|| {
                self.left_builder
                    .account_config
                    .message
                    .as_ref()
                    .and_then(|c| c.sync.as_ref())
                    .map(|c| c.permissions.clone())
            })
            .unwrap_or_default();

        let right_folder_permissions = self
            .config
            .right_folder_permissions
            .clone()
            .or_else(|| {
                self.right_builder
                    .account_config
                    .folder
                    .as_ref()
                    .and_then(|c| c.sync.as_ref())
                    .map(|c| c.permissions.clone())
            })
            .unwrap_or_default();

        let right_flag_permissions = self
            .config
            .right_flag_permissions
            .clone()
            .or_else(|| {
                self.right_builder
                    .account_config
                    .flag
                    .as_ref()
                    .and_then(|c| c.sync.as_ref())
                    .map(|c| c.permissions.clone())
            })
            .unwrap_or_default();

        let right_message_permissions = self
            .config
            .right_message_permissions
            .clone()
            .or_else(|| {
                self.right_builder
                    .account_config
                    .message
                    .as_ref()
                    .and_then(|c| c.sync.as_ref())
                    .map(|c| c.permissions.clone())
            })
            .unwrap_or_default();

        let folder_filters = self
            .config
            .folder_filters
            .clone()
            .or_else(|| {
                self.right_builder
                    .account_config
                    .folder
                    .as_ref()
                    .and_then(|c| c.sync.as_ref())
                    .map(|c| c.filter.clone())
            })
            .unwrap_or_default();

        let envelope_filters = self
            .config
            .envelope_filters
            .clone()
            .or_else(|| {
                self.right_builder
                    .account_config
                    .envelope
                    .as_ref()
                    .and_then(|c| c.sync.as_ref())
                    .map(|c| c.filter.clone())
            })
            .unwrap_or_default();

        let (left_cache, left, right_cache, right) = tokio::try_join!(
            self.left_cache_builder.build(),
            self.left_builder.build(),
            self.right_cache_builder.build(),
            self.right_builder.build(),
        )?;

        Ok(SyncPoolContext {
            left_cache,
            left,
            left_folder_permissions,
            left_flag_permissions,
            left_message_permissions,
            right_cache,
            right,
            right_folder_permissions,
            right_flag_permissions,
            right_message_permissions,
            folder_filters,
            envelope_filters,
            handler: self.config.handler,
            dry_run: self.config.dry_run.unwrap_or_default(),
        })
    }
}

pub struct SyncPoolContext<L: BackendContext, R: BackendContext> {
    pub left_cache: Backend<MaildirContextSync>,
    pub left: Backend<L>,
    pub right_cache: Backend<MaildirContextSync>,
    pub right: Backend<R>,
    pub left_folder_permissions: FolderSyncPermissions,
    pub left_flag_permissions: FlagSyncPermissions,
    pub left_message_permissions: MessageSyncPermissions,
    pub right_folder_permissions: FolderSyncPermissions,
    pub right_flag_permissions: FlagSyncPermissions,
    pub right_message_permissions: MessageSyncPermissions,
    pub folder_filters: FolderSyncStrategy,
    pub envelope_filters: EnvelopeSyncFilters,
    pub handler: Option<Arc<SyncEventHandler>>,
    pub dry_run: bool,
}

impl<L: BackendContext, R: BackendContext> SyncPoolContext<L, R> {
    pub fn apply_folder_permissions(&self, patch: &mut FolderSyncPatches) {
        use FolderSyncHunk::*;
        use SyncDestination::*;

        for (_, patch) in patch.iter_mut() {
            patch.retain(|hunk| match hunk {
                Create(_, Left) | Cache(_, Left) => self.left_folder_permissions.create,
                Create(_, Right) | Cache(_, Right) => self.right_folder_permissions.create,
                Delete(_, Left) | Uncache(_, Left) => self.left_folder_permissions.delete,
                Delete(_, Right) | Uncache(_, Right) => self.right_folder_permissions.delete,
            });
        }
    }

    pub fn apply_flag_and_message_permissions(&self, patch: &mut BTreeSet<EmailSyncHunk>) {
        use EmailSyncHunk::*;
        use SyncDestination::*;

        patch.retain(|hunk| match hunk {
            GetThenCache(_, _, Left) => self.left_message_permissions.create,
            GetThenCache(_, _, Right) => self.right_message_permissions.create,
            CopyThenCache(_, _, _, Left, _) => self.left_message_permissions.create,
            CopyThenCache(_, _, _, Right, _) => self.right_message_permissions.create,
            UpdateCachedFlags(_, _, Left) => self.left_flag_permissions.update,
            UpdateCachedFlags(_, _, Right) => self.right_flag_permissions.update,
            UpdateFlags(_, _, Left) => self.left_flag_permissions.update,
            UpdateFlags(_, _, Right) => self.right_flag_permissions.update,
            Uncache(_, _, Left) | Delete(_, _, Left) => self.left_message_permissions.delete,
            Uncache(_, _, Right) | Delete(_, _, Right) => self.right_message_permissions.delete,
        });
    }
}