1// Copyright (c) 2017-2021 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7use crate::data_forms::DataForm;
8use crate::forwarding::Forwarded;
9use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
10use crate::message::MessagePayload;
11use crate::pubsub::NodeName;
12use crate::rsm::{SetQuery, SetResult};
13
14generate_id!(
15 /// An identifier matching a result message to the query requesting it.
16 QueryId
17);
18
19generate_element!(
20 /// Starts a query to the archive.
21 Query, "query", MAM,
22 attributes: [
23 /// An optional identifier for matching forwarded messages to this
24 /// query.
25 queryid: Option<QueryId> = "queryid",
26
27 /// Must be set to Some when querying a PubSub node’s archive.
28 node: Option<NodeName> = "node"
29 ],
30 children: [
31 /// Used for filtering the results.
32 form: Option<DataForm> = ("x", DATA_FORMS) => DataForm,
33
34 /// Used for paging through results.
35 set: Option<SetQuery> = ("set", RSM) => SetQuery
36 ]
37);
38
39impl IqGetPayload for Query {}
40impl IqSetPayload for Query {}
41impl IqResultPayload for Query {}
42
43generate_element!(
44 /// The wrapper around forwarded stanzas.
45 Result_, "result", MAM,
46 attributes: [
47 /// The stanza-id under which the archive stored this stanza.
48 id: Required<String> = "id",
49
50 /// The same queryid as the one requested in the
51 /// [query](struct.Query.html).
52 queryid: Option<QueryId> = "queryid",
53 ],
54 children: [
55 /// The actual stanza being forwarded.
56 forwarded: Required<Forwarded> = ("forwarded", FORWARD) => Forwarded
57 ]
58);
59
60impl MessagePayload for Result_ {}
61
62generate_attribute!(
63 /// True when the end of a MAM query has been reached.
64 Complete,
65 "complete",
66 bool
67);
68
69generate_element!(
70 /// Notes the end of a page in a query.
71 Fin, "fin", MAM,
72 attributes: [
73 /// True when the end of a MAM query has been reached.
74 complete: Default<Complete> = "complete",
75 ],
76 children: [
77 /// Describes the current page, it should contain at least [first]
78 /// (with an [index]) and [last], and generally [count].
79 ///
80 /// [first]: ../rsm/struct.SetResult.html#structfield.first
81 /// [index]: ../rsm/struct.SetResult.html#structfield.first_index
82 /// [last]: ../rsm/struct.SetResult.html#structfield.last
83 /// [count]: ../rsm/struct.SetResult.html#structfield.count
84 set: Required<SetResult> = ("set", RSM) => SetResult
85 ]
86);
87
88impl IqResultPayload for Fin {}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use crate::util::error::Error;
94 use minidom::Element;
95 use std::convert::TryFrom;
96
97 #[cfg(target_pointer_width = "32")]
98 #[test]
99 fn test_size() {
100 assert_size!(QueryId, 12);
101 assert_size!(Query, 116);
102 assert_size!(Result_, 236);
103 assert_size!(Complete, 1);
104 assert_size!(Fin, 44);
105 }
106
107 #[cfg(target_pointer_width = "64")]
108 #[test]
109 fn test_size() {
110 assert_size!(QueryId, 24);
111 assert_size!(Query, 232);
112 assert_size!(Result_, 456);
113 assert_size!(Complete, 1);
114 assert_size!(Fin, 88);
115 }
116
117 #[test]
118 fn test_query() {
119 let elem: Element = "<query xmlns='urn:xmpp:mam:2'/>".parse().unwrap();
120 Query::try_from(elem).unwrap();
121 }
122
123 #[test]
124 fn test_result() {
125 #[cfg(not(feature = "component"))]
126 let elem: Element = r#"<result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
127 <forwarded xmlns='urn:xmpp:forward:0'>
128 <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
129 <message xmlns='jabber:client' from="witch@shakespeare.lit" to="macbeth@shakespeare.lit">
130 <body>Hail to thee</body>
131 </message>
132 </forwarded>
133</result>
134"#
135 .parse()
136 .unwrap();
137 #[cfg(feature = "component")]
138 let elem: Element = r#"<result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
139 <forwarded xmlns='urn:xmpp:forward:0'>
140 <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
141 <message xmlns='jabber:component:accept' from="witch@shakespeare.lit" to="macbeth@shakespeare.lit">
142 <body>Hail to thee</body>
143 </message>
144 </forwarded>
145</result>
146"#.parse().unwrap();
147 Result_::try_from(elem).unwrap();
148 }
149
150 #[test]
151 fn test_fin() {
152 let elem: Element = r#"<fin xmlns='urn:xmpp:mam:2'>
153 <set xmlns='http://jabber.org/protocol/rsm'>
154 <first index='0'>28482-98726-73623</first>
155 <last>09af3-cc343-b409f</last>
156 </set>
157</fin>
158"#
159 .parse()
160 .unwrap();
161 Fin::try_from(elem).unwrap();
162 }
163
164 #[test]
165 fn test_query_x() {
166 let elem: Element = r#"<query xmlns='urn:xmpp:mam:2'>
167 <x xmlns='jabber:x:data' type='submit'>
168 <field var='FORM_TYPE' type='hidden'>
169 <value>urn:xmpp:mam:2</value>
170 </field>
171 <field var='with'>
172 <value>juliet@capulet.lit</value>
173 </field>
174 </x>
175</query>
176"#
177 .parse()
178 .unwrap();
179 Query::try_from(elem).unwrap();
180 }
181
182 #[test]
183 fn test_query_x_set() {
184 let elem: Element = r#"<query xmlns='urn:xmpp:mam:2'>
185 <x xmlns='jabber:x:data' type='submit'>
186 <field var='FORM_TYPE' type='hidden'>
187 <value>urn:xmpp:mam:2</value>
188 </field>
189 <field var='start'>
190 <value>2010-08-07T00:00:00Z</value>
191 </field>
192 </x>
193 <set xmlns='http://jabber.org/protocol/rsm'>
194 <max>10</max>
195 </set>
196</query>
197"#
198 .parse()
199 .unwrap();
200 Query::try_from(elem).unwrap();
201 }
202
203 #[test]
204 fn test_invalid_child() {
205 let elem: Element = "<query xmlns='urn:xmpp:mam:2'><coucou/></query>"
206 .parse()
207 .unwrap();
208 let error = Query::try_from(elem).unwrap_err();
209 let message = match error {
210 Error::ParseError(string) => string,
211 _ => panic!(),
212 };
213 assert_eq!(message, "Unknown child in query element.");
214 }
215
216 #[test]
217 fn test_serialise_empty() {
218 let elem: Element = "<query xmlns='urn:xmpp:mam:2'/>".parse().unwrap();
219 let replace = Query {
220 queryid: None,
221 node: None,
222 form: None,
223 set: None,
224 };
225 let elem2 = replace.into();
226 assert_eq!(elem, elem2);
227 }
228
229 #[test]
230 fn test_serialize_query_with_form() {
231 let reference: Element = "<query xmlns='urn:xmpp:mam:2'><x xmlns='jabber:x:data' type='submit'><field xmlns='jabber:x:data' var='FORM_TYPE' type='hidden'><value xmlns='jabber:x:data'>urn:xmpp:mam:2</value></field><field xmlns='jabber:x:data' var='with'><value xmlns='jabber:x:data'>juliet@capulet.lit</value></field></x></query>"
232 .parse()
233 .unwrap();
234
235 let elem: Element = "<x xmlns='jabber:x:data' type='submit'><field xmlns='jabber:x:data' var='FORM_TYPE' type='hidden'><value xmlns='jabber:x:data'>urn:xmpp:mam:2</value></field><field xmlns='jabber:x:data' var='with'><value xmlns='jabber:x:data'>juliet@capulet.lit</value></field></x>"
236 .parse()
237 .unwrap();
238
239 let form = DataForm::try_from(elem).unwrap();
240
241 let query = Query {
242 queryid: None,
243 node: None,
244 set: None,
245 form: Some(form),
246 };
247 let serialized: Element = query.into();
248 assert_eq!(serialized, reference);
249 }
250
251 #[test]
252 fn test_serialize_result() {
253 let reference: Element = "<result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'><forwarded xmlns='urn:xmpp:forward:0'><delay xmlns='urn:xmpp:delay' stamp='2002-09-10T23:08:25+00:00'/><message xmlns='jabber:client' to='juliet@capulet.example/balcony' from='romeo@montague.example/home'/></forwarded></result>"
254 .parse()
255 .unwrap();
256
257 let elem: Element = "<forwarded xmlns='urn:xmpp:forward:0'><delay xmlns='urn:xmpp:delay' stamp='2002-09-10T23:08:25+00:00'/><message xmlns='jabber:client' to='juliet@capulet.example/balcony' from='romeo@montague.example/home'/></forwarded>"
258 .parse()
259 .unwrap();
260
261 let forwarded = Forwarded::try_from(elem).unwrap();
262
263 let result = Result_ {
264 id: String::from("28482-98726-73623"),
265 queryid: Some(QueryId(String::from("f27"))),
266 forwarded: forwarded,
267 };
268 let serialized: Element = result.into();
269 assert_eq!(serialized, reference);
270 }
271
272 #[test]
273 fn test_serialize_fin() {
274 let reference: Element = "<fin xmlns='urn:xmpp:mam:2'><set xmlns='http://jabber.org/protocol/rsm'><first index='0'>28482-98726-73623</first><last>09af3-cc343-b409f</last></set></fin>"
275 .parse()
276 .unwrap();
277
278 let elem: Element = "<set xmlns='http://jabber.org/protocol/rsm'><first index='0'>28482-98726-73623</first><last>09af3-cc343-b409f</last></set>"
279 .parse()
280 .unwrap();
281
282 let set = SetResult::try_from(elem).unwrap();
283
284 let fin = Fin {
285 set: set,
286 complete: Complete::default(),
287 };
288 let serialized: Element = fin.into();
289 assert_eq!(serialized, reference);
290 }
291}