1use rusmpp_macros::Rusmpp;
2
3use crate::{
4 encode::Length,
5 pdus::owned::Pdu,
6 tlvs::owned::{MessageSubmissionRequestTlvValue, Tlv},
7 types::owned::{COctetString, EmptyOrFullCOctetString, OctetString},
8 values::{owned::*, *},
9};
10
11#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
14#[rusmpp(decode = owned, test = skip)]
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 struct SubmitSm {
19 pub service_type: ServiceType,
29 pub source_addr_ton: Ton,
31 pub source_addr_npi: Npi,
33 pub source_addr: COctetString<1, 21>,
35 pub dest_addr_ton: Ton,
37 pub dest_addr_npi: Npi,
39 pub destination_addr: COctetString<1, 21>,
45 pub esm_class: EsmClass,
48 pub protocol_id: u8,
51 pub priority_flag: PriorityFlag,
53 pub schedule_delivery_time: EmptyOrFullCOctetString<17>,
57 pub validity_period: EmptyOrFullCOctetString<17>,
63 pub registered_delivery: RegisteredDelivery,
66 pub replace_if_present_flag: ReplaceIfPresentFlag,
68 pub data_coding: DataCoding,
70 pub sm_default_msg_id: u8,
73 sm_length: u8,
75 #[rusmpp(length = sm_length)]
83 short_message: OctetString<0, 255>,
84 #[rusmpp(length = "unchecked")]
86 tlvs: alloc::vec::Vec<Tlv>,
87}
88
89impl SubmitSm {
90 const DEFAULT_MAX_SHORT_MESSAGE_SIZE: usize = 140;
92
93 pub const fn default_max_short_message_size() -> usize {
113 Self::DEFAULT_MAX_SHORT_MESSAGE_SIZE
114 }
115
116 #[allow(clippy::too_many_arguments)]
117 pub fn new(
118 service_type: ServiceType,
119 source_addr_ton: Ton,
120 source_addr_npi: Npi,
121 source_addr: COctetString<1, 21>,
122 dest_addr_ton: Ton,
123 dest_addr_npi: Npi,
124 destination_addr: COctetString<1, 21>,
125 esm_class: EsmClass,
126 protocol_id: u8,
127 priority_flag: PriorityFlag,
128 schedule_delivery_time: EmptyOrFullCOctetString<17>,
129 validity_period: EmptyOrFullCOctetString<17>,
130 registered_delivery: RegisteredDelivery,
131 replace_if_present_flag: ReplaceIfPresentFlag,
132 data_coding: DataCoding,
133 sm_default_msg_id: u8,
134 short_message: OctetString<0, 255>,
135 tlvs: alloc::vec::Vec<MessageSubmissionRequestTlvValue>,
136 ) -> Self {
137 let tlvs = tlvs.into_iter().map(From::from).collect();
138
139 let sm_length = short_message.length() as u8;
140
141 Self {
142 service_type,
143 source_addr_ton,
144 source_addr_npi,
145 source_addr,
146 dest_addr_ton,
147 dest_addr_npi,
148 destination_addr,
149 esm_class,
150 protocol_id,
151 priority_flag,
152 schedule_delivery_time,
153 validity_period,
154 registered_delivery,
155 replace_if_present_flag,
156 data_coding,
157 sm_default_msg_id,
158 sm_length,
159 short_message,
160 tlvs,
161 }
162 }
163
164 pub fn sm_length(&self) -> u8 {
165 self.sm_length
166 }
167
168 pub fn short_message(&self) -> &OctetString<0, 255> {
169 &self.short_message
170 }
171
172 pub fn set_short_message(&mut self, short_message: OctetString<0, 255>) {
179 self.short_message = short_message;
180 self.sm_length = self.short_message.length() as u8;
181 }
182
183 pub fn tlvs(&self) -> &[Tlv] {
184 &self.tlvs
185 }
186
187 pub fn set_tlvs(&mut self, tlvs: alloc::vec::Vec<MessageSubmissionRequestTlvValue>) {
188 self.tlvs = tlvs.into_iter().map(From::from).collect();
189 }
190
191 pub fn clear_tlvs(&mut self) {
192 self.tlvs.clear();
193 }
194
195 pub fn push_tlv(&mut self, tlv: impl Into<MessageSubmissionRequestTlvValue>) {
196 self.tlvs.push(Tlv::from(tlv.into()));
197 }
198
199 pub fn builder() -> SubmitSmBuilder {
200 SubmitSmBuilder::new()
201 }
202
203 pub fn with_data_coding(mut self, data_coding: DataCoding) -> Self {
205 self.data_coding = data_coding;
206 self
207 }
208
209 pub fn with_udhi_indicator(mut self) -> Self {
211 self.esm_class = self.esm_class.with_udhi_indicator();
212 self
213 }
214
215 pub fn with_short_message(mut self, short_message: OctetString<0, 255>) -> Self {
219 self.set_short_message(short_message);
220 self
221 }
222}
223
224impl From<SubmitSm> for Pdu {
225 fn from(value: SubmitSm) -> Self {
226 Self::SubmitSm(value)
227 }
228}
229
230#[derive(Debug, Default, Clone)]
231pub struct SubmitSmBuilder {
232 inner: SubmitSm,
233}
234
235impl SubmitSmBuilder {
236 pub fn new() -> Self {
237 Self::default()
238 }
239
240 pub fn service_type(mut self, service_type: ServiceType) -> Self {
241 self.inner.service_type = service_type;
242 self
243 }
244
245 pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
246 self.inner.source_addr_ton = source_addr_ton;
247 self
248 }
249
250 pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
251 self.inner.source_addr_npi = source_addr_npi;
252 self
253 }
254
255 pub fn source_addr(mut self, source_addr: COctetString<1, 21>) -> Self {
256 self.inner.source_addr = source_addr;
257 self
258 }
259
260 pub fn dest_addr_ton(mut self, dest_addr_ton: Ton) -> Self {
261 self.inner.dest_addr_ton = dest_addr_ton;
262 self
263 }
264
265 pub fn dest_addr_npi(mut self, dest_addr_npi: Npi) -> Self {
266 self.inner.dest_addr_npi = dest_addr_npi;
267 self
268 }
269
270 pub fn destination_addr(mut self, destination_addr: COctetString<1, 21>) -> Self {
271 self.inner.destination_addr = destination_addr;
272 self
273 }
274
275 pub fn esm_class(mut self, esm_class: EsmClass) -> Self {
276 self.inner.esm_class = esm_class;
277 self
278 }
279
280 pub fn protocol_id(mut self, protocol_id: u8) -> Self {
281 self.inner.protocol_id = protocol_id;
282 self
283 }
284
285 pub fn priority_flag(mut self, priority_flag: PriorityFlag) -> Self {
286 self.inner.priority_flag = priority_flag;
287 self
288 }
289
290 pub fn schedule_delivery_time(
291 mut self,
292 schedule_delivery_time: EmptyOrFullCOctetString<17>,
293 ) -> Self {
294 self.inner.schedule_delivery_time = schedule_delivery_time;
295 self
296 }
297
298 pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<17>) -> Self {
299 self.inner.validity_period = validity_period;
300 self
301 }
302
303 pub fn registered_delivery(mut self, registered_delivery: RegisteredDelivery) -> Self {
304 self.inner.registered_delivery = registered_delivery;
305 self
306 }
307
308 pub fn replace_if_present_flag(
309 mut self,
310 replace_if_present_flag: ReplaceIfPresentFlag,
311 ) -> Self {
312 self.inner.replace_if_present_flag = replace_if_present_flag;
313 self
314 }
315
316 pub fn data_coding(mut self, data_coding: DataCoding) -> Self {
317 self.inner.data_coding = data_coding;
318 self
319 }
320
321 pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
322 self.inner.sm_default_msg_id = sm_default_msg_id;
323 self
324 }
325
326 pub fn short_message(mut self, short_message: OctetString<0, 255>) -> Self {
327 self.inner.set_short_message(short_message);
328 self
329 }
330
331 pub fn tlvs(mut self, tlvs: alloc::vec::Vec<MessageSubmissionRequestTlvValue>) -> Self {
332 self.inner.set_tlvs(tlvs);
333 self
334 }
335
336 pub fn clear_tlvs(mut self) -> Self {
337 self.inner.clear_tlvs();
338 self
339 }
340
341 pub fn push_tlv(mut self, tlv: impl Into<MessageSubmissionRequestTlvValue>) -> Self {
342 self.inner.push_tlv(tlv);
343 self
344 }
345
346 pub fn build(self) -> SubmitSm {
347 self.inner
348 }
349}
350
351#[cfg(test)]
352mod tests {
353 use std::str::FromStr;
354
355 use crate::{tests::TestInstance, types::owned::AnyOctetString};
356
357 use super::*;
358
359 impl TestInstance for SubmitSm {
360 fn instances() -> alloc::vec::Vec<Self> {
361 alloc::vec![
362 Self::default(),
363 Self::builder()
364 .service_type(ServiceType::new(
365 GenericServiceType::CellularMessaging.into(),
366 ))
367 .source_addr_ton(Ton::International)
368 .source_addr_npi(Npi::Isdn)
369 .source_addr(COctetString::from_str("Source Address").unwrap())
370 .dest_addr_ton(Ton::International)
371 .dest_addr_npi(Npi::Isdn)
372 .destination_addr(COctetString::from_str("Destination Address").unwrap())
373 .esm_class(EsmClass::new(
374 MessagingMode::StoreAndForward,
375 MessageType::ShortMessageContainsMCDeliveryReceipt,
376 Ansi41Specific::ShortMessageContainsDeliveryAcknowledgement,
377 GsmFeatures::SetUdhiAndReplyPath,
378 ))
379 .protocol_id(0)
380 .priority_flag(PriorityFlag::from(PriorityFlagType::from(Ansi136::Bulk)))
381 .schedule_delivery_time(
382 EmptyOrFullCOctetString::from_static_slice(b"2023-09-01T12:00\0").unwrap(),
383 )
384 .validity_period(EmptyOrFullCOctetString::from_str("2023-10-01T12:00").unwrap())
385 .registered_delivery(RegisteredDelivery::request_all())
386 .replace_if_present_flag(ReplaceIfPresentFlag::Replace)
387 .data_coding(DataCoding::Ksc5601)
388 .sm_default_msg_id(69)
389 .short_message(OctetString::from_static_slice(b"Short Message").unwrap())
390 .build(),
391 Self::builder()
392 .service_type(ServiceType::new(
393 GenericServiceType::CellularMessaging.into(),
394 ))
395 .source_addr_ton(Ton::International)
396 .source_addr_npi(Npi::Isdn)
397 .source_addr(COctetString::from_static_slice(b"Source Address\0").unwrap())
398 .dest_addr_ton(Ton::International)
399 .dest_addr_npi(Npi::Isdn)
400 .destination_addr(
401 COctetString::from_static_slice(b"Destination Address\0").unwrap()
402 )
403 .esm_class(EsmClass::new(
404 MessagingMode::Default,
405 MessageType::ShortMessageContainsIntermediateDeliveryNotification,
406 Ansi41Specific::ShortMessageContainsUserAcknowledgment,
407 GsmFeatures::SetUdhiAndReplyPath,
408 ))
409 .protocol_id(0)
410 .priority_flag(PriorityFlag::from(PriorityFlagType::from(
411 Ansi136::VeryUrgent,
412 )))
413 .schedule_delivery_time(
414 EmptyOrFullCOctetString::from_static_slice(b"2023-09-01T12:01\0").unwrap(),
415 )
416 .validity_period(EmptyOrFullCOctetString::from_str("2023-10-01T12:20").unwrap())
417 .registered_delivery(RegisteredDelivery::request_all())
418 .replace_if_present_flag(ReplaceIfPresentFlag::DoNotReplace)
419 .data_coding(DataCoding::Jis)
420 .sm_default_msg_id(96)
421 .short_message(OctetString::from_static_slice(b"Short Message").unwrap())
422 .tlvs(alloc::vec![
423 MessageSubmissionRequestTlvValue::MessagePayload(MessagePayload::new(
424 AnyOctetString::from_static_slice(b"Message Payload")
425 ),)
426 ])
427 .build(),
428 Self::builder()
429 .short_message(OctetString::from_static_slice(b"Short Message").unwrap())
430 .tlvs(alloc::vec![
431 MessageSubmissionRequestTlvValue::MessagePayload(MessagePayload::new(
432 AnyOctetString::from_static_slice(b"Message Payload"),
433 )),
434 MessageSubmissionRequestTlvValue::UserResponseCode(3),
435 MessageSubmissionRequestTlvValue::DestBearerType(BearerType::FlexReFlex),
436 MessageSubmissionRequestTlvValue::SourceSubaddress(Subaddress::new(
437 SubaddressTag::NsapOdd,
438 OctetString::from_str("Subaddress :D").unwrap(),
439 )),
440 ])
441 .build(),
442 ]
443 }
444 }
445
446 #[test]
447 fn encode_decode() {
448 crate::tests::owned::encode_decode_with_length_test_instances::<SubmitSm>();
449 }
450
451 #[test]
452 fn short_message_length() {
453 let short_message = OctetString::from_static_slice(b"Short Message").unwrap();
454
455 let submit_sm = SubmitSm::builder()
456 .short_message(short_message.clone())
457 .build();
458
459 assert_eq!(submit_sm.short_message(), &short_message);
460 assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
461 }
462}