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