1// Copyright (c) 2017 Maxime “pep” Buquet <pep@bouah.net>
2// Copyright (c) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8use crate::date::DateTime;
9use crate::presence::PresencePayload;
10
11generate_element!(
12 /// Represents the query for messages before our join.
13 #[derive(Default)]
14 History, "history", MUC,
15 attributes: [
16 /// How many characters of history to send, in XML characters.
17 maxchars: Option<u32> = "maxchars",
18
19 /// How many messages to send.
20 maxstanzas: Option<u32> = "maxstanzas",
21
22 /// Only send messages received in these last seconds.
23 seconds: Option<u32> = "seconds",
24
25 /// Only send messages after this date.
26 since: Option<DateTime> = "since",
27 ]
28);
29
30impl History {
31 /// Create a new empty history element.
32 pub fn new() -> Self {
33 History::default()
34 }
35
36 /// Set how many characters of history to send.
37 pub fn with_maxchars(mut self, maxchars: u32) -> Self {
38 self.maxchars = Some(maxchars);
39 self
40 }
41
42 /// Set how many messages to send.
43 pub fn with_maxstanzas(mut self, maxstanzas: u32) -> Self {
44 self.maxstanzas = Some(maxstanzas);
45 self
46 }
47
48 /// Only send messages received in these last seconds.
49 pub fn with_seconds(mut self, seconds: u32) -> Self {
50 self.seconds = Some(seconds);
51 self
52 }
53
54 /// Only send messages received since this date.
55 pub fn with_since(mut self, since: DateTime) -> Self {
56 self.since = Some(since);
57 self
58 }
59}
60
61generate_element!(
62 /// Represents a room join request.
63 #[derive(Default)]
64 Muc, "x", MUC, children: [
65 /// Password to use when the room is protected by a password.
66 password: Option<String> = ("password", MUC) => String,
67
68 /// Controls how much and how old we want to receive history on join.
69 history: Option<History> = ("history", MUC) => History
70 ]
71);
72
73impl PresencePayload for Muc {}
74
75impl Muc {
76 /// Create a new MUC join element.
77 pub fn new() -> Self {
78 Muc::default()
79 }
80
81 /// Join a room with this password.
82 pub fn with_password(mut self, password: String) -> Self {
83 self.password = Some(password);
84 self
85 }
86
87 /// Join a room with only that much history.
88 pub fn with_history(mut self, history: History) -> Self {
89 self.history = Some(history);
90 self
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use crate::util::error::Error;
98 use crate::Element;
99 use std::convert::TryFrom;
100 use std::str::FromStr;
101
102 #[test]
103 fn test_muc_simple() {
104 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'/>"
105 .parse()
106 .unwrap();
107 Muc::try_from(elem).unwrap();
108 }
109
110 #[test]
111 fn test_muc_invalid_child() {
112 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'><coucou/></x>"
113 .parse()
114 .unwrap();
115 let error = Muc::try_from(elem).unwrap_err();
116 let message = match error {
117 Error::ParseError(string) => string,
118 _ => panic!(),
119 };
120 assert_eq!(message, "Unknown child in x element.");
121 }
122
123 #[test]
124 fn test_muc_serialise() {
125 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'/>"
126 .parse()
127 .unwrap();
128 let muc = Muc {
129 password: None,
130 history: None,
131 };
132 let elem2 = muc.into();
133 assert_eq!(elem, elem2);
134 }
135
136 #[cfg(not(feature = "disable-validation"))]
137 #[test]
138 fn test_muc_invalid_attribute() {
139 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc' coucou=''/>"
140 .parse()
141 .unwrap();
142 let error = Muc::try_from(elem).unwrap_err();
143 let message = match error {
144 Error::ParseError(string) => string,
145 _ => panic!(),
146 };
147 assert_eq!(message, "Unknown attribute in x element.");
148 }
149
150 #[test]
151 fn test_muc_simple_password() {
152 let elem: Element =
153 "<x xmlns='http://jabber.org/protocol/muc'><password>coucou</password></x>"
154 .parse()
155 .unwrap();
156 let elem1 = elem.clone();
157 let muc = Muc::try_from(elem).unwrap();
158 assert_eq!(muc.password, Some("coucou".to_owned()));
159
160 let elem2 = Element::from(muc);
161 assert_eq!(elem1, elem2);
162 }
163
164 #[test]
165 fn history() {
166 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'>
167 <history maxstanzas='0'/>
168 </x>"
169 .parse()
170 .unwrap();
171 let muc = Muc::try_from(elem).unwrap();
172 let muc2 = Muc::new().with_history(History::new().with_maxstanzas(0));
173 assert_eq!(muc, muc2);
174
175 let history = muc.history.unwrap();
176 assert_eq!(history.maxstanzas, Some(0));
177 assert_eq!(history.maxchars, None);
178 assert_eq!(history.seconds, None);
179 assert_eq!(history.since, None);
180
181 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'>
182 <history since='1970-01-01T00:00:00Z'/>
183 </x>"
184 .parse()
185 .unwrap();
186 let muc = Muc::try_from(elem).unwrap();
187 assert_eq!(
188 muc.history.unwrap().since.unwrap(),
189 DateTime::from_str("1970-01-01T00:00:00+00:00").unwrap()
190 );
191 }
192}