Skip to main content

imap_client/
flags.rs

1//! IMAP message flags and `STORE` actions.
2
3use std::fmt;
4
5/// An IMAP message flag. The system flags render with their leading `\`;
6/// [`Flag::Custom`] renders verbatim. Use the [`Display`](fmt::Display) impl
7/// to produce wire form.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum Flag {
10    /// `\Seen` — the message has been read.
11    Seen,
12    /// `\Answered` — the message has been answered.
13    Answered,
14    /// `\Flagged` — the message is flagged for urgent/special attention.
15    Flagged,
16    /// `\Deleted` — the message is marked for deletion (removed on `EXPUNGE`).
17    Deleted,
18    /// `\Draft` — the message is a draft.
19    Draft,
20    /// `\Recent` — the message arrived recently (session-scoped, IMAP4rev1).
21    Recent,
22    /// A server- or client-defined keyword, rendered as-is.
23    Custom(String),
24}
25
26impl fmt::Display for Flag {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        match self {
29            Flag::Seen => write!(f, "\\Seen"),
30            Flag::Answered => write!(f, "\\Answered"),
31            Flag::Flagged => write!(f, "\\Flagged"),
32            Flag::Deleted => write!(f, "\\Deleted"),
33            Flag::Draft => write!(f, "\\Draft"),
34            Flag::Recent => write!(f, "\\Recent"),
35            Flag::Custom(s) => write!(f, "{}", s),
36        }
37    }
38}
39
40/// How a `STORE` / `UID STORE` command should modify a message's flags.
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum StoreAction {
43    /// Add the given flags to the existing set (`+FLAGS`).
44    Add,
45    /// Remove the given flags from the existing set (`-FLAGS`).
46    Remove,
47    /// Replace the existing set with the given flags (`FLAGS`).
48    Set,
49}
50
51impl StoreAction {
52    /// Return the IMAP item name for this action, e.g. `+FLAGS` or, when
53    /// `silent` is `true`, the `.SILENT` form that suppresses the untagged
54    /// `FETCH` response.
55    pub fn to_imap_prefix(&self, silent: bool) -> &str {
56        match self {
57            StoreAction::Add => {
58                if silent {
59                    "+FLAGS.SILENT"
60                } else {
61                    "+FLAGS"
62                }
63            }
64            StoreAction::Remove => {
65                if silent {
66                    "-FLAGS.SILENT"
67                } else {
68                    "-FLAGS"
69                }
70            }
71            StoreAction::Set => {
72                if silent {
73                    "FLAGS.SILENT"
74                } else {
75                    "FLAGS"
76                }
77            }
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_flag_display() {
88        assert_eq!(Flag::Seen.to_string(), "\\Seen");
89        assert_eq!(Flag::Answered.to_string(), "\\Answered");
90        assert_eq!(Flag::Flagged.to_string(), "\\Flagged");
91        assert_eq!(Flag::Deleted.to_string(), "\\Deleted");
92        assert_eq!(Flag::Draft.to_string(), "\\Draft");
93        assert_eq!(Flag::Recent.to_string(), "\\Recent");
94        assert_eq!(Flag::Custom("MyFlag".into()).to_string(), "MyFlag");
95    }
96
97    #[test]
98    fn test_store_action_prefix() {
99        assert_eq!(StoreAction::Add.to_imap_prefix(false), "+FLAGS");
100        assert_eq!(StoreAction::Add.to_imap_prefix(true), "+FLAGS.SILENT");
101        assert_eq!(StoreAction::Remove.to_imap_prefix(false), "-FLAGS");
102        assert_eq!(StoreAction::Remove.to_imap_prefix(true), "-FLAGS.SILENT");
103        assert_eq!(StoreAction::Set.to_imap_prefix(false), "FLAGS");
104        assert_eq!(StoreAction::Set.to_imap_prefix(true), "FLAGS.SILENT");
105    }
106}