diff --git a/src/backends/id_mapper.rs b/src/backends/id_mapper.rs index 7ca77a1..953a729 100644 --- a/src/backends/id_mapper.rs +++ b/src/backends/id_mapper.rs @@ -76,42 +76,39 @@ impl IdMapper { } pub fn append(&mut self, lines: Vec<(String, String)>) -> Result { - let mut entries = String::new(); + self.extend(lines); - self.extend(lines.clone()); + let mut entries = String::new(); + let mut short_hash_len = self.short_hash_len; 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 - }) + .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; + short_hash_len += 1; } entries.push_str(&format!("{} {}\n", hash, id)); } + self.short_hash_len = short_hash_len; + 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()) + .write(format!("{}\n{}", short_hash_len, entries).as_bytes()) .context("cannot write maildir id hash map cache")?; - Ok(self.short_hash_len) + Ok(short_hash_len) } } diff --git a/src/backends/maildir/maildir_backend.rs b/src/backends/maildir/maildir_backend.rs index c3e64b4..2bf3a9c 100644 --- a/src/backends/maildir/maildir_backend.rs +++ b/src/backends/maildir/maildir_backend.rs @@ -54,6 +54,12 @@ impl<'a> MaildirBackend<'a> { // maildir subdirectory by adding a "." in front // of the name as described in the spec: // https://cr.yp.to/proto/maildir.html + let dir = self + .account_config + .mailboxes + .get(dir) + .map(|s| s.as_str()) + .unwrap_or(dir); let path = self.mdir.path().join(format!(".{}", dir)); self.validate_mdir_path(path) }) diff --git a/src/backends/notmuch/notmuch_backend.rs b/src/backends/notmuch/notmuch_backend.rs index 6393d68..416e1c0 100644 --- a/src/backends/notmuch/notmuch_backend.rs +++ b/src/backends/notmuch/notmuch_backend.rs @@ -193,24 +193,16 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> { Ok(envelopes) } - fn add_msg(&mut self, dir: &str, msg: &[u8], tags: &str) -> Result> { + fn add_msg(&mut self, _: &str, msg: &[u8], tags: &str) -> Result> { info!(">> add notmuch envelopes"); - debug!("dir: {:?}", dir); debug!("tags: {:?}", tags); - let mdir = self - .mdir - .get_mdir_from_dir(dir) - .with_context(|| format!("cannot get maildir instance from {:?}", dir))?; - let mdir_path_str = mdir - .path() - .to_str() - .ok_or_else(|| anyhow!("cannot parse maildir path to string"))?; + let dir = &self.notmuch_config.notmuch_database_dir; // Adds the message to the maildir folder and gets its hash. let hash = self .mdir - .add_msg(mdir_path_str, msg, "seen") + .add_msg("inbox", msg, "seen") .with_context(|| { format!( "cannot add notmuch message to maildir {:?}", @@ -222,12 +214,13 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> { // Retrieves the file path of the added message by its maildir // identifier. - let id = IdMapper::new(mdir.path()) - .with_context(|| format!("cannot create id mapper instance for {:?}", dir))? + let mut mapper = IdMapper::new(dir) + .with_context(|| format!("cannot create id mapper instance for {:?}", dir))?; + let id = mapper .find(&hash) .with_context(|| format!("cannot find notmuch message from short hash {:?}", hash))?; debug!("id: {:?}", id); - let file_path = mdir.path().join("cur").join(format!("{}:2,S", id)); + let file_path = dir.join("cur").join(format!("{}:2,S", id)); debug!("file path: {:?}", file_path); // Adds the message to the notmuch database by indexing it. @@ -240,13 +233,6 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> { let hash = format!("{:x}", md5::compute(&id)); // Appends hash entry to the id mapper cache file. - let mut mapper = - IdMapper::new(&self.notmuch_config.notmuch_database_dir).with_context(|| { - format!( - "cannot create id mapper instance for {:?}", - self.notmuch_config.notmuch_database_dir - ) - })?; mapper .append(vec![(hash.clone(), id.clone())]) .with_context(|| { @@ -264,7 +250,7 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> { Ok(Box::new(hash)) } - fn get_msg(&mut self, _virt_mbox: &str, short_hash: &str) -> Result { + fn get_msg(&mut self, _: &str, short_hash: &str) -> Result { info!(">> add notmuch envelopes"); debug!("short hash: {:?}", short_hash); @@ -300,7 +286,7 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> { Ok(msg) } - fn copy_msg(&mut self, _mbox_src: &str, _mbox_dst: &str, _id: &str) -> Result<()> { + fn copy_msg(&mut self, _dir_src: &str, _dir_dst: &str, _short_hash: &str) -> Result<()> { info!(">> copy notmuch message"); info!("<< copy notmuch message"); Err(anyhow!( @@ -308,7 +294,7 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> { )) } - fn move_msg(&mut self, _src: &str, _dst: &str, _id: &str) -> Result<()> { + fn move_msg(&mut self, _dir_src: &str, _dir_dst: &str, _short_hash: &str) -> Result<()> { info!(">> move notmuch message"); info!("<< move notmuch message"); Err(anyhow!( diff --git a/tests/test_maildir_backend.rs b/tests/test_maildir_backend.rs index adcc2e2..d998789 100644 --- a/tests/test_maildir_backend.rs +++ b/tests/test_maildir_backend.rs @@ -19,7 +19,10 @@ fn test_maildir_backend() { // configure accounts let account_config = AccountConfig { - mailboxes: HashMap::from_iter([("inbox".into(), "INBOX".into())]), + mailboxes: HashMap::from_iter([ + ("inbox".into(), "INBOX".into()), + ("subdir".into(), "Subdir".into()), + ]), ..AccountConfig::default() }; let mdir_config = MaildirBackendConfig { @@ -33,16 +36,16 @@ fn test_maildir_backend() { // check that a message can be added let msg = include_bytes!("./emails/alice-to-patrick.eml"); - let hash = mdir.add_msg("INBOX", msg, "seen").unwrap().to_string(); + let hash = mdir.add_msg("inbox", msg, "seen").unwrap().to_string(); // check that the added message exists - let msg = mdir.get_msg("INBOX", &hash).unwrap(); + let msg = mdir.get_msg("inbox", &hash).unwrap(); assert_eq!("alice@localhost", msg.from.clone().unwrap().to_string()); assert_eq!("patrick@localhost", msg.to.clone().unwrap().to_string()); assert_eq!("Ceci est un message.", msg.fold_text_plain_parts()); // check that the envelope of the added message exists - let envelopes = mdir.get_envelopes("INBOX", 10, 0).unwrap(); + let envelopes = mdir.get_envelopes("inbox", 10, 0).unwrap(); let envelopes: &MaildirEnvelopes = envelopes.as_any().downcast_ref().unwrap(); let envelope = envelopes.first().unwrap(); assert_eq!(1, envelopes.len()); @@ -50,9 +53,9 @@ fn test_maildir_backend() { assert_eq!("Plain message", envelope.subject); // check that a flag can be added to the message - mdir.add_flags("INBOX", &envelope.hash, "flagged passed") + mdir.add_flags("inbox", &envelope.hash, "flagged passed") .unwrap(); - let envelopes = mdir.get_envelopes("INBOX", 1, 0).unwrap(); + let envelopes = mdir.get_envelopes("inbox", 1, 0).unwrap(); let envelopes: &MaildirEnvelopes = envelopes.as_any().downcast_ref().unwrap(); let envelope = envelopes.first().unwrap(); assert!(envelope.flags.contains(&MaildirFlag::Seen)); @@ -60,8 +63,8 @@ fn test_maildir_backend() { assert!(envelope.flags.contains(&MaildirFlag::Passed)); // check that the message flags can be changed - mdir.set_flags("INBOX", &envelope.hash, "passed").unwrap(); - let envelopes = mdir.get_envelopes("INBOX", 1, 0).unwrap(); + mdir.set_flags("inbox", &envelope.hash, "passed").unwrap(); + let envelopes = mdir.get_envelopes("inbox", 1, 0).unwrap(); let envelopes: &MaildirEnvelopes = envelopes.as_any().downcast_ref().unwrap(); let envelope = envelopes.first().unwrap(); assert!(!envelope.flags.contains(&MaildirFlag::Seen)); @@ -69,8 +72,8 @@ fn test_maildir_backend() { assert!(envelope.flags.contains(&MaildirFlag::Passed)); // check that a flag can be removed from the message - mdir.del_flags("INBOX", &envelope.hash, "passed").unwrap(); - let envelopes = mdir.get_envelopes("INBOX", 1, 0).unwrap(); + mdir.del_flags("inbox", &envelope.hash, "passed").unwrap(); + let envelopes = mdir.get_envelopes("inbox", 1, 0).unwrap(); let envelopes: &MaildirEnvelopes = envelopes.as_any().downcast_ref().unwrap(); let envelope = envelopes.first().unwrap(); assert!(!envelope.flags.contains(&MaildirFlag::Seen)); @@ -78,19 +81,19 @@ fn test_maildir_backend() { assert!(!envelope.flags.contains(&MaildirFlag::Passed)); // check that the message can be copied - mdir.copy_msg("INBOX", "Subdir", &envelope.hash).unwrap(); - assert!(mdir.get_msg("INBOX", &hash).is_ok()); - assert!(mdir.get_msg("Subdir", &hash).is_ok()); - assert!(mdir_subdir.get_msg("INBOX", &hash).is_ok()); + mdir.copy_msg("inbox", "subdir", &envelope.hash).unwrap(); + assert!(mdir.get_msg("inbox", &hash).is_ok()); + assert!(mdir.get_msg("subdir", &hash).is_ok()); + assert!(mdir_subdir.get_msg("inbox", &hash).is_ok()); // check that the message can be moved - mdir.move_msg("INBOX", "Subdir", &envelope.hash).unwrap(); - assert!(mdir.get_msg("INBOX", &hash).is_err()); - assert!(mdir.get_msg("Subdir", &hash).is_ok()); - assert!(mdir_subdir.get_msg("INBOX", &hash).is_ok()); + mdir.move_msg("inbox", "subdir", &envelope.hash).unwrap(); + assert!(mdir.get_msg("inbox", &hash).is_err()); + assert!(mdir.get_msg("subdir", &hash).is_ok()); + assert!(mdir_subdir.get_msg("inbox", &hash).is_ok()); // check that the message can be deleted - mdir.del_msg("Subdir", &hash).unwrap(); - assert!(mdir.get_msg("Subdir", &hash).is_err()); - assert!(mdir_subdir.get_msg("INBOX", &hash).is_err()); + mdir.del_msg("subdir", &hash).unwrap(); + assert!(mdir.get_msg("subdir", &hash).is_err()); + assert!(mdir_subdir.get_msg("inbox", &hash).is_err()); } diff --git a/tests/test_notmuch_backend.rs b/tests/test_notmuch_backend.rs index d015073..93e707b 100644 --- a/tests/test_notmuch_backend.rs +++ b/tests/test_notmuch_backend.rs @@ -49,7 +49,7 @@ fn test_notmuch_backend() { notmuch .add_flags("", &envelope.hash, "flagged passed") .unwrap(); - let envelopes = notmuch.get_envelopes("inbox", 1, 0).unwrap(); + let envelopes = notmuch.get_envelopes("inbox", 10, 0).unwrap(); let envelopes: &NotmuchEnvelopes = envelopes.as_any().downcast_ref().unwrap(); let envelope = envelopes.first().unwrap(); assert!(envelope.flags.contains(&"inbox".into())); @@ -61,7 +61,7 @@ fn test_notmuch_backend() { notmuch .set_flags("", &envelope.hash, "inbox passed") .unwrap(); - let envelopes = notmuch.get_envelopes("inbox", 1, 0).unwrap(); + let envelopes = notmuch.get_envelopes("inbox", 10, 0).unwrap(); let envelopes: &NotmuchEnvelopes = envelopes.as_any().downcast_ref().unwrap(); let envelope = envelopes.first().unwrap(); assert!(envelope.flags.contains(&"inbox".into())); @@ -71,11 +71,15 @@ fn test_notmuch_backend() { // check that a flag can be removed from the message notmuch.del_flags("", &envelope.hash, "passed").unwrap(); - let envelopes = notmuch.get_envelopes("inbox", 1, 0).unwrap(); + let envelopes = notmuch.get_envelopes("inbox", 10, 0).unwrap(); let envelopes: &NotmuchEnvelopes = envelopes.as_any().downcast_ref().unwrap(); let envelope = envelopes.first().unwrap(); assert!(envelope.flags.contains(&"inbox".into())); assert!(!envelope.flags.contains(&"seen".into())); assert!(!envelope.flags.contains(&"flagged".into())); assert!(!envelope.flags.contains(&"passed".into())); + + // check that the message can be deleted + notmuch.del_msg("", &hash).unwrap(); + assert!(notmuch.get_msg("inbox", &hash).is_err()); }