matc/
messages.rs

1use anyhow::{Context, Result};
2use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
3use core::fmt;
4use rand::RngCore;
5use std::io::{Read, Write};
6
7use crate::tlv::{self, TlvItem, TlvItemEnc, TlvItemValueEnc};
8
9#[derive(Debug)]
10pub struct MessageHeader {
11    pub flags: u8,
12    pub security_flags: u8,
13    pub session_id: u16,
14    pub message_counter: u32,
15    pub source_node_id: Option<Vec<u8>>,
16    pub destination_node_id: Option<Vec<u8>>,
17}
18
19impl MessageHeader {
20    const FLAG_SRC_PRESENT: u8 = 4;
21    const DSIZ_64: u8 = 1;
22    const DSIZ_16: u8 = 2;
23    pub fn encode(&self) -> Result<Vec<u8>> {
24        let mut flags: u8 = 0;
25        if self.source_node_id.as_ref().is_some_and(|x| x.len() == 8) {
26            flags |= Self::FLAG_SRC_PRESENT;
27        }
28        if let Some(destination_node_id) = &self.destination_node_id {
29            if destination_node_id.len() == 2 {
30                flags |= Self::DSIZ_16
31            } else if destination_node_id.len() == 8 {
32                flags |= Self::DSIZ_64
33            }
34        }
35        let mut out = Vec::with_capacity(1024);
36        out.write_u8(flags)?;
37        out.write_u16::<LittleEndian>(self.session_id)?;
38        out.write_u8(self.security_flags)?;
39        out.write_u32::<LittleEndian>(self.message_counter)?;
40        if let Some(sn) = &self.source_node_id {
41            if sn.len() == 8 {
42                out.write_all(sn)?;
43            }
44        }
45        if let Some(destination_node_id) = &self.destination_node_id {
46            out.write_all(destination_node_id)?;
47        }
48        Ok(out)
49    }
50    pub fn decode(data: &[u8]) -> Result<(Self, Vec<u8>)> {
51        let mut cursor = std::io::Cursor::new(data);
52        let flags = cursor.read_u8()?;
53        let session_id = cursor.read_u16::<LittleEndian>()?;
54        let security_flags = cursor.read_u8()?;
55        let message_counter = cursor.read_u32::<LittleEndian>()?;
56        let source_node_id = if (flags & Self::FLAG_SRC_PRESENT) != 0 {
57            let mut sn = vec![0; 8];
58            cursor.read_exact(sn.as_mut())?;
59            Some(sn)
60        } else {
61            None
62        };
63        let destination_node_id = if (flags & 3) != 0 {
64            let dst_size = match flags & 3 {
65                Self::DSIZ_64 => 8,
66                Self::DSIZ_16 => 2,
67                _ => 0,
68            };
69            if dst_size > 0 {
70                let mut dn = vec![0; dst_size];
71                cursor.read_exact(dn.as_mut())?;
72                Some(dn)
73            } else {
74                None
75            }
76        } else {
77            None
78        };
79        let mut rest = Vec::new();
80        cursor.read_to_end(&mut rest)?;
81        Ok((
82            Self {
83                flags,
84                security_flags,
85                session_id,
86                message_counter,
87                source_node_id,
88                destination_node_id,
89            },
90            rest,
91        ))
92    }
93}
94
95/*#[derive(Debug)]
96enum SecChannelOpcode {
97    None = 0x0,
98    Ack = 0x10,
99    PbkdfReq = 0x20,
100    PbkdfResp = 0x21,
101    Pake1 = 0x22,
102    Pake2 = 0x23,
103    Pake3 = 0x24,
104    Sigma1 = 0x30,
105    Sigma2 = 0x31,
106    Sigma3 = 0x32,
107    Status = 0x40,
108}*/
109
110#[derive(Debug)]
111pub struct ProtocolMessageHeader {
112    exchange_flags: u8,
113    pub opcode: u8,
114    pub exchange_id: u16,
115    pub protocol_id: u16,
116    pub ack_counter: u32,
117}
118
119impl ProtocolMessageHeader {
120    pub const FLAG_INITIATOR: u8 = 1;
121    pub const FLAG_ACK: u8 = 2;
122    pub const FLAG_RELIABILITY: u8 = 4;
123
124    pub const OPCODE_ACK: u8 = 0x10;
125    pub const OPCODE_PBKDF_REQ: u8 = 0x20;
126    pub const OPCODE_PBKDF_RESP: u8 = 0x21;
127    pub const OPCODE_PASE_PAKE1: u8 = 0x22;
128    pub const OPCODE_PASE_PAKE2: u8 = 0x23;
129    pub const OPCODE_PASE_PAKE3: u8 = 0x24;
130    pub const OPCODE_CASE_SIGMA1: u8 = 0x30;
131    pub const OPCODE_CASE_SIGMA2: u8 = 0x31;
132    pub const OPCODE_CASE_SIGMA3: u8 = 0x32;
133    pub const OPCODE_STATUS: u8 = 0x40;
134
135    pub const INTERACTION_OPCODE_STATUS_RESP: u8 = 0x1;
136    pub const INTERACTION_OPCODE_READ_REQ: u8 = 0x2;
137    pub const INTERACTION_OPCODE_REPORT_DATA: u8 = 0x5;
138    pub const INTERACTION_OPCODE_INVOKE_REQ: u8 = 0x8;
139    pub const INTERACTION_OPCODE_INVOKE_RESP: u8 = 0x9;
140    pub const INTERACTION_OPCODE_TIMED_REQ: u8 = 0xa;
141
142    pub const PROTOCOL_ID_SECURE_CHANNEL: u16 = 0;
143    pub const PROTOCOL_ID_INTERACTION: u16 = 1;
144
145    pub fn encode(&self) -> Result<Vec<u8>> {
146        let mut out = Vec::with_capacity(1024);
147        out.write_u8(self.exchange_flags)?;
148        out.write_u8(self.opcode)?;
149        out.write_u16::<LittleEndian>(self.exchange_id)?;
150        out.write_u16::<LittleEndian>(self.protocol_id)?;
151        if (self.exchange_flags & Self::FLAG_ACK) != 0 {
152            out.write_u32::<LittleEndian>(self.ack_counter)?;
153        }
154        Ok(out)
155    }
156    pub fn decode(data: &[u8]) -> Result<(Self, Vec<u8>)> {
157        let mut cursor = std::io::Cursor::new(data);
158        let exchange_flags = cursor.read_u8()?;
159        let opcode = cursor.read_u8()?;
160        let exchange_id = cursor.read_u16::<LittleEndian>()?;
161        let protocol_id = cursor.read_u16::<LittleEndian>()?;
162        let mut ack_counter = 0;
163        if (exchange_flags & Self::FLAG_ACK) != 0 {
164            ack_counter = cursor.read_u32::<LittleEndian>()?;
165        }
166        let mut rest = Vec::new();
167        cursor.read_to_end(&mut rest)?;
168        Ok((
169            Self {
170                exchange_flags,
171                opcode,
172                exchange_id,
173                protocol_id,
174                ack_counter,
175            },
176            rest,
177        ))
178    }
179}
180
181
182#[derive(Debug, Clone, Copy)]
183pub enum SecureChannelGeneralCode {
184    Success = 0,
185    Failure = 1,
186    BadPrecondition = 2,
187    OutOfRange = 3,
188    BadRequest = 4,
189    Unsupported = 5,
190    Unexpected = 6,
191    ResourceExhausted = 7,
192    Busy = 8,
193    Timeout = 9,
194    Continue = 10,
195    Aborted = 11,
196    InvalidArgument = 12,
197    NotFound = 13,
198    AlreadyExists = 14,
199    PermissionDenied = 15,
200    DataLoss = 16,
201    MessageTooLarge = 17,
202    Unknown = 0xffff
203}
204
205impl From<u16> for SecureChannelGeneralCode {
206    fn from(value: u16) -> Self {
207        match value {
208            0 => SecureChannelGeneralCode::Success,
209            1 => SecureChannelGeneralCode::Failure,
210            2 => SecureChannelGeneralCode::BadPrecondition,
211            3 => SecureChannelGeneralCode::OutOfRange,
212            4 => SecureChannelGeneralCode::BadRequest,
213            5 => SecureChannelGeneralCode::Unsupported,
214            6 => SecureChannelGeneralCode::Unexpected,
215            7 => SecureChannelGeneralCode::ResourceExhausted,
216            8 => SecureChannelGeneralCode::Busy,
217            9 => SecureChannelGeneralCode::Timeout,
218            10 => SecureChannelGeneralCode::Continue,
219            11 => SecureChannelGeneralCode::Aborted,
220            12 => SecureChannelGeneralCode::InvalidArgument,
221            13 => SecureChannelGeneralCode::NotFound,
222            14 => SecureChannelGeneralCode::AlreadyExists,
223            15 => SecureChannelGeneralCode::PermissionDenied,
224            16 => SecureChannelGeneralCode::DataLoss,
225            17 => SecureChannelGeneralCode::MessageTooLarge,
226            _ => SecureChannelGeneralCode::Unknown
227        }
228    }
229}
230
231impl std::fmt::Display for SecureChannelGeneralCode {
232    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233        match self {
234            SecureChannelGeneralCode::Success => write!(f, "SUCCESS"),
235            SecureChannelGeneralCode::Failure => write!(f, "FAILURE"),
236            SecureChannelGeneralCode::BadPrecondition => write!(f, "BAD_PRECONDITION"),
237            SecureChannelGeneralCode::OutOfRange => write!(f, "OUT_OF_RANGE"),
238            SecureChannelGeneralCode::BadRequest => write!(f, "BAD_REQUEST"),
239            SecureChannelGeneralCode::Unsupported => write!(f, "UNSUPPORTED"),
240            SecureChannelGeneralCode::Unexpected => write!(f, "UNEXPECTED"),
241            SecureChannelGeneralCode::ResourceExhausted => write!(f, "RESOURCE_EXHAUSTED"),
242            SecureChannelGeneralCode::Busy => write!(f, "BUSY"),
243            SecureChannelGeneralCode::Timeout => write!(f, "TIMEOUT"),
244            SecureChannelGeneralCode::Continue => write!(f, "CONTINUE"),
245            SecureChannelGeneralCode::Aborted => write!(f, "ABORTED"),
246            SecureChannelGeneralCode::InvalidArgument => write!(f, "INVALID_ARGUMENT"),
247            SecureChannelGeneralCode::NotFound => write!(f, "NOT_FOUND"),
248            SecureChannelGeneralCode::AlreadyExists => write!(f, "ALREADY_EXISTS"),
249            SecureChannelGeneralCode::PermissionDenied => write!(f, "PERMISSION_DENIED"),
250            SecureChannelGeneralCode::DataLoss => write!(f, "DATA_LOSS"),
251            SecureChannelGeneralCode::MessageTooLarge => write!(f, "MESSAGE_TOO_LARGE"),
252            SecureChannelGeneralCode::Unknown => write!(f, "UNKNOWN {}", *self as u16),
253        }
254    }
255}
256
257#[derive(Debug, Clone, Copy)]
258pub enum SecureChannelProtocolCode {
259    SessionEstablishmentSuccess = 0,
260    NoSharedTrustRoots = 1,
261    InvalidParameter = 2,
262    CloseSession = 3,
263    Busy = 4,
264    RequiredCatMismatch = 5,
265    Unknown = 0xffff
266}
267
268impl std::fmt::Display for SecureChannelProtocolCode {
269    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270        match self {
271            SecureChannelProtocolCode::SessionEstablishmentSuccess => write!(f, "SESSION_ESTABLISHMENT_SUCCESS"),
272            SecureChannelProtocolCode::NoSharedTrustRoots => write!(f, "NO_SHARED_TRUST_ROOTS"),
273            SecureChannelProtocolCode::InvalidParameter => write!(f, "INVALID_PARAMETER"),
274            SecureChannelProtocolCode::CloseSession => write!(f, "CLOSE_SESSION"),
275            SecureChannelProtocolCode::Busy => write!(f, "BUSY"),
276            SecureChannelProtocolCode::RequiredCatMismatch => write!(f, "REQUIRED_CAT_MISMATCH"),
277            SecureChannelProtocolCode::Unknown => write!(f, "UNKNOWN {}", *self as u16),
278        }
279    }
280}
281
282impl From<u16> for SecureChannelProtocolCode {
283    fn from(value: u16) -> Self {
284        match value {
285            0 => SecureChannelProtocolCode::SessionEstablishmentSuccess,
286            1 => SecureChannelProtocolCode::NoSharedTrustRoots,
287            2 => SecureChannelProtocolCode::InvalidParameter,
288            3 => SecureChannelProtocolCode::CloseSession,
289            4 => SecureChannelProtocolCode::Busy,
290            5 => SecureChannelProtocolCode::RequiredCatMismatch,
291            _ => SecureChannelProtocolCode::Unknown,
292        }
293    }
294}
295
296#[derive(Debug, Clone, Copy)]
297pub struct StatusReportInfo {
298    general_code: u16,
299    protocol_id: u32,
300    protocol_code: u16,
301}
302impl std::fmt::Display for StatusReportInfo {
303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304        if self.general_code == 0 {
305            return write!(f, "StatusReportInfo: OK");
306        }
307        let gc = Into::<SecureChannelGeneralCode>::into(self.general_code);
308        match self.protocol_id as u16{
309            ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL => {
310                let pc = Into::<SecureChannelProtocolCode>::into(self.protocol_code);
311                write!(
312                    f,
313                    "StatusReportInfo: general_code={}, protocol_id={}, protocol_code={}",
314                    gc, self.protocol_id, pc
315                )
316
317            },
318            _ => {
319                write!(f, "StatusReportInfo: general_code={}, protocol_id={}, protocol_code={}",
320                    gc, self.protocol_id, self.protocol_code
321                )
322            }
323
324        }
325    }
326}
327impl StatusReportInfo {
328    fn parse(data: &[u8]) -> Result<Self> {
329        let mut cursor = std::io::Cursor::new(data);
330        let general_code = cursor.read_u16::<LittleEndian>()?;
331        let protocol_id = cursor.read_u32::<LittleEndian>()?;
332        let protocol_code = cursor.read_u16::<LittleEndian>()?;
333        Ok(Self {
334            general_code,
335            protocol_id,
336            protocol_code,
337        })
338    }
339    pub fn is_ok(&self) -> bool {
340        self.general_code == 0 && self.protocol_id == 0 && self.protocol_code == 0
341    }
342}
343
344pub struct Message {
345    pub message_header: MessageHeader,
346    pub protocol_header: ProtocolMessageHeader,
347    pub payload: Vec<u8>,
348    pub tlv: TlvItem,
349    pub status_report_info: Option<StatusReportInfo>,
350}
351
352impl fmt::Debug for Message {
353    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
354        f.debug_struct("Message")
355            .field("message_header", &self.message_header)
356            .field("protocol_header", &self.protocol_header)
357            .field("payload", &hex::encode(&self.payload))
358            .field("tlv", &self.tlv)
359            .field("status_report_info", &self.status_report_info)
360            .finish()
361    }
362}
363
364impl Message {
365    pub fn decode(data: &[u8]) -> Result<Self> {
366        let (message_header, rest) = MessageHeader::decode(data)?;
367        let (protocol_header, rest) = ProtocolMessageHeader::decode(&rest)?;
368        if (protocol_header.protocol_id == ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL)
369            && (protocol_header.opcode == ProtocolMessageHeader::OPCODE_STATUS)
370        {
371            let status_report_info = StatusReportInfo::parse(&rest)?;
372            return Ok(Self {
373                message_header,
374                protocol_header,
375                payload: rest,
376                tlv: TlvItem {
377                    tag: 0,
378                    value: tlv::TlvItemValue::Invalid(),
379                },
380                status_report_info: Some(status_report_info),
381            });
382        }
383        let tlv = tlv::decode_tlv(&rest)?;
384        Ok(Self {
385            message_header,
386            protocol_header,
387            payload: rest,
388            tlv,
389            status_report_info: None,
390        })
391    }
392}
393
394pub fn ack(exchange: u16, ack: i64) -> Result<Vec<u8>> {
395    let mut flags = ProtocolMessageHeader::FLAG_INITIATOR;
396    flags |= ProtocolMessageHeader::FLAG_ACK;
397    ProtocolMessageHeader {
398        exchange_flags: flags,
399        opcode: ProtocolMessageHeader::OPCODE_ACK,
400        exchange_id: exchange,
401        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
402        ack_counter: ack as u32,
403    }
404    .encode()
405}
406
407pub fn pbkdf_req(exchange: u16) -> Result<Vec<u8>> {
408    let mut b = ProtocolMessageHeader {
409        exchange_flags: ProtocolMessageHeader::FLAG_INITIATOR
410            | ProtocolMessageHeader::FLAG_RELIABILITY,
411        opcode: ProtocolMessageHeader::OPCODE_PBKDF_REQ,
412        exchange_id: exchange,
413        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
414        ack_counter: 0,
415    }
416    .encode()?;
417    let mut tlv = tlv::TlvBuffer::new();
418    tlv.write_anon_struct()?;
419    let mut initiator_random = [0u8; 32];
420    rand::thread_rng().fill_bytes(&mut initiator_random);
421    tlv.write_octetstring(0x1, &initiator_random)?;
422    tlv.write_uint16(2, 1)?;
423    tlv.write_uint8(3, 0)?;
424    tlv.write_bool(4, false)?;
425    tlv.write_struct_end()?;
426    b.write_all(&tlv.data)?;
427    Ok(b)
428}
429
430pub fn pake1(exchange: u16, key: &[u8], ack: i64) -> Result<Vec<u8>> {
431    let mut flags = ProtocolMessageHeader::FLAG_INITIATOR | ProtocolMessageHeader::FLAG_RELIABILITY;
432    if ack >= 0 {
433        flags |= ProtocolMessageHeader::FLAG_ACK
434    }
435    let mut b = ProtocolMessageHeader {
436        exchange_flags: flags,
437        opcode: ProtocolMessageHeader::OPCODE_PASE_PAKE1,
438        exchange_id: exchange,
439        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
440        ack_counter: ack as u32,
441    }
442    .encode()?;
443
444    let tlv = TlvItemEnc {
445        tag: 0,
446        value: TlvItemValueEnc::StructAnon(vec![TlvItemEnc {
447            tag: 1,
448            value: TlvItemValueEnc::OctetString(key.to_owned()),
449        }]),
450    }
451    .encode()?;
452    b.write_all(&tlv)?;
453
454    Ok(b)
455}
456
457pub fn pake3(exchange: u16, key: &[u8], ack: i64) -> Result<Vec<u8>> {
458    let mut flags = 0x5;
459    if ack >= 0 {
460        flags |= 2
461    }
462    let mut b = ProtocolMessageHeader {
463        exchange_flags: flags,
464        opcode: ProtocolMessageHeader::OPCODE_PASE_PAKE3,
465        exchange_id: exchange,
466        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
467        ack_counter: ack as u32,
468    }
469    .encode()?;
470    let mut tlv = tlv::TlvBuffer::new();
471    tlv.write_anon_struct()?;
472    tlv.write_octetstring(0x1, key)?;
473    tlv.write_struct_end()?;
474
475    b.write_all(&tlv.data)?;
476    Ok(b)
477}
478
479pub fn sigma1(exchange: u16, payload: &[u8]) -> Result<Vec<u8>> {
480    let mut b = ProtocolMessageHeader {
481        exchange_flags: 5,
482        opcode: ProtocolMessageHeader::OPCODE_CASE_SIGMA1,
483        exchange_id: exchange,
484        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
485        ack_counter: 0,
486    }
487    .encode()?;
488    b.write_all(payload)?;
489    Ok(b)
490}
491
492pub fn sigma3(exchange: u16, payload: &[u8]) -> Result<Vec<u8>> {
493    let mut b = ProtocolMessageHeader {
494        exchange_flags: 5,
495        opcode: ProtocolMessageHeader::OPCODE_CASE_SIGMA3,
496        exchange_id: exchange,
497        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
498        ack_counter: 0,
499    }
500    .encode()?;
501    b.write_all(payload)?;
502    Ok(b)
503}
504
505pub fn im_invoke_request(
506    endpoint: u16,
507    cluster: u32,
508    command: u32,
509    exchange_id: u16,
510    payload: &[u8],
511    timed: bool,
512) -> Result<Vec<u8>> {
513    let b = ProtocolMessageHeader {
514        exchange_flags: 5,
515        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_INVOKE_REQ,
516        exchange_id,
517        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
518        ack_counter: 0,
519    }
520    .encode()?;
521
522    let mut tlv = tlv::TlvBuffer::from_vec(b);
523    tlv.write_anon_struct()?;
524    tlv.write_bool(0x0, false)?;
525    tlv.write_bool(0x1, timed)?; // timed
526    tlv.write_array(2)?;
527    tlv.write_anon_struct()?;
528    tlv.write_list(0)?;
529    tlv.write_uint16(0, endpoint)?;
530    tlv.write_uint32(1, cluster)?;
531    tlv.write_uint32(2, command)?;
532    tlv.write_struct_end()?;
533    tlv.write_struct(1)?;
534    tlv.write_raw(payload)?;
535    tlv.write_struct_end()?;
536    tlv.write_struct_end()?;
537    tlv.write_struct_end()?;
538    tlv.write_uint8(0xff, 10)?;
539    tlv.write_struct_end()?;
540    Ok(tlv.data)
541}
542
543pub fn im_timed_request(exchange_id: u16, timeout: u16) -> Result<Vec<u8>> {
544    let b = ProtocolMessageHeader {
545        exchange_flags: 5,
546        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_TIMED_REQ,
547        exchange_id,
548        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
549        ack_counter: 0,
550    }
551    .encode()?;
552
553    let mut tlv = tlv::TlvBuffer::from_vec(b);
554    tlv.write_anon_struct()?;
555    tlv.write_uint16(0, timeout)?;
556    tlv.write_uint8(0xff, 10)?;
557    tlv.write_struct_end()?;
558    Ok(tlv.data)
559}
560
561pub fn im_read_request(endpoint: u16, cluster: u32, attr: u32, exchange: u16) -> Result<Vec<u8>> {
562    let b = ProtocolMessageHeader {
563        exchange_flags: 5,
564        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_READ_REQ,
565        exchange_id: exchange,
566        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
567        ack_counter: 0,
568    }
569    .encode()?;
570
571    let mut tlv = tlv::TlvBuffer::from_vec(b);
572    tlv.write_anon_struct()?;
573    tlv.write_array(0)?;
574    tlv.write_anon_list()?;
575    tlv.write_uint16(2, endpoint)?;
576    tlv.write_uint32(3, cluster)?;
577    tlv.write_uint32(4, attr)?;
578    tlv.write_struct_end()?;
579    tlv.write_struct_end()?;
580    tlv.write_bool(3, true)?;
581    tlv.write_uint8(0xff, 10)?;
582    tlv.write_struct_end()?;
583    Ok(tlv.data)
584}
585
586pub fn parse_im_invoke_resp(resp: &TlvItem) -> Result<(u32, u32)> {
587    let common_status = resp
588        .get_int(&[1, 0, 1, 1, 0])
589        .context("parse_im_invoke_resp: status not found")?;
590    if common_status == 0 {
591        return Ok((0, 0));
592    }
593    let stat = resp
594        .get_int(&[1, 0, 1, 1, 1])
595        .context("parse_im_invoke_resp: unexpected response")?;
596    Ok((common_status as u32, stat as u32))
597}
598
599#[cfg(test)]
600mod tests {
601    use super::Message;
602
603    #[test]
604    pub fn test_1() {
605        let msg = "04000000a5a0b90d3320764c7d52ef86052060d5000015300120cabe444262d4e5dd568c755ed77e0829b9983c4d62b480b579811ec383eb69c625020837240300280418";
606        let msg = hex::decode(msg).unwrap();
607        let m = Message::decode(&msg).unwrap();
608        println!("{:?}", m);
609
610        let msg = "04000000000000000000000000000000012001000000153001203052998af1897150086e6c84003c074df93a796b4f68a9221ee4e40325014aaf25020100240300280418";
611        let msg = hex::decode(msg).unwrap();
612        let m = Message::decode(&msg).unwrap();
613        println!("{:?}", m);
614    }
615}