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 try_from::TryFrom;
8
9use minidom::Element;
10use jid::Jid;
11
12use error::Error;
13
14use ns;
15
16#[derive(Debug, Clone)]
17pub struct StanzaId {
18 pub id: String,
19 pub by: Jid,
20}
21
22impl TryFrom<Element> for StanzaId {
23 type Err = Error;
24
25 fn try_from(elem: Element) -> Result<StanzaId, Error> {
26 if !elem.is("stanza-id", ns::SID) {
27 return Err(Error::ParseError("This is not a stanza-id element."));
28 }
29 for _ in elem.children() {
30 return Err(Error::ParseError("Unknown child in stanza-id element."));
31 }
32 Ok(StanzaId {
33 id: get_attr!(elem, "id", required),
34 by: get_attr!(elem, "by", required),
35 })
36 }
37}
38
39impl From<StanzaId> for Element {
40 fn from(stanza_id: StanzaId) -> Element {
41 Element::builder("stanza-id")
42 .ns(ns::SID)
43 .attr("id", stanza_id.id)
44 .attr("by", stanza_id.by)
45 .build()
46 }
47}
48
49#[derive(Debug, Clone)]
50pub struct OriginId {
51 pub id: String,
52}
53
54impl TryFrom<Element> for OriginId {
55 type Err = Error;
56
57 fn try_from(elem: Element) -> Result<OriginId, Error> {
58 if !elem.is("origin-id", ns::SID) {
59 return Err(Error::ParseError("This is not an origin-id element."));
60 }
61 for _ in elem.children() {
62 return Err(Error::ParseError("Unknown child in origin-id element."));
63 }
64 Ok(OriginId {
65 id: get_attr!(elem, "id", required),
66 })
67 }
68}
69
70impl From<OriginId> for Element {
71 fn from(origin_id: OriginId) -> Element {
72 Element::builder("origin-id")
73 .ns(ns::SID)
74 .attr("id", origin_id.id)
75 .build()
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use std::str::FromStr;
83
84 #[test]
85 fn test_simple() {
86 let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0' id='coucou' by='coucou@coucou'/>".parse().unwrap();
87 let stanza_id = StanzaId::try_from(elem).unwrap();
88 assert_eq!(stanza_id.id, String::from("coucou"));
89 assert_eq!(stanza_id.by, Jid::from_str("coucou@coucou").unwrap());
90
91 let elem: Element = "<origin-id xmlns='urn:xmpp:sid:0' id='coucou'/>".parse().unwrap();
92 let origin_id = OriginId::try_from(elem).unwrap();
93 assert_eq!(origin_id.id, String::from("coucou"));
94 }
95
96 #[test]
97 fn test_invalid_child() {
98 let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0'><coucou/></stanza-id>".parse().unwrap();
99 let error = StanzaId::try_from(elem).unwrap_err();
100 let message = match error {
101 Error::ParseError(string) => string,
102 _ => panic!(),
103 };
104 assert_eq!(message, "Unknown child in stanza-id element.");
105 }
106
107 #[test]
108 fn test_invalid_id() {
109 let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0'/>".parse().unwrap();
110 let error = StanzaId::try_from(elem).unwrap_err();
111 let message = match error {
112 Error::ParseError(string) => string,
113 _ => panic!(),
114 };
115 assert_eq!(message, "Required attribute 'id' missing.");
116 }
117
118 #[test]
119 fn test_invalid_by() {
120 let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0' id='coucou'/>".parse().unwrap();
121 let error = StanzaId::try_from(elem).unwrap_err();
122 let message = match error {
123 Error::ParseError(string) => string,
124 _ => panic!(),
125 };
126 assert_eq!(message, "Required attribute 'by' missing.");
127 }
128
129 #[test]
130 fn test_serialise() {
131 let elem: Element = "<stanza-id xmlns='urn:xmpp:sid:0' id='coucou' by='coucou@coucou'/>".parse().unwrap();
132 let stanza_id = StanzaId { id: String::from("coucou"), by: Jid::from_str("coucou@coucou").unwrap() };
133 let elem2 = stanza_id.into();
134 assert_eq!(elem, elem2);
135 }
136}