smpp_codec/pdus/session_pdus/outbind.rs
1use crate::common::{write_c_string, PduError, CMD_OUTBIND, HEADER_LEN};
2use std::io::{Cursor, Read, Write};
3
4/// Represents an Outbind PDU.
5///
6/// Sent by the SMSC to the ESME to request the ESME to initiate a Bind.
7#[derive(Debug, Clone)]
8pub struct OutbindRequest {
9 pub sequence_number: u32,
10 pub system_id: String,
11 pub password: String,
12}
13
14impl OutbindRequest {
15 /// Create a new Outbind Request.
16 ///
17 /// # Examples
18 ///
19 /// ```
20 /// use smpp_codec::pdus::OutbindRequest;
21 ///
22 /// let sequence_number: u32 = 1;
23 /// let outbind = OutbindRequest::new(
24 /// sequence_number, // Sequence number
25 /// "my_system_id".to_string(),
26 /// "password".to_string(),
27 /// );
28 /// ```
29 pub fn new(sequence_number: u32, system_id: String, password: String) -> Self {
30 Self {
31 sequence_number,
32 system_id,
33 password,
34 }
35 }
36
37 /// Encode the struct into raw bytes for the network.
38 ///
39 /// # Errors
40 ///
41 /// Returns a [`PduError`] if:
42 /// * `system_id` exceeds 16 characters.
43 /// * `password` exceeds 9 characters.
44 /// * An I/O error occurs while writing.
45 ///
46 /// # Examples
47 ///
48 /// ```
49 /// # use smpp_codec::pdus::OutbindRequest;
50 /// # let sequence_number: u32 = 1;
51 /// # let outbind = OutbindRequest::new(sequence_number, "id".into(), "pwd".into());
52 /// let mut buffer = Vec::new();
53 /// outbind.encode(&mut buffer).expect("Encoding failed");
54 /// ```
55 pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
56 // Validate
57 if self.system_id.len() > 16 {
58 return Err(PduError::StringTooLong("system_id".into(), 16));
59 }
60 if self.password.len() > 9 {
61 return Err(PduError::StringTooLong("password".into(), 9));
62 }
63
64 let mut body = Vec::new();
65 write_c_string(&mut body, &self.system_id)?;
66 write_c_string(&mut body, &self.password)?;
67
68 let command_len = (HEADER_LEN + body.len()) as u32;
69
70 // Header
71 writer.write_all(&command_len.to_be_bytes())?;
72 writer.write_all(&CMD_OUTBIND.to_be_bytes())?;
73 writer.write_all(&0u32.to_be_bytes())?; // Status is always 0
74 writer.write_all(&self.sequence_number.to_be_bytes())?;
75
76 // Body
77 writer.write_all(&body)?;
78
79 Ok(())
80 }
81
82 /// Decode raw bytes from the network into the struct.
83 ///
84 /// # Errors
85 ///
86 /// Returns a [`PduError`] if:
87 /// * The buffer is too short.
88 /// * The buffer data is malformed.
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// # use smpp_codec::pdus::OutbindRequest;
94 /// # let sequence_number: u32 = 1;
95 /// # let outbind = OutbindRequest::new(sequence_number, "id".into(), "pwd".into());
96 /// # let mut buffer = Vec::new();
97 /// # outbind.encode(&mut buffer).unwrap();
98 /// let decoded = OutbindRequest::decode(&buffer).expect("Decoding failed");
99 /// assert_eq!(decoded.system_id, "id");
100 /// ```
101 pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
102 if buffer.len() < HEADER_LEN {
103 return Err(PduError::BufferTooShort);
104 }
105
106 let mut cursor = Cursor::new(buffer);
107
108 // Skip Header (assuming caller checked ID, or we just consume it)
109 cursor.set_position(12); // Skip len, id, status
110 let mut bytes = [0u8; 4];
111 cursor.read_exact(&mut bytes)?;
112 let sequence_number = u32::from_be_bytes(bytes);
113
114 // Body
115 let system_id = crate::common::read_c_string(&mut cursor)?;
116 let password = crate::common::read_c_string(&mut cursor)?;
117
118 Ok(Self {
119 sequence_number,
120 system_id,
121 password,
122 })
123 }
124}