rust_rcs_client/provisioning/
wap_provisioning_doc.rs

1// Copyright 2023 宋昊文
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15extern 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(&parameter.value);
373            }
374        }
375
376        None
377    }
378}