Skip to main content

libquassel/primitive/
message.rs

1use std::vec::Vec;
2
3use failure::Error;
4
5use crate::{Deserialize, DeserializeUTF8};
6use crate::{Serialize, SerializeUTF8};
7
8use crate::primitive::BufferInfo;
9
10extern crate bytes;
11
12/// The Message struct represents a Message as received in IRC
13///
14/// Messages are, like all other struct based types, serialized sequentially.
15#[derive(Clone, Debug, std::cmp::PartialEq)]
16pub struct Message {
17    /// The unique, sequential id for the message
18    pub msg_id: i32,
19    /// The timestamp of the message in UNIX time (32-bit, seconds, 64-bit if LONGMESSAGE feature enabled)
20    pub timestamp: i64,
21    /// The message type as it's own type serialized as i32
22    pub msg_type: MessageType,
23    /// The flags
24    pub flags: i8,
25    /// The buffer the message belongs to, usually everything but BufferId is set to NULL
26    pub buffer: BufferInfo,
27    /// The sender as nick!ident@host
28    pub sender: String,
29    /// The prefix modes of the sender.
30    /// Only Some when the SenderPrefix features is enabled
31    pub sender_prefixes: Option<String>,
32    /// The realName of the sender
33    /// Only Some when the RichMessage features is enabled
34    pub real_name: Option<String>,
35    /// The avatarUrl of the sender, if available
36    /// Only Some when the RichMessage features is enabled
37    pub avatar_url: Option<String>,
38    /// The message content, already stripped from CTCP formatting, but containing mIRC format codes
39    pub content: String,
40}
41
42impl Serialize for Message {
43    fn serialize(&self) -> Result<Vec<u8>, Error> {
44        let mut values: Vec<u8> = Vec::new();
45
46        values.append(&mut i32::serialize(&self.msg_id)?);
47
48        // TODO LONGMESSAGE feature
49        if false {
50            values.append(&mut i64::serialize(&self.timestamp)?);
51        } else {
52            values.append(&mut i32::serialize(&(self.timestamp as i32))?);
53        }
54
55        values.append(&mut i32::serialize(&(self.msg_type as i32))?);
56        values.append(&mut i8::serialize(&(self.flags as i8))?);
57        values.append(&mut BufferInfo::serialize(&self.buffer)?);
58        values.append(&mut String::serialize_utf8(&self.sender)?);
59
60        // TODO SenderPrefixes feature
61        if false {
62            if let Some(x) = &self.sender_prefixes {
63                values.append(&mut String::serialize_utf8(&x)?);
64            }
65        }
66
67        // TODO RichMessages feature
68        if false {
69            if let Some(x) = &self.real_name {
70                values.append(&mut String::serialize_utf8(&x)?);
71            }
72            if let Some(x) = &self.avatar_url {
73                values.append(&mut String::serialize_utf8(&x)?);
74            }
75        }
76
77        values.append(&mut String::serialize_utf8(&self.content)?);
78
79        return Ok(values);
80    }
81}
82
83impl Deserialize for Message {
84    fn parse(b: &[u8]) -> Result<(usize, Self), Error> {
85        let mut pos = 0;
86        let (parsed, msg_id) = i32::parse(&b[pos..])?;
87        pos += parsed;
88
89        // TODO LONGMESSAGES feature
90        let timestamp;
91        if false {
92            let (parsed, temp_timestamp) = i64::parse(&b[pos..])?;
93            pos += parsed;
94            timestamp = temp_timestamp;
95        } else {
96            let (parsed, temp_timestamp) = i32::parse(&b[pos..])?;
97            pos += parsed;
98            timestamp = temp_timestamp as i64;
99        }
100
101        let (parsed, msg_type) = i32::parse(&b[pos..])?;
102        pos += parsed;
103        let (parsed, flags) = i8::parse(&b[pos..])?;
104        pos += parsed;
105        let (parsed, buffer) = BufferInfo::parse(&b[pos..])?;
106        pos += parsed;
107        let (parsed, sender) = String::parse_utf8(&b[pos..])?;
108        pos += parsed;
109
110        // TODO SenderPrefixes feature
111        let mut sender_prefixes = None;
112        if false {
113            let (parsed, temp) = String::parse_utf8(&b[pos..])?;
114            sender_prefixes = Some(temp);
115            pos += parsed;
116        }
117
118        // TODO SenderPrefixes feature
119        let mut real_name = None;
120        let mut avatar_url = None;
121        if false {
122            let (parsed, temp) = String::parse_utf8(&b[pos..])?;
123            real_name = Some(temp);
124            pos += parsed;
125
126            let (parsed, temp) = String::parse_utf8(&b[pos..])?;
127            avatar_url = Some(temp);
128            pos += parsed;
129        }
130
131        let (parsed, content) = String::parse_utf8(&b[pos..])?;
132        pos += parsed;
133
134        return Ok((
135            pos,
136            Self {
137                msg_id,
138                timestamp,
139                msg_type: MessageType::from(msg_type),
140                flags,
141                buffer,
142                sender,
143                sender_prefixes,
144                real_name,
145                avatar_url,
146                content,
147            },
148        ));
149    }
150}
151
152#[repr(i32)]
153#[derive(Copy, Clone, Debug, std::cmp::PartialEq)]
154pub enum MessageType {
155    Plain = 0x00000001,
156    Notice = 0x00000002,
157    Action = 0x00000004,
158    Nick = 0x00000008,
159    Mode = 0x00000010,
160    Join = 0x00000020,
161    Part = 0x00000040,
162    Quit = 0x00000080,
163    Kick = 0x00000100,
164    Kill = 0x00000200,
165    Server = 0x00000400,
166    Info = 0x00000800,
167    Error = 0x00001000,
168    DayChange = 0x00002000,
169    Topic = 0x00004000,
170    NetsplitJoin = 0x00008000,
171    NetsplitQuit = 0x00010000,
172    Invite = 0x00020000,
173    Markerline = 0x00040000,
174}
175
176impl From<i32> for MessageType {
177    fn from(val: i32) -> Self {
178        match val {
179            0x00000001 => MessageType::Plain,
180            0x00000002 => MessageType::Notice,
181            0x00000004 => MessageType::Action,
182            0x00000008 => MessageType::Nick,
183            0x00000010 => MessageType::Mode,
184            0x00000020 => MessageType::Join,
185            0x00000040 => MessageType::Part,
186            0x00000080 => MessageType::Quit,
187            0x00000100 => MessageType::Kick,
188            0x00000200 => MessageType::Kill,
189            0x00000400 => MessageType::Server,
190            0x00000800 => MessageType::Info,
191            0x00001000 => MessageType::Error,
192            0x00002000 => MessageType::DayChange,
193            0x00004000 => MessageType::Topic,
194            0x00008000 => MessageType::NetsplitJoin,
195            0x00010000 => MessageType::NetsplitQuit,
196            0x00020000 => MessageType::Invite,
197            0x00040000 => MessageType::Markerline,
198            _ => unimplemented!(),
199        }
200    }
201}