3 /// `MailDrop` can't find folders to sync because it implements `IMAPv3` and
4 /// sends FIND MAILBOXES /*, which does not exist in `IMAPv4`.
5 /// which is not understood by modern servers. It instead replaces it with
7 pub struct FindMailboxesCompatibility {
11 impl FindMailboxesCompatibility {
12 pub fn new() -> Self {
13 FindMailboxesCompatibility { tags: vec![] }
17 impl Middleware for FindMailboxesCompatibility {
18 fn client_message(&mut self, input: &[u8]) -> Vec<u8> {
19 let command = String::from_utf8_lossy(input);
20 if command.contains("FIND MAILBOXES /*") {
21 if let Some(tag) = command.split("FIND MAILBOXES /*").next() {
22 // We'll need to convert the LIST to a FIND
23 self.tags.push(tag.trim().to_string());
24 let replacement = format!("{} LIST \"\" \"*\"\r\n", tag.trim());
25 return replacement.into_bytes();
31 fn server_message(&mut self, input: &[u8]) -> Vec<u8> {
32 let command = String::from_utf8_lossy(input);
33 let contains_ok_completed = self
36 .any(|tag| command.contains(&format!("{tag} OK Completed")));
38 // We want to only modify responses that were a result of a MAILBOX call.
39 if !contains_ok_completed {
40 return input.to_vec();
43 let lines: Vec<String> = command
46 // The IMAPv3 spec specifically says INBOX is excluded from MAILBOX
47 if line.starts_with("* LIST") && line.trim_end().ends_with("\"/\" INBOX") {
51 // Transform IMAPv4 "* LIST" lines to IMAPv3 "* MAILBOX"
52 if line.starts_with("* LIST") {
53 if let Some(last_slash_pos) = line.rfind("\"/\"") {
54 let mailbox_name = line[(last_slash_pos + 3)..].replace('"', "");
55 return Some(format!("* MAILBOX {}\r", mailbox_name.trim()));
59 if line.contains("OK") {
60 return Some("{tag} OK MAILBOX Completed.".to_string());
63 Some(line.to_string())
67 lines.join("\n").into_bytes()