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
7#![deny(missing_docs)]
8
9use helpers::Base64;
10use iq::IqSetPayload;
11
12generate_id!(
13/// An identifier matching a stream.
14StreamId);
15
16generate_attribute!(
17/// Which stanza type to use to exchange data.
18Stanza, "stanza", {
19 /// `<iq/>` gives a feedback on whether the chunk has been received or not,
20 /// which is useful in the case the recipient might not receive them in a
21 /// timely manner, or to do your own throttling based on the results.
22 Iq => "iq",
23
24 /// `<message/>` can be faster, since it doesn’t require any feedback, but in
25 /// practice it will be throttled by the servers on the way.
26 Message => "message",
27}, Default = Iq);
28
29generate_element!(
30/// Starts an In-Band Bytestream session with the given parameters.
31Open, "open", IBB,
32attributes: [
33 /// Maximum size in bytes for each chunk.
34 block_size: u16 = "block-size" => required,
35
36 /// The identifier to be used to create a stream.
37 sid: StreamId = "sid" => required,
38
39 /// Which stanza type to use to exchange data.
40 stanza: Stanza = "stanza" => default,
41]);
42
43impl IqSetPayload for Open {}
44
45generate_element!(
46/// Exchange a chunk of data in an open stream.
47Data, "data", IBB,
48 attributes: [
49 /// Sequence number of this chunk, must wraparound after 65535.
50 seq: u16 = "seq" => required,
51
52 /// The identifier of the stream on which data is being exchanged.
53 sid: StreamId = "sid" => required
54 ],
55 text: (
56 /// Vector of bytes to be exchanged.
57 data: Base64<Vec<u8>>
58 )
59);
60
61impl IqSetPayload for Data {}
62
63generate_element!(
64/// Close an open stream.
65Close, "close", IBB,
66attributes: [
67 /// The identifier of the stream to be closed.
68 sid: StreamId = "sid" => required,
69]);
70
71impl IqSetPayload for Close {}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use try_from::TryFrom;
77 use minidom::Element;
78 use error::Error;
79 use std::error::Error as StdError;
80
81 #[test]
82 fn test_simple() {
83 let sid = StreamId(String::from("coucou"));
84
85 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb' block-size='3' sid='coucou'/>".parse().unwrap();
86 let open = Open::try_from(elem).unwrap();
87 assert_eq!(open.block_size, 3);
88 assert_eq!(open.sid, sid);
89 assert_eq!(open.stanza, Stanza::Iq);
90
91 let elem: Element = "<data xmlns='http://jabber.org/protocol/ibb' seq='0' sid='coucou'>AAAA</data>".parse().unwrap();
92 let data = Data::try_from(elem).unwrap();
93 assert_eq!(data.seq, 0);
94 assert_eq!(data.sid, sid);
95 assert_eq!(data.data, vec!(0, 0, 0));
96
97 let elem: Element = "<close xmlns='http://jabber.org/protocol/ibb' sid='coucou'/>".parse().unwrap();
98 let close = Close::try_from(elem).unwrap();
99 assert_eq!(close.sid, sid);
100 }
101
102 #[test]
103 fn test_invalid() {
104 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb'/>".parse().unwrap();
105 let error = Open::try_from(elem).unwrap_err();
106 let message = match error {
107 Error::ParseError(string) => string,
108 _ => panic!(),
109 };
110 assert_eq!(message, "Required attribute 'block-size' missing.");
111
112 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb' block-size='-5'/>".parse().unwrap();
113 let error = Open::try_from(elem).unwrap_err();
114 let message = match error {
115 Error::ParseIntError(error) => error,
116 _ => panic!(),
117 };
118 assert_eq!(message.description(), "invalid digit found in string");
119
120 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb' block-size='128'/>".parse().unwrap();
121 let error = Open::try_from(elem).unwrap_err();
122 let message = match error {
123 Error::ParseError(error) => error,
124 _ => panic!(),
125 };
126 assert_eq!(message, "Required attribute 'sid' missing.");
127 }
128
129 #[test]
130 fn test_invalid_stanza() {
131 let elem: Element = "<open xmlns='http://jabber.org/protocol/ibb' block-size='128' sid='coucou' stanza='fdsq'/>".parse().unwrap();
132 let error = Open::try_from(elem).unwrap_err();
133 let message = match error {
134 Error::ParseError(string) => string,
135 _ => panic!(),
136 };
137 assert_eq!(message, "Unknown value for 'stanza' attribute.");
138 }
139}