rusmpp_core/pdus/owned/
broadcast_sm.rs

1use rusmpp_macros::Rusmpp;
2
3use crate::{
4    pdus::owned::Pdu,
5    tlvs::owned::{BroadcastRequestTlvValue, Tlv},
6    types::owned::{COctetString, EmptyOrFullCOctetString},
7    values::{owned::*, *},
8};
9
10/// This operation is issued by the ESME to submit a message to the Message Centre for
11/// broadcast to a specified geographical area or set of geographical areas.
12#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Rusmpp)]
13#[rusmpp(decode = owned, test = skip)]
14#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
15#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
16#[cfg_attr(feature = "serde-deserialize-unchecked", derive(::serde::Deserialize))]
17pub struct BroadcastSm {
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
23    /// service_type” or control the teleservice used on the air
24    /// interface.
25    ///
26    /// Set to NULL for default MC settings.
27    pub service_type: ServiceType,
28    /// Type of Number for source address.
29    ///
30    /// If not known, set to NULL (Unknown).
31    pub source_addr_ton: Ton,
32    /// Numbering Plan Indicator for source address.
33    ///
34    /// If not known, set to NULL (Unknown).
35    pub source_addr_npi: Npi,
36    /// Address of SME which originated this message.
37    ///
38    /// If not known, set to NULL (Unknown).
39    pub source_addr: COctetString<1, 21>,
40    /// If using broadcast_sm to replace a message,
41    /// previously submitted for broadcast, then set
42    /// message_id to the MC assigned message ID
43    /// allocated to the original message and returned in
44    /// the broadcast_sm_resp  (to the original broadcast_sm request).
45    ///
46    /// Note: For "broadcast replace", either the message_id or the
47    /// user_message_reference field should be used. Both
48    /// fields must not be used simultaneously.
49    /// Set to NULL:
50    ///
51    /// * if not using MC message ID in broadcast_sm to
52    ///   replace a message, previously submitted for broadcast.
53    /// * if setting user_message_reference TLV.
54    pub message_id: COctetString<1, 65>,
55    /// Designates the propriety level of the message.
56    pub priority_flag: PriorityFlag,
57    /// The short message is to be scheduled by the MC for
58    /// delivery.
59    ///
60    /// Set to NULL for immediate message broadcast.
61    pub schedule_delivery_time: EmptyOrFullCOctetString<17>,
62    /// The validity period of this message.
63    ///
64    /// Set to NULL to specify that a ‘broadcast_rep_num’
65    /// parameter and a ‘broadcast_frequency_interval’
66    /// parameter have been specified from which a
67    /// default value should be derived.
68    pub validity_period: EmptyOrFullCOctetString<17>,
69    /// Flag indicating if the submitted message should
70    /// replace an existing message which has:
71    /// * (1) MC message ID matching the ID supplied in
72    ///   the message_id field.
73    /// * (2) or ESME assigned message reference number
74    ///   supplied in the user_message_reference field.
75    pub replace_if_present_flag: ReplaceIfPresentFlag,
76    /// Defines the encoding scheme of the short
77    /// message user data.
78    pub data_coding: DataCoding,
79    /// Indicates the short message to send from a list of pre-
80    /// defined (‘canned’) short messages stored on the MC.
81    ///
82    /// If not using a MC canned message, set to NULL.
83    pub sm_default_msg_id: u8,
84    /// Broadcast request TLVs ([`BroadcastRequestTlvValue`]).
85    #[rusmpp(length = "unchecked")]
86    tlvs: alloc::vec::Vec<Tlv>,
87}
88
89impl BroadcastSm {
90    #[allow(clippy::too_many_arguments)]
91    pub fn new(
92        service_type: ServiceType,
93        source_addr_ton: Ton,
94        source_addr_npi: Npi,
95        source_addr: COctetString<1, 21>,
96        message_id: COctetString<1, 65>,
97        priority_flag: PriorityFlag,
98        schedule_delivery_time: EmptyOrFullCOctetString<17>,
99        validity_period: EmptyOrFullCOctetString<17>,
100        replace_if_present_flag: ReplaceIfPresentFlag,
101        data_coding: DataCoding,
102        sm_default_msg_id: u8,
103        tlvs: alloc::vec::Vec<BroadcastRequestTlvValue>,
104    ) -> Self {
105        let tlvs = tlvs.into_iter().map(From::from).collect();
106
107        Self {
108            service_type,
109            source_addr_ton,
110            source_addr_npi,
111            source_addr,
112            message_id,
113            priority_flag,
114            schedule_delivery_time,
115            validity_period,
116            replace_if_present_flag,
117            data_coding,
118            sm_default_msg_id,
119            tlvs,
120        }
121    }
122
123    pub fn tlvs(&self) -> &[Tlv] {
124        &self.tlvs
125    }
126
127    pub fn set_tlvs(&mut self, tlvs: alloc::vec::Vec<BroadcastRequestTlvValue>) {
128        self.tlvs = tlvs.into_iter().map(From::from).collect();
129    }
130
131    pub fn clear_tlvs(&mut self) {
132        self.tlvs.clear();
133    }
134
135    pub fn push_tlv(&mut self, tlv: impl Into<BroadcastRequestTlvValue>) {
136        self.tlvs.push(Tlv::from(tlv.into()));
137    }
138
139    pub fn builder() -> BroadcastSmBuilder {
140        BroadcastSmBuilder::new()
141    }
142}
143
144impl From<BroadcastSm> for Pdu {
145    fn from(value: BroadcastSm) -> Self {
146        Self::BroadcastSm(value)
147    }
148}
149
150#[derive(Debug, Default)]
151pub struct BroadcastSmBuilder {
152    inner: BroadcastSm,
153}
154
155impl BroadcastSmBuilder {
156    pub fn new() -> Self {
157        Self::default()
158    }
159
160    pub fn service_type(mut self, service_type: ServiceType) -> Self {
161        self.inner.service_type = service_type;
162        self
163    }
164
165    pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
166        self.inner.source_addr_ton = source_addr_ton;
167        self
168    }
169
170    pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
171        self.inner.source_addr_npi = source_addr_npi;
172        self
173    }
174
175    pub fn source_addr(mut self, source_addr: COctetString<1, 21>) -> Self {
176        self.inner.source_addr = source_addr;
177        self
178    }
179
180    pub fn message_id(mut self, message_id: COctetString<1, 65>) -> Self {
181        self.inner.message_id = message_id;
182        self
183    }
184
185    pub fn priority_flag(mut self, priority_flag: PriorityFlag) -> Self {
186        self.inner.priority_flag = priority_flag;
187        self
188    }
189
190    pub fn schedule_delivery_time(
191        mut self,
192        schedule_delivery_time: EmptyOrFullCOctetString<17>,
193    ) -> Self {
194        self.inner.schedule_delivery_time = schedule_delivery_time;
195        self
196    }
197
198    pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<17>) -> Self {
199        self.inner.validity_period = validity_period;
200        self
201    }
202
203    pub fn replace_if_present_flag(
204        mut self,
205        replace_if_present_flag: ReplaceIfPresentFlag,
206    ) -> Self {
207        self.inner.replace_if_present_flag = replace_if_present_flag;
208        self
209    }
210
211    pub fn data_coding(mut self, data_coding: DataCoding) -> Self {
212        self.inner.data_coding = data_coding;
213        self
214    }
215
216    pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
217        self.inner.sm_default_msg_id = sm_default_msg_id;
218        self
219    }
220
221    pub fn tlvs(mut self, tlvs: alloc::vec::Vec<BroadcastRequestTlvValue>) -> Self {
222        self.inner.set_tlvs(tlvs);
223        self
224    }
225
226    pub fn clear_tlvs(mut self) -> Self {
227        self.inner.clear_tlvs();
228        self
229    }
230
231    pub fn push_tlv(mut self, tlv: impl Into<BroadcastRequestTlvValue>) -> Self {
232        self.inner.push_tlv(tlv);
233        self
234    }
235
236    pub fn build(self) -> BroadcastSm {
237        self.inner
238    }
239}
240
241#[cfg(test)]
242mod tests {
243    use std::str::FromStr;
244
245    use crate::{tests::TestInstance, types::owned::OctetString};
246
247    use super::*;
248
249    impl TestInstance for BroadcastSm {
250        fn instances() -> alloc::vec::Vec<Self> {
251            alloc::vec![
252                Self::default(),
253                Self::builder()
254                    .service_type(ServiceType::new(
255                        GenericServiceType::CellularMessaging.into(),
256                    ))
257                    .source_addr_ton(Ton::International)
258                    .source_addr_npi(Npi::Isdn)
259                    .source_addr(COctetString::from_str("SourceAddr").unwrap())
260                    .message_id(COctetString::from_str("MessageId").unwrap())
261                    .priority_flag(PriorityFlag::from(PriorityFlagType::from(GsmSms::from(1))))
262                    .schedule_delivery_time(EmptyOrFullCOctetString::empty())
263                    .validity_period(EmptyOrFullCOctetString::empty())
264                    .replace_if_present_flag(ReplaceIfPresentFlag::Replace)
265                    .data_coding(DataCoding::LatinHebrew)
266                    .sm_default_msg_id(0)
267                    .build(),
268                Self::builder()
269                    .service_type(ServiceType::new(
270                        GenericServiceType::UnstructuredSupplementaryServicesData.into(),
271                    ))
272                    .source_addr_ton(Ton::International)
273                    .source_addr_npi(Npi::Isdn)
274                    .source_addr(COctetString::from_str("SourceAddr").unwrap())
275                    .message_id(COctetString::from_str("MessageId").unwrap())
276                    .priority_flag(PriorityFlag::from(PriorityFlagType::from(Ansi136::Bulk)))
277                    .schedule_delivery_time(
278                        EmptyOrFullCOctetString::from_static_slice(b"2023-10-01T00:00\0").unwrap(),
279                    )
280                    .validity_period(EmptyOrFullCOctetString::empty())
281                    .replace_if_present_flag(ReplaceIfPresentFlag::DoNotReplace)
282                    .data_coding(DataCoding::GsmMessageClassControl)
283                    .sm_default_msg_id(255)
284                    .tlvs(alloc::vec![
285                        BroadcastRequestTlvValue::CallbackNum(
286                            OctetString::from_str("1234567890").unwrap(),
287                        ),
288                        BroadcastRequestTlvValue::LanguageIndicator(LanguageIndicator::German),
289                        BroadcastRequestTlvValue::SmsSignal(1024),
290                    ])
291                    .build(),
292            ]
293        }
294    }
295
296    #[test]
297    fn encode_decode() {
298        crate::tests::owned::encode_decode_with_length_test_instances::<BroadcastSm>();
299    }
300}