Skip to main content

imsg_map/
mns_event.rs

1//! MAP-event-report event types and the parser that decodes them from the phone's MNS PUT body.
2
3use std::fmt;
4
5use obex_core::client::ObexError;
6use obex_core::TransportError;
7use quick_xml::{events::Event, Reader, XmlVersion};
8use thiserror::Error;
9
10/// Reported in `MAP-event-report` `<event type=...>` attribute.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum EventType {
13    /// New message in store; `handle` and `folder` are always present.
14    NewMessage,
15    /// An outbound message was delivered to its recipient.
16    DeliverySuccess,
17    /// An outbound message was accepted by the network for delivery.
18    SendingSuccess,
19    /// Delivery of an outbound message permanently failed.
20    DeliveryFailure,
21    /// The network rejected an outbound message.
22    SendingFailure,
23    /// Message removed from store; `handle` present, `folder` is the folder it was in.
24    MessageDeleted,
25    /// A message was moved to a different folder; `old_folder` carries the previous location.
26    MessageShift,
27    /// Message store is full; no new messages can be received until space is freed.
28    MemoryFull,
29    /// Message store has space available again after a `MemoryFull` event.
30    MemoryAvailable,
31    /// Read/unread flag toggled on device; `handle` present.
32    ReadStatusChanged,
33}
34
35impl fmt::Display for EventType {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        // Canonical MAP 1.4 event-type strings — must stay in sync with `FromStr for EventType`.
38        f.write_str(match self {
39            Self::NewMessage => "NewMessage",
40            Self::DeliverySuccess => "DeliverySuccess",
41            Self::SendingSuccess => "SendingSuccess",
42            Self::DeliveryFailure => "DeliveryFailure",
43            Self::SendingFailure => "SendingFailure",
44            Self::MessageDeleted => "MessageDeleted",
45            Self::MessageShift => "MessageShift",
46            Self::MemoryFull => "MemoryFull",
47            Self::MemoryAvailable => "MemoryAvailable",
48            Self::ReadStatusChanged => "ReadStatusChanged",
49        })
50    }
51}
52
53/// Fields absent in the `<event>` element are `None`.
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct MnsEvent {
56    event_type: EventType,
57    handle: Option<String>,
58    folder: Option<String>,
59    old_folder: Option<String>,
60    msg_type: Option<String>,
61    datetime: Option<String>,
62}
63
64impl MnsEvent {
65    /// Governs which optional fields are present.
66    #[must_use]
67    pub const fn event_type(&self) -> EventType {
68        self.event_type
69    }
70
71    /// Opaque message handle assigned by the device; absent for `MemoryFull`/`MemoryAvailable`.
72    #[must_use]
73    pub fn handle(&self) -> Option<&str> {
74        self.handle.as_deref()
75    }
76
77    /// Current folder path, e.g. `TELECOM/MSG/INBOX`; absent for memory events.
78    #[must_use]
79    pub fn folder(&self) -> Option<&str> {
80        self.folder.as_deref()
81    }
82
83    /// Previous folder path; present only for `MessageShift`.
84    #[must_use]
85    pub fn old_folder(&self) -> Option<&str> {
86        self.old_folder.as_deref()
87    }
88
89    /// Message type string, e.g. `SMS_GSM`; absent for memory events.
90    #[must_use]
91    pub fn msg_type(&self) -> Option<&str> {
92        self.msg_type.as_deref()
93    }
94
95    /// ISO 8601 basic datetime string, e.g. `20260604T120000`; present for `NewMessage`.
96    #[must_use]
97    pub fn datetime(&self) -> Option<&str> {
98        self.datetime.as_deref()
99    }
100}
101
102/// MNS server and event report XML parsing errors.
103#[derive(Debug, Error)]
104pub enum MnsError {
105    /// quick-xml reader error encountered while parsing the event report body.
106    #[error("XML error: {0}")]
107    Parse(#[from] quick_xml::Error),
108    /// Attribute value in the `<event>` element could not be decoded.
109    #[error("attribute error: {0}")]
110    Attr(#[from] quick_xml::events::attributes::AttrError),
111    /// `type` attribute value did not match any MAP 1.4 event type; inner string is the raw value.
112    #[error("unknown event type: {0}")]
113    UnknownEventType(String),
114    /// `<event>` element present but `type` attribute is absent.
115    #[error("<event> element has no type attribute")]
116    MissingEventType,
117    /// Document contained no `<event>` element; body may be empty or malformed.
118    #[error("MAP-event-report contained no <event> element")]
119    MissingEvent,
120    /// Packet decode failure while framing an MNS request or response.
121    #[error("OBEX: {0}")]
122    Obex(#[from] ObexError),
123    /// I/O failure reading or writing the MNS OBEX stream.
124    #[error("transport: {0}")]
125    Transport(#[from] TransportError),
126    /// Transport stream closed before the device sent a clean OBEX DISCONNECT.
127    #[error("unexpected end of stream")]
128    UnexpectedEof,
129    /// Device sent an opcode other than PUT, `PUT_FINAL`, or DISCONNECT after CONNECT.
130    #[error("unexpected OBEX opcode {0:#04x} from MNS client")]
131    UnexpectedOpcode(u8),
132    /// CONNECT request Target header is absent or does not match the MNS service UUID.
133    #[error("CONNECT Target UUID does not match MNS service UUID")]
134    InvalidTarget,
135}
136
137/// Parses an OBEX PUT body into an [`MnsEvent`].
138///
139/// The document must contain at least one `<event>` element; only the first is returned. The
140/// `type` attribute is required and must match a known [`EventType`] value. All other attributes
141/// are optional and default to `None` when absent.
142///
143/// # Errors
144///
145/// Returns [`MnsError::Parse`] on malformed XML, [`MnsError::Attr`] on undecodable attribute
146/// values, [`MnsError::UnknownEventType`] if the `type` attribute is not a defined MAP 1.4 event
147/// type, or [`MnsError::MissingEvent`] if no `<event>` element is found.
148pub fn parse_event_report(xml: &[u8]) -> Result<MnsEvent, MnsError> {
149    let mut reader = Reader::from_reader(xml);
150    reader.config_mut().trim_text(true);
151    let mut buf = Vec::with_capacity(256);
152    loop {
153        match reader.read_event_into(&mut buf)? {
154            Event::Empty(e) | Event::Start(e) if e.name().as_ref() == b"event" => {
155                let mut raw_type: Option<String> = None;
156                let mut handle = None;
157                let mut folder = None;
158                let mut old_folder = None;
159                let mut msg_type = None;
160                let mut datetime = None;
161                for attr in e.attributes() {
162                    let a = attr?;
163                    let val = a.normalized_value(XmlVersion::Implicit1_0)?.into_owned();
164                    match a.key.as_ref() {
165                        b"type" => raw_type = Some(val),
166                        b"handle" => handle = Some(val),
167                        b"folder" => folder = Some(val),
168                        b"old_folder" => old_folder = Some(val),
169                        b"msg_type" => msg_type = Some(val),
170                        b"datetime" => datetime = Some(val),
171                        _ => {}
172                    }
173                }
174                let event_type = match raw_type {
175                    Some(ref s) => s.parse()?,
176                    None => return Err(MnsError::MissingEventType),
177                };
178                return Ok(MnsEvent { event_type, handle, folder, old_folder, msg_type, datetime });
179            }
180            Event::Eof => return Err(MnsError::MissingEvent),
181            _ => {}
182        }
183        buf.clear();
184    }
185}
186
187impl std::str::FromStr for EventType {
188    type Err = MnsError;
189
190    fn from_str(s: &str) -> Result<Self, Self::Err> {
191        match s {
192            "NewMessage" => Ok(Self::NewMessage),
193            "DeliverySuccess" => Ok(Self::DeliverySuccess),
194            "SendingSuccess" => Ok(Self::SendingSuccess),
195            "DeliveryFailure" => Ok(Self::DeliveryFailure),
196            "SendingFailure" => Ok(Self::SendingFailure),
197            "MessageDeleted" => Ok(Self::MessageDeleted),
198            "MessageShift" => Ok(Self::MessageShift),
199            "MemoryFull" => Ok(Self::MemoryFull),
200            "MemoryAvailable" => Ok(Self::MemoryAvailable),
201            "ReadStatusChanged" => Ok(Self::ReadStatusChanged),
202            other => Err(MnsError::UnknownEventType(other.to_owned())),
203        }
204    }
205}