1// Copyright (c) 2018 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::stanza_error::DefinedCondition;
8
9generate_element!(
10 /// Acknowledgement of the currently received stanzas.
11 A, "a", SM,
12 attributes: [
13 /// The last handled stanza.
14 h: u32 = "h" => required,
15 ]
16);
17
18impl A {
19 /// Generates a new `<a/>` element.
20 pub fn new(h: u32) -> A {
21 A { h }
22 }
23}
24
25generate_attribute!(
26 /// Whether to allow resumption of a previous stream.
27 ResumeAttr,
28 "resume",
29 bool
30);
31
32generate_element!(
33 /// Client request for enabling stream management.
34 Enable, "enable", SM,
35 attributes: [
36 /// The preferred resumption time in seconds by the client.
37 // TODO: should be the infinite integer set ≥ 1.
38 max: Option<u32> = "max" => optional,
39
40 /// Whether the client wants to be allowed to resume the stream.
41 resume: ResumeAttr = "resume" => default,
42 ]
43);
44
45impl Enable {
46 /// Generates a new `<enable/>` element.
47 pub fn new() -> Self {
48 Enable {
49 max: None,
50 resume: ResumeAttr::False,
51 }
52 }
53
54 /// Sets the preferred resumption time in seconds.
55 pub fn with_max(mut self, max: u32) -> Self {
56 self.max = Some(max);
57 self
58 }
59
60 /// Asks for resumption to be possible.
61 pub fn with_resume(mut self) -> Self {
62 self.resume = ResumeAttr::True;
63 self
64 }
65}
66
67generate_id!(
68 /// A random identifier used for stream resumption.
69 StreamId
70);
71
72generate_element!(
73 /// Server response once stream management is enabled.
74 Enabled, "enabled", SM,
75 attributes: [
76 /// A random identifier used for stream resumption.
77 id: Option<StreamId> = "id" => optional,
78
79 /// The preferred IP, domain, IP:port or domain:port location for
80 /// resumption.
81 location: Option<String> = "location" => optional,
82
83 /// The preferred resumption time in seconds by the server.
84 // TODO: should be the infinite integer set ≥ 1.
85 max: Option<u32> = "max" => optional,
86
87 /// Whether stream resumption is allowed.
88 resume: ResumeAttr = "resume" => default,
89 ]
90);
91
92generate_element!(
93 /// A stream management error happened.
94 Failed, "failed", SM,
95 attributes: [
96 /// The last handled stanza.
97 h: Option<u32> = "h" => optional,
98 ],
99 children: [
100 /// The error returned.
101 // XXX: implement the * handling.
102 error: Option<DefinedCondition> = ("*", XMPP_STANZAS) => DefinedCondition
103 ]
104);
105
106generate_empty_element!(
107 /// Requests the currently received stanzas by the other party.
108 R,
109 "r",
110 SM
111);
112
113generate_element!(
114 /// Requests a stream resumption.
115 Resume, "resume", SM,
116 attributes: [
117 /// The last handled stanza.
118 h: u32 = "h" => required,
119
120 /// The previous id given by the server on
121 /// [enabled](struct.Enabled.html).
122 previd: StreamId = "previd" => required,
123 ]
124);
125
126generate_element!(
127 /// The response by the server for a successfully resumed stream.
128 Resumed, "resumed", SM,
129 attributes: [
130 /// The last handled stanza.
131 h: u32 = "h" => required,
132
133 /// The previous id given by the server on
134 /// [enabled](struct.Enabled.html).
135 previd: StreamId = "previd" => required,
136 ]
137);
138
139// TODO: add support for optional and required.
140generate_empty_element!(
141 /// Represents availability of Stream Management in `<stream:features/>`.
142 StreamManagement,
143 "sm",
144 SM
145);
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use minidom::Element;
151 use try_from::TryFrom;
152
153 #[cfg(target_pointer_width = "32")]
154 #[test]
155 fn test_size() {
156 assert_size!(A, 4);
157 assert_size!(ResumeAttr, 1);
158 assert_size!(Enable, 12);
159 assert_size!(StreamId, 12);
160 assert_size!(Enabled, 36);
161 assert_size!(Failed, 12);
162 assert_size!(R, 0);
163 assert_size!(Resume, 16);
164 assert_size!(Resumed, 16);
165 assert_size!(StreamManagement, 0);
166 }
167
168 #[cfg(target_pointer_width = "64")]
169 #[test]
170 fn test_size() {
171 assert_size!(A, 4);
172 assert_size!(ResumeAttr, 1);
173 assert_size!(Enable, 12);
174 assert_size!(StreamId, 24);
175 assert_size!(Enabled, 64);
176 assert_size!(Failed, 12);
177 assert_size!(R, 0);
178 assert_size!(Resume, 32);
179 assert_size!(Resumed, 32);
180 assert_size!(StreamManagement, 0);
181 }
182
183 #[test]
184 fn a() {
185 let elem: Element = "<a xmlns='urn:xmpp:sm:3' h='5'".parse().unwrap();
186 let a = A::try_from(elem).unwrap();
187 assert_eq!(a.h, 5);
188 }
189
190 #[test]
191 fn stream_feature() {
192 let elem: Element = "<sm xmlns='urn:xmpp:sm:3'/>".parse().unwrap();
193 StreamManagement::try_from(elem).unwrap();
194 }
195
196 #[test]
197 fn resume() {
198 let elem: Element = "<enable xmlns='urn:xmpp:sm:3' resume='true'/>"
199 .parse()
200 .unwrap();
201 let enable = Enable::try_from(elem).unwrap();
202 assert_eq!(enable.max, None);
203 assert_eq!(enable.resume, ResumeAttr::True);
204
205 let elem: Element = "<enabled xmlns='urn:xmpp:sm:3' resume='true' id='coucou' max='600'/>"
206 .parse()
207 .unwrap();
208 let enabled = Enabled::try_from(elem).unwrap();
209 let previd = enabled.id.unwrap();
210 assert_eq!(enabled.resume, ResumeAttr::True);
211 assert_eq!(previd, StreamId(String::from("coucou")));
212 assert_eq!(enabled.max, Some(600));
213 assert_eq!(enabled.location, None);
214
215 let elem: Element = "<resume xmlns='urn:xmpp:sm:3' h='5' previd='coucou'/>"
216 .parse()
217 .unwrap();
218 let resume = Resume::try_from(elem).unwrap();
219 assert_eq!(resume.h, 5);
220 assert_eq!(resume.previd, previd);
221
222 let elem: Element = "<resumed xmlns='urn:xmpp:sm:3' h='5' previd='coucou'/>"
223 .parse()
224 .unwrap();
225 let resumed = Resumed::try_from(elem).unwrap();
226 assert_eq!(resumed.h, 5);
227 assert_eq!(resumed.previd, previd);
228 }
229}