-pub fn middleware(input: &[u8]) -> Vec<u8> {
- let command = String::from_utf8_lossy(input);
- if let Some(tag) = command.split("FIND MAILBOXES /*").next() {
- let replacement = format!("{} LIST \"/INBOX\" \"*\"\r\n", tag.trim());
- debug!("### {replacement}");
- return replacement.into_bytes();
+pub struct FindMailboxesCompatibility {
+ tags: Vec<String>,
+}
+
+impl FindMailboxesCompatibility {
+ pub fn new() -> Self {
+ FindMailboxesCompatibility { tags: vec![] }
+ }
+}
+
+impl Middleware for FindMailboxesCompatibility {
+ fn client_message(&mut self, input: &[u8]) -> Vec<u8> {
+ let command = String::from_utf8_lossy(input);
+ if command.contains("FIND MAILBOXES /*") {
+ if let Some(tag) = command.split("FIND MAILBOXES /*").next() {
+ // We'll need to convert the LIST to a FIND
+ self.tags.push(tag.trim().to_string());
+ let replacement = format!("{} LIST \"\" \"*\"\r\n", tag.trim());
+ return replacement.into_bytes();
+ }
+ }
+ input.to_vec()
+ }
+
+ fn server_message(&mut self, input: &[u8]) -> Vec<u8> {
+ let command = String::from_utf8_lossy(input);
+ let contains_ok_completed = self
+ .tags
+ .iter()
+ .any(|tag| command.contains(&format!("{tag} OK Completed")));
+
+ // We want to only modify responses that were a result of a MAILBOX call.
+ if !contains_ok_completed {
+ return input.to_vec();
+ }
+
+ let lines: Vec<String> = command
+ .lines()
+ .filter_map(|line| {
+ // The IMAPv3 spec specifically says INBOX is excluded from MAILBOX
+ if line.starts_with("* LIST") && line.trim_end().ends_with("\"/\" INBOX") {
+ return None;
+ }
+
+ // Transform IMAPv4 "* LIST" lines to IMAPv3 "* MAILBOX"
+ if line.starts_with("* LIST") {
+ if let Some(last_slash_pos) = line.rfind("\"/\"") {
+ let mailbox_name = line[(last_slash_pos + 3)..].replace('"', "");
+ return Some(format!("* MAILBOX {}\r", mailbox_name.trim()));
+ }
+ }
+
+ if line.contains("OK") {
+ if let Some(tag) = line.split("OK").next() {
+ return Some(format!("{} OK MAILBOX Completed.\r", tag.trim()).to_string());
+ }
+ }
+
+ Some(line.to_string())
+ })
+ .collect();
+
+ lines.join("\n").into_bytes()