1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
use super::to_owned_cow;

use std::borrow::Cow;

// IMAP4 ACL Extension 4313/2086

#[derive(Debug, Eq, PartialEq)]
pub struct Acl<'a> {
    pub mailbox: Cow<'a, str>,
    pub acls: Vec<AclEntry<'a>>,
}

impl<'a> Acl<'a> {
    pub fn into_owned(self) -> Acl<'static> {
        Acl {
            mailbox: to_owned_cow(self.mailbox),
            acls: self.acls.into_iter().map(AclEntry::into_owned).collect(),
        }
    }
}

#[derive(Debug, Eq, PartialEq)]
pub struct AclEntry<'a> {
    pub identifier: Cow<'a, str>,
    pub rights: Vec<AclRight>,
}

impl<'a> AclEntry<'a> {
    pub fn into_owned(self) -> AclEntry<'static> {
        AclEntry {
            identifier: to_owned_cow(self.identifier),
            rights: self.rights,
        }
    }
}

#[derive(Debug, Eq, PartialEq)]
pub struct ListRights<'a> {
    pub mailbox: Cow<'a, str>,
    pub identifier: Cow<'a, str>,
    pub required: Vec<AclRight>,
    pub optional: Vec<AclRight>,
}

impl<'a> ListRights<'a> {
    pub fn into_owned(self) -> ListRights<'static> {
        ListRights {
            mailbox: to_owned_cow(self.mailbox),
            identifier: to_owned_cow(self.identifier),
            required: self.required,
            optional: self.optional,
        }
    }
}

#[derive(Debug, Eq, PartialEq)]
pub struct MyRights<'a> {
    pub mailbox: Cow<'a, str>,
    pub rights: Vec<AclRight>,
}

impl<'a> MyRights<'a> {
    pub fn into_owned(self) -> MyRights<'static> {
        MyRights {
            mailbox: to_owned_cow(self.mailbox),
            rights: self.rights,
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum AclRight {
    /// l - lookup (mailbox is visible to LIST/LSUB commands, SUBSCRIBE
    /// mailbox)
    Lookup,
    /// r - read (SELECT the mailbox, perform STATUS)
    Read,
    /// s - keep seen/unseen information across sessions (set or clear
    /// \SEEN flag via STORE, also set \SEEN during APPEND/COPY/
    /// FETCH BODY[...])
    Seen,
    /// w - write (set or clear flags other than \SEEN and \DELETED via
    /// STORE, also set them during APPEND/COPY)
    Write,
    /// i - insert (perform APPEND, COPY into mailbox)
    Insert,
    /// p - post (send mail to submission address for mailbox,
    /// not enforced by IMAP4 itself)
    Post,
    /// k - create mailboxes (CREATE new sub-mailboxes in any
    /// implementation-defined hierarchy, parent mailbox for the new
    /// mailbox name in RENAME)
    CreateMailbox,
    /// x - delete mailbox (DELETE mailbox, old mailbox name in RENAME)
    DeleteMailbox,
    /// t - delete messages (set or clear \DELETED flag via STORE, set
    /// \DELETED flag during APPEND/COPY)
    DeleteMessage,
    /// e - perform EXPUNGE and expunge as a part of CLOSE
    Expunge,
    /// a - administer (perform SETACL/DELETEACL/GETACL/LISTRIGHTS)
    Administer,
    /// n - ability to write .shared annotations values
    /// From RFC 5257
    Annotation,
    /// c - old (deprecated) create. Do not use. Read RFC 4314 for more information.
    OldCreate,
    /// d - old (deprecated) delete. Do not use. Read RFC 4314 for more information.
    OldDelete,
    /// A custom right
    Custom(char),
}

impl From<char> for AclRight {
    fn from(c: char) -> Self {
        match c {
            'l' => AclRight::Lookup,
            'r' => AclRight::Read,
            's' => AclRight::Seen,
            'w' => AclRight::Write,
            'i' => AclRight::Insert,
            'p' => AclRight::Post,
            'k' => AclRight::CreateMailbox,
            'x' => AclRight::DeleteMailbox,
            't' => AclRight::DeleteMessage,
            'e' => AclRight::Expunge,
            'a' => AclRight::Administer,
            'n' => AclRight::Annotation,
            'c' => AclRight::OldCreate,
            'd' => AclRight::OldDelete,
            _ => AclRight::Custom(c),
        }
    }
}

impl From<AclRight> for char {
    fn from(right: AclRight) -> Self {
        match right {
            AclRight::Lookup => 'l',
            AclRight::Read => 'r',
            AclRight::Seen => 's',
            AclRight::Write => 'w',
            AclRight::Insert => 'i',
            AclRight::Post => 'p',
            AclRight::CreateMailbox => 'k',
            AclRight::DeleteMailbox => 'x',
            AclRight::DeleteMessage => 't',
            AclRight::Expunge => 'e',
            AclRight::Administer => 'a',
            AclRight::Annotation => 'n',
            AclRight::OldCreate => 'c',
            AclRight::OldDelete => 'd',
            AclRight::Custom(c) => c,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_char_to_acl_right() {
        assert_eq!(Into::<AclRight>::into('l'), AclRight::Lookup);
        assert_eq!(Into::<AclRight>::into('c'), AclRight::OldCreate);
        assert_eq!(Into::<AclRight>::into('k'), AclRight::CreateMailbox);
        assert_eq!(Into::<AclRight>::into('0'), AclRight::Custom('0'));
    }

    #[test]
    fn test_acl_right_to_char() {
        assert_eq!(Into::<char>::into(AclRight::Lookup), 'l');
        assert_eq!(Into::<char>::into(AclRight::OldCreate), 'c');
        assert_eq!(Into::<char>::into(AclRight::CreateMailbox), 'k');
        assert_eq!(Into::<char>::into(AclRight::Custom('0')), '0');
    }
}