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