rusmpp_core/pdus/borrowed/
pdu.rs

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