5 /// `MailDrop` can't find folders to sync because it implements IMAPv3 and
6 /// sends FIND MAILBOXES /*, which does not exist in IMAPv4.
7 /// which is not understood by modern servers. It instead replaces it with
9 pub struct FindMailboxesCompatibility {
13 impl FindMailboxesCompatibility {
14 pub fn new() -> Self {
15 FindMailboxesCompatibility { tags: vec![] }
19 impl Middleware for FindMailboxesCompatibility {
20 fn client_message(&mut self, input: &[u8]) -> Vec<u8> {
21 let command = String::from_utf8_lossy(input);
22 if command.contains("FIND MAILBOXES /*") {
23 if let Some(tag) = command.split("FIND MAILBOXES /*").next() {
24 // We'll need to convert the LIST to a FIND
25 self.tags.push(tag.to_string());
26 let replacement = format!("{} LIST \"\" \"*\"\r\n", tag.trim());
27 debug!("### {replacement}");
28 return replacement.into_bytes();
34 fn server_message(&mut self, input: &[u8]) -> Vec<u8> {
35 let command = String::from_utf8_lossy(input);
36 let contains_ok_completed = self
39 .any(|tag| command.contains(&format!("{} OK Completed", tag)));
41 // We want to only modify responses that were a result of a MAILBOX call.
42 if !contains_ok_completed {
43 return input.to_vec();
46 let lines: Vec<String> = command
49 // The IMAPv3 spec specifically says INBOX is excluded from MAILBOX
50 if line.starts_with("* LIST") && line.trim_end().ends_with("\"/\" INBOX") {
54 // Transform IMAPv4 "* LIST" lines to IMAPv3 "* MAILBOX"
55 if line.starts_with("* LIST") {
56 if let Some(last_slash_pos) = line.rfind('/') {
57 let mailbox_name = line[(last_slash_pos + 1)..].trim();
58 return Some(format!("* MAILBOX {}\r", mailbox_name));
62 return Some(line.to_string());
66 return lines.join("\n").into_bytes();