rust_rcs_client/provisioning/
local_provisioning_doc.rs1extern crate chrono;
16extern crate quick_xml;
17
18use std::{fs::File, io::Write};
19
20use chrono::{DateTime, Duration, FixedOffset, Utc};
21
22use quick_xml::{
23 events::{BytesEnd, BytesStart, Event},
24 Reader, Writer,
25};
26
27use rust_rcs_core::{ffi::log::platform_log, util::raw_string::StrEq};
28
29use super::{
30 characteristic::Characteristic,
31 wap_provisioning_doc::{
32 read_wap_provisioning_doc, write_wap_provisioning_doc, WapProvisioningDoc,
33 },
34};
35
36const LOG_TAG: &str = "provisioning-doc";
37
38pub struct LocalProvisioningDoc {
39 root: Vec<ProvisiongingInfo>,
40}
41
42impl LocalProvisioningDoc {
43 pub fn new(root: Vec<ProvisiongingInfo>) -> LocalProvisioningDoc {
44 LocalProvisioningDoc { root }
45 }
46
47 pub fn get_provisioning_info(
48 &self,
49 get_default: bool,
50 id: &str,
51 ) -> Option<(
52 i64,
53 DateTime<FixedOffset>,
54 Option<(&str, DateTime<FixedOffset>)>,
55 Option<&WapProvisioningDoc>,
56 )> {
57 for provisioning_info in &self.root {
58 if (get_default && provisioning_info.default == "yes") || provisioning_info.id == id {
59 return destructure_provisioning_info(&provisioning_info);
60 }
61 }
62
63 None
64 }
65
66 pub fn unlink(mut self, is_default: bool, id: &str) -> Self {
67 self.root.retain(|provisioning_info| -> bool {
68 if (is_default && provisioning_info.default == "yes") || provisioning_info.id == id {
69 return false;
70 }
71
72 true
73 });
74
75 self
76 }
77
78 pub fn unlink_token(mut self, is_default: bool, id: &str) -> Self {
79 for provisioning_info in self.root.iter_mut() {
80 if (is_default && provisioning_info.default == "yes") || provisioning_info.id == id {
81 if provisioning_info.default == "yes" {
82 provisioning_info.TOKEN_token.take();
83 provisioning_info.TOKEN_validity_through.take();
84 continue;
85 }
86 }
87 }
88
89 self
90 }
91
92 pub fn update_application(
93 mut self,
94 is_default: bool,
95 id: &str,
96 app_id: &str,
97 application: &Characteristic,
98 ) -> Self {
99 platform_log(
100 LOG_TAG,
101 format!("update application {} for server {}", app_id, id),
102 );
103
104 for provisioning_info in &mut self.root {
105 if (is_default && provisioning_info.default == "yes") || provisioning_info.id == id {
106 if let Some(ref mut wap_provisioning_doc) = &mut provisioning_info.wap_doc {
107 wap_provisioning_doc.update_application(app_id, application);
108 } else {
109 platform_log(
110 LOG_TAG,
111 format!("inserting application {} for server {}", app_id, id),
112 );
113
114 let mut v = Vec::new();
115
116 v.push(application.clone());
117
118 let wap_provisioning_doc = WapProvisioningDoc::new(v);
119
120 provisioning_info.wap_doc.replace(wap_provisioning_doc);
121 }
122
123 continue;
124 }
125 }
126
127 self
128 }
129
130 pub fn update_vers_token(
131 &mut self,
132 is_default: bool,
133 id: &str,
134 vers: i64,
135 vers_validity_through: String,
136 token: Option<(&str, Option<i64>)>,
137 ) {
138 let update_token = |provisioning_info: &mut ProvisiongingInfo,
139 token: Option<(&str, Option<i64>)>| {
140 if let Some((token_string, token_validity)) = token {
141 provisioning_info
142 .TOKEN_token
143 .replace(String::from(token_string));
144
145 if let Some(token_validity) = token_validity {
146 if token_validity > 0 {
147 let token_validity_through =
148 (Utc::now() + Duration::seconds(token_validity)).to_rfc3339();
149 provisioning_info
150 .TOKEN_validity_through
151 .replace(token_validity_through);
152 } else {
153 let token_validity_through =
154 (Utc::now() + Duration::days(365)).to_rfc3339();
155 provisioning_info
156 .TOKEN_validity_through
157 .replace(token_validity_through);
158 }
159 } else {
160 let token_validity_through = (Utc::now() + Duration::days(365)).to_rfc3339();
161 provisioning_info
162 .TOKEN_validity_through
163 .replace(token_validity_through);
164 }
165 } else {
166 provisioning_info.TOKEN_token.take();
167 provisioning_info.TOKEN_validity_through.take();
168 }
169 };
170
171 for provisioning_info in &mut self.root {
172 if (is_default && provisioning_info.default == "yes") || provisioning_info.id == id {
173 provisioning_info.VERS_version = format!("{}", vers);
174 provisioning_info.VERS_validity_through = format!("{}", vers_validity_through);
175 update_token(provisioning_info, token);
176 return;
177 }
178 }
179
180 let mut provisioning_info = ProvisiongingInfo {
181 default: if is_default {
182 String::from("yes")
183 } else {
184 String::from("no")
185 },
186 id: String::from(id),
187 VERS_version: format!("{}", vers),
188 VERS_validity_through: vers_validity_through,
189 TOKEN_token: None,
190 TOKEN_validity_through: None,
191 wap_doc: None,
192 };
193
194 update_token(&mut provisioning_info, token);
195
196 self.root.push(provisioning_info);
197 }
198
199 pub fn remove_non_application_characteristics_for_default_server(&mut self) {
200 for provisioning_info in &mut self.root {
201 if provisioning_info.default == "yes" {
202 if let Some(wap_provisioning_doc) = &mut provisioning_info.wap_doc {
203 wap_provisioning_doc.remove_non_application_characteristics();
204 }
205 break;
206 }
207 }
208 }
209
210 pub fn update_characteristics_for_default_server(&mut self, characteristic: &Characteristic) {
211 for provisioning_info in &mut self.root {
212 if provisioning_info.default == "yes" {
213 if let Some(wap_provisioning_doc) = &mut provisioning_info.wap_doc {
214 wap_provisioning_doc.add_non_application_characteristic(characteristic);
215 } else {
216 let v = Vec::new();
217 let mut wap_provisioning_doc = WapProvisioningDoc::new(v);
218 wap_provisioning_doc.add_non_application_characteristic(characteristic);
219 provisioning_info.wap_doc.replace(wap_provisioning_doc);
220 }
221 break;
222 }
223 }
224 }
225
226 pub fn provisioning_files(&self) -> ProvisiongingFiles {
227 ProvisiongingFiles {
228 root: self.root.iter(),
229 }
230 }
231}
232
233pub fn read_provisionging_info<R>(
234 xml_reader: &mut Reader<R>,
235 buf: &mut Vec<u8>,
236 e: &BytesStart,
237) -> Option<ProvisiongingInfo>
238where
239 R: std::io::BufRead,
240{
241 let mut level = 1;
242
243 let mut default: Option<String> = None;
244 let mut id: Option<String> = None;
245 let mut VERS_version: Option<String> = None;
246 let mut VERS_validity_through: Option<String> = None;
247 let mut TOKEN_token: Option<String> = None;
248 let mut TOKEN_validity_through: Option<String> = None;
249
250 let mut wap_provisioning_doc: Option<WapProvisioningDoc> = None;
251
252 for attribute in e.attributes() {
253 if let Ok(attribute) = attribute {
254 if attribute.key.as_ref() == b"default" {
255 if let Ok(attribute_value) = attribute.unescape_value() {
256 default.replace(attribute_value.into_owned());
257 }
258 } else if attribute.key.as_ref() == b"id" {
259 if let Ok(attribute_value) = attribute.unescape_value() {
260 id.replace(attribute_value.into_owned());
261 }
262 } else if attribute.key.as_ref() == b"VERS_version" {
263 if let Ok(attribute_value) = attribute.unescape_value() {
264 VERS_version.replace(attribute_value.into_owned());
265 }
266 } else if attribute.key.as_ref() == b"VERS_validity_through" {
267 if let Ok(attribute_value) = attribute.unescape_value() {
268 VERS_validity_through.replace(attribute_value.into_owned());
269 }
270 } else if attribute.key.as_ref() == b"TOKEN_token" {
271 if let Ok(attribute_value) = attribute.unescape_value() {
272 TOKEN_token.replace(attribute_value.into_owned());
273 }
274 } else if attribute.key.as_ref() == b"TOKEN_validity_through" {
275 if let Ok(attribute_value) = attribute.unescape_value() {
276 TOKEN_validity_through.replace(attribute_value.into_owned());
277 }
278 }
279 }
280 }
281
282 loop {
283 match xml_reader.read_event_into(buf) {
284 Ok(Event::Start(ref e)) => {
285 level += 1;
286 if e.name().as_ref().equals_bytes(b"wap-provisioningdoc", true) {
287 let mut buf = Vec::new();
288 wap_provisioning_doc
289 .replace(read_wap_provisioning_doc(xml_reader, &mut buf, e));
290 level -= 1;
291 }
292 }
293
294 Ok(Event::End(_)) => {
295 level -= 1;
296 if level == 0 {
297 break;
298 }
299 }
300
301 Ok(Event::Eof) | Err(_) => {
302 return None;
303 }
304
305 _ => {}
306 }
307 }
308
309 buf.clear();
310
311 if let (Some(default), Some(id), Some(VERS_version), Some(VERS_validity_through)) =
312 (default, id, VERS_version, VERS_validity_through)
313 {
314 return Some(ProvisiongingInfo {
315 default,
316 id,
317 VERS_version,
318 VERS_validity_through,
319 TOKEN_token,
320 TOKEN_validity_through,
321 wap_doc: wap_provisioning_doc,
322 });
323 }
324
325 None
326}
327
328pub fn read_provisionging_doc<R>(
329 xml_reader: &mut Reader<R>,
330 buf: &mut Vec<u8>,
331 e: &BytesStart,
332) -> LocalProvisioningDoc
333where
334 R: std::io::BufRead,
335{
336 let mut level = 1;
337
338 let mut root = Vec::new();
339
340 loop {
341 match xml_reader.read_event_into(buf) {
342 Ok(Event::Start(ref e)) => {
343 level += 1;
344 if e.name().as_ref().equals_bytes(b"provisioning-info", true) {
345 let mut buf = Vec::new();
346 if let Some(provisioning_info) =
347 read_provisionging_info(xml_reader, &mut buf, e)
348 {
349 root.push(provisioning_info);
350 }
351 level -= 1;
352 }
353 }
354
355 Ok(Event::End(_)) => {
356 level -= 1;
357 if level == 0 {
358 break;
359 }
360 }
361
362 Ok(Event::Eof) | Err(_) => {
363 break;
364 }
365
366 _ => {}
367 }
368 }
369
370 buf.clear();
371
372 LocalProvisioningDoc { root }
373}
374
375pub fn load_provisionging_doc(path: &str) -> Option<LocalProvisioningDoc> {
376 if let Ok(mut xml_reader) = Reader::from_file(path) {
377 let mut buf = Vec::new();
378 loop {
379 match xml_reader.read_event_into(&mut buf) {
380 Ok(Event::Start(ref e)) => {
381 if e.name().as_ref().equals_bytes(b"provisioning-doc", true) {
382 let mut buf = Vec::new();
383 return Some(read_provisionging_doc(&mut xml_reader, &mut buf, e));
384 }
385 }
386
387 Ok(Event::Eof) | Err(_) => {
388 break;
389 }
390
391 _ => {}
392 }
393 }
394 }
395
396 None
397}
398
399pub fn write_provisioning_info<W>(
400 xml_writer: &mut Writer<W>,
401 provisioning_info: &ProvisiongingInfo,
402) -> quick_xml::Result<()>
403where
404 W: Write,
405{
406 let mut elem = BytesStart::new("provisioning-info");
407
408 elem.push_attribute(("default", provisioning_info.default.as_str()));
409 elem.push_attribute(("id", provisioning_info.id.as_str()));
410 elem.push_attribute(("VERS_version", provisioning_info.VERS_version.as_str()));
411 elem.push_attribute((
412 "VERS_validity_through",
413 provisioning_info.VERS_validity_through.as_str(),
414 ));
415
416 if let (Some(TOKEN_token), Some(TOKEN_validity_through)) = (
417 &provisioning_info.TOKEN_token,
418 &provisioning_info.TOKEN_validity_through,
419 ) {
420 elem.push_attribute(("TOKEN_token", TOKEN_token.as_str()));
421 elem.push_attribute(("TOKEN_validity_through", TOKEN_validity_through.as_str()));
422 }
423
424 xml_writer.write_event(Event::Start(elem))?;
425
426 if let Some(wap_provisioning_doc) = &provisioning_info.wap_doc {
427 write_wap_provisioning_doc(xml_writer, wap_provisioning_doc)?;
428 }
429
430 xml_writer.write_event(Event::End(BytesEnd::new("provisioning-info")))?;
431
432 Ok(())
433}
434
435pub fn write_provisionging_doc<W>(
436 xml_writer: &mut Writer<W>,
437 provisioning_doc: &LocalProvisioningDoc,
438) -> quick_xml::Result<()>
439where
440 W: Write,
441{
442 let elem = BytesStart::new("provisioning-doc");
443
444 xml_writer.write_event(Event::Start(elem))?;
445
446 for provisioning_info in &provisioning_doc.root {
447 write_provisioning_info(xml_writer, provisioning_info)?;
448 }
449
450 xml_writer.write_event(Event::End(BytesEnd::new("provisioning-doc")))?;
451
452 Ok(())
453}
454
455pub fn store_provisionging_doc(
456 provisioning_doc: &LocalProvisioningDoc,
457 path: &str,
458) -> Result<(), ()> {
459 if let Ok(f) = File::create(path) {
460 let mut xml_writer = Writer::new(f);
461 if let Ok(_) = write_provisionging_doc(&mut xml_writer, provisioning_doc) {
462 return Ok(());
463 }
464 }
465
466 Err(())
467}
468
469pub struct ProvisiongingInfo {
470 pub default: String,
471 pub id: String,
472 pub VERS_version: String,
473 pub VERS_validity_through: String,
474 pub TOKEN_token: Option<String>,
475 pub TOKEN_validity_through: Option<String>,
476 pub wap_doc: Option<WapProvisioningDoc>,
477}
478
479fn destructure_provisioning_info(
480 provisioning_info: &ProvisiongingInfo,
481) -> Option<(
482 i64,
483 DateTime<FixedOffset>,
484 Option<(&str, DateTime<FixedOffset>)>,
485 Option<&WapProvisioningDoc>,
486)> {
487 platform_log(LOG_TAG, "de-structuring provisioning-info");
488
489 if let (Ok(vers_version), Ok(vers_validity_through)) = (
490 provisioning_info.VERS_version.parse::<i64>(),
491 DateTime::parse_from_rfc3339(&provisioning_info.VERS_validity_through),
492 ) {
493 if let (Some(token_string), Some(token_validity_through)) = (
494 &provisioning_info.TOKEN_token,
495 &provisioning_info.TOKEN_validity_through,
496 ) {
497 if let (Ok(token_validity_through),) =
498 (DateTime::parse_from_rfc3339(&token_validity_through),)
499 {
500 if let Some(wap_doc) = &provisioning_info.wap_doc {
501 return Some((
502 vers_version,
503 vers_validity_through,
504 Some((&token_string, token_validity_through)),
505 Some(wap_doc),
506 ));
507 } else {
508 return Some((
509 vers_version,
510 vers_validity_through,
511 Some((&token_string, token_validity_through)),
512 None,
513 ));
514 }
515 }
516 } else {
517 if let Some(wap_doc) = &provisioning_info.wap_doc {
518 return Some((vers_version, vers_validity_through, None, Some(wap_doc)));
519 } else {
520 return Some((vers_version, vers_validity_through, None, None));
521 }
522 }
523 }
524
525 None
526}
527
528pub struct ProvisiongingFiles<'a> {
529 root: std::slice::Iter<'a, ProvisiongingInfo>,
530}
531
532impl<'a> Iterator for ProvisiongingFiles<'a> {
533 type Item = &'a WapProvisioningDoc;
534 fn next(&mut self) -> Option<&'a WapProvisioningDoc> {
535 while let Some(provisioning_info) = self.root.next() {
536 if let Some(wap_doc) = &provisioning_info.wap_doc {
537 return Some(wap_doc);
538 }
539 }
540
541 None
542 }
543}