Skip to main content

smpp_codec/pdus/session_pdus/
unbind.rs

1use crate::common::{
2    get_status_code, get_status_description, PduError, CMD_UNBIND, CMD_UNBIND_RESP, HEADER_LEN,
3};
4use std::io::{Cursor, Read, Write};
5
6// --- Unbind Request ---
7#[derive(Debug, Clone)]
8pub struct UnbindRequest {
9    pub sequence_number: u32,
10}
11
12impl UnbindRequest {
13    /// Create a new Unbind Request.
14    ///
15    /// # Examples
16    ///
17    /// ```
18    /// use smpp_codec::pdus::UnbindRequest;
19    ///
20    /// let sequence_number: u32 = 1;
21    /// let unbind_req = UnbindRequest::new(sequence_number);
22    /// ```
23    pub fn new(sequence_number: u32) -> Self {
24        Self { sequence_number }
25    }
26
27    /// Encode the struct into raw bytes for the network.
28    ///
29    /// # Errors
30    ///
31    /// Returns a [`PduError`] if an I/O error occurs while writing.
32    ///
33    /// # Examples
34    ///
35    /// ```
36    /// # use smpp_codec::pdus::UnbindRequest;
37    /// # let sequence_number: u32 = 1;
38    /// # let unbind_req = UnbindRequest::new(sequence_number);
39    /// let mut buffer = Vec::new();
40    /// unbind_req.encode(&mut buffer).expect("Encoding failed");
41    /// ```
42    pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
43        let command_len = HEADER_LEN as u32;
44        writer.write_all(&command_len.to_be_bytes())?;
45        writer.write_all(&CMD_UNBIND.to_be_bytes())?;
46        writer.write_all(&0u32.to_be_bytes())?; // Status always 0 for requests
47        writer.write_all(&self.sequence_number.to_be_bytes())?;
48        Ok(())
49    }
50
51    /// Decode raw bytes from the network into the struct.
52    ///
53    /// # Errors
54    ///
55    /// Returns a [`PduError`] if the buffer is too short.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// # use smpp_codec::pdus::UnbindRequest;
61    /// # let sequence_number: u32 = 1;
62    /// # let unbind_req = UnbindRequest::new(sequence_number);
63    /// # let mut buffer = Vec::new();
64    /// # unbind_req.encode(&mut buffer).unwrap();
65    /// let decoded = UnbindRequest::decode(&buffer).expect("Decoding failed");
66    /// assert_eq!(decoded.sequence_number, 1);
67    /// ```
68    pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
69        if buffer.len() < HEADER_LEN {
70            return Err(PduError::BufferTooShort);
71        }
72        let mut cursor = Cursor::new(buffer);
73        cursor.set_position(12); // Skip len, id, status
74
75        let mut bytes = [0u8; 4];
76        cursor.read_exact(&mut bytes)?;
77        let sequence_number = u32::from_be_bytes(bytes);
78
79        Ok(Self { sequence_number })
80    }
81}
82
83// --- Unbind Response ---
84#[derive(Debug, Clone)]
85pub struct UnbindResponse {
86    pub sequence_number: u32,
87    pub command_status: u32,
88    pub status_description: String,
89}
90
91impl UnbindResponse {
92    /// Create a new Unbind Response.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use smpp_codec::pdus::UnbindResponse;
98    ///
99    /// let sequence_number: u32 = 1;
100    /// let unbind_resp = UnbindResponse::new(sequence_number, "ESME_ROK");
101    /// ```
102    pub fn new(sequence_number: u32, status_name: &str) -> Self {
103        let command_status = get_status_code(status_name);
104        Self {
105            sequence_number,
106            command_status,
107            status_description: status_name.to_string(),
108        }
109    }
110
111    /// Encode the struct into raw bytes for the network.
112    ///
113    /// # Errors
114    ///
115    /// Returns a [`PduError`] if an I/O error occurs while writing.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// # use smpp_codec::pdus::UnbindResponse;
121    /// # let sequence_number: u32 = 1;
122    /// # let unbind_resp = UnbindResponse::new(sequence_number, "ESME_ROK");
123    /// let mut buffer = Vec::new();
124    /// unbind_resp.encode(&mut buffer).expect("Encoding failed");
125    /// ```
126    pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
127        let command_len = HEADER_LEN as u32;
128        writer.write_all(&command_len.to_be_bytes())?;
129        writer.write_all(&CMD_UNBIND_RESP.to_be_bytes())?;
130        writer.write_all(&self.command_status.to_be_bytes())?;
131        writer.write_all(&self.sequence_number.to_be_bytes())?;
132        Ok(())
133    }
134
135    /// Decode raw bytes from the network into the struct.
136    ///
137    /// # Errors
138    ///
139    /// Returns a [`PduError`] if the buffer is too short.
140    ///
141    /// # Examples
142    ///
143    /// ```
144    /// # use smpp_codec::pdus::UnbindResponse;
145    /// # let sequence_number: u32 = 1;
146    /// # let unbind_resp = UnbindResponse::new(sequence_number, "ESME_ROK");
147    /// # let mut buffer = Vec::new();
148    /// # unbind_resp.encode(&mut buffer).unwrap();
149    /// let decoded = UnbindResponse::decode(&buffer).expect("Decoding failed");
150    /// assert_eq!(decoded.sequence_number, 1);
151    /// ```
152    pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
153        if buffer.len() < HEADER_LEN {
154            return Err(PduError::BufferTooShort);
155        }
156        let mut cursor = Cursor::new(buffer);
157
158        // Skip Length (4) + ID (4)
159        cursor.set_position(8);
160
161        let mut bytes = [0u8; 4];
162
163        // Read Status
164        cursor.read_exact(&mut bytes)?;
165        let command_status = u32::from_be_bytes(bytes);
166
167        // Read Sequence
168        cursor.read_exact(&mut bytes)?;
169        let sequence_number = u32::from_be_bytes(bytes);
170
171        Ok(Self {
172            sequence_number,
173            command_status,
174            status_description: get_status_description(command_status),
175        })
176    }
177}