]> git.r.bdr.sh - rbdr/olden-mail/blob - src/middleware/find_mailboxes_compatibility.rs
af03f7983bf2f05f36eb7edee3548f2bf901e90a
[rbdr/olden-mail] / src / middleware / find_mailboxes_compatibility.rs
1 use super::Middleware;
2
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
6 /// a LIST command.
7 pub struct FindMailboxesCompatibility {
8 tags: Vec<String>,
9 }
10
11 impl FindMailboxesCompatibility {
12 pub fn new() -> Self {
13 FindMailboxesCompatibility { tags: vec![] }
14 }
15 }
16
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();
26 }
27 }
28 input.to_vec()
29 }
30
31 fn server_message(&mut self, input: &[u8]) -> Vec<u8> {
32 let command = String::from_utf8_lossy(input);
33 let contains_ok_completed = self
34 .tags
35 .iter()
36 .any(|tag| command.contains(&format!("{tag} OK Completed")));
37
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();
41 }
42
43 let lines: Vec<String> = command
44 .lines()
45 .filter_map(|line| {
46 // The IMAPv3 spec specifically says INBOX is excluded from MAILBOX
47 if line.starts_with("* LIST") && line.trim_end().ends_with("\"/\" INBOX") {
48 return None;
49 }
50
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 + 1)..].replace('"', "");
55 return Some(format!("* MAILBOX {}\r", mailbox_name.trim()));
56 }
57 }
58
59 Some(line.to_string())
60 })
61 .collect();
62
63 lines.join("\n").into_bytes()
64 }
65 }