rust_rcs_client/provisioning/
wap_provisioning_doc.rs1extern crate quick_xml;
16
17use std::{io::Write, str::FromStr};
18
19use quick_xml::{
20 events::{BytesEnd, BytesStart, Event},
21 Reader, Writer,
22};
23
24use rust_rcs_core::{ffi::log::platform_log, util::raw_string::StrEq};
25
26use super::characteristic::{read_characteristic, write_characteristic, Characteristic, Parameter};
27
28const LOG_TAG: &str = "wap_doc";
29
30pub const DEFAULT_APPLICATION_PORT: u16 = 37273;
31
32pub struct WapProvisioningDoc {
33 root: Vec<Characteristic>,
34}
35
36impl WapProvisioningDoc {
37 pub fn new(root: Vec<Characteristic>) -> WapProvisioningDoc {
38 WapProvisioningDoc { root }
39 }
40
41 fn get_child_characteristic(&self, name: &str) -> Option<&Characteristic> {
42 for child in &self.root {
43 if child.characteristic_type == name {
44 return Some(child);
45 }
46 }
47
48 None
49 }
50
51 pub fn get_vers_token(&self) -> Option<(i64, i64, Option<(&str, Option<i64>)>)> {
52 if let Some(vers) = self.get_child_characteristic("VERS") {
53 if let (Some(version), Some(version_validity)) = (
54 vers.get_parameter("version"),
55 vers.get_parameter("validity"),
56 ) {
57 if let (Ok(version), Ok(version_validity)) =
58 (version.parse::<i64>(), version_validity.parse::<i64>())
59 {
60 if (version > 0 && version_validity > 0) || version <= 0 {
61 if let Some(token) = self.get_child_characteristic("TOKEN") {
62 if let Some(token_string) = token.get_parameter("token") {
63 if let Some(token_validity) = token.get_parameter("validity") {
64 if let Ok(token_validity) = token_validity.parse::<i64>() {
65 return Some((
66 version,
67 version_validity,
68 Some((token_string, Some(token_validity))),
69 ));
70 }
71 }
72
73 return Some((
74 version,
75 version_validity,
76 Some((token_string, None)),
77 ));
78 }
79 }
80 return Some((version, version_validity, None));
81 }
82 }
83 }
84 }
85
86 None
87 }
88
89 pub fn access_control(&self) -> Option<AccessControl> {
90 if let Some(access_control) = self.get_child_characteristic("ACCESS-CONTROL") {
91 return Some(AccessControl {
92 root: access_control.child_characteristics.iter(),
93 });
94 }
95
96 None
97 }
98
99 pub fn get_user_msisdn(&self) -> Option<&str> {
100 if let Some(user) = self.get_child_characteristic("User") {
101 return user.get_parameter("msisdn");
102 }
103
104 None
105 }
106
107 pub fn get_msg(&self) -> Option<&Characteristic> {
108 self.get_child_characteristic("MSG")
109 }
110
111 pub fn get_sms_policy(&self) -> Option<u16> {
112 if self.root.len() == 1 {
113 if let Some(policy) = self.get_child_characteristic("POLICY") {
114 if let Some(sms_port) = policy.get_parameter("SMS_port") {
115 if let Ok(port) = sms_port.parse::<u16>() {
116 return Some(port);
117 }
118 }
119 return Some(DEFAULT_APPLICATION_PORT);
120 }
121 }
122
123 None
124 }
125
126 pub fn children(&self) -> std::slice::Iter<Characteristic> {
127 self.root.iter()
128 }
129
130 pub fn applications(&self) -> Applications {
131 Applications {
132 root: self.root.iter(),
133 }
134 }
135
136 pub fn get_application_characteristic(&self, app_id: &str) -> Option<&Characteristic> {
137 for child in &self.root {
138 if child.characteristic_type == "APPLICATION" {
139 if let Some(app_id_parm) = child.get_parameter("AppID") {
140 if app_id_parm == app_id {
141 return Some(child);
142 }
143 }
144 }
145 }
146
147 None
148 }
149
150 pub fn update_application(&mut self, app_id: &str, application: &Characteristic) {
151 platform_log(LOG_TAG, format!("update application {}", app_id));
152
153 for child in self.root.iter_mut() {
154 if child.characteristic_type == "APPLICATION" {
155 if let Some(app_id_parm) = child.get_parameter("AppID") {
156 if app_id_parm == app_id {
157 child.characteristic_parameters =
158 application.characteristic_parameters.clone();
159 child.child_characteristics = application.child_characteristics.clone();
160 return;
161 }
162 }
163 }
164 }
165
166 platform_log(LOG_TAG, format!("inserting application {}", app_id));
167
168 self.root.push(application.clone())
169 }
170
171 pub fn remove_non_application_characteristics(&mut self) {
172 self.root
173 .retain(|child| child.characteristic_type == "APPLICATION");
174 }
175
176 pub fn add_non_application_characteristic(&mut self, characteristic: &Characteristic) {
177 self.root.push(characteristic.clone())
178 }
179}
180
181pub fn read_wap_provisioning_doc<R>(
182 xml_reader: &mut Reader<R>,
183 buf: &mut Vec<u8>,
184 _e: &BytesStart,
185) -> WapProvisioningDoc
186where
187 R: std::io::BufRead,
188{
189 let mut level = 1;
190
191 let mut root = Vec::new();
192
193 let mut handle_element = |xml_reader: &mut Reader<R>, e: &BytesStart, level: i32| -> bool {
194 if e.name().as_ref().equals_bytes(b"characteristic", true) {
195 let mut buf = Vec::new();
196 if let Some(characteristic) = read_characteristic(xml_reader, &mut buf, e, level) {
197 root.push(characteristic);
198 }
199 return true;
200 }
201 false
202 };
203
204 loop {
205 match xml_reader.read_event_into(buf) {
206 Ok(Event::Start(ref e)) => {
207 if !handle_element(xml_reader, e, 1) {
208 level += 1;
209 }
210 }
211
212 Ok(Event::Empty(ref e)) => {
213 handle_element(xml_reader, e, 0);
214 }
215
216 Ok(Event::End(_)) => {
217 level -= 1;
218 if level == 0 {
219 break;
220 }
221 }
222
223 Ok(Event::Eof) | Err(_) => {
224 break;
225 }
226
227 _ => {}
228 }
229 }
230
231 buf.clear();
232
233 WapProvisioningDoc { root }
234}
235
236pub fn write_wap_provisioning_doc<W>(
237 xml_writer: &mut Writer<W>,
238 wap_provisioning_doc: &WapProvisioningDoc,
239) -> quick_xml::Result<()>
240where
241 W: Write,
242{
243 let elem = BytesStart::new("wap-provisioningdoc");
244
245 xml_writer.write_event(Event::Start(elem))?;
246
247 for characteristic in &wap_provisioning_doc.root {
248 write_characteristic(xml_writer, &characteristic)?;
249 }
250
251 xml_writer.write_event(Event::End(BytesEnd::new("wap-provisioningdoc")))?;
252
253 Ok(())
254}
255
256impl FromStr for WapProvisioningDoc {
257 type Err = &'static str;
258 fn from_str(s: &str) -> Result<Self, Self::Err> {
259 let mut xml_reader = Reader::from_str(s);
260 let mut buf = Vec::new();
261 loop {
262 match xml_reader.read_event_into(&mut buf) {
263 Ok(Event::Start(ref e)) => {
264 if e.name().as_ref().equals_bytes(b"wap-provisioningdoc", true) {
265 let mut buf = Vec::new();
266 return Ok(read_wap_provisioning_doc(&mut xml_reader, &mut buf, e));
267 }
268 }
269
270 Ok(Event::Eof) | Err(_) => {
271 break;
272 }
273
274 _ => {}
275 }
276 }
277
278 Err("Bad XML")
279 }
280}
281
282pub struct Applications<'a> {
283 root: std::slice::Iter<'a, Characteristic>,
284}
285
286impl<'a> Iterator for Applications<'a> {
287 type Item = &'a Characteristic;
288 fn next(&mut self) -> Option<&'a Characteristic> {
289 while let Some(characteristic) = self.root.next() {
290 platform_log(
291 LOG_TAG,
292 format!("iterating ROOT, {}", characteristic.characteristic_type),
293 );
294 if characteristic.characteristic_type == "APPLICATION" {
295 return Some(characteristic);
296 }
297 }
298
299 None
300 }
301}
302
303pub struct AccessControl<'a> {
304 root: std::slice::Iter<'a, Characteristic>,
305}
306
307impl<'a> Iterator for AccessControl<'a> {
308 type Item = AccessControlInfo<'a>;
309 fn next(&mut self) -> Option<AccessControlInfo<'a>> {
310 while let Some(characteristic) = self.root.next() {
311 platform_log(
312 LOG_TAG,
313 format!(
314 "iterating ACCESS-CONTROL, {}",
315 characteristic.characteristic_type
316 ),
317 );
318 if characteristic.characteristic_type == "DEFAULT"
319 || characteristic.characteristic_type == "SERVER"
320 {
321 if let Some(fqdn) = characteristic.get_parameter("fqdn") {
322 return Some(AccessControlInfo {
323 is_default_server: characteristic.characteristic_type == "DEFAULT",
324 fqdn,
325 is_id_provider: if let Some(id_provider) =
326 characteristic.get_parameter("id-provider")
327 {
328 if id_provider == "1" {
329 true
330 } else {
331 false
332 }
333 } else {
334 false
335 },
336 root: characteristic,
337 });
338 } else {
339 platform_log(LOG_TAG, "cannot find parm fqdn");
340 }
341 }
342 }
343
344 None
345 }
346}
347
348pub struct AccessControlInfo<'a> {
349 pub is_default_server: bool,
350 pub fqdn: &'a str,
351 pub is_id_provider: bool,
352 root: &'a Characteristic,
353}
354
355impl<'a> AccessControlInfo<'a> {
356 pub fn app_ids(&self) -> AppIDs {
357 AppIDs {
358 root: self.root.characteristic_parameters.iter(),
359 }
360 }
361}
362
363pub struct AppIDs<'a> {
364 root: std::slice::Iter<'a, Parameter>,
365}
366
367impl<'a> Iterator for AppIDs<'a> {
368 type Item = &'a str;
369 fn next(&mut self) -> Option<&'a str> {
370 while let Some(parameter) = self.root.next() {
371 if parameter.name == "app-id" {
372 return Some(¶meter.value);
373 }
374 }
375
376 None
377 }
378}