imap_proto/parser/
rfc4314.rs

1//!
2//! Current
3//! https://tools.ietf.org/html/rfc4314
4//!
5//! Original
6//! https://tools.ietf.org/html/rfc2086
7//!
8//! The IMAP ACL Extension
9//!
10
11use std::borrow::Cow;
12
13use nom::{
14    bytes::streaming::tag_no_case,
15    character::complete::{space0, space1},
16    combinator::map,
17    multi::separated_list0,
18    sequence::{preceded, separated_pair, tuple},
19    IResult,
20};
21
22use crate::parser::core::astring_utf8;
23use crate::parser::rfc3501::mailbox;
24use crate::types::*;
25
26/// 3.6. ACL Response
27/// ```ignore
28/// acl_response  ::= "ACL" SP mailbox SP acl_list
29/// ```
30pub(crate) fn acl(i: &[u8]) -> IResult<&[u8], Response> {
31    let (rest, (_, _, mailbox, acls)) = tuple((
32        tag_no_case("ACL"),
33        space1,
34        map(mailbox, Cow::Borrowed),
35        acl_list,
36    ))(i)?;
37
38    Ok((rest, Response::Acl(Acl { mailbox, acls })))
39}
40
41/// ```ignore
42/// acl_list  ::= *(SP acl_entry)
43/// ```
44fn acl_list(i: &[u8]) -> IResult<&[u8], Vec<AclEntry>> {
45    preceded(space0, separated_list0(space1, acl_entry))(i)
46}
47
48/// ```ignore
49/// acl_entry ::= SP identifier SP rights
50/// ```
51fn acl_entry(i: &[u8]) -> IResult<&[u8], AclEntry> {
52    let (rest, (identifier, rights)) = separated_pair(
53        map(astring_utf8, Cow::Borrowed),
54        space1,
55        map(astring_utf8, map_text_to_rights),
56    )(i)?;
57
58    Ok((rest, AclEntry { identifier, rights }))
59}
60
61/// 3.7. LISTRIGHTS Response
62/// ```ignore
63/// list_rights_response  ::= "LISTRIGHTS" SP mailbox SP identifier SP required_rights *(SP optional_rights)
64/// ```
65pub(crate) fn list_rights(i: &[u8]) -> IResult<&[u8], Response> {
66    let (rest, (_, _, mailbox, _, identifier, _, required, optional)) = tuple((
67        tag_no_case("LISTRIGHTS"),
68        space1,
69        map(mailbox, Cow::Borrowed),
70        space1,
71        map(astring_utf8, Cow::Borrowed),
72        space1,
73        map(astring_utf8, map_text_to_rights),
74        list_rights_optional,
75    ))(i)?;
76
77    Ok((
78        rest,
79        Response::ListRights(ListRights {
80            mailbox,
81            identifier,
82            required,
83            optional,
84        }),
85    ))
86}
87
88fn list_rights_optional(i: &[u8]) -> IResult<&[u8], Vec<AclRight>> {
89    let (rest, items) = preceded(space0, separated_list0(space1, astring_utf8))(i)?;
90
91    Ok((
92        rest,
93        items
94            .into_iter()
95            .flat_map(|s| s.chars().map(|c| c.into()))
96            .collect(),
97    ))
98}
99
100/// 3.7. MYRIGHTS Response
101/// ```ignore
102/// my_rights_response  ::= "MYRIGHTS" SP mailbox SP rights
103/// ```
104pub(crate) fn my_rights(i: &[u8]) -> IResult<&[u8], Response> {
105    let (rest, (_, _, mailbox, _, rights)) = tuple((
106        tag_no_case("MYRIGHTS"),
107        space1,
108        map(mailbox, Cow::Borrowed),
109        space1,
110        map(astring_utf8, map_text_to_rights),
111    ))(i)?;
112
113    Ok((rest, Response::MyRights(MyRights { mailbox, rights })))
114}
115
116/// helper routine to map a string to a vec of AclRights
117fn map_text_to_rights(i: &str) -> Vec<AclRight> {
118    i.chars().map(|c| c.into()).collect()
119}