1// Copyright (c) 2017 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 xso::{AsXml, FromXml};
8
9use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
10use crate::ns;
11use jid::Jid;
12
13/// The element requesting the blocklist, the result iq will contain a
14/// [BlocklistResult].
15#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
16#[xml(namespace = ns::BLOCKING, name = "blocklist")]
17pub struct BlocklistRequest;
18
19impl IqGetPayload for BlocklistRequest {}
20
21/// The element containing the current blocklist, as a reply from
22/// [BlocklistRequest].
23#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
24#[xml(namespace = ns::BLOCKING, name = "blocklist")]
25pub struct BlocklistResult {
26 /// List of JIDs affected by this command.
27 #[xml(extract(n = .., name = "item", fields(attribute(name = "jid", type_ = Jid))))]
28 pub items: Vec<Jid>,
29}
30
31impl IqResultPayload for BlocklistResult {}
32
33/// A query to block one or more JIDs.
34// TODO: Prevent zero elements from being allowed.
35#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
36#[xml(namespace = ns::BLOCKING, name = "block")]
37pub struct Block {
38 /// List of JIDs affected by this command.
39 #[xml(extract(n = .., name = "item", fields(attribute(name = "jid", type_ = Jid))))]
40 pub items: Vec<Jid>,
41}
42
43impl IqSetPayload for Block {}
44
45/// A query to unblock one or more JIDs, or all of them.
46///
47/// Warning: not putting any JID there means clearing out the blocklist.
48#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
49#[xml(namespace = ns::BLOCKING, name = "unblock")]
50pub struct Unblock {
51 /// List of JIDs affected by this command.
52 #[xml(extract(n = .., name = "item", fields(attribute(name = "jid", type_ = Jid))))]
53 pub items: Vec<Jid>,
54}
55
56impl IqSetPayload for Unblock {}
57
58/// The application-specific error condition when a message is blocked.
59#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
60#[xml(namespace = ns::BLOCKING_ERRORS, name = "blocked")]
61pub struct Blocked;
62
63#[cfg(test)]
64mod tests {
65 use xso::error::{Error, FromElementError};
66
67 use super::*;
68 use minidom::Element;
69
70 #[cfg(target_pointer_width = "32")]
71 #[test]
72 fn test_size() {
73 assert_size!(BlocklistRequest, 0);
74 assert_size!(BlocklistResult, 12);
75 assert_size!(Block, 12);
76 assert_size!(Unblock, 12);
77 }
78
79 #[cfg(target_pointer_width = "64")]
80 #[test]
81 fn test_size() {
82 assert_size!(BlocklistRequest, 0);
83 assert_size!(BlocklistResult, 24);
84 assert_size!(Block, 24);
85 assert_size!(Unblock, 24);
86 }
87
88 #[test]
89 fn test_simple() {
90 let elem: Element = "<blocklist xmlns='urn:xmpp:blocking'/>".parse().unwrap();
91 let request_elem = elem.clone();
92 BlocklistRequest::try_from(request_elem).unwrap();
93
94 let result_elem = elem.clone();
95 let result = BlocklistResult::try_from(result_elem).unwrap();
96 assert!(result.items.is_empty());
97
98 let elem: Element = "<block xmlns='urn:xmpp:blocking'/>".parse().unwrap();
99 let block = Block::try_from(elem).unwrap();
100 assert!(block.items.is_empty());
101
102 let elem: Element = "<unblock xmlns='urn:xmpp:blocking'/>".parse().unwrap();
103 let unblock = Unblock::try_from(elem).unwrap();
104 assert!(unblock.items.is_empty());
105 }
106
107 #[test]
108 fn test_items() {
109 let elem: Element = "<blocklist xmlns='urn:xmpp:blocking'><item jid='coucou@coucou'/><item jid='domain'/></blocklist>".parse().unwrap();
110 let two_items = vec![
111 Jid::new("coucou@coucou").unwrap(),
112 Jid::new("domain").unwrap(),
113 ];
114
115 let result_elem = elem.clone();
116 let result = BlocklistResult::try_from(result_elem).unwrap();
117 assert_eq!(result.items, two_items);
118
119 let elem: Element = "<block xmlns='urn:xmpp:blocking'><item jid='coucou@coucou'/><item jid='domain'/></block>".parse().unwrap();
120 let block = Block::try_from(elem).unwrap();
121 assert_eq!(block.items, two_items);
122
123 let elem: Element = "<unblock xmlns='urn:xmpp:blocking'><item jid='coucou@coucou'/><item jid='domain'/></unblock>".parse().unwrap();
124 let unblock = Unblock::try_from(elem).unwrap();
125 assert_eq!(unblock.items, two_items);
126 }
127
128 #[cfg(not(feature = "disable-validation"))]
129 #[test]
130 fn test_invalid() {
131 let elem: Element = "<blocklist xmlns='urn:xmpp:blocking' coucou=''/>"
132 .parse()
133 .unwrap();
134 let request_elem = elem.clone();
135 let error = BlocklistRequest::try_from(request_elem).unwrap_err();
136 let message = match error {
137 FromElementError::Invalid(Error::Other(string)) => string,
138 _ => panic!(),
139 };
140 assert_eq!(message, "Unknown attribute in BlocklistRequest element.");
141
142 let result_elem = elem.clone();
143 let error = BlocklistResult::try_from(result_elem).unwrap_err();
144 let message = match error {
145 FromElementError::Invalid(Error::Other(string)) => string,
146 _ => panic!(),
147 };
148 assert_eq!(message, "Unknown attribute in BlocklistResult element.");
149
150 let elem: Element = "<block xmlns='urn:xmpp:blocking' coucou=''/>"
151 .parse()
152 .unwrap();
153 let error = Block::try_from(elem).unwrap_err();
154 let message = match error {
155 FromElementError::Invalid(Error::Other(string)) => string,
156 _ => panic!(),
157 };
158 assert_eq!(message, "Unknown attribute in Block element.");
159
160 let elem: Element = "<unblock xmlns='urn:xmpp:blocking' coucou=''/>"
161 .parse()
162 .unwrap();
163 let error = Unblock::try_from(elem).unwrap_err();
164 let message = match error {
165 FromElementError::Invalid(Error::Other(string)) => string,
166 _ => panic!(),
167 };
168 assert_eq!(message, "Unknown attribute in Unblock element.");
169 }
170
171 #[cfg(not(feature = "disable-validation"))]
172 #[test]
173 fn test_non_empty_blocklist_request() {
174 let elem: Element = "<blocklist xmlns='urn:xmpp:blocking'><item jid='coucou@coucou'/><item jid='domain'/></blocklist>".parse().unwrap();
175 let error = BlocklistRequest::try_from(elem).unwrap_err();
176 let message = match error {
177 FromElementError::Invalid(Error::Other(string)) => string,
178 _ => panic!(),
179 };
180 assert_eq!(message, "Unknown child in BlocklistRequest element.");
181 }
182}