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(PartialEq, 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(PartialEq, 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::compare_elements::NamespaceAwareCompare;
98 use crate::util::error::Error;
99 use minidom::Element;
100 use std::str::FromStr;
101 use std::convert::TryFrom;
102
103 #[test]
104 fn test_muc_simple() {
105 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'/>"
106 .parse()
107 .unwrap();
108 Muc::try_from(elem).unwrap();
109 }
110
111 #[test]
112 fn test_muc_invalid_child() {
113 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'><coucou/></x>"
114 .parse()
115 .unwrap();
116 let error = Muc::try_from(elem).unwrap_err();
117 let message = match error {
118 Error::ParseError(string) => string,
119 _ => panic!(),
120 };
121 assert_eq!(message, "Unknown child in x element.");
122 }
123
124 #[test]
125 fn test_muc_serialise() {
126 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc'/>"
127 .parse()
128 .unwrap();
129 let muc = Muc {
130 password: None,
131 history: None,
132 };
133 let elem2 = muc.into();
134 assert_eq!(elem, elem2);
135 }
136
137 #[cfg(not(feature = "disable-validation"))]
138 #[test]
139 fn test_muc_invalid_attribute() {
140 let elem: Element = "<x xmlns='http://jabber.org/protocol/muc' coucou=''/>"
141 .parse()
142 .unwrap();
143 let error = Muc::try_from(elem).unwrap_err();
144 let message = match error {
145 Error::ParseError(string) => string,
146 _ => panic!(),
147 };
148 assert_eq!(message, "Unknown attribute in x element.");
149 }
150
151 #[test]
152 fn test_muc_simple_password() {
153 let elem: Element = "
154 <x xmlns='http://jabber.org/protocol/muc'>
155 <password>coucou</password>
156 </x>"
157 .parse()
158 .unwrap();
159 let elem1 = elem.clone();
160 let muc = Muc::try_from(elem).unwrap();
161 assert_eq!(muc.password, Some("coucou".to_owned()));
162
163 let elem2 = Element::from(muc);
164 assert!(elem1.compare_to(&elem2));
165 }
166
167 #[test]
168 fn history() {
169 let elem: Element = "
170 <x xmlns='http://jabber.org/protocol/muc'>
171 <history maxstanzas='0'/>
172 </x>"
173 .parse()
174 .unwrap();
175 let muc = Muc::try_from(elem).unwrap();
176 let muc2 = Muc::new().with_history(History::new().with_maxstanzas(0));
177 assert_eq!(muc, muc2);
178
179 let history = muc.history.unwrap();
180 assert_eq!(history.maxstanzas, Some(0));
181 assert_eq!(history.maxchars, None);
182 assert_eq!(history.seconds, None);
183 assert_eq!(history.since, None);
184
185 let elem: Element = "
186 <x xmlns='http://jabber.org/protocol/muc'>
187 <history since='1970-01-01T00:00:00Z'/>
188 </x>"
189 .parse()
190 .unwrap();
191 let muc = Muc::try_from(elem).unwrap();
192 assert_eq!(
193 muc.history.unwrap().since.unwrap(),
194 DateTime::from_str("1970-01-01T00:00:00+00:00").unwrap()
195 );
196 }
197}