rusmpp_core/pdus/owned/
pdu.rs

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