Skip to main content

imsg_map/
xml.rs

1//! MAP XML parser for message listings (`MAP-msg-listing`).
2
3use quick_xml::{events::Event, Reader, XmlVersion};
4use thiserror::Error;
5
6use crate::messages::MessageEntry;
7
8/// quick-xml parse, attribute decode, and u32 invalid int.
9#[derive(Debug, Error)]
10pub enum MessageListingError {
11    /// Underlying quick-xml reader error; also covers entity-decoding failures.
12    #[error("XML error: {0}")]
13    Parse(#[from] quick_xml::Error),
14    /// Attribute encoding error from quick-xml.
15    #[error("attribute error: {0}")]
16    Attr(#[from] quick_xml::events::attributes::AttrError),
17    /// Numeric attribute (`size`) could not be parsed as a `u32`.
18    #[error("invalid integer attribute: {0}")]
19    InvalidInt(#[from] std::num::ParseIntError),
20}
21
22/// Parses a `<MAP-msg-listing>` document from raw bytes.
23///
24/// Returns one [`MessageEntry`] per `<msg>` element in document order. Attributes absent from
25/// an element default to their zero/false/empty value.
26///
27/// # Errors
28///
29/// Returns [`MessageListingError`] on malformed XML, undecodable attributes, non-UTF-8
30/// attribute values, or a non-numeric `size` field.
31pub fn parse_message_listing(xml: &[u8]) -> Result<Vec<MessageEntry>, MessageListingError> {
32    let mut reader = Reader::from_reader(xml);
33    reader.config_mut().trim_text(true);
34    let mut messages = Vec::new();
35    let mut buf = Vec::new();
36    loop {
37        match reader.read_event_into(&mut buf)? {
38            Event::Empty(e) | Event::Start(e) if e.name().as_ref() == b"msg" => {
39                let mut handle = String::new();
40                let mut subject = String::new();
41                let mut datetime = String::new();
42                let mut sender_name = String::new();
43                let mut sender_addressing = String::new();
44                let mut recipient_name = String::new();
45                let mut recipient_addressing = String::new();
46                let mut msg_type = String::new();
47                let mut size = 0u32;
48                let mut read = false;
49                let mut sent = false;
50                for attr in e.attributes() {
51                    let a = attr?;
52                    let val = a.normalized_value(XmlVersion::Implicit1_0)?.into_owned();
53                    match a.key.as_ref() {
54                        b"handle" => handle = val,
55                        b"subject" => subject = val,
56                        b"datetime" => datetime = val,
57                        b"sender_name" => sender_name = val,
58                        b"sender_addressing" => sender_addressing = val,
59                        b"recipient_name" => recipient_name = val,
60                        b"recipient_addressing" => recipient_addressing = val,
61                        b"type" => msg_type = val,
62                        b"size" => size = val.parse()?,
63                        b"read" => read = val == "yes",
64                        b"sent" => sent = val == "yes",
65                        _ => {}
66                    }
67                }
68                messages.push(MessageEntry {
69                    handle,
70                    subject,
71                    datetime,
72                    sender_name,
73                    sender_addressing,
74                    recipient_name,
75                    recipient_addressing,
76                    msg_type,
77                    size,
78                    read,
79                    sent,
80                });
81            }
82            Event::Eof => break,
83            _ => {}
84        }
85        buf.clear();
86    }
87    Ok(messages)
88}