mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-08 10:35:13 +00:00
move id mapper to its dedicated module
This commit is contained in:
parent
5b002b1f30
commit
ad1f97faed
130
src/backends/id_mapper.rs
Normal file
130
src/backends/id_mapper.rs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fs::OpenOptions,
|
||||||
|
io::{BufRead, BufReader, Write},
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct IdMapper {
|
||||||
|
path: PathBuf,
|
||||||
|
map: HashMap<String, String>,
|
||||||
|
short_hash_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdMapper {
|
||||||
|
pub fn new(dir: &Path) -> Result<Self> {
|
||||||
|
let mut mapper = Self::default();
|
||||||
|
mapper.path = dir.join(".himalaya-id-map");
|
||||||
|
|
||||||
|
let file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&mapper.path)
|
||||||
|
.context("cannot open id hash map file")?;
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
|
||||||
|
for line in reader.lines() {
|
||||||
|
let line =
|
||||||
|
line.context("cannot read line from maildir envelopes id mapper cache file")?;
|
||||||
|
if mapper.short_hash_len == 0 {
|
||||||
|
mapper.short_hash_len = 2.max(line.parse().unwrap_or(2));
|
||||||
|
} else {
|
||||||
|
let (hash, id) = line.split_once(' ').ok_or_else(|| {
|
||||||
|
anyhow!(
|
||||||
|
"cannot parse line {:?} from maildir envelopes id mapper cache file",
|
||||||
|
line
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
mapper.insert(hash.to_owned(), id.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(mapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find(&self, short_hash: &str) -> Result<String> {
|
||||||
|
let matching_hashes: Vec<_> = self
|
||||||
|
.keys()
|
||||||
|
.filter(|hash| hash.starts_with(short_hash))
|
||||||
|
.collect();
|
||||||
|
if matching_hashes.len() == 0 {
|
||||||
|
Err(anyhow!(
|
||||||
|
"cannot find maildir message id from short hash {:?}",
|
||||||
|
short_hash,
|
||||||
|
))
|
||||||
|
} else if matching_hashes.len() > 1 {
|
||||||
|
Err(anyhow!(
|
||||||
|
"the short hash {:?} matches more than one hash: {}",
|
||||||
|
short_hash,
|
||||||
|
matching_hashes
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
.context(format!(
|
||||||
|
"cannot find maildir message id from short hash {:?}",
|
||||||
|
short_hash
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Ok(self.get(matching_hashes[0]).unwrap().to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, lines: Vec<(String, String)>) -> Result<usize> {
|
||||||
|
let mut entries = String::new();
|
||||||
|
|
||||||
|
self.extend(lines.clone());
|
||||||
|
|
||||||
|
for (hash, id) in self.iter() {
|
||||||
|
entries.push_str(&format!("{} {}\n", hash, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (hash, id) in lines {
|
||||||
|
loop {
|
||||||
|
let short_hash = &hash[0..self.short_hash_len];
|
||||||
|
let conflict_found = self
|
||||||
|
.map
|
||||||
|
.keys()
|
||||||
|
.find(|cached_hash| {
|
||||||
|
cached_hash.starts_with(short_hash) && *cached_hash != &hash
|
||||||
|
})
|
||||||
|
.is_some();
|
||||||
|
if self.short_hash_len > 32 || !conflict_found {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.short_hash_len += 1;
|
||||||
|
}
|
||||||
|
entries.push_str(&format!("{} {}\n", hash, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(&self.path)
|
||||||
|
.context("cannot open maildir id hash map cache")?
|
||||||
|
.write(format!("{}\n{}", self.short_hash_len, entries).as_bytes())
|
||||||
|
.context("cannot write maildir id hash map cache")?;
|
||||||
|
|
||||||
|
Ok(self.short_hash_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for IdMapper {
|
||||||
|
type Target = HashMap<String, String>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.map
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for IdMapper {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.map
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,149 +1,13 @@
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use std::{
|
use std::{convert::TryInto, fs, path::PathBuf};
|
||||||
collections::HashMap,
|
|
||||||
convert::TryInto,
|
|
||||||
env::temp_dir,
|
|
||||||
fs::{self, OpenOptions},
|
|
||||||
io::{BufRead, BufReader, Write},
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
path::PathBuf,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::{Backend, MaildirEnvelopes, MaildirFlags, MaildirMboxes},
|
backends::{Backend, IdMapper, MaildirEnvelopes, MaildirFlags, MaildirMboxes},
|
||||||
config::{AccountConfig, MaildirBackendConfig, DEFAULT_INBOX_FOLDER},
|
config::{AccountConfig, MaildirBackendConfig, DEFAULT_INBOX_FOLDER},
|
||||||
mbox::Mboxes,
|
mbox::Mboxes,
|
||||||
msg::{Envelopes, Msg},
|
msg::{Envelopes, Msg},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct MaildirEnvelopesIdHashMapper {
|
|
||||||
path: PathBuf,
|
|
||||||
map: HashMap<String, String>,
|
|
||||||
short_hash_len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaildirEnvelopesIdHashMapper {
|
|
||||||
fn get_cache_path(mdir: &maildir::Maildir) -> PathBuf {
|
|
||||||
let path_digest = md5::compute(format!("{:?}", mdir.path()));
|
|
||||||
let file_name = format!("himalaya-hash-map-{:x}", path_digest);
|
|
||||||
temp_dir().join(file_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(mdir: &maildir::Maildir) -> Result<Self> {
|
|
||||||
let mut mapper = Self::default();
|
|
||||||
mapper.path = Self::get_cache_path(mdir);
|
|
||||||
|
|
||||||
let file = OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.write(true)
|
|
||||||
.create(true)
|
|
||||||
.open(&mapper.path)
|
|
||||||
.context("cannot open id hash map file")?;
|
|
||||||
let reader = BufReader::new(file);
|
|
||||||
|
|
||||||
for line in reader.lines() {
|
|
||||||
let line =
|
|
||||||
line.context("cannot read line from maildir envelopes id mapper cache file")?;
|
|
||||||
if mapper.short_hash_len == 0 {
|
|
||||||
mapper.short_hash_len = 2.max(line.parse().unwrap_or(2));
|
|
||||||
} else {
|
|
||||||
let (hash, id) = line.split_once(' ').ok_or_else(|| {
|
|
||||||
anyhow!(
|
|
||||||
"cannot parse line {:?} from maildir envelopes id mapper cache file",
|
|
||||||
line
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
mapper.insert(hash.to_owned(), id.to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find(&self, short_hash: &str) -> Result<String> {
|
|
||||||
let matching_hashes: Vec<_> = self
|
|
||||||
.keys()
|
|
||||||
.filter(|hash| hash.starts_with(short_hash))
|
|
||||||
.collect();
|
|
||||||
if matching_hashes.len() == 0 {
|
|
||||||
Err(anyhow!(
|
|
||||||
"cannot find maildir message id from short hash {:?}",
|
|
||||||
short_hash,
|
|
||||||
))
|
|
||||||
} else if matching_hashes.len() > 1 {
|
|
||||||
Err(anyhow!(
|
|
||||||
"the short hash {:?} matches more than one hash: {}",
|
|
||||||
short_hash,
|
|
||||||
matching_hashes
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ")
|
|
||||||
)
|
|
||||||
.context(format!(
|
|
||||||
"cannot find maildir message id from short hash {:?}",
|
|
||||||
short_hash
|
|
||||||
)))
|
|
||||||
} else {
|
|
||||||
Ok(self.get(matching_hashes[0]).unwrap().to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append(&mut self, lines: Vec<(String, String)>) -> Result<usize> {
|
|
||||||
let mut entries = String::new();
|
|
||||||
|
|
||||||
self.extend(lines.clone());
|
|
||||||
|
|
||||||
for (hash, id) in self.iter() {
|
|
||||||
entries.push_str(&format!("{} {}\n", hash, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (hash, id) in lines {
|
|
||||||
loop {
|
|
||||||
let short_hash = &hash[0..self.short_hash_len];
|
|
||||||
let conflict_found = self
|
|
||||||
.map
|
|
||||||
.keys()
|
|
||||||
.find(|cached_hash| {
|
|
||||||
cached_hash.starts_with(short_hash) && *cached_hash != &hash
|
|
||||||
})
|
|
||||||
.is_some();
|
|
||||||
if self.short_hash_len > 32 || !conflict_found {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
self.short_hash_len += 1;
|
|
||||||
}
|
|
||||||
entries.push_str(&format!("{} {}\n", hash, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenOptions::new()
|
|
||||||
.write(true)
|
|
||||||
.create(true)
|
|
||||||
.truncate(true)
|
|
||||||
.open(&self.path)
|
|
||||||
.context("cannot open maildir id hash map cache")?
|
|
||||||
.write(format!("{}\n{}", self.short_hash_len, entries).as_bytes())
|
|
||||||
.context("cannot write maildir id hash map cache")?;
|
|
||||||
|
|
||||||
Ok(self.short_hash_len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for MaildirEnvelopesIdHashMapper {
|
|
||||||
type Target = HashMap<String, String>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.map
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for MaildirEnvelopesIdHashMapper {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.map
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MaildirBackend<'a> {
|
pub struct MaildirBackend<'a> {
|
||||||
mdir: maildir::Maildir,
|
mdir: maildir::Maildir,
|
||||||
account_config: &'a AccountConfig,
|
account_config: &'a AccountConfig,
|
||||||
|
@ -211,18 +75,18 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
|
|
||||||
fn get_envelopes(
|
fn get_envelopes(
|
||||||
&mut self,
|
&mut self,
|
||||||
mdir_str: &str,
|
mdir: &str,
|
||||||
page_size: usize,
|
page_size: usize,
|
||||||
page: usize,
|
page: usize,
|
||||||
) -> Result<Box<dyn Envelopes>> {
|
) -> Result<Box<dyn Envelopes>> {
|
||||||
let mdir = self.get_mdir_from_name(mdir_str)?;
|
let mdir = self.get_mdir_from_name(mdir)?;
|
||||||
|
|
||||||
// Reads envelopes from the "cur" folder of the selected
|
// Reads envelopes from the "cur" folder of the selected
|
||||||
// maildir.
|
// maildir.
|
||||||
let mut envelopes: MaildirEnvelopes = mdir
|
let mut envelopes: MaildirEnvelopes = mdir.list_cur().try_into().context(format!(
|
||||||
.list_cur()
|
"cannot parse maildir envelopes from {:?}",
|
||||||
.try_into()
|
self.mdir.path()
|
||||||
.context("cannot parse maildir envelopes from {:?}")?;
|
))?;
|
||||||
|
|
||||||
// Calculates pagination boundaries.
|
// Calculates pagination boundaries.
|
||||||
let page_begin = page * page_size;
|
let page_begin = page * page_size;
|
||||||
|
@ -244,7 +108,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
// cache file name is based on the name of the given maildir:
|
// cache file name is based on the name of the given maildir:
|
||||||
// this way there is one cache per maildir.
|
// this way there is one cache per maildir.
|
||||||
let short_hash_len = {
|
let short_hash_len = {
|
||||||
let mut mapper = MaildirEnvelopesIdHashMapper::new(&mdir)?;
|
let mut mapper = IdMapper::new(mdir.path())?;
|
||||||
let entries = envelopes
|
let entries = envelopes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|env| (env.hash.to_owned(), env.id.to_owned()))
|
.map(|env| (env.hash.to_owned(), env.id.to_owned()))
|
||||||
|
@ -278,11 +142,11 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
let flags: MaildirFlags = flags.try_into()?;
|
let flags: MaildirFlags = flags.try_into()?;
|
||||||
let id = mdir
|
let id = mdir
|
||||||
.store_cur_with_flags(msg, &flags.to_string())
|
.store_cur_with_flags(msg, &flags.to_string())
|
||||||
.context(format!("cannot add maildir message at {:?}", mdir.path()))?;
|
.context(format!("cannot add maildir message to {:?}", mdir.path()))?;
|
||||||
let hash = format!("{:x}", md5::compute(&id));
|
let hash = format!("{:x}", md5::compute(&id));
|
||||||
|
|
||||||
// Appends hash line to the maildir cache file.
|
// Appends hash line to the maildir cache file.
|
||||||
let mut mapper = MaildirEnvelopesIdHashMapper::new(&mdir)?;
|
let mut mapper = IdMapper::new(mdir.path())?;
|
||||||
mapper.append(vec![(hash.clone(), id)])?;
|
mapper.append(vec![(hash.clone(), id)])?;
|
||||||
|
|
||||||
Ok(Box::new(hash))
|
Ok(Box::new(hash))
|
||||||
|
@ -290,7 +154,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
|
|
||||||
fn get_msg(&mut self, mdir: &str, short_hash: &str) -> Result<Msg> {
|
fn get_msg(&mut self, mdir: &str, short_hash: &str) -> Result<Msg> {
|
||||||
let mdir = self.get_mdir_from_name(mdir)?;
|
let mdir = self.get_mdir_from_name(mdir)?;
|
||||||
let id = MaildirEnvelopesIdHashMapper::new(&mdir)?
|
let id = IdMapper::new(mdir.path())?
|
||||||
.find(short_hash)
|
.find(short_hash)
|
||||||
.context(format!(
|
.context(format!(
|
||||||
"cannot get maildir message from short hash {:?}",
|
"cannot get maildir message from short hash {:?}",
|
||||||
|
@ -314,7 +178,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
fn copy_msg(&mut self, mdir_src: &str, mdir_dst: &str, short_hash: &str) -> Result<()> {
|
fn copy_msg(&mut self, mdir_src: &str, mdir_dst: &str, short_hash: &str) -> Result<()> {
|
||||||
let mdir_src = self.get_mdir_from_name(mdir_src)?;
|
let mdir_src = self.get_mdir_from_name(mdir_src)?;
|
||||||
let mdir_dst = self.get_mdir_from_name(mdir_dst)?;
|
let mdir_dst = self.get_mdir_from_name(mdir_dst)?;
|
||||||
let id = MaildirEnvelopesIdHashMapper::new(&mdir_src)?.find(short_hash)?;
|
let id = IdMapper::new(mdir_src.path())?.find(short_hash)?;
|
||||||
|
|
||||||
mdir_src.copy_to(&id, &mdir_dst).context(format!(
|
mdir_src.copy_to(&id, &mdir_dst).context(format!(
|
||||||
"cannot copy message {:?} from maildir {:?} to maildir {:?}",
|
"cannot copy message {:?} from maildir {:?} to maildir {:?}",
|
||||||
|
@ -324,8 +188,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Appends hash line to the destination maildir cache file.
|
// Appends hash line to the destination maildir cache file.
|
||||||
MaildirEnvelopesIdHashMapper::new(&mdir_dst)?
|
IdMapper::new(mdir_dst.path())?.append(vec![(format!("{:x}", md5::compute(&id)), id)])?;
|
||||||
.append(vec![(format!("{:x}", md5::compute(&id)), id)])?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -333,7 +196,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
fn move_msg(&mut self, mdir_src: &str, mdir_dst: &str, short_hash: &str) -> Result<()> {
|
fn move_msg(&mut self, mdir_src: &str, mdir_dst: &str, short_hash: &str) -> Result<()> {
|
||||||
let mdir_src = self.get_mdir_from_name(mdir_src)?;
|
let mdir_src = self.get_mdir_from_name(mdir_src)?;
|
||||||
let mdir_dst = self.get_mdir_from_name(mdir_dst)?;
|
let mdir_dst = self.get_mdir_from_name(mdir_dst)?;
|
||||||
let id = MaildirEnvelopesIdHashMapper::new(&mdir_src)?.find(short_hash)?;
|
let id = IdMapper::new(mdir_src.path())?.find(short_hash)?;
|
||||||
|
|
||||||
mdir_src.move_to(&id, &mdir_dst).context(format!(
|
mdir_src.move_to(&id, &mdir_dst).context(format!(
|
||||||
"cannot move message {:?} from maildir {:?} to maildir {:?}",
|
"cannot move message {:?} from maildir {:?} to maildir {:?}",
|
||||||
|
@ -343,15 +206,14 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Appends hash line to the destination maildir cache file.
|
// Appends hash line to the destination maildir cache file.
|
||||||
MaildirEnvelopesIdHashMapper::new(&mdir_dst)?
|
IdMapper::new(mdir_dst.path())?.append(vec![(format!("{:x}", md5::compute(&id)), id)])?;
|
||||||
.append(vec![(format!("{:x}", md5::compute(&id)), id)])?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn del_msg(&mut self, mdir: &str, short_hash: &str) -> Result<()> {
|
fn del_msg(&mut self, mdir: &str, short_hash: &str) -> Result<()> {
|
||||||
let mdir = self.get_mdir_from_name(mdir)?;
|
let mdir = self.get_mdir_from_name(mdir)?;
|
||||||
let id = MaildirEnvelopesIdHashMapper::new(&mdir)?.find(short_hash)?;
|
let id = IdMapper::new(mdir.path())?.find(short_hash)?;
|
||||||
mdir.delete(&id).context(format!(
|
mdir.delete(&id).context(format!(
|
||||||
"cannot delete message {:?} from maildir {:?}",
|
"cannot delete message {:?} from maildir {:?}",
|
||||||
id,
|
id,
|
||||||
|
@ -361,7 +223,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
|
|
||||||
fn add_flags(&mut self, mdir: &str, short_hash: &str, flags_str: &str) -> Result<()> {
|
fn add_flags(&mut self, mdir: &str, short_hash: &str, flags_str: &str) -> Result<()> {
|
||||||
let mdir = self.get_mdir_from_name(mdir)?;
|
let mdir = self.get_mdir_from_name(mdir)?;
|
||||||
let id = MaildirEnvelopesIdHashMapper::new(&mdir)?.find(short_hash)?;
|
let id = IdMapper::new(mdir.path())?.find(short_hash)?;
|
||||||
let flags: MaildirFlags = flags_str.try_into()?;
|
let flags: MaildirFlags = flags_str.try_into()?;
|
||||||
mdir.add_flags(&id, &flags.to_string()).context(format!(
|
mdir.add_flags(&id, &flags.to_string()).context(format!(
|
||||||
"cannot add flags {:?} to maildir message {:?}",
|
"cannot add flags {:?} to maildir message {:?}",
|
||||||
|
@ -371,7 +233,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
|
|
||||||
fn set_flags(&mut self, mdir: &str, short_hash: &str, flags_str: &str) -> Result<()> {
|
fn set_flags(&mut self, mdir: &str, short_hash: &str, flags_str: &str) -> Result<()> {
|
||||||
let mdir = self.get_mdir_from_name(mdir)?;
|
let mdir = self.get_mdir_from_name(mdir)?;
|
||||||
let id = MaildirEnvelopesIdHashMapper::new(&mdir)?.find(short_hash)?;
|
let id = IdMapper::new(mdir.path())?.find(short_hash)?;
|
||||||
let flags: MaildirFlags = flags_str.try_into()?;
|
let flags: MaildirFlags = flags_str.try_into()?;
|
||||||
mdir.set_flags(&id, &flags.to_string()).context(format!(
|
mdir.set_flags(&id, &flags.to_string()).context(format!(
|
||||||
"cannot set flags {:?} to maildir message {:?}",
|
"cannot set flags {:?} to maildir message {:?}",
|
||||||
|
@ -381,7 +243,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
|
||||||
|
|
||||||
fn del_flags(&mut self, mdir: &str, short_hash: &str, flags_str: &str) -> Result<()> {
|
fn del_flags(&mut self, mdir: &str, short_hash: &str, flags_str: &str) -> Result<()> {
|
||||||
let mdir = self.get_mdir_from_name(mdir)?;
|
let mdir = self.get_mdir_from_name(mdir)?;
|
||||||
let id = MaildirEnvelopesIdHashMapper::new(&mdir)?.find(short_hash)?;
|
let id = IdMapper::new(mdir.path())?.find(short_hash)?;
|
||||||
let flags: MaildirFlags = flags_str.try_into()?;
|
let flags: MaildirFlags = flags_str.try_into()?;
|
||||||
mdir.remove_flags(&id, &flags.to_string()).context(format!(
|
mdir.remove_flags(&id, &flags.to_string()).context(format!(
|
||||||
"cannot remove flags {:?} from maildir message {:?}",
|
"cannot remove flags {:?} from maildir message {:?}",
|
||||||
|
|
|
@ -37,6 +37,9 @@ pub mod backends {
|
||||||
pub use backend::*;
|
pub use backend::*;
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
|
|
||||||
|
pub use id_mapper::*;
|
||||||
|
pub mod id_mapper;
|
||||||
|
|
||||||
pub use self::imap::*;
|
pub use self::imap::*;
|
||||||
pub mod imap {
|
pub mod imap {
|
||||||
pub mod imap_arg;
|
pub mod imap_arg;
|
||||||
|
|
Loading…
Reference in a new issue