rusmpp_core/pdus/borrowed/
deliver_sm.rs

1use rusmpp_macros::Rusmpp;
2
3use crate::{
4    encode::Length,
5    pdus::borrowed::Pdu,
6    tlvs::borrowed::{MessageDeliveryRequestTlvValue, Tlv},
7    types::borrowed::{COctetString, EmptyOrFullCOctetString, OctetString},
8    values::{borrowed::*, *},
9};
10
11/// This operation is used by an ESME to submit a short message to the MC for onward
12/// transmission to a specified short message entity (SME).
13#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
14#[rusmpp(decode = borrowed, test = skip)]
15#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
16#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
17pub struct DeliverSm<'a, const N: usize> {
18    /// The service_type parameter can be used to
19    /// indicate the SMS Application service
20    /// associated with the message. Specifying the
21    /// service_type allows the ESME to avail of enhanced
22    /// messaging services such as “replace by service_type”
23    /// or to control the teleservice used on the
24    /// air interface.
25    ///
26    /// Set to NULL for default MC settings.
27    pub service_type: ServiceType<'a>,
28    /// Type of Number for source address.
29    pub source_addr_ton: Ton,
30    /// Numbering Plan Indicator for source address.
31    pub source_addr_npi: Npi,
32    /// Address of SME which originated this message.
33    pub source_addr: COctetString<'a, 1, 21>,
34    /// Type of Number for destination.
35    pub dest_addr_ton: Ton,
36    /// Numbering Plan Indicator for destination.
37    pub dest_addr_npi: Npi,
38    /// Destination address of this
39    /// short message For mobile
40    /// terminated messages, this
41    /// is the directory number of
42    /// the recipient MS
43    pub destination_addr: COctetString<'a, 1, 21>,
44    /// Indicates Message Mode
45    /// and Message Type.
46    pub esm_class: EsmClass,
47    /// Protocol Identifier.
48    /// Network specific field.
49    pub protocol_id: u8,
50    /// Designates the priority level of the message.
51    pub priority_flag: PriorityFlag,
52    /// The short message is to be
53    /// scheduled by the MC for delivery.
54    ///
55    /// Set to NULL for immediate message delivery.
56    pub schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
57    /// The validity period of this message.
58    ///
59    /// Set to NULL to request the MC default validity period.
60    ///
61    /// Note: this is superseded by the qos_time_to_live TLV if
62    /// specified.
63    pub validity_period: EmptyOrFullCOctetString<'a, 17>,
64    /// Indicator to signify if a MC delivery receipt, manual
65    /// ACK, delivery ACK or an intermediate notification is required.
66    pub registered_delivery: RegisteredDelivery,
67    /// Flag indicating if the submitted message should replace an existing message.
68    pub replace_if_present_flag: ReplaceIfPresentFlag,
69    /// Defines the encoding scheme of the short message user data.
70    pub data_coding: DataCoding,
71    /// Indicates the short message to send from a list of pre- defined (‘canned’)
72    /// short messages stored on the MC. If not using a MC canned message, set to NULL.
73    pub sm_default_msg_id: u8,
74    /// Length in octets of the short_message user data.
75    sm_length: u8,
76    /// Up to 255 octets of short message user data.
77    ///
78    /// The exact physical limit for short_message size may
79    /// vary according to the underlying network
80    ///
81    /// Note: this field is superceded by the message_payload TLV if
82    /// specified.
83    #[rusmpp(length = sm_length)]
84    short_message: OctetString<'a, 0, 255>,
85    /// Message delivery request TLVs ([`MessageDeliveryRequestTlvValue`])
86    #[rusmpp(length = "unchecked")]
87    #[cfg_attr(feature = "arbitrary", arbitrary(default))]
88    tlvs: heapless::vec::Vec<Tlv<'a>, N>,
89}
90
91impl<'a, const N: usize> DeliverSm<'a, N> {
92    #[allow(clippy::too_many_arguments)]
93    pub fn new(
94        service_type: ServiceType<'a>,
95        source_addr_ton: Ton,
96        source_addr_npi: Npi,
97        source_addr: COctetString<'a, 1, 21>,
98        dest_addr_ton: Ton,
99        dest_addr_npi: Npi,
100        destination_addr: COctetString<'a, 1, 21>,
101        esm_class: EsmClass,
102        protocol_id: u8,
103        priority_flag: PriorityFlag,
104        schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
105        validity_period: EmptyOrFullCOctetString<'a, 17>,
106        registered_delivery: RegisteredDelivery,
107        replace_if_present_flag: ReplaceIfPresentFlag,
108        data_coding: DataCoding,
109        sm_default_msg_id: u8,
110        short_message: OctetString<'a, 0, 255>,
111        tlvs: heapless::vec::Vec<MessageDeliveryRequestTlvValue<'a>, N>,
112    ) -> Self {
113        let tlvs = tlvs.into_iter().map(From::from).collect();
114
115        let sm_length = short_message.length() as u8;
116
117        Self {
118            service_type,
119            source_addr_ton,
120            source_addr_npi,
121            source_addr,
122            dest_addr_ton,
123            dest_addr_npi,
124            destination_addr,
125            esm_class,
126            protocol_id,
127            priority_flag,
128            schedule_delivery_time,
129            validity_period,
130            registered_delivery,
131            replace_if_present_flag,
132            data_coding,
133            sm_default_msg_id,
134            sm_length,
135            short_message,
136            tlvs,
137        }
138    }
139
140    pub const fn sm_length(&self) -> u8 {
141        self.sm_length
142    }
143
144    pub fn short_message(&self) -> &OctetString<'a, 0, 255> {
145        &self.short_message
146    }
147
148    /// Sets the `short_message` and `sm_length`.
149    ///
150    /// # Note
151    ///
152    /// `short_message` is superceded by [`TlvValue::MessagePayload`](crate::tlvs::borrowed::TlvValue::MessagePayload) and should only be used if
153    /// [`TlvValue::MessagePayload`](crate::tlvs::borrowed::TlvValue::MessagePayload) is not present.
154    pub fn set_short_message(&mut self, short_message: OctetString<'a, 0, 255>) {
155        self.short_message = short_message;
156        self.sm_length = self.short_message.length() as u8;
157    }
158
159    pub fn tlvs(&'_ self) -> &'_ [Tlv<'_>] {
160        &self.tlvs
161    }
162
163    pub fn set_tlvs(&mut self, tlvs: heapless::vec::Vec<MessageDeliveryRequestTlvValue<'a>, N>) {
164        self.tlvs = tlvs.into_iter().map(From::from).collect();
165    }
166
167    pub fn clear_tlvs(&mut self) {
168        self.tlvs.clear();
169    }
170
171    pub fn push_tlv(
172        &mut self,
173        tlv: impl Into<MessageDeliveryRequestTlvValue<'a>>,
174    ) -> Result<(), Tlv<'a>> {
175        self.tlvs.push(Tlv::from(tlv.into()))?;
176        Ok(())
177    }
178
179    pub fn builder() -> DeliverSmBuilder<'a, N> {
180        DeliverSmBuilder::new()
181    }
182}
183
184impl<'a, const N: usize> From<DeliverSm<'a, N>> for Pdu<'a, N> {
185    fn from(value: DeliverSm<'a, N>) -> Self {
186        Self::DeliverSm(value)
187    }
188}
189
190#[derive(Debug, Default)]
191pub struct DeliverSmBuilder<'a, const N: usize> {
192    inner: DeliverSm<'a, N>,
193}
194
195impl<'a, const N: usize> DeliverSmBuilder<'a, N> {
196    pub fn new() -> Self {
197        Self::default()
198    }
199
200    pub fn service_type(mut self, service_type: ServiceType<'a>) -> Self {
201        self.inner.service_type = service_type;
202        self
203    }
204
205    pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
206        self.inner.source_addr_ton = source_addr_ton;
207        self
208    }
209
210    pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
211        self.inner.source_addr_npi = source_addr_npi;
212        self
213    }
214
215    pub fn source_addr(mut self, source_addr: COctetString<'a, 1, 21>) -> Self {
216        self.inner.source_addr = source_addr;
217        self
218    }
219
220    pub fn dest_addr_ton(mut self, dest_addr_ton: Ton) -> Self {
221        self.inner.dest_addr_ton = dest_addr_ton;
222        self
223    }
224
225    pub fn dest_addr_npi(mut self, dest_addr_npi: Npi) -> Self {
226        self.inner.dest_addr_npi = dest_addr_npi;
227        self
228    }
229
230    pub fn destination_addr(mut self, destination_addr: COctetString<'a, 1, 21>) -> Self {
231        self.inner.destination_addr = destination_addr;
232        self
233    }
234
235    pub fn esm_class(mut self, esm_class: EsmClass) -> Self {
236        self.inner.esm_class = esm_class;
237        self
238    }
239
240    pub fn protocol_id(mut self, protocol_id: u8) -> Self {
241        self.inner.protocol_id = protocol_id;
242        self
243    }
244
245    pub fn priority_flag(mut self, priority_flag: PriorityFlag) -> Self {
246        self.inner.priority_flag = priority_flag;
247        self
248    }
249
250    pub fn schedule_delivery_time(
251        mut self,
252        schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
253    ) -> Self {
254        self.inner.schedule_delivery_time = schedule_delivery_time;
255        self
256    }
257
258    pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<'a, 17>) -> Self {
259        self.inner.validity_period = validity_period;
260        self
261    }
262
263    pub fn registered_delivery(mut self, registered_delivery: RegisteredDelivery) -> Self {
264        self.inner.registered_delivery = registered_delivery;
265        self
266    }
267
268    pub fn replace_if_present_flag(
269        mut self,
270        replace_if_present_flag: ReplaceIfPresentFlag,
271    ) -> Self {
272        self.inner.replace_if_present_flag = replace_if_present_flag;
273        self
274    }
275
276    pub fn data_coding(mut self, data_coding: DataCoding) -> Self {
277        self.inner.data_coding = data_coding;
278        self
279    }
280
281    pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
282        self.inner.sm_default_msg_id = sm_default_msg_id;
283        self
284    }
285
286    pub fn short_message(mut self, short_message: OctetString<'a, 0, 255>) -> Self {
287        self.inner.set_short_message(short_message);
288        self
289    }
290
291    pub fn tlvs(mut self, tlvs: heapless::vec::Vec<MessageDeliveryRequestTlvValue<'a>, N>) -> Self {
292        self.inner.set_tlvs(tlvs);
293        self
294    }
295
296    pub fn clear_tlvs(mut self) -> Self {
297        self.inner.clear_tlvs();
298        self
299    }
300
301    pub fn push_tlv(
302        mut self,
303        tlv: impl Into<MessageDeliveryRequestTlvValue<'a>>,
304    ) -> Result<Self, Tlv<'a>> {
305        self.inner.push_tlv(tlv)?;
306        Ok(self)
307    }
308
309    pub fn build(self) -> DeliverSm<'a, N> {
310        self.inner
311    }
312}
313
314#[cfg(test)]
315mod tests {
316    use crate::{tests::TestInstance, types::borrowed::AnyOctetString};
317
318    use super::*;
319
320    impl<const N: usize> TestInstance for DeliverSm<'_, N> {
321        fn instances() -> alloc::vec::Vec<Self> {
322            alloc::vec![
323                Self::default(),
324                Self::builder()
325                    .source_addr_ton(Ton::International)
326                    .source_addr_npi(Npi::Isdn)
327                    .source_addr(COctetString::new(b"Source Address\0").unwrap())
328                    .dest_addr_ton(Ton::International)
329                    .dest_addr_npi(Npi::Isdn)
330                    .destination_addr(COctetString::new(b"Destination Address\0").unwrap())
331                    .schedule_delivery_time(EmptyOrFullCOctetString::empty())
332                    .validity_period(EmptyOrFullCOctetString::empty())
333                    .registered_delivery(RegisteredDelivery::default())
334                    .replace_if_present_flag(ReplaceIfPresentFlag::Replace)
335                    .short_message(OctetString::new(b"Short Message").unwrap())
336                    .build(),
337                Self::builder()
338                    .source_addr_ton(Ton::International)
339                    .source_addr_npi(Npi::Isdn)
340                    .source_addr(COctetString::new(b"Source Address\0").unwrap())
341                    .dest_addr_ton(Ton::International)
342                    .dest_addr_npi(Npi::Isdn)
343                    .destination_addr(COctetString::new(b"Destination Address\0").unwrap())
344                    .protocol_id(0)
345                    .schedule_delivery_time(EmptyOrFullCOctetString::empty())
346                    .validity_period(EmptyOrFullCOctetString::empty())
347                    .registered_delivery(RegisteredDelivery::default())
348                    .replace_if_present_flag(ReplaceIfPresentFlag::Replace)
349                    .data_coding(DataCoding::default())
350                    .sm_default_msg_id(0)
351                    .short_message(OctetString::new(b"Short Message").unwrap())
352                    .tlvs(
353                        [
354                            MessageDeliveryRequestTlvValue::MessagePayload(MessagePayload::new(
355                                AnyOctetString::new(b"Message Payload"),
356                            )),
357                            MessageDeliveryRequestTlvValue::MessagePayload(MessagePayload::new(
358                                AnyOctetString::new(b"Message Payload 2"),
359                            )),
360                            MessageDeliveryRequestTlvValue::CallbackNumPresInd(
361                                CallbackNumPresInd::new(
362                                    Presentation::NumberNotAvailable,
363                                    Screening::VerifiedAndPassed,
364                                ),
365                            ),
366                        ]
367                        .into()
368                    )
369                    .build(),
370            ]
371        }
372    }
373
374    #[test]
375    fn encode_decode() {
376        crate::tests::borrowed::encode_decode_with_length_test_instances::<DeliverSm<'static, 16>>(
377        );
378    }
379
380    #[test]
381    fn short_message_length() {
382        let short_message = OctetString::new(b"Short Message").unwrap();
383
384        let submit_sm = DeliverSm::<'static, 16>::builder()
385            .short_message(short_message.clone())
386            .build();
387
388        assert_eq!(submit_sm.short_message(), &short_message);
389        assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
390    }
391}