/*
* meli - mailbox 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/>.
*/
use super::{
BackendFolder, BackendOp, Folder, FolderHash, MailBackend, RefreshEvent, RefreshEventConsumer,
RefreshEventKind::*,
};
use super::{MaildirFolder, MaildirOp};
use crate::async_workers::*;
use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{MeliError, Result};
extern crate notify;
use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use std::time::Duration;
use std::sync::mpsc::channel;
//use std::sync::mpsc::sync_channel;
//use std::sync::mpsc::SyncSender;
//use std::time::Duration;
use fnv::{FnvHashMap, FnvHasher};
use std::collections::hash_map::DefaultHasher;
use std::ffi::OsStr;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Read, Write};
use std::ops::{Deref, DerefMut};
use std::path::{Component, Path, PathBuf};
use std::result;
use std::sync::{Arc, Mutex};
use std::thread;
#[derive(Clone, Debug, PartialEq)]
pub(super) enum PathMod {
Path(PathBuf),
Hash(EnvelopeHash),
}
#[derive(Debug, Default)]
pub struct MaildirPath {
pub(super) buf: PathBuf,
pub(super) modified: Option<PathMod>,
pub(super) removed: bool,
}
impl Deref for MaildirPath {
type Target = PathBuf;
fn deref(&self) -> &PathBuf {
assert!(!(self.removed && self.modified.is_none()));
&self.buf
}
}
impl DerefMut for MaildirPath {
fn deref_mut(&mut self) -> &mut PathBuf {
assert!(!(self.removed && self.modified.is_none()));
&mut self.buf
}
}
impl From<PathBuf> for MaildirPath {
fn from(val: PathBuf) -> MaildirPath {
MaildirPath {
buf: val,
modified: None,
removed: false,
}
}
}
#[derive(Debug, Default)]
pub struct HashIndex {
index: FnvHashMap<EnvelopeHash, MaildirPath>,
hash: FolderHash,
}
impl Deref for HashIndex {
type Target = FnvHashMap<EnvelopeHash, MaildirPath>;
fn deref(&self) -> &FnvHashMap<EnvelopeHash, MaildirPath> {
&self.index
}
}
impl DerefMut for HashIndex {
fn deref_mut(&mut self) -> &mut FnvHashMap<EnvelopeHash, MaildirPath> {
&mut self.index
}
}
pub type HashIndexes = Arc<Mutex<FnvHashMap<FolderHash, HashIndex>>>;
/// Maildir backend https://cr.yp.to/proto/maildir.html
#[derive(Debug)]
pub struct MaildirType {
name: String,
folders: FnvHashMap<FolderHash, MaildirFolder>,
//folder_index: FnvHashMap<FolderHash, usize>,
hash_indexes: HashIndexes,
path: PathBuf,
}
macro_rules! path_is_new {
($path:expr) => {
if $path.is_dir() {
false
} else {
let mut iter = $path.components().rev();
iter.next();
iter.next() == Some(Component::Normal(OsStr::new("new")))
}
};
}
#[macro_export]
macro_rules! get_path_hash {
($path:expr) => {{
let mut path = $path.clone();
if path.is_dir() {
if path.ends_with("cur") | path.ends_with("new") {
path.pop();
}
} else {
path.pop();
path.pop();
};
let mut hasher = DefaultHasher::new();
path.hash(&mut hasher);
hasher.finish()
}};
}
pub(super) fn get_file_hash(file: &Path) -> EnvelopeHash {
/*
let mut buf = Vec::with_capacity(2048);
let mut f = fs::File::open(&file).unwrap_or_else(|_| panic!("Can't open {}", file.display()));
f.read_to_end(&mut buf)
.unwrap_or_else(|_| panic!("Can't read {}", file.display()));
let mut hasher = FnvHasher::default();
hasher.write(&buf);
hasher.finish()
*/
let mut hasher = FnvHasher::default();
file.hash(&mut hasher);
hasher.finish()
}
fn move_to_cur(p: PathBuf) -> PathBuf {
let mut new = p.clone();
let file_name = p.to_string_lossy();
let slash_pos = file_name.bytes().rposition(|c| c == b'/').unwrap() + 1;
new.pop();
new.pop();
new.push("cur");
new.push(&file_name[slash_pos..]);