1use crate::error::{MessageError, MessageErrorDetails::*};
2
3#[derive(Debug, PartialEq, Clone)]
4#[allow(non_camel_case_types)]
5pub enum IRCCommand {
6 NONE,
7 NAMES,
8 PRIVMSG,
9 NOTICE,
10 NICK,
11 USER,
12 QUIT,
13 MOTD,
14 LUSERS,
15 WHOIS,
16 TOPIC,
17 RPL_WELCOME,
18 RPL_YOURHOST,
19 RPL_CREATED,
20 RPL_MYINFO,
21 RPL_NAMREPLY,
22 RPL_ENDOFNAMES,
23 RPL_LUSERCLIENT,
24 RPL_LUSEROP,
25 RPL_LUSERUNKNOWN,
26 RPL_LUSERCHANNELS,
27 RPL_LUSERME,
28 RPL_WHOISUSER,
29 RPL_WHOISSERVER,
30 RPL_ENDOFWHOIS,
31 PING,
32 PONG,
33 ERR_NONICKNAMEGIVEN,
34 ERR_NICKNAMEINUSE,
35 ERR_ALREADYREGISTRED,
36 ERR_NEEDMOREPARAMS,
37 ERR_NOTREGISTERED,
38 ERR_UNKNOWNCOMMAND,
39 ERR_NORECIPIENT,
40 ERR_NOTEXTTOSEND,
41 ERR_NOSUCHNICK,
42 ERR_NOMOTD,
43}
44
45impl IRCCommand {
46 pub fn command_text(&self) -> &str {
48 match *self {
49 IRCCommand::NONE => "NONE",
50 IRCCommand::NAMES => "NAMES",
51 IRCCommand::PRIVMSG => "PRIVMSG",
52 IRCCommand::NICK => "NICK",
53 IRCCommand::RPL_NAMREPLY => "353",
54 IRCCommand::RPL_ENDOFNAMES => "366",
55 IRCCommand::RPL_WELCOME => "001",
56 IRCCommand::PING => "PING",
57 IRCCommand::PONG => "PONG",
58 IRCCommand::USER => "USER",
59 IRCCommand::QUIT => "QUIT",
60 IRCCommand::NOTICE => "NOTICE",
61 IRCCommand::MOTD => "MOTD",
62 IRCCommand::LUSERS => "LUSERS",
63 IRCCommand::WHOIS => "WHOIS",
64 IRCCommand::RPL_YOURHOST => "002",
65 IRCCommand::RPL_CREATED => "003",
66 IRCCommand::RPL_MYINFO => "004",
67 IRCCommand::RPL_LUSERCLIENT => "251",
68 IRCCommand::RPL_LUSEROP => "252",
69 IRCCommand::RPL_LUSERUNKNOWN => "253",
70 IRCCommand::RPL_LUSERCHANNELS => "254",
71 IRCCommand::RPL_LUSERME => "255",
72 IRCCommand::RPL_WHOISUSER => "311",
73 IRCCommand::RPL_WHOISSERVER => "312",
74 IRCCommand::RPL_ENDOFWHOIS => "318",
75 IRCCommand::ERR_NONICKNAMEGIVEN => "431",
76 IRCCommand::ERR_NICKNAMEINUSE => "433",
77 IRCCommand::ERR_ALREADYREGISTRED => "462",
78 IRCCommand::ERR_NEEDMOREPARAMS => "461",
79 IRCCommand::ERR_NOTREGISTERED => "451",
80 IRCCommand::ERR_UNKNOWNCOMMAND => "421",
81 IRCCommand::ERR_NORECIPIENT => "411",
82 IRCCommand::ERR_NOTEXTTOSEND => "412",
83 IRCCommand::ERR_NOSUCHNICK => "401",
84 IRCCommand::ERR_NOMOTD => "422",
85 IRCCommand::TOPIC => "TOPIC",
86 }
87 }
88
89 pub fn text_command(text: &str) -> IRCCommand {
90 match text {
91 "NAMES" => return IRCCommand::NAMES,
92 "NICK" => return IRCCommand::NICK,
93 "PRIVMSG" => return IRCCommand::PRIVMSG,
94 "001" => return IRCCommand::RPL_WELCOME,
95 "353" => return IRCCommand::RPL_NAMREPLY,
96 "366" => return IRCCommand::RPL_ENDOFNAMES,
97 "PING" => return IRCCommand::PING,
98 "PONG" => return IRCCommand::PONG,
99 "USER" => return IRCCommand::USER,
100 "QUIT" => return IRCCommand::QUIT,
101 "NOTICE" => return IRCCommand::NOTICE,
102 "MOTD" => return IRCCommand::MOTD,
103 "LUSERS" => return IRCCommand::LUSERS,
104 "WHOIS" => return IRCCommand::WHOIS,
105 "TOPIC" => return IRCCommand::TOPIC,
106 "002" => return IRCCommand::RPL_YOURHOST,
107 "003" => return IRCCommand::RPL_CREATED,
108 "004" => return IRCCommand::RPL_MYINFO,
109 "251" => return IRCCommand::RPL_LUSERCLIENT,
110 "252" => return IRCCommand::RPL_LUSEROP,
111 "253" => return IRCCommand::RPL_LUSERUNKNOWN,
112 "254" => return IRCCommand::RPL_LUSERCHANNELS,
113 "255" => return IRCCommand::RPL_LUSERME,
114 "311" => return IRCCommand::RPL_WHOISUSER,
115 "312" => return IRCCommand::RPL_WHOISSERVER,
116 "318" => return IRCCommand::RPL_ENDOFWHOIS,
117 "431" => return IRCCommand::ERR_NONICKNAMEGIVEN,
118 "433" => return IRCCommand::ERR_NICKNAMEINUSE,
119 "462" => return IRCCommand::ERR_ALREADYREGISTRED,
120 "461" => return IRCCommand::ERR_NEEDMOREPARAMS,
121 "451" => return IRCCommand::ERR_NOTREGISTERED,
122 "421" => return IRCCommand::ERR_UNKNOWNCOMMAND,
123 "411" => return IRCCommand::ERR_NORECIPIENT,
124 "412" => return IRCCommand::ERR_NOTEXTTOSEND,
125 "401" => return IRCCommand::ERR_NOSUCHNICK,
126 "422" => return IRCCommand::ERR_NOMOTD,
127 _ => return IRCCommand::NONE,
128 }
129 }
130
131 pub fn params_before_colon(&self) -> usize {
132 match *self {
133 IRCCommand::PRIVMSG => 1,
134 IRCCommand::USER => 3,
135 IRCCommand::TOPIC => 1,
136 _ => 0,
137 }
138 }
139
140 pub fn parse_params(&self, raw_input: Vec<Vec<u8>>) -> Result<Vec<Vec<u8>>, MessageError> {
146 let mut return_vec: Vec<Vec<u8>> = Vec::new();
147 match *self {
148 IRCCommand::NONE => Ok(Vec::new()),
149 IRCCommand::NAMES => Ok(Vec::new()),
150 IRCCommand::PRIVMSG => self.number_and_presence(&raw_input, 2),
151 IRCCommand::NICK => self.number_and_presence(&raw_input, 1),
152 IRCCommand::RPL_NAMREPLY => self.number_and_presence(&raw_input, 2),
153 IRCCommand::RPL_ENDOFNAMES => self.number_and_presence(&raw_input, 2),
154 IRCCommand::RPL_WELCOME => self.number_and_presence(&raw_input, 2),
155 IRCCommand::PING => self.number_and_presence(&raw_input, 1),
156 IRCCommand::PONG => self.number_and_presence(&raw_input, 1),
157 IRCCommand::USER => self.number_and_presence(&raw_input, 4),
158 IRCCommand::QUIT => {
159 IRCCommand::parse_irc_params(&raw_input, &mut return_vec);
160 Ok(return_vec)
161 }
162 IRCCommand::NOTICE => self.number_and_presence(&raw_input, 2),
163 IRCCommand::MOTD => {
164 IRCCommand::parse_irc_params(&raw_input, &mut return_vec);
165 Ok(return_vec)
166 }
167 IRCCommand::LUSERS => {
168 IRCCommand::parse_irc_params(&raw_input, &mut return_vec);
169 Ok(return_vec)
170 }
171 IRCCommand::WHOIS => self.number_and_presence(&raw_input, 1),
172 IRCCommand::RPL_YOURHOST => self.number_and_presence(&raw_input, 2),
173 IRCCommand::RPL_CREATED => self.number_and_presence(&raw_input, 2),
174 IRCCommand::RPL_MYINFO => self.number_and_presence(&raw_input, 2),
175 IRCCommand::RPL_LUSERCLIENT => self.number_and_presence(&raw_input, 2),
176 IRCCommand::RPL_LUSEROP => self.number_and_presence(&raw_input, 3),
177 IRCCommand::RPL_LUSERUNKNOWN => self.number_and_presence(&raw_input, 3),
178 IRCCommand::RPL_LUSERCHANNELS => self.number_and_presence(&raw_input, 3),
179 IRCCommand::RPL_LUSERME => self.number_and_presence(&raw_input, 1),
180 IRCCommand::RPL_WHOISUSER => self.number_and_presence(&raw_input, 6),
181 IRCCommand::RPL_WHOISSERVER => self.number_and_presence(&raw_input, 4),
182 IRCCommand::RPL_ENDOFWHOIS => self.number_and_presence(&raw_input, 3),
183 IRCCommand::ERR_NONICKNAMEGIVEN => self.number_and_presence(&raw_input, 1),
184 IRCCommand::ERR_NICKNAMEINUSE => self.number_and_presence(&raw_input, 2),
185 IRCCommand::ERR_ALREADYREGISTRED => self.number_and_presence(&raw_input, 2),
186 IRCCommand::ERR_NEEDMOREPARAMS => self.number_and_presence(&raw_input, 3),
187 IRCCommand::ERR_NOTREGISTERED => self.number_and_presence(&raw_input, 1),
188 IRCCommand::ERR_UNKNOWNCOMMAND => self.number_and_presence(&raw_input, 3),
189 IRCCommand::ERR_NORECIPIENT => self.number_and_presence(&raw_input, 2),
190 IRCCommand::ERR_NOTEXTTOSEND => self.number_and_presence(&raw_input, 2),
191 IRCCommand::ERR_NOSUCHNICK => self.number_and_presence(&raw_input, 3),
192 IRCCommand::ERR_NOMOTD => self.number_and_presence(&raw_input, 2),
193 IRCCommand::TOPIC => self.parse_topic(&raw_input),
194 }
195 }
196
197 fn parse_topic(&self, params: &Vec<Vec<u8>>) -> Result<Vec<Vec<u8>>, MessageError> {
198 if params.len() < 1 {
199 return Err(MessageError {
200 command: Some(self.clone()),
201 detail: NotEnoughParams,
202 });
203 }
204 let mut return_vec: Vec<Vec<u8>> = Vec::new();
205 IRCCommand::parse_irc_params(¶ms, &mut return_vec);
206 Ok(return_vec)
207 }
208
209 fn number_and_presence(
210 &self,
211 params: &Vec<Vec<u8>>,
212 number: usize,
213 ) -> Result<Vec<Vec<u8>>, MessageError> {
214 let mut return_vec: Vec<Vec<u8>> = Vec::new();
215 if !IRCCommand::validate_param_presence(¶ms) {
216 return Err(MessageError {
217 detail: BlankParams,
218 command: Some(self.clone()),
219 });
220 }
221 if params.len() < number {
222 return Err(MessageError {
223 detail: NotEnoughParams,
224 command: Some(self.clone()),
225 });
226 }
227 IRCCommand::parse_irc_params(¶ms, &mut return_vec);
228 Ok(return_vec)
229 }
230
231 fn validate_param_presence(params: &Vec<Vec<u8>>) -> bool {
232 for p in params {
233 if p.len() < 1 {
234 return false;
235 }
236 }
237 true
238 }
239
240 fn parse_irc_params(raw_input: &Vec<Vec<u8>>, return_vec: &mut Vec<Vec<u8>>) {
241 for (i, r) in raw_input.into_iter().enumerate() {
242 if r[0] != 58 {
243 return_vec.push(r.to_vec());
244 } else {
245 let rest = raw_input.clone().split_off(i);
246 let mut message: Vec<u8> = Vec::new();
247 for (j, s) in rest.into_iter().enumerate() {
248 if j == 0 {
249 message = [message, s[1..].to_vec()].concat();
250 } else {
251 message = [message, [[32].to_vec(), s].concat()].concat();
252 }
253 }
254 return_vec.push(message);
255 return;
256 }
257 }
258 }
259}
260
261#[test]
262fn test_no_params() {
263 let command_params = vec!["".as_bytes().to_vec()];
264 let res = IRCCommand::NAMES.parse_params(command_params);
265 assert!(res.is_ok());
266 assert_eq!(res.ok().unwrap().len(), 0);
267 let command_params = vec!["abc".as_bytes().to_vec()];
268 let res = IRCCommand::NAMES.parse_params(command_params);
269 assert!(res.is_ok());
270 assert_eq!(res.ok().unwrap().len(), 0);
271 let command_params = vec!["abc :Hello".as_bytes().to_vec()];
272 let res = IRCCommand::NAMES.parse_params(command_params);
273 assert!(res.is_ok());
274 assert_eq!(res.ok().unwrap().len(), 0);
275}
276
277#[test]
278fn test_one_param() {
279 let command_params = vec!["".as_bytes().to_vec()];
280 let res = IRCCommand::NICK.parse_params(command_params);
281 assert!(res.is_err());
282 assert_eq!(res.err().unwrap().detail, BlankParams);
283 let command_params = vec!["Anon".as_bytes().to_vec()];
284 let res = IRCCommand::NICK.parse_params(command_params);
285 assert!(res.is_ok());
286 assert_eq!(res.ok().unwrap()[0][0], 65);
287 let command_params = vec!["Anon".as_bytes().to_vec(), "B".as_bytes().to_vec()];
288 let res = IRCCommand::NICK.parse_params(command_params);
289 assert!(res.is_ok());
290 assert_eq!(res.ok().unwrap().len(), 2);
291}
292
293#[test]
294fn test_message_param() {
295 let command_params = vec!["".as_bytes().to_vec()];
296 let res = IRCCommand::PRIVMSG.parse_params(command_params);
297 assert!(res.is_err());
298 assert_eq!(res.err().unwrap().detail, BlankParams);
299 let command_params = vec!["Anon".as_bytes().to_vec()];
300 let res = IRCCommand::PRIVMSG.parse_params(command_params);
301 assert!(res.is_err());
302 assert_eq!(res.err().unwrap().detail, NotEnoughParams);
303 let command_params = vec![
304 "Anon".as_bytes().to_vec(),
305 ":Hello".as_bytes().to_vec(),
306 "anon".as_bytes().to_vec(),
307 ];
308 let res = IRCCommand::PRIVMSG.parse_params(command_params);
309 assert!(res.is_ok());
310 assert_eq!(res.as_ref().ok().unwrap().len(), 2);
311 assert_eq!(res.as_ref().ok().unwrap()[1][0], 72);
312}
313
314#[test]
315fn test_welcome() {
316 let raw_input = vec![
317 "Anon".as_bytes().to_vec(),
318 ":Welcome".as_bytes().to_vec(),
319 "to".as_bytes().to_vec(),
320 "the".as_bytes().to_vec(),
321 "server".as_bytes().to_vec(),
322 ];
323 let res = IRCCommand::RPL_WELCOME.parse_params(raw_input);
324 println!("{:?}", res);
325 assert!(res.is_ok());
326 assert_eq!(res.as_ref().unwrap().len(), 2);
327 assert_eq!(res.as_ref().unwrap()[1].len(), 21);
328 let raw_input = vec!["Anon".as_bytes().to_vec()];
329 let res = IRCCommand::RPL_WELCOME.parse_params(raw_input);
330 println!("{:?}", res);
331 assert!(res.is_err());
332}