Skip to main content

smpp_codec/pdus/ancillary_pdus/
query_sm.rs

1use crate::common::{get_status_code, Npi, PduError, Ton, CMD_QUERY_SM, HEADER_LEN};
2use std::io::{Cursor, Read, Write};
3
4// --- Request ---
5#[derive(Debug, Clone)]
6pub struct QuerySmRequest {
7    pub sequence_number: u32,
8    pub message_id: String,
9    pub source_addr_ton: Ton,
10    pub source_addr_npi: Npi,
11    pub source_addr: String,
12}
13
14impl QuerySmRequest {
15    pub fn new(sequence_number: u32, message_id: String, source_addr: String) -> Self {
16        Self {
17            sequence_number,
18            message_id,
19            source_addr_ton: Ton::Unknown,
20            source_addr_npi: Npi::Unknown,
21            source_addr,
22        }
23    }
24
25    pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
26        // 1. Validation
27        if self.message_id.len() > 64 {
28            return Err(PduError::StringTooLong("message_id".into(), 64));
29        }
30        if self.source_addr.len() > 21 {
31            return Err(PduError::StringTooLong("source_addr".into(), 21));
32        }
33
34        // 2. Buffer Body to Calculate Length
35        let mut body = Vec::new();
36        write_c_string(&mut body, &self.message_id)?;
37        body.write_all(&[self.source_addr_ton as u8, self.source_addr_npi as u8])?;
38        write_c_string(&mut body, &self.source_addr)?;
39
40        // 3. Write Header
41        let command_len = (HEADER_LEN + body.len()) as u32;
42        writer.write_all(&command_len.to_be_bytes())?;
43        writer.write_all(&CMD_QUERY_SM.to_be_bytes())?;
44        writer.write_all(&0u32.to_be_bytes())?;
45        writer.write_all(&self.sequence_number.to_be_bytes())?;
46
47        // 4. Write Body
48        writer.write_all(&body)?;
49
50        Ok(())
51    }
52
53    pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
54        if buffer.len() < HEADER_LEN {
55            return Err(PduError::BufferTooShort);
56        }
57
58        let mut cursor = Cursor::new(buffer);
59        cursor.set_position(12);
60
61        let mut bytes = [0u8; 4];
62        cursor.read_exact(&mut bytes)?;
63        let sequence_number = u32::from_be_bytes(bytes);
64
65        let message_id = crate::common::read_c_string(&mut cursor)?;
66
67        let mut u8_buf = [0u8; 1];
68        cursor.read_exact(&mut u8_buf)?;
69        let source_addr_ton = Ton::from(u8_buf[0]);
70        cursor.read_exact(&mut u8_buf)?;
71        let source_addr_npi = Npi::from(u8_buf[0]);
72
73        let source_addr = crate::common::read_c_string(&mut cursor)?;
74
75        Ok(Self {
76            sequence_number,
77            message_id,
78            source_addr_ton,
79            source_addr_npi,
80            source_addr,
81        })
82    }
83}
84
85/// Query_SM Response
86#[derive(Debug, Clone)]
87pub struct QuerySmResponse {
88    pub sequence_number: u32,
89    pub command_status: u32,
90    pub message_id: String,
91    pub final_date: String,
92    pub message_state: u8,
93    pub error_code: u8,
94    pub status_description: String,
95}
96
97// Message States (SMPP v3.4 Spec section 5.2.28)
98#[derive(Debug, Clone, Copy, PartialEq)]
99#[repr(u8)]
100pub enum MessageState {
101    Enroute = 1,
102    Delivered = 2,
103    Expired = 3,
104    Deleted = 4,
105    Undeliverable = 5,
106    Accepted = 6,
107    Unknown = 7,
108    Rejected = 8,
109}
110
111impl QuerySmResponse {
112    pub fn new(
113        sequence_number: u32,
114        status_name: &str,
115        message_id: String,
116        final_date: String,
117        message_state: u8,
118        error_code: u8,
119    ) -> Self {
120        let command_status = get_status_code(status_name);
121        Self {
122            sequence_number,
123            command_status,
124            message_id,
125            final_date,
126            message_state,
127            error_code,
128            status_description: status_name.to_string(),
129        }
130    }
131
132    pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
133        let mut body = Vec::new();
134
135        if self.command_status == 0 {
136            write_c_string(&mut body, &self.message_id)?;
137            write_c_string(&mut body, &self.final_date)?;
138            body.write_all(&[self.message_state, self.error_code])?;
139        }
140
141        let command_len = (HEADER_LEN + body.len()) as u32;
142        writer.write_all(&command_len.to_be_bytes())?;
143        writer.write_all(&crate::common::CMD_QUERY_SM_RESP.to_be_bytes())?;
144        writer.write_all(&self.command_status.to_be_bytes())?;
145        writer.write_all(&self.sequence_number.to_be_bytes())?;
146        writer.write_all(&body)?;
147
148        Ok(())
149    }
150
151    pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
152        if buffer.len() < HEADER_LEN {
153            return Err(PduError::BufferTooShort);
154        }
155        let mut cursor = Cursor::new(buffer);
156        cursor.set_position(8);
157
158        let mut bytes = [0u8; 4];
159        cursor.read_exact(&mut bytes)?;
160        let command_status = u32::from_be_bytes(bytes);
161        cursor.read_exact(&mut bytes)?;
162        let sequence_number = u32::from_be_bytes(bytes);
163
164        let message_id: String;
165        let final_date: String;
166        let message_state: u8;
167        let error_code: u8;
168
169        if command_status == 0 && buffer.len() > HEADER_LEN {
170            message_id = crate::common::read_c_string(&mut cursor)?;
171            final_date = crate::common::read_c_string(&mut cursor)?;
172
173            let mut u8_buf = [0u8; 1];
174            cursor.read_exact(&mut u8_buf)?;
175            message_state = u8_buf[0];
176            cursor.read_exact(&mut u8_buf)?;
177            error_code = u8_buf[0];
178        } else {
179            message_id = String::new();
180            final_date = String::new();
181            message_state = 0;
182            error_code = 0;
183        }
184
185        let status_description = crate::common::get_status_description(command_status);
186
187        Ok(Self {
188            sequence_number,
189            command_status,
190            message_id,
191            final_date,
192            message_state,
193            error_code,
194            status_description,
195        })
196    }
197}
198
199// Helpers
200fn write_c_string(w: &mut impl Write, s: &str) -> std::io::Result<()> {
201    w.write_all(s.as_bytes())?;
202    w.write_all(&[0])
203}