rusmpp_core/pdus/owned/
pdu.rs

1use crate::{
2    CommandId,
3    decode::{
4        DecodeError, DecodeResultExt,
5        owned::{Decode, DecodeWithKeyOptional, DecodeWithLength},
6    },
7    encode::{Encode, Length},
8    types::owned::AnyOctetString,
9};
10
11use super::*;
12
13/// `SMPP` PDU.
14#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
15#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
16#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
17#[cfg_attr(feature = "serde-deserialize-unchecked", derive(::serde::Deserialize))]
18pub enum Pdu {
19    /// Authentication PDU used by a transmitter ESME to bind to
20    /// the Message Centre. The PDU contains identification
21    /// information and an access password for the ESME.
22    BindTransmitter(BindTransmitter),
23    /// Message Centre response to a bind_transmitter PDU. This
24    /// PDU indicates the success or failure of the ESME’s attempt
25    /// to bind as a transmitter.
26    BindTransmitterResp(BindTransmitterResp),
27    /// Authentication PDU used by a receiver ESME to bind to the
28    /// Message Centre. The PDU contains identification information,
29    /// an access password for the ESME and may also contain
30    /// routing information specifying the range of addresses
31    /// serviced by the ESME.
32    BindReceiver(BindReceiver),
33    /// Message Centre response to a bind_receiver PDU. This PDU
34    /// indicates the success or failure of the ESME’s attempt to bind
35    /// as a receiver.
36    BindReceiverResp(BindReceiverResp),
37    /// Authentication PDU used by a transceiver ESME to bind to
38    /// the Message Centre. The PDU contains identification
39    /// information, an access password for the ESME and may also
40    /// contain routing information specifying the range of addresses
41    /// serviced by the ESME.
42    BindTransceiver(BindTransceiver),
43    /// Message Centre response to a bind_transceiver PDU. This
44    /// PDU indicates the success or failure of the ESME’s attempt
45    /// to bind as a transceiver.
46    BindTransceiverResp(BindTransceiverResp),
47    /// Authentication PDU used by a Message Centre to Outbind to
48    /// an ESME to inform it that messages are present in the MC.
49    /// The PDU contains identification, and access password for the
50    /// ESME. If the ESME authenticates the request, it will respond
51    /// with a bind_receiver or bind_transceiver to begin the process
52    /// of binding into the MC.
53    Outbind(Outbind),
54    /// The alert_notification PDU is sent by the MC to the ESME across a Receiver or Transceiver
55    /// session. It is sent when the MC has detected that a particular mobile subscriber has become
56    /// available and a delivery pending flag had been previously set for that subscriber by means of
57    /// the set_dpf TLV.
58    ///
59    /// A typical use of this operation is to trigger a data content ‘Push’ to the subscriber from a WAP
60    /// Proxy Server.
61    ///
62    /// Note: There is no associated alert_notification_resp PDU.
63    AlertNotification(AlertNotification),
64    /// This operation is used by an ESME to submit a short message to the MC for onward
65    /// transmission to a specified short message entity (SME).
66    SubmitSm(SubmitSm),
67    SubmitSmResp(SubmitSmResp),
68    /// This command is issued by the ESME to query the status of a previously submitted short
69    /// message.
70    /// The matching mechanism is based on the MC assigned message_id and source address.
71    /// Where the original submit_sm, data_sm or submit_multi ‘source address’ was defaulted to
72    /// NULL, then the source address in the query_sm command should also be set to NULL.
73    QuerySm(QuerySm),
74    QuerySmResp(QuerySmResp),
75    /// The deliver_sm is issued by the MC to send a message to an ESME. Using this command,
76    /// the MC may route a short message to the ESME for delivery.
77    DeliverSm(DeliverSm),
78    DeliverSmResp(DeliverSmResp),
79    /// The data_sm operation is similar to the submit_sm in that it provides a means to submit a
80    /// mobile-terminated message. However, data_sm is intended for packet-based applications
81    /// such as WAP in that it features a reduced PDU body containing fields relevant to WAP or
82    /// packet-based applications.
83    DataSm(DataSm),
84    DataSmResp(DataSmResp),
85    /// This command is issued by the ESME to cancel one or more previously submitted short
86    /// messages that are pending delivery. The command may specify a particular message to
87    /// cancel, or all messages matching a particular source, destination and service_type.
88    ///
89    /// If the message_id is set to the ID of a previously submitted message, then provided the
90    /// source address supplied by the ESME matches that of the stored message, that message
91    /// will be cancelled.
92    ///
93    /// If the message_id is NULL, all outstanding undelivered messages with matching source and
94    /// destination addresses (and service_type if specified) are cancelled.
95    /// Where the original submit_sm, data_sm or submit_multi ‘source address’ is defaulted to
96    /// NULL, then the source address in the cancel_sm command should also be NULL.
97    CancelSm(CancelSm),
98    /// This command is issued by the ESME to replace a previously submitted short message that
99    /// is pending delivery. The matching mechanism is based on the message_id and source
100    /// address of the original message.
101    ///
102    /// Where the original submit_sm ‘source address’ was defaulted to NULL, then the source
103    /// address in the replace_sm command should also be NULL.
104    ReplaceSm(ReplaceSm),
105    /// The submit_multi operation is an enhanced variation of submit_sm designed to support up to
106    /// 255 different destinations instead of the default single destination. It provides an efficient
107    /// means of sending the same message to several different subscribers at the same time.
108    SubmitMulti(SubmitMulti),
109    SubmitMultiResp(SubmitMultiResp),
110    /// This operation is issued by the ESME to submit a message to the Message Centre for
111    /// broadcast to a specified geographical area or set of geographical areas.
112    BroadcastSm(BroadcastSm),
113    BroadcastSmResp(BroadcastSmResp),
114    /// This command is issued by the ESME to query the status of a previously submitted
115    /// broadcast message. The message can be queried either on the basis of the Message Center
116    /// assigned reference message_id returned in the broadcast_sm_resp or by the ESME
117    /// assigned message reference number user_message_reference as indicated in the
118    /// broadcast_sm operation associated with that message.
119    ///
120    /// Note:  Where the broadcast is queried on the basis of the ESME assigned message
121    /// reference user_message_reference this should be qualified within the service by the
122    /// system_id and/or the system_type associated with the query_broadcast_sm operation
123    /// (specified in the bind operation). If more than one message with the same
124    /// user_message_reference value is present in the Message Center, the details of the most
125    /// recently submitted message with the specified user_message_reference value will be
126    /// returned in the query_broadcast_sm_resp.
127    QueryBroadcastSm(QueryBroadcastSm),
128    QueryBroadcastSmResp(QueryBroadcastSmResp),
129    /// This command is issued by the ESME to cancel a broadcast message which has been
130    /// previously submitted to the Message Centre for broadcast via broadcast_sm and which is still
131    /// pending delivery.
132    ///
133    /// If the message_id is set to the ID of a previously submitted message, then provided the
134    /// source address supplied by the ESME matches that of the stored message, that message
135    /// will be cancelled.
136    ///
137    /// If the message_id is NULL, all outstanding undelivered messages with matching source and
138    /// destination addresses (and service_type if specified) are cancelled.
139    ///
140    /// If the user_message_reference is set to the ESME-assigned reference of a previously
141    /// submitted message, then provided the source address supplied by the ESME matches that of
142    /// the stored message, that message will be cancelled.
143    ///
144    /// Where the original broadcast_sm ‘source address’ was defaulted to NULL, then the source
145    /// address in the cancel_broadcast_sm command should also be NULL.
146    CancelBroadcastSm(CancelBroadcastSm),
147    /// This PDU can be sent by the ESME or MC as a means of
148    /// initiating the termination of a `SMPP` session.
149    Unbind,
150    /// This PDU can be sent by the ESME or MC as a means of
151    /// acknowledging the receipt of an unbind request. After
152    /// sending this PDU the MC typically closes the network
153    /// connection.
154    UnbindResp,
155    /// This PDU can be sent by the ESME or MC to test the network
156    /// connection. The receiving peer is expected to acknowledge
157    /// the PDU as a means of verifying the test.
158    EnquireLink,
159    /// This PDU is used to acknowledge an enquire_link request
160    /// sent by an ESME or MC.
161    EnquireLinkResp,
162    /// This PDU can be sent by an ESME or MC as a means of
163    /// indicating the receipt of an invalid PDU. The receipt of a
164    /// generic_nack usually indicates that the remote peer either
165    /// cannot identify the PDU or has deemed it an invalid PDU due
166    /// to its size or content.
167    GenericNack,
168    /// The MC returns this PDU to indicate the success or failure of
169    /// a cancel_sm PDU.
170    CancelSmResp,
171    /// The replace_sm_resp PDU indicates the success or failure of
172    /// a replace_sm PDU.
173    ReplaceSmResp,
174    /// The MC returns a query_broadcast_sm_resp PDU as a
175    /// means of indicating the result of a broadcast query
176    /// attempt. The PDU will indicate the success or failure of the
177    /// attempt and for successful attempts will also include the
178    /// current state of the message.
179    CancelBroadcastSmResp,
180    Other {
181        command_id: CommandId,
182        body: AnyOctetString,
183    },
184}
185
186impl Pdu {
187    pub const fn command_id(&self) -> CommandId {
188        match self {
189            Pdu::BindTransmitter(_) => CommandId::BindTransmitter,
190            Pdu::BindTransmitterResp(_) => CommandId::BindTransmitterResp,
191            Pdu::BindReceiver(_) => CommandId::BindReceiver,
192            Pdu::BindReceiverResp(_) => CommandId::BindReceiverResp,
193            Pdu::BindTransceiver(_) => CommandId::BindTransceiver,
194            Pdu::BindTransceiverResp(_) => CommandId::BindTransceiverResp,
195            Pdu::Outbind(_) => CommandId::Outbind,
196            Pdu::AlertNotification(_) => CommandId::AlertNotification,
197            Pdu::SubmitSm(_) => CommandId::SubmitSm,
198            Pdu::SubmitSmResp(_) => CommandId::SubmitSmResp,
199            Pdu::QuerySm(_) => CommandId::QuerySm,
200            Pdu::QuerySmResp(_) => CommandId::QuerySmResp,
201            Pdu::DeliverSm(_) => CommandId::DeliverSm,
202            Pdu::DeliverSmResp(_) => CommandId::DeliverSmResp,
203            Pdu::DataSm(_) => CommandId::DataSm,
204            Pdu::DataSmResp(_) => CommandId::DataSmResp,
205            Pdu::CancelSm(_) => CommandId::CancelSm,
206            Pdu::ReplaceSm(_) => CommandId::ReplaceSm,
207            Pdu::SubmitMulti(_) => CommandId::SubmitMulti,
208            Pdu::SubmitMultiResp(_) => CommandId::SubmitMultiResp,
209            Pdu::BroadcastSm(_) => CommandId::BroadcastSm,
210            Pdu::BroadcastSmResp(_) => CommandId::BroadcastSmResp,
211            Pdu::QueryBroadcastSm(_) => CommandId::QueryBroadcastSm,
212            Pdu::QueryBroadcastSmResp(_) => CommandId::QueryBroadcastSmResp,
213            Pdu::CancelBroadcastSm(_) => CommandId::CancelBroadcastSm,
214            Pdu::Other { command_id, .. } => *command_id,
215            // These are empty pdus.
216            // The reason they exist is to force the creation of a command with the correct command_id using a pdu.
217            Pdu::Unbind => CommandId::Unbind,
218            Pdu::UnbindResp => CommandId::UnbindResp,
219            Pdu::EnquireLink => CommandId::EnquireLink,
220            Pdu::EnquireLinkResp => CommandId::EnquireLinkResp,
221            Pdu::GenericNack => CommandId::GenericNack,
222            Pdu::CancelSmResp => CommandId::CancelSmResp,
223            Pdu::ReplaceSmResp => CommandId::ReplaceSmResp,
224            Pdu::CancelBroadcastSmResp => CommandId::CancelBroadcastSmResp,
225        }
226    }
227}
228
229impl Length for Pdu {
230    fn length(&self) -> usize {
231        match self {
232            Pdu::BindTransmitter(body) => body.length(),
233            Pdu::BindTransmitterResp(body) => body.length(),
234            Pdu::BindReceiver(body) => body.length(),
235            Pdu::BindReceiverResp(body) => body.length(),
236            Pdu::BindTransceiver(body) => body.length(),
237            Pdu::BindTransceiverResp(body) => body.length(),
238            Pdu::Outbind(body) => body.length(),
239            Pdu::AlertNotification(body) => body.length(),
240            Pdu::SubmitSm(body) => body.length(),
241            Pdu::SubmitSmResp(body) => body.length(),
242            Pdu::QuerySm(body) => body.length(),
243            Pdu::QuerySmResp(body) => body.length(),
244            Pdu::DeliverSm(body) => body.length(),
245            Pdu::DeliverSmResp(body) => body.length(),
246            Pdu::DataSm(body) => body.length(),
247            Pdu::DataSmResp(body) => body.length(),
248            Pdu::CancelSm(body) => body.length(),
249            Pdu::ReplaceSm(body) => body.length(),
250            Pdu::SubmitMulti(body) => body.length(),
251            Pdu::SubmitMultiResp(body) => body.length(),
252            Pdu::BroadcastSm(body) => body.length(),
253            Pdu::BroadcastSmResp(body) => body.length(),
254            Pdu::QueryBroadcastSm(body) => body.length(),
255            Pdu::QueryBroadcastSmResp(body) => body.length(),
256            Pdu::CancelBroadcastSm(body) => body.length(),
257            Pdu::Unbind => 0,
258            Pdu::UnbindResp => 0,
259            Pdu::EnquireLink => 0,
260            Pdu::EnquireLinkResp => 0,
261            Pdu::GenericNack => 0,
262            Pdu::CancelSmResp => 0,
263            Pdu::ReplaceSmResp => 0,
264            Pdu::CancelBroadcastSmResp => 0,
265            Pdu::Other { body, .. } => body.length(),
266        }
267    }
268}
269
270impl Encode for Pdu {
271    fn encode(&self, dst: &mut [u8]) -> usize {
272        match self {
273            Pdu::BindTransmitter(body) => body.encode(dst),
274            Pdu::BindTransmitterResp(body) => body.encode(dst),
275            Pdu::BindReceiver(body) => body.encode(dst),
276            Pdu::BindReceiverResp(body) => body.encode(dst),
277            Pdu::BindTransceiver(body) => body.encode(dst),
278            Pdu::BindTransceiverResp(body) => body.encode(dst),
279            Pdu::Outbind(body) => body.encode(dst),
280            Pdu::AlertNotification(body) => body.encode(dst),
281            Pdu::SubmitSm(body) => body.encode(dst),
282            Pdu::SubmitSmResp(body) => body.encode(dst),
283            Pdu::QuerySm(body) => body.encode(dst),
284            Pdu::QuerySmResp(body) => body.encode(dst),
285            Pdu::DeliverSm(body) => body.encode(dst),
286            Pdu::DeliverSmResp(body) => body.encode(dst),
287            Pdu::DataSm(body) => body.encode(dst),
288            Pdu::DataSmResp(body) => body.encode(dst),
289            Pdu::CancelSm(body) => body.encode(dst),
290            Pdu::ReplaceSm(body) => body.encode(dst),
291            Pdu::SubmitMulti(body) => body.encode(dst),
292            Pdu::SubmitMultiResp(body) => body.encode(dst),
293            Pdu::BroadcastSm(body) => body.encode(dst),
294            Pdu::BroadcastSmResp(body) => body.encode(dst),
295            Pdu::QueryBroadcastSm(body) => body.encode(dst),
296            Pdu::QueryBroadcastSmResp(body) => body.encode(dst),
297            Pdu::CancelBroadcastSm(body) => body.encode(dst),
298            Pdu::Unbind
299            | Pdu::UnbindResp
300            | Pdu::EnquireLink
301            | Pdu::EnquireLinkResp
302            | Pdu::GenericNack
303            | Pdu::CancelSmResp
304            | Pdu::ReplaceSmResp
305            | Pdu::CancelBroadcastSmResp => 0,
306            Pdu::Other { body, .. } => body.encode(dst),
307        }
308    }
309}
310
311impl DecodeWithKeyOptional for Pdu {
312    type Key = CommandId;
313
314    fn decode(
315        key: Self::Key,
316        src: &[u8],
317        length: usize,
318    ) -> Result<Option<(Self, usize)>, DecodeError> {
319        if length == 0 {
320            let body = match key {
321                CommandId::Unbind => Pdu::Unbind,
322                CommandId::UnbindResp => Pdu::UnbindResp,
323                CommandId::EnquireLink => Pdu::EnquireLink,
324                CommandId::EnquireLinkResp => Pdu::EnquireLinkResp,
325                CommandId::GenericNack => Pdu::GenericNack,
326                CommandId::CancelSmResp => Pdu::CancelSmResp,
327                CommandId::ReplaceSmResp => Pdu::ReplaceSmResp,
328                CommandId::CancelBroadcastSmResp => Pdu::CancelBroadcastSmResp,
329                _ => return Ok(None),
330            };
331
332            return Ok(Some((body, 0)));
333        }
334
335        let (body, size) = match key {
336            CommandId::BindTransmitter => Decode::decode(src).map_decoded(Self::BindTransmitter)?,
337            CommandId::BindTransmitterResp => {
338                DecodeWithLength::decode(src, length).map_decoded(Self::BindTransmitterResp)?
339            }
340            CommandId::BindReceiver => Decode::decode(src).map_decoded(Self::BindReceiver)?,
341            CommandId::BindReceiverResp => {
342                DecodeWithLength::decode(src, length).map_decoded(Self::BindReceiverResp)?
343            }
344            CommandId::BindTransceiver => Decode::decode(src).map_decoded(Self::BindTransceiver)?,
345            CommandId::BindTransceiverResp => {
346                DecodeWithLength::decode(src, length).map_decoded(Self::BindTransceiverResp)?
347            }
348            CommandId::Outbind => Decode::decode(src).map_decoded(Self::Outbind)?,
349            CommandId::AlertNotification => {
350                DecodeWithLength::decode(src, length).map_decoded(Self::AlertNotification)?
351            }
352            CommandId::SubmitSm => SubmitSm::decode(src, length).map_decoded(Self::SubmitSm)?,
353            CommandId::SubmitSmResp => {
354                DecodeWithLength::decode(src, length).map_decoded(Self::SubmitSmResp)?
355            }
356            CommandId::QuerySm => Decode::decode(src).map_decoded(Self::QuerySm)?,
357            CommandId::QuerySmResp => Decode::decode(src).map_decoded(Self::QuerySmResp)?,
358            CommandId::DeliverSm => {
359                DecodeWithLength::decode(src, length).map_decoded(Self::DeliverSm)?
360            }
361            CommandId::DeliverSmResp => {
362                DecodeWithLength::decode(src, length).map_decoded(Self::DeliverSmResp)?
363            }
364            CommandId::DataSm => DecodeWithLength::decode(src, length).map_decoded(Self::DataSm)?,
365            CommandId::DataSmResp => {
366                DecodeWithLength::decode(src, length).map_decoded(Self::DataSmResp)?
367            }
368            CommandId::CancelSm => Decode::decode(src).map_decoded(Self::CancelSm)?,
369            CommandId::ReplaceSm => {
370                DecodeWithLength::decode(src, length).map_decoded(Self::ReplaceSm)?
371            }
372            CommandId::SubmitMulti => {
373                DecodeWithLength::decode(src, length).map_decoded(Self::SubmitMulti)?
374            }
375            CommandId::SubmitMultiResp => {
376                DecodeWithLength::decode(src, length).map_decoded(Self::SubmitMultiResp)?
377            }
378            CommandId::BroadcastSm => {
379                DecodeWithLength::decode(src, length).map_decoded(Self::BroadcastSm)?
380            }
381            CommandId::BroadcastSmResp => {
382                DecodeWithLength::decode(src, length).map_decoded(Self::BroadcastSmResp)?
383            }
384            CommandId::QueryBroadcastSm => {
385                DecodeWithLength::decode(src, length).map_decoded(Self::QueryBroadcastSm)?
386            }
387            CommandId::QueryBroadcastSmResp => {
388                DecodeWithLength::decode(src, length).map_decoded(Self::QueryBroadcastSmResp)?
389            }
390            CommandId::CancelBroadcastSm => {
391                DecodeWithLength::decode(src, length).map_decoded(Self::CancelBroadcastSm)?
392            }
393            CommandId::Other(_) => {
394                DecodeWithLength::decode(src, length).map_decoded(|body| Pdu::Other {
395                    command_id: key,
396                    body,
397                })?
398            }
399            // Length is not 0 and still have to decode the body. This is an invalid PDU.
400            CommandId::Unbind
401            | CommandId::UnbindResp
402            | CommandId::EnquireLink
403            | CommandId::EnquireLinkResp
404            | CommandId::GenericNack
405            | CommandId::CancelSmResp
406            | CommandId::ReplaceSmResp
407            | CommandId::CancelBroadcastSmResp => return Ok(None),
408        };
409
410        Ok(Some((body, size)))
411    }
412}