parent
d2b4057b7b
commit
65efb23f14
|
@ -248,6 +248,13 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
|
|||
fn is_online(&self) -> Result<()>;
|
||||
fn connect(&mut self) {}
|
||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>>;
|
||||
fn refresh(
|
||||
&mut self,
|
||||
folder_hash: FolderHash,
|
||||
sender: RefreshEventConsumer,
|
||||
) -> Async<Result<Vec<RefreshEvent>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn watch(
|
||||
&self,
|
||||
sender: RefreshEventConsumer,
|
||||
|
|
|
@ -199,6 +199,136 @@ impl MailBackend for MaildirType {
|
|||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||
self.multicore(4, folder)
|
||||
}
|
||||
fn refresh(
|
||||
&mut self,
|
||||
folder_hash: FolderHash,
|
||||
sender: RefreshEventConsumer,
|
||||
) -> Async<Result<Vec<RefreshEvent>>> {
|
||||
let w = AsyncBuilder::new();
|
||||
let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap();
|
||||
|
||||
let handle = {
|
||||
let folder: &MaildirFolder = &self.folders[&folder_hash];
|
||||
let path: PathBuf = folder.fs_path().into();
|
||||
let name = format!("refresh {:?}", folder.name());
|
||||
let root_path = self.path.to_path_buf();
|
||||
let map = self.hash_indexes.clone();
|
||||
let folder_index = self.folder_index.clone();
|
||||
let cache_dir = cache_dir.clone();
|
||||
let sender = Arc::new(sender);
|
||||
|
||||
Box::new(move |work_context: crate::async_workers::WorkContext| {
|
||||
let cache_dir = cache_dir.clone();
|
||||
let folder_index = folder_index.clone();
|
||||
let root_path = root_path.clone();
|
||||
let path = path.clone();
|
||||
let name = name.clone();
|
||||
let map = map.clone();
|
||||
let sender = sender.clone();
|
||||
work_context
|
||||
.set_name
|
||||
.send((std::thread::current().id(), name.clone()))
|
||||
.unwrap();
|
||||
let thunk = move |sender: &RefreshEventConsumer| {
|
||||
debug!("refreshing");
|
||||
let cache_dir = cache_dir.clone();
|
||||
let map = map.clone();
|
||||
let folder_index = folder_index.clone();
|
||||
let folder_hash = folder_hash.clone();
|
||||
let root_path = root_path.clone();
|
||||
let mut path = path.clone();
|
||||
let cache_dir = cache_dir.clone();
|
||||
path.push("new");
|
||||
for d in path.read_dir()? {
|
||||
if let Ok(p) = d {
|
||||
move_to_cur(p.path()).ok().take();
|
||||
}
|
||||
}
|
||||
path.pop();
|
||||
|
||||
path.push("cur");
|
||||
let iter = path.read_dir()?;
|
||||
let count = path.read_dir()?.count();
|
||||
let mut files: Vec<PathBuf> = Vec::with_capacity(count);
|
||||
for e in iter {
|
||||
let e = e.and_then(|x| {
|
||||
let path = x.path();
|
||||
Ok(path)
|
||||
})?;
|
||||
files.push(e);
|
||||
}
|
||||
let mut current_hashes = {
|
||||
let mut map = map.lock().unwrap();
|
||||
let map = map.entry(folder_hash).or_default();
|
||||
map.keys().cloned().collect::<FnvHashSet<EnvelopeHash>>()
|
||||
};
|
||||
for file in files {
|
||||
let hash = get_file_hash(&file);
|
||||
{
|
||||
let mut map = map.lock().unwrap();
|
||||
let map = map.entry(folder_hash).or_default();
|
||||
if map.contains_key(&hash) {
|
||||
map.remove(&hash);
|
||||
current_hashes.remove(&hash);
|
||||
continue;
|
||||
}
|
||||
(*map).insert(hash, PathBuf::from(&file).into());
|
||||
}
|
||||
let op = Box::new(MaildirOp::new(hash, map.clone(), folder_hash));
|
||||
if let Some(e) = Envelope::from_token(op, hash) {
|
||||
folder_index.lock().unwrap().insert(e.hash(), folder_hash);
|
||||
let file_name = PathBuf::from(file)
|
||||
.strip_prefix(&root_path)
|
||||
.unwrap()
|
||||
.to_path_buf();
|
||||
if let Ok(cached) = cache_dir.place_cache_file(file_name) {
|
||||
/* place result in cache directory */
|
||||
let f = match fs::File::create(cached) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
panic!("{}", e);
|
||||
}
|
||||
};
|
||||
let metadata = f.metadata().unwrap();
|
||||
let mut permissions = metadata.permissions();
|
||||
|
||||
permissions.set_mode(0o600); // Read/write for owner only.
|
||||
f.set_permissions(permissions).unwrap();
|
||||
|
||||
let writer = io::BufWriter::new(f);
|
||||
bincode::serialize_into(writer, &e).unwrap();
|
||||
}
|
||||
sender.send(RefreshEvent {
|
||||
hash: folder_hash,
|
||||
kind: Create(Box::new(e)),
|
||||
});
|
||||
} else {
|
||||
debug!(
|
||||
"DEBUG: hash {}, path: {} couldn't be parsed",
|
||||
hash,
|
||||
file.as_path().display()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for ev in current_hashes.into_iter().map(|h| RefreshEvent {
|
||||
hash: folder_hash,
|
||||
kind: Remove(h),
|
||||
}) {
|
||||
sender.send(ev);
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
if let Err(err) = thunk(&sender) {
|
||||
sender.send(RefreshEvent {
|
||||
hash: folder_hash,
|
||||
kind: Failure(err),
|
||||
});
|
||||
}
|
||||
})
|
||||
};
|
||||
w.build(handle)
|
||||
}
|
||||
fn watch(
|
||||
&self,
|
||||
sender: RefreshEventConsumer,
|
||||
|
|
|
@ -33,6 +33,8 @@ pub struct AccountSettings {
|
|||
pub subscribed_folders: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub folders: HashMap<String, FolderConf>,
|
||||
#[serde(default)]
|
||||
pub manual_refresh: bool,
|
||||
#[serde(flatten)]
|
||||
pub extra: HashMap<String, String>,
|
||||
}
|
||||
|
|
|
@ -673,6 +673,15 @@ impl Component for Listing {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Listing::DESCRIPTION]["refresh"]) =>
|
||||
{
|
||||
let folder_hash =
|
||||
context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1];
|
||||
let account = &mut context.accounts[self.cursor_pos.0];
|
||||
account.refresh(folder_hash);
|
||||
return true;
|
||||
}
|
||||
UIEvent::StartupCheck(_) => {
|
||||
self.dirty = true;
|
||||
context
|
||||
|
|
|
@ -100,10 +100,6 @@ pub struct FileAccount {
|
|||
root_folder: String,
|
||||
format: String,
|
||||
identity: String,
|
||||
#[serde(flatten)]
|
||||
#[serde(deserialize_with = "extra_settings")]
|
||||
pub extra: HashMap<String, String>, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */
|
||||
|
||||
#[serde(default = "none")]
|
||||
display_name: Option<String>,
|
||||
index_style: IndexStyle,
|
||||
|
@ -115,6 +111,11 @@ pub struct FileAccount {
|
|||
folders: HashMap<String, FileFolderConf>,
|
||||
#[serde(default)]
|
||||
cache_type: CacheType,
|
||||
#[serde(default)]
|
||||
pub manual_refresh: bool,
|
||||
#[serde(flatten)]
|
||||
#[serde(deserialize_with = "extra_settings")]
|
||||
pub extra: HashMap<String, String>, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */
|
||||
}
|
||||
|
||||
impl From<FileAccount> for AccountConf {
|
||||
|
@ -138,6 +139,7 @@ impl From<FileAccount> for AccountConf {
|
|||
display_name,
|
||||
subscribed_folders: x.subscribed_folders.clone(),
|
||||
folders,
|
||||
manual_refresh: x.manual_refresh,
|
||||
extra: x.extra.clone(),
|
||||
};
|
||||
|
||||
|
@ -344,6 +346,7 @@ impl FileSettings {
|
|||
subscribed_folders,
|
||||
folders,
|
||||
extra,
|
||||
manual_refresh,
|
||||
index_style: _,
|
||||
cache_type: _,
|
||||
} = acc;
|
||||
|
@ -357,6 +360,7 @@ impl FileSettings {
|
|||
read_only,
|
||||
display_name,
|
||||
subscribed_folders,
|
||||
manual_refresh,
|
||||
folders: folders
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.folder_conf))
|
||||
|
|
|
@ -699,7 +699,19 @@ impl Account {
|
|||
}
|
||||
None
|
||||
}
|
||||
pub fn refresh(&mut self, folder_hash: FolderHash) {
|
||||
let sender_ = self.sender.clone();
|
||||
let r = RefreshEventConsumer::new(Box::new(move |r| {
|
||||
sender_.send(ThreadEvent::from(r)).unwrap();
|
||||
}));
|
||||
let mut h = self.backend.write().unwrap().refresh(folder_hash, r);
|
||||
self.work_context.new_work.send(h.work().unwrap()).unwrap();
|
||||
}
|
||||
pub fn watch(&self) {
|
||||
if self.settings.account().manual_refresh {
|
||||
return;
|
||||
}
|
||||
|
||||
let sender_ = self.sender.clone();
|
||||
let r = RefreshEventConsumer::new(Box::new(move |r| {
|
||||
sender_.send(ThreadEvent::from(r)).unwrap();
|
||||
|
|
|
@ -115,6 +115,7 @@ shortcut_key_values! { "listing",
|
|||
prev_folder |> "Go to previous folder." |> Key::Char('K'),
|
||||
prev_page |> "Go to previous page." |> Key::PageUp,
|
||||
search |> "Search within list of e-mails." |> Key::Char('/'),
|
||||
refresh |> "Manually request a folder refresh." |> Key::F(5),
|
||||
set_seen |> "Set thread as seen." |> Key::Char('n'),
|
||||
toggle_menu_visibility |> "Toggle visibility of side menu in mail list." |> Key::Char('`')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue