Skip to main content

smpp_codec/pdus/session_pdus/
generic_nack.rs

1use crate::common::{get_status_code, get_status_description, PduError, GENERIC_NACK, HEADER_LEN};
2use std::io::{Cursor, Read, Write};
3
4/// Represents a Generic NACK PDU.
5///
6/// Sent when a PDU cannot be identified or is malformed (e.g., invalid Command ID).
7#[derive(Debug, Clone)]
8pub struct GenericNack {
9    pub sequence_number: u32,
10    pub command_status: u32, // The error code explaining why the NACK was sent
11    pub status_name: String,
12}
13
14impl GenericNack {
15    /// Create a new Generic NACK.
16    ///
17    /// # Examples
18    ///
19    /// ```
20    /// use smpp_codec::pdus::GenericNack;
21    ///
22    /// let sequence_number: u32 = 1;
23    /// let nack = GenericNack::new("ESME_RINVCMDID", sequence_number);
24    /// ```
25    pub fn new(status_name: &str, sequence_number: u32) -> Self {
26        let command_status = get_status_code(status_name);
27        Self {
28            sequence_number,
29            command_status,
30            status_name: status_name.to_string(),
31        }
32    }
33
34    /// Encode the struct into raw bytes for the network.
35    ///
36    /// # Errors
37    ///
38    /// Returns a [`PduError`] if an I/O error occurs while writing.
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// # use smpp_codec::pdus::GenericNack;
44    /// # let sequence_number: u32 = 1;
45    /// # let nack = GenericNack::new("ESME_RINVCMDID", sequence_number);
46    /// let mut buffer = Vec::new();
47    /// nack.encode(&mut buffer).expect("Encoding failed");
48    /// ```
49    pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
50        let command_len = HEADER_LEN as u32;
51        writer.write_all(&command_len.to_be_bytes())?;
52        writer.write_all(&GENERIC_NACK.to_be_bytes())?;
53        writer.write_all(&self.command_status.to_be_bytes())?;
54        writer.write_all(&self.sequence_number.to_be_bytes())?;
55        Ok(())
56    }
57
58    /// Decode raw bytes from the network into the struct.
59    ///
60    /// # Errors
61    ///
62    /// Returns a [`PduError`] if the buffer is too short.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// # use smpp_codec::pdus::GenericNack;
68    /// # let sequence_number: u32 = 1;
69    /// # let nack = GenericNack::new("ESME_RINVCMDID", sequence_number);
70    /// # let mut buffer = Vec::new();
71    /// # nack.encode(&mut buffer).unwrap();
72    /// let decoded = GenericNack::decode(&buffer).expect("Decoding failed");
73    /// assert_eq!(decoded.status_name, "ESME_RINVCMDID");
74    /// ```
75    pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
76        if buffer.len() < HEADER_LEN {
77            return Err(PduError::BufferTooShort);
78        }
79        let mut cursor = Cursor::new(buffer);
80
81        // Skip Length (4) and ID (4)
82        cursor.set_position(8);
83
84        let mut bytes = [0u8; 4];
85
86        // Status
87        cursor.read_exact(&mut bytes)?;
88        let command_status = u32::from_be_bytes(bytes);
89
90        // Sequence
91        cursor.read_exact(&mut bytes)?;
92        let sequence_number = u32::from_be_bytes(bytes);
93
94        Ok(Self {
95            sequence_number,
96            command_status,
97            status_name: get_status_description(command_status),
98        })
99    }
100}