sieve/compiler/grammar/tests/
test_mailbox.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
5 */
6
7
8
9use crate::{
10    compiler::{
11        grammar::{
12            instruction::{CompilerState, MapLocalVars},
13            Capability, Comparator,
14        },
15        lexer::{word::Word, Token},
16        CompileError, Value,
17    },
18    Metadata,
19};
20
21use crate::compiler::grammar::{test::Test, MatchType};
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24#[cfg_attr(
25    any(test, feature = "serde"),
26    derive(serde::Serialize, serde::Deserialize)
27)]
28#[cfg_attr(
29    feature = "rkyv",
30    derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
31)]
32pub(crate) struct TestMailboxExists {
33    pub mailbox_names: Vec<Value>,
34    pub is_not: bool,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38#[cfg_attr(
39    any(test, feature = "serde"),
40    derive(serde::Serialize, serde::Deserialize)
41)]
42#[cfg_attr(
43    feature = "rkyv",
44    derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
45)]
46pub(crate) struct TestMetadataExists {
47    pub mailbox: Option<Value>,
48    pub annotation_names: Vec<Value>,
49    pub is_not: bool,
50}
51
52/*
53
54metadata [MATCH-TYPE] [COMPARATOR]
55           <mailbox: string>
56           <annotation-name: string> <key-list: string-list>
57
58*/
59
60#[derive(Debug, Clone, PartialEq, Eq)]
61#[cfg_attr(
62    any(test, feature = "serde"),
63    derive(serde::Serialize, serde::Deserialize)
64)]
65#[cfg_attr(
66    feature = "rkyv",
67    derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
68)]
69pub(crate) struct TestMetadata {
70    pub match_type: MatchType,
71    pub comparator: Comparator,
72    pub medatata: Metadata<Value>,
73    pub key_list: Vec<Value>,
74    pub is_not: bool,
75}
76
77/*
78
79servermetadata [MATCH-TYPE] [COMPARATOR]
80           <annotation-name: string> <key-list: string-list>
81
82*/
83
84impl CompilerState<'_> {
85    pub(crate) fn parse_test_mailboxexists(&mut self) -> Result<Test, CompileError> {
86        Ok(Test::MailboxExists(TestMailboxExists {
87            mailbox_names: self.parse_strings(false)?,
88            is_not: false,
89        }))
90    }
91
92    pub(crate) fn parse_test_metadataexists(&mut self) -> Result<Test, CompileError> {
93        Ok(Test::MetadataExists(TestMetadataExists {
94            mailbox: self.parse_string()?.into(),
95            annotation_names: self.parse_strings(false)?,
96            is_not: false,
97        }))
98    }
99
100    pub(crate) fn parse_test_servermetadataexists(&mut self) -> Result<Test, CompileError> {
101        Ok(Test::MetadataExists(TestMetadataExists {
102            mailbox: None,
103            annotation_names: self.parse_strings(false)?,
104            is_not: false,
105        }))
106    }
107
108    pub(crate) fn parse_test_metadata(&mut self) -> Result<Test, CompileError> {
109        let mut match_type = MatchType::Is;
110        let mut comparator = Comparator::AsciiCaseMap;
111        let mut mailbox = None;
112        let mut annotation_name = None;
113        let mut key_list: Vec<Value>;
114
115        loop {
116            let token_info = self.tokens.unwrap_next()?;
117            match token_info.token {
118                Token::Tag(
119                    word @ (Word::Is
120                    | Word::Contains
121                    | Word::Matches
122                    | Word::Value
123                    | Word::Count
124                    | Word::Regex),
125                ) => {
126                    self.validate_argument(
127                        1,
128                        match word {
129                            Word::Value | Word::Count => Capability::Relational.into(),
130                            Word::Regex => Capability::Regex.into(),
131                            Word::List => Capability::ExtLists.into(),
132                            _ => None,
133                        },
134                        token_info.line_num,
135                        token_info.line_pos,
136                    )?;
137
138                    match_type = self.parse_match_type(word)?;
139                }
140                Token::Tag(Word::Comparator) => {
141                    self.validate_argument(2, None, token_info.line_num, token_info.line_pos)?;
142                    comparator = self.parse_comparator()?;
143                }
144                _ => {
145                    if mailbox.is_none() {
146                        mailbox = self.parse_string_token(token_info)?.into();
147                    } else if annotation_name.is_none() {
148                        annotation_name = self.parse_string_token(token_info)?.into();
149                    } else {
150                        key_list = self.parse_strings_token(token_info)?;
151                        break;
152                    }
153                }
154            }
155        }
156        self.validate_match(&match_type, &mut key_list)?;
157
158        Ok(Test::Metadata(TestMetadata {
159            match_type,
160            comparator,
161            medatata: Metadata::Mailbox {
162                name: mailbox.unwrap(),
163                annotation: annotation_name.unwrap(),
164            },
165            key_list,
166            is_not: false,
167        }))
168    }
169
170    pub(crate) fn parse_test_servermetadata(&mut self) -> Result<Test, CompileError> {
171        let mut match_type = MatchType::Is;
172        let mut comparator = Comparator::AsciiCaseMap;
173        let mut annotation_name = None;
174        let mut key_list: Vec<Value>;
175
176        loop {
177            let token_info = self.tokens.unwrap_next()?;
178            match token_info.token {
179                Token::Tag(
180                    word @ (Word::Is
181                    | Word::Contains
182                    | Word::Matches
183                    | Word::Value
184                    | Word::Count
185                    | Word::Regex),
186                ) => {
187                    self.validate_argument(
188                        1,
189                        match word {
190                            Word::Value | Word::Count => Capability::Relational.into(),
191                            Word::Regex => Capability::Regex.into(),
192                            Word::List => Capability::ExtLists.into(),
193                            _ => None,
194                        },
195                        token_info.line_num,
196                        token_info.line_pos,
197                    )?;
198
199                    match_type = self.parse_match_type(word)?;
200                }
201                Token::Tag(Word::Comparator) => {
202                    self.validate_argument(2, None, token_info.line_num, token_info.line_pos)?;
203                    comparator = self.parse_comparator()?;
204                }
205                _ => {
206                    if annotation_name.is_none() {
207                        annotation_name = self.parse_string_token(token_info)?.into();
208                    } else {
209                        key_list = self.parse_strings_token(token_info)?;
210                        break;
211                    }
212                }
213            }
214        }
215        self.validate_match(&match_type, &mut key_list)?;
216
217        Ok(Test::Metadata(TestMetadata {
218            match_type,
219            comparator,
220            medatata: Metadata::Server {
221                annotation: annotation_name.unwrap(),
222            },
223            key_list,
224            is_not: false,
225        }))
226    }
227}
228
229impl MapLocalVars for Metadata<Value> {
230    fn map_local_vars(&mut self, last_id: usize) {
231        match self {
232            Metadata::Mailbox { name, annotation } => {
233                name.map_local_vars(last_id);
234                annotation.map_local_vars(last_id);
235            }
236            Metadata::Server { annotation } => {
237                annotation.map_local_vars(last_id);
238            }
239        }
240    }
241}