vomit-sync 0.10.1

A library for IMAP to maildir synchronization
Documentation
use imap::extensions::list_status::ExtendedNames;
use std::collections::BTreeMap;
use thiserror::Error;
use vomit::VomitError;

use crate::state::{self, StateError, SyncState};

#[derive(Error, Debug)]
pub enum MailboxesError {
    #[error("error loading local mailboxes: {0}")]
    VomitError(#[from] VomitError),
    #[error("error loading mailbox state: {0}")]
    StateError(#[from] StateError),
}

#[derive(Debug)]
pub enum SyncAction {
    Sync,
    CreateLocal,
    CreateRemote,
    DeleteLocal,
    DeleteRemote,
}

pub struct SyncJob {
    pub name: String,
    pub delimiter: String,
    pub action: SyncAction,
}

pub(crate) fn load_local(
    path: &str,
    delimiter: &str,
) -> Result<BTreeMap<String, SyncState>, MailboxesError> {
    vomit::load_mailboxes(path, false, false)?
        .into_iter()
        .map(|mb| {
            let name = mb.imap_name(delimiter);
            let state = SyncState::load(&mb.abs_path())?;
            Ok((name, state))
        })
        .collect::<Result<BTreeMap<_, _>, _>>()
}

pub fn load_remote(names: &ExtendedNames) -> BTreeMap<String, u64> {
    names
        .iter()
        .map(|name| {
            let modseq = name
                .1
                .as_ref()
                .map(|mb| mb.highest_mod_seq.unwrap_or(0))
                .unwrap_or(0);
            (String::from(name.0.name()), modseq)
        })
        .collect()
}

pub(crate) fn sync_create_local(name: String, delimiter: String) -> Option<SyncJob> {
    Some(SyncJob {
        name,
        delimiter,
        action: SyncAction::CreateLocal,
    })
}

pub(crate) fn sync_delete_local(name: String, delimiter: String) -> Option<SyncJob> {
    Some(SyncJob {
        name,
        delimiter,
        action: SyncAction::DeleteLocal,
    })
}

pub(crate) fn sync_create_remote(name: String, delimiter: String) -> Option<SyncJob> {
    Some(SyncJob {
        name,
        delimiter,
        action: SyncAction::CreateRemote,
    })
}

pub(crate) fn sync_delete_remote(name: String, delimiter: String) -> Option<SyncJob> {
    Some(SyncJob {
        name,
        delimiter,
        action: SyncAction::DeleteRemote,
    })
}

pub fn sync(name: String, delimiter: String) -> Option<SyncJob> {
    Some(SyncJob {
        name,
        delimiter,
        action: SyncAction::Sync,
    })
}

pub(crate) fn sync_done(job: SyncJob, state: &mut state::RootState) {
    let dirname = vomit::Mailbox::virtual_to_dir(&job.name, &job.delimiter);
    match job.action {
        SyncAction::CreateLocal | SyncAction::CreateRemote => state.subdirs.insert(dirname),
        SyncAction::DeleteLocal | SyncAction::DeleteRemote => state.subdirs.remove(&dirname),
        SyncAction::Sync => state.subdirs.insert(dirname),
    };
}