Browse Source

mbox: add support for multiple mbox mailboxes in config

Concerns #9
master
parent
commit
1db2c16f95
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS. GPG Key ID: 73627C2F690DF710
2 changed files with 98 additions and 42 deletions
  1. +11
    -0
      meli.conf.5
  2. +87
    -42
      melib/src/backends/mbox.rs

+ 11
- 0
meli.conf.5 View File

@@ -257,6 +257,17 @@ Valid values are:
.\" default value
.Pq Em auto
.El
to set multiple mailboxes, you have to explicitly state the mailboxes you want in the
.Ic mailboxes
field and set the
.Ar path
property to each of them.
Example:
.Bd -literal
[accounts.mbox]
format = "mbox"
mailboxes."Python mailing list" = { path = "~/.mail/python.mbox", subscribe = true, autoload = true }
.Ed
.Sh mailboxes
.Bl -tag -width 36n
.It Ic alias Ar String


+ 87
- 42
melib/src/backends/mbox.rs View File

@@ -84,6 +84,7 @@ struct MboxMailbox {
hash: MailboxHash,
name: String,
path: PathBuf,
fs_path: PathBuf,
content: Vec<u8>,
children: Vec<MailboxHash>,
parent: Option<MailboxHash>,
@@ -92,6 +93,7 @@ struct MboxMailbox {
permissions: MailboxPermissions,
pub total: Arc<Mutex<usize>>,
pub unseen: Arc<Mutex<usize>>,
index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>,
}

impl BackendMailbox for MboxMailbox {
@@ -117,6 +119,7 @@ impl BackendMailbox for MboxMailbox {
hash: self.hash,
name: self.name.clone(),
path: self.path.clone(),
fs_path: self.fs_path.clone(),
content: self.content.clone(),
children: self.children.clone(),
usage: self.usage.clone(),
@@ -125,6 +128,7 @@ impl BackendMailbox for MboxMailbox {
permissions: self.permissions,
unseen: self.unseen.clone(),
total: self.total.clone(),
index: self.index.clone(),
})
}

@@ -659,7 +663,7 @@ pub fn mbox_parse(
pub struct MboxType {
account_name: String,
path: PathBuf,
index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>,
mailbox_index: Arc<Mutex<HashMap<EnvelopeHash, MailboxHash>>>,
mailboxes: Arc<Mutex<HashMap<MailboxHash, MboxMailbox>>>,
prefer_mbox_type: Option<MboxReader>,
}
@@ -673,14 +677,13 @@ impl MailBackend for MboxType {
let mut w = AsyncBuilder::new();
let handle = {
let tx = w.tx();
let index = self.index.clone();
let mailbox_path = mailbox.path().to_string();
let mailbox_hash = mailbox.hash();
let mailbox_index = self.mailbox_index.clone();
let mailboxes = self.mailboxes.clone();
let mailbox_path = mailboxes.lock().unwrap()[&mailbox_hash].fs_path.clone();
let prefer_mbox_type = self.prefer_mbox_type.clone();
let closure = move |_work_context| {
let tx = tx.clone();
let index = index.clone();
let file = match std::fs::OpenOptions::new()
.read(true)
.write(true)
@@ -702,9 +705,18 @@ impl MailBackend for MboxType {
return;
};

let mailboxes_lck = mailboxes.lock().unwrap();
let mut mailbox_index_lck = mailbox_index.lock().unwrap();
let index = mailboxes_lck[&mailbox_hash].index.clone();
drop(mailboxes_lck);
let payload = mbox_parse(index, contents.as_slice(), 0, prefer_mbox_type)
.map_err(|e| MeliError::from(e))
.map(|(_, v)| v);
.map(|(_, v)| {
for v in v.iter() {
mailbox_index_lck.insert(v.hash(), mailbox_hash);
}
v
});
{
let mut mailbox_lock = mailboxes.lock().unwrap();
mailbox_lock
@@ -731,17 +743,16 @@ impl MailBackend for MboxType {
.map_err(MeliError::new)?;
for f in self.mailboxes.lock().unwrap().values() {
watcher
.watch(&f.path, RecursiveMode::Recursive)
.watch(&f.fs_path, RecursiveMode::Recursive)
.map_err(|e| e.to_string())
.map_err(MeliError::new)?;
debug!("watching {:?}", f.path.as_path());
debug!("watching {:?}", f.fs_path.as_path());
}
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(self.account_name.as_bytes());
hasher.finish()
};
let index = self.index.clone();
let mailboxes = self.mailboxes.clone();
let prefer_mbox_type = self.prefer_mbox_type.clone();
let handle = std::thread::Builder::new()
@@ -750,7 +761,6 @@ impl MailBackend for MboxType {
// Move `watcher` in the closure's scope so that it doesn't get dropped.
let _watcher = watcher;
let _work_context = work_context;
let index = index;
let mailboxes = mailboxes;
loop {
match rx.recv() {
@@ -791,7 +801,7 @@ impl MailBackend for MboxType {
.starts_with(mailbox_lock[&mailbox_hash].content.as_slice())
{
if let Ok((_, envelopes)) = mbox_parse(
index.clone(),
mailbox_lock[&mailbox_hash].index.clone(),
&contents[mailbox_lock[&mailbox_hash].content.len()..],
mailbox_lock[&mailbox_hash].content.len(),
prefer_mbox_type,
@@ -822,7 +832,7 @@ impl MailBackend for MboxType {
.lock()
.unwrap()
.values()
.any(|f| &f.path == &pathbuf)
.any(|f| &f.fs_path == &pathbuf)
{
let mailbox_hash = get_path_hash!(&pathbuf);
sender.send(RefreshEvent {
@@ -837,7 +847,12 @@ impl MailBackend for MboxType {
}
}
DebouncedEvent::Rename(src, dest) => {
if mailboxes.lock().unwrap().values().any(|f| &f.path == &src) {
if mailboxes
.lock()
.unwrap()
.values()
.any(|f| &f.fs_path == &src)
{
let mailbox_hash = get_path_hash!(&src);
sender.send(RefreshEvent {
account_hash,
@@ -879,12 +894,20 @@ impl MailBackend for MboxType {
.map(|(h, f)| (*h, f.clone() as Mailbox))
.collect())
}
fn operation(&self, hash: EnvelopeHash) -> Box<dyn BackendOp> {
fn operation(&self, env_hash: EnvelopeHash) -> Box<dyn BackendOp> {
let mailbox_hash = self.mailbox_index.lock().unwrap()[&env_hash];
let mailboxes_lck = self.mailboxes.lock().unwrap();
let (offset, length) = {
let index = self.index.lock().unwrap();
index[&hash]
let index = mailboxes_lck[&mailbox_hash].index.lock().unwrap();
index[&env_hash]
};
Box::new(MboxOp::new(hash, self.path.as_path(), offset, length))
let mailbox_path = mailboxes_lck[&mailbox_hash].fs_path.clone();
Box::new(MboxOp::new(
env_hash,
mailbox_path.as_path(),
offset,
length,
))
}

fn save(&self, _bytes: &[u8], _mailbox_hash: MailboxHash, _flags: Option<Flag>) -> Result<()> {
@@ -974,7 +997,8 @@ impl MboxType {
hash,
MboxMailbox {
hash,
path: ret.path.clone(),
path: name.clone().into(),
fs_path: ret.path.clone(),
name,
content: Vec::new(),
children: Vec::new(),
@@ -993,39 +1017,60 @@ impl MboxType {
},
unseen: Arc::new(Mutex::new(0)),
total: Arc::new(Mutex::new(0)),
index: Default::default(),
},
);
/*
/* Look for other mailboxes */
let parent_mailbox = Path::new(path).parent().unwrap();
let read_dir = std::fs::read_dir(parent_mailbox);
if read_dir.is_ok() {
for f in read_dir.unwrap() {
if f.is_err() {
continue;
for (k, f) in s.mailboxes.iter() {
if let Some(path_str) = f.extra.get("path") {
let hash = get_path_hash!(path_str);
let pathbuf: PathBuf = path_str.into();
if !pathbuf.exists() || pathbuf.is_dir() {
return Err(MeliError::new(format!(
"mbox mailbox configuration entry \"{}\" path value {} is not a file.",
k, path_str
)));
}
let f = f.unwrap().path();
if f.is_file() && f != path {
let name: String = f
.file_name()
.map(|f| f.to_string_lossy().into())
.unwrap_or(String::new());
let hash = get_path_hash!(f);
ret.mailboxes.lock().unwrap().insert(
let read_only = if let Ok(metadata) = std::fs::metadata(&pathbuf) {
metadata.permissions().readonly()
} else {
true
};

ret.mailboxes.lock().unwrap().insert(
hash,
MboxMailbox {
hash,
MboxMailbox {
hash,
path: f,
name,
content: Vec::new(),
children: Vec::new(),
parent: None,
name: k.to_string(),
fs_path: pathbuf,
path: k.into(),
content: Vec::new(),
children: Vec::new(),
parent: None,
usage: Arc::new(RwLock::new(f.usage.unwrap_or_default())),
is_subscribed: f.subscribe.is_true(),
permissions: MailboxPermissions {
create_messages: !read_only,
remove_messages: !read_only,
set_flags: !read_only,
create_child: !read_only,
rename_messages: !read_only,
delete_messages: !read_only,
delete_mailbox: !read_only,
change_permissions: false,
},
);
}
unseen: Arc::new(Mutex::new(0)),
total: Arc::new(Mutex::new(0)),
index: Default::default(),
},
);
} else {
return Err(MeliError::new(format!(
"mbox mailbox configuration entry \"{}\" should have a \"path\" value set pointing to an mbox file.",
k
)));
}
}
*/
Ok(Box::new(ret))
}



Loading…
Cancel
Save