1use std::str::FromStr;
3
4use crate::proto::{ChannelExt, ChannelMode, MessageParseError, Mode, Response, UserMode};
5
6#[derive(Clone, Debug, PartialEq)]
11pub enum Command {
12 PASS(String),
15 NICK(String),
17 USER(String, String, String),
19 OPER(String, String),
21 UserMODE(String, Vec<Mode<UserMode>>),
23 SERVICE(String, String, String, String, String, String),
25 QUIT(Option<String>),
27 SQUIT(String, String),
29
30 JOIN(String, Option<String>, Option<String>),
33 PART(String, Option<String>),
35 ChannelMODE(String, Vec<Mode<ChannelMode>>),
37 TOPIC(String, Option<String>),
39 NAMES(Option<String>, Option<String>),
41 LIST(Option<String>, Option<String>),
43 INVITE(String, String),
45 KICK(String, String, Option<String>),
47
48 PRIVMSG(String, String),
63 NOTICE(String, String),
77
78 MOTD(Option<String>),
81 LUSERS(Option<String>, Option<String>),
83 VERSION(Option<String>),
85 STATS(Option<String>, Option<String>),
87 LINKS(Option<String>, Option<String>),
89 TIME(Option<String>),
91 CONNECT(String, String, Option<String>),
93 TRACE(Option<String>),
95 ADMIN(Option<String>),
97 INFO(Option<String>),
99
100 SERVLIST(Option<String>, Option<String>),
103 SQUERY(String, String),
105
106 WHO(Option<String>, Option<bool>),
109 WHOIS(Option<String>, String),
111 WHOWAS(String, Option<String>, Option<String>),
113
114 KILL(String, String),
117 PING(String, Option<String>),
119 PONG(String, Option<String>),
121 ERROR(String),
123
124 AWAY(Option<String>),
127 REHASH,
129 DIE,
131 RESTART,
133 SUMMON(String, Option<String>, Option<String>),
135 USERS(Option<String>),
137 WALLOPS(String),
139 USERHOST(Vec<String>),
141 ISON(Vec<String>),
143
144 SAJOIN(String, String),
147 SAMODE(String, String, Option<String>),
149 SANICK(String, String),
151 SAPART(String, String),
153 SAQUIT(String, String),
155 NICKSERV(String),
157 CHANSERV(String),
159 OPERSERV(String),
161 BOTSERV(String),
163 HOSTSERV(String),
165 MEMOSERV(String),
167
168 CAP(
171 Option<String>,
172 CapSubCommand,
173 Option<String>,
174 Option<String>,
175 ),
176
177 AUTHENTICATE(String),
180 ACCOUNT(String),
182 METADATA(
190 String,
191 Option<MetadataSubCommand>,
192 Option<Vec<String>>,
193 Option<String>,
194 ),
195 MONITOR(String, Option<String>),
197 BATCH(String, Option<BatchSubCommand>, Option<Vec<String>>),
199 CHGHOST(String, String),
201
202 Response(Response, Vec<String>, Option<String>),
205 Raw(String, Vec<String>, Option<String>),
207}
208
209fn stringify(cmd: &str, args: &[&str], suffix: Option<&str>) -> String {
210 let args = args.join(" ");
211 let sp = if args.is_empty() { "" } else { " " };
212 match suffix {
213 Some(suffix) => format!("{}{}{} :{}", cmd, sp, args, suffix),
214 None => format!("{}{}{}", cmd, sp, args),
215 }
216}
217
218impl<'a> From<&'a Command> for String {
219 #[allow(clippy::many_single_char_names)]
220 fn from(cmd: &'a Command) -> String {
221 match *cmd {
222 Command::PASS(ref p) => stringify("PASS", &[], Some(p)),
223 Command::NICK(ref n) => stringify("NICK", &[], Some(n)),
224 Command::USER(ref u, ref m, ref r) => stringify("USER", &[u, m, "*"], Some(r)),
225 Command::OPER(ref u, ref p) => stringify("OPER", &[u], Some(p)),
226 Command::UserMODE(ref u, ref m) => format!(
227 "MODE {}{}",
228 u,
229 m.iter().fold(String::new(), |mut acc, mode| {
230 acc.push_str(" ");
231 acc.push_str(&mode.to_string());
232 acc
233 })
234 ),
235 Command::SERVICE(ref n, ref r, ref d, ref t, ref re, ref i) => {
236 stringify("SERVICE", &[n, r, d, t, re], Some(i))
237 }
238 Command::QUIT(Some(ref m)) => stringify("QUIT", &[], Some(m)),
239 Command::QUIT(None) => stringify("QUIT", &[], None),
240 Command::SQUIT(ref s, ref c) => stringify("SQUIT", &[s], Some(c)),
241 Command::JOIN(ref c, Some(ref k), Some(ref n)) => stringify("JOIN", &[c, k], Some(n)),
242 Command::JOIN(ref c, Some(ref k), None) => stringify("JOIN", &[c, k], None),
243 Command::JOIN(ref c, None, Some(ref n)) => stringify("JOIN", &[c], Some(n)),
244 Command::JOIN(ref c, None, None) => stringify("JOIN", &[c], None),
245 Command::PART(ref c, Some(ref m)) => stringify("PART", &[c], Some(m)),
246 Command::PART(ref c, None) => stringify("PART", &[c], None),
247 Command::ChannelMODE(ref u, ref m) => format!(
248 "MODE {}{}",
249 u,
250 m.iter().fold(String::new(), |mut acc, mode| {
251 acc.push_str(" ");
252 acc.push_str(&mode.to_string());
253 acc
254 })
255 ),
256 Command::TOPIC(ref c, Some(ref t)) => stringify("TOPIC", &[c], Some(t)),
257 Command::TOPIC(ref c, None) => stringify("TOPIC", &[c], None),
258 Command::NAMES(Some(ref c), Some(ref t)) => stringify("NAMES", &[c], Some(t)),
259 Command::NAMES(Some(ref c), None) => stringify("NAMES", &[c], None),
260 Command::NAMES(None, _) => stringify("NAMES", &[], None),
261 Command::LIST(Some(ref c), Some(ref t)) => stringify("LIST", &[c], Some(t)),
262 Command::LIST(Some(ref c), None) => stringify("LIST", &[c], None),
263 Command::LIST(None, _) => stringify("LIST", &[], None),
264 Command::INVITE(ref n, ref c) => stringify("INVITE", &[n, c], None),
265 Command::KICK(ref c, ref n, Some(ref r)) => stringify("KICK", &[c, n], Some(r)),
266 Command::KICK(ref c, ref n, None) => stringify("KICK", &[c, n], None),
267 Command::PRIVMSG(ref t, ref m) => stringify("PRIVMSG", &[t], Some(m)),
268 Command::NOTICE(ref t, ref m) => stringify("NOTICE", &[t], Some(m)),
269 Command::MOTD(Some(ref t)) => stringify("MOTD", &[], Some(t)),
270 Command::MOTD(None) => stringify("MOTD", &[], None),
271 Command::LUSERS(Some(ref m), Some(ref t)) => stringify("LUSERS", &[m], Some(t)),
272 Command::LUSERS(Some(ref m), None) => stringify("LUSERS", &[m], None),
273 Command::LUSERS(None, _) => stringify("LUSERS", &[], None),
274 Command::VERSION(Some(ref t)) => stringify("VERSION", &[], Some(t)),
275 Command::VERSION(None) => stringify("VERSION", &[], None),
276 Command::STATS(Some(ref q), Some(ref t)) => stringify("STATS", &[q], Some(t)),
277 Command::STATS(Some(ref q), None) => stringify("STATS", &[q], None),
278 Command::STATS(None, _) => stringify("STATS", &[], None),
279 Command::LINKS(Some(ref r), Some(ref s)) => stringify("LINKS", &[r], Some(s)),
280 Command::LINKS(None, Some(ref s)) => stringify("LINKS", &[], Some(s)),
281 Command::LINKS(_, None) => stringify("LINKS", &[], None),
282 Command::TIME(Some(ref t)) => stringify("TIME", &[], Some(t)),
283 Command::TIME(None) => stringify("TIME", &[], None),
284 Command::CONNECT(ref t, ref p, Some(ref r)) => stringify("CONNECT", &[t, p], Some(r)),
285 Command::CONNECT(ref t, ref p, None) => stringify("CONNECT", &[t, p], None),
286 Command::TRACE(Some(ref t)) => stringify("TRACE", &[], Some(t)),
287 Command::TRACE(None) => stringify("TRACE", &[], None),
288 Command::ADMIN(Some(ref t)) => stringify("ADMIN", &[], Some(t)),
289 Command::ADMIN(None) => stringify("ADMIN", &[], None),
290 Command::INFO(Some(ref t)) => stringify("INFO", &[], Some(t)),
291 Command::INFO(None) => stringify("INFO", &[], None),
292 Command::SERVLIST(Some(ref m), Some(ref t)) => stringify("SERVLIST", &[m], Some(t)),
293 Command::SERVLIST(Some(ref m), None) => stringify("SERVLIST", &[m], None),
294 Command::SERVLIST(None, _) => stringify("SERVLIST", &[], None),
295 Command::SQUERY(ref s, ref t) => stringify("SQUERY", &[s, t], None),
296 Command::WHO(Some(ref s), Some(true)) => stringify("WHO", &[s, "o"], None),
297 Command::WHO(Some(ref s), _) => stringify("WHO", &[s], None),
298 Command::WHO(None, _) => stringify("WHO", &[], None),
299 Command::WHOIS(Some(ref t), ref m) => stringify("WHOIS", &[t, m], None),
300 Command::WHOIS(None, ref m) => stringify("WHOIS", &[m], None),
301 Command::WHOWAS(ref n, Some(ref c), Some(ref t)) => {
302 stringify("WHOWAS", &[n, c], Some(t))
303 }
304 Command::WHOWAS(ref n, Some(ref c), None) => stringify("WHOWAS", &[n, c], None),
305 Command::WHOWAS(ref n, None, _) => stringify("WHOWAS", &[n], None),
306 Command::KILL(ref n, ref c) => stringify("KILL", &[n], Some(c)),
307 Command::PING(ref s, Some(ref t)) => stringify("PING", &[s], Some(t)),
308 Command::PING(ref s, None) => stringify("PING", &[], Some(s)),
309 Command::PONG(ref s, Some(ref t)) => stringify("PONG", &[s], Some(t)),
310 Command::PONG(ref s, None) => stringify("PONG", &[], Some(s)),
311 Command::ERROR(ref m) => stringify("ERROR", &[], Some(m)),
312 Command::AWAY(Some(ref m)) => stringify("AWAY", &[], Some(m)),
313 Command::AWAY(None) => stringify("AWAY", &[], None),
314 Command::REHASH => stringify("REHASH", &[], None),
315 Command::DIE => stringify("DIE", &[], None),
316 Command::RESTART => stringify("RESTART", &[], None),
317 Command::SUMMON(ref u, Some(ref t), Some(ref c)) => {
318 stringify("SUMMON", &[u, t], Some(c))
319 }
320 Command::SUMMON(ref u, Some(ref t), None) => stringify("SUMMON", &[u, t], None),
321 Command::SUMMON(ref u, None, _) => stringify("SUMMON", &[u], None),
322 Command::USERS(Some(ref t)) => stringify("USERS", &[], Some(t)),
323 Command::USERS(None) => stringify("USERS", &[], None),
324 Command::WALLOPS(ref t) => stringify("WALLOPS", &[], Some(t)),
325 Command::USERHOST(ref u) => stringify(
326 "USERHOST",
327 &u.iter().map(|s| &s[..]).collect::<Vec<_>>(),
328 None,
329 ),
330 Command::ISON(ref u) => {
331 stringify("ISON", &u.iter().map(|s| &s[..]).collect::<Vec<_>>(), None)
332 }
333
334 Command::SAJOIN(ref n, ref c) => stringify("SAJOIN", &[n, c], None),
335 Command::SAMODE(ref t, ref m, Some(ref p)) => stringify("SAMODE", &[t, m, p], None),
336 Command::SAMODE(ref t, ref m, None) => stringify("SAMODE", &[t, m], None),
337 Command::SANICK(ref o, ref n) => stringify("SANICK", &[o, n], None),
338 Command::SAPART(ref c, ref r) => stringify("SAPART", &[c], Some(r)),
339 Command::SAQUIT(ref c, ref r) => stringify("SAQUIT", &[c], Some(r)),
340
341 Command::NICKSERV(ref m) => stringify("NICKSERV", &[m], None),
342 Command::CHANSERV(ref m) => stringify("CHANSERV", &[m], None),
343 Command::OPERSERV(ref m) => stringify("OPERSERV", &[m], None),
344 Command::BOTSERV(ref m) => stringify("BOTSERV", &[m], None),
345 Command::HOSTSERV(ref m) => stringify("HOSTSERV", &[m], None),
346 Command::MEMOSERV(ref m) => stringify("MEMOSERV", &[m], None),
347
348 Command::CAP(None, ref s, None, Some(ref p)) => {
349 stringify("CAP", &[s.to_str()], Some(p))
350 }
351 Command::CAP(None, ref s, None, None) => stringify("CAP", &[s.to_str()], None),
352 Command::CAP(Some(ref k), ref s, None, Some(ref p)) => {
353 stringify("CAP", &[k, s.to_str()], Some(p))
354 }
355 Command::CAP(Some(ref k), ref s, None, None) => {
356 stringify("CAP", &[k, s.to_str()], None)
357 }
358 Command::CAP(None, ref s, Some(ref c), Some(ref p)) => {
359 stringify("CAP", &[s.to_str(), c], Some(p))
360 }
361 Command::CAP(None, ref s, Some(ref c), None) => {
362 stringify("CAP", &[s.to_str(), c], None)
363 }
364 Command::CAP(Some(ref k), ref s, Some(ref c), Some(ref p)) => {
365 stringify("CAP", &[k, s.to_str(), c], Some(p))
366 }
367 Command::CAP(Some(ref k), ref s, Some(ref c), None) => {
368 stringify("CAP", &[k, s.to_str(), c], None)
369 }
370
371 Command::AUTHENTICATE(ref d) => stringify("AUTHENTICATE", &[d], None),
372 Command::ACCOUNT(ref a) => stringify("ACCOUNT", &[a], None),
373
374 Command::METADATA(ref t, Some(ref c), None, Some(ref p)) => {
375 stringify("METADATA", &[&t[..], c.to_str()], Some(p))
376 }
377 Command::METADATA(ref t, Some(ref c), None, None) => {
378 stringify("METADATA", &[&t[..], c.to_str()], None)
379 }
380
381 Command::METADATA(ref t, Some(ref c), Some(ref a), Some(ref p)) => stringify(
382 "METADATA",
383 &vec![t, &c.to_str().to_owned()]
384 .iter()
385 .map(|s| &s[..])
386 .chain(a.iter().map(|s| &s[..]))
387 .collect::<Vec<_>>(),
388 Some(p),
389 ),
390 Command::METADATA(ref t, Some(ref c), Some(ref a), None) => stringify(
391 "METADATA",
392 &vec![t, &c.to_str().to_owned()]
393 .iter()
394 .map(|s| &s[..])
395 .chain(a.iter().map(|s| &s[..]))
396 .collect::<Vec<_>>(),
397 None,
398 ),
399 Command::METADATA(ref t, None, None, Some(ref p)) => {
400 stringify("METADATA", &[t], Some(p))
401 }
402 Command::METADATA(ref t, None, None, None) => stringify("METADATA", &[t], None),
403 Command::METADATA(ref t, None, Some(ref a), Some(ref p)) => stringify(
404 "METADATA",
405 &vec![t]
406 .iter()
407 .map(|s| &s[..])
408 .chain(a.iter().map(|s| &s[..]))
409 .collect::<Vec<_>>(),
410 Some(p),
411 ),
412 Command::METADATA(ref t, None, Some(ref a), None) => stringify(
413 "METADATA",
414 &vec![t]
415 .iter()
416 .map(|s| &s[..])
417 .chain(a.iter().map(|s| &s[..]))
418 .collect::<Vec<_>>(),
419 None,
420 ),
421 Command::MONITOR(ref c, Some(ref t)) => stringify("MONITOR", &[c, t], None),
422 Command::MONITOR(ref c, None) => stringify("MONITOR", &[c], None),
423 Command::BATCH(ref t, Some(ref c), Some(ref a)) => stringify(
424 "BATCH",
425 &vec![t, &c.to_str().to_owned()]
426 .iter()
427 .map(|s| &s[..])
428 .chain(a.iter().map(|s| &s[..]))
429 .collect::<Vec<_>>(),
430 None,
431 ),
432 Command::BATCH(ref t, Some(ref c), None) => stringify("BATCH", &[t, c.to_str()], None),
433 Command::BATCH(ref t, None, Some(ref a)) => stringify(
434 "BATCH",
435 &vec![t]
436 .iter()
437 .map(|s| &s[..])
438 .chain(a.iter().map(|s| &s[..]))
439 .collect::<Vec<_>>(),
440 None,
441 ),
442 Command::BATCH(ref t, None, None) => stringify("BATCH", &[t], None),
443 Command::CHGHOST(ref u, ref h) => stringify("CHGHOST", &[u, h], None),
444
445 Command::Response(ref resp, ref a, Some(ref s)) => stringify(
446 &format!("{:03}", *resp as u16),
447 &a.iter().map(|s| &s[..]).collect::<Vec<_>>(),
448 Some(s),
449 ),
450 Command::Response(ref resp, ref a, None) => stringify(
451 &format!("{:03}", *resp as u16),
452 &a.iter().map(|s| &s[..]).collect::<Vec<_>>(),
453 None,
454 ),
455 Command::Raw(ref c, ref a, Some(ref s)) => {
456 stringify(c, &a.iter().map(|s| &s[..]).collect::<Vec<_>>(), Some(s))
457 }
458 Command::Raw(ref c, ref a, None) => {
459 stringify(c, &a.iter().map(|s| &s[..]).collect::<Vec<_>>(), None)
460 }
461 }
462 }
463}
464
465impl Command {
466 #[allow(clippy::complexity)]
468 pub fn new(
469 cmd: &str,
470 args: Vec<&str>,
471 suffix: Option<&str>,
472 ) -> Result<Command, MessageParseError> {
473 Ok(if cmd.eq_ignore_ascii_case("PASS") {
474 match suffix {
475 Some(suffix) => {
476 if !args.is_empty() {
477 raw(cmd, args, Some(suffix))
478 } else {
479 Command::PASS(suffix.to_owned())
480 }
481 }
482 None => {
483 if args.len() != 1 {
484 raw(cmd, args, suffix)
485 } else {
486 Command::PASS(args[0].to_owned())
487 }
488 }
489 }
490 } else if cmd.eq_ignore_ascii_case("NICK") {
491 match suffix {
492 Some(suffix) => {
493 if !args.is_empty() {
494 raw(cmd, args, Some(suffix))
495 } else {
496 Command::NICK(suffix.to_owned())
497 }
498 }
499 None => {
500 if args.len() != 1 {
501 raw(cmd, args, suffix)
502 } else {
503 Command::NICK(args[0].to_owned())
504 }
505 }
506 }
507 } else if cmd.eq_ignore_ascii_case("USER") {
508 match suffix {
509 Some(suffix) => {
510 if args.len() != 3 {
511 raw(cmd, args, Some(suffix))
512 } else {
513 Command::USER(args[0].to_owned(), args[1].to_owned(), suffix.to_owned())
514 }
515 }
516 None => {
517 if args.len() != 4 {
518 raw(cmd, args, suffix)
519 } else {
520 Command::USER(args[0].to_owned(), args[1].to_owned(), args[3].to_owned())
521 }
522 }
523 }
524 } else if cmd.eq_ignore_ascii_case("OPER") {
525 match suffix {
526 Some(suffix) => {
527 if args.len() != 1 {
528 raw(cmd, args, Some(suffix))
529 } else {
530 Command::OPER(args[0].to_owned(), suffix.to_owned())
531 }
532 }
533 None => {
534 if args.len() != 2 {
535 raw(cmd, args, suffix)
536 } else {
537 Command::OPER(args[0].to_owned(), args[1].to_owned())
538 }
539 }
540 }
541 } else if cmd.eq_ignore_ascii_case("MODE") {
542 match suffix {
543 Some(suffix) => raw(cmd, args, Some(suffix)),
544 None => {
545 if args[0].is_channel_name() {
546 let arg = args[1..].join(" ");
547 Command::ChannelMODE(
548 args[0].to_owned(),
549 Mode::from_channel_mode_string(&arg)?,
550 )
551 } else {
552 let arg = args[1..].join(" ");
553 Command::UserMODE(args[0].to_owned(), Mode::from_user_mode_string(&arg)?)
554 }
555 }
556 }
557 } else if cmd.eq_ignore_ascii_case("SERVICE") {
558 match suffix {
559 Some(suffix) => {
560 if args.len() != 5 {
561 raw(cmd, args, Some(suffix))
562 } else {
563 Command::SERVICE(
564 args[0].to_owned(),
565 args[1].to_owned(),
566 args[2].to_owned(),
567 args[3].to_owned(),
568 args[4].to_owned(),
569 suffix.to_owned(),
570 )
571 }
572 }
573 None => {
574 if args.len() != 6 {
575 raw(cmd, args, suffix)
576 } else {
577 Command::SERVICE(
578 args[0].to_owned(),
579 args[1].to_owned(),
580 args[2].to_owned(),
581 args[3].to_owned(),
582 args[4].to_owned(),
583 args[5].to_owned(),
584 )
585 }
586 }
587 }
588 } else if cmd.eq_ignore_ascii_case("QUIT") {
589 if !args.is_empty() {
590 raw(cmd, args, suffix)
591 } else {
592 match suffix {
593 Some(suffix) => Command::QUIT(Some(suffix.to_owned())),
594 None => Command::QUIT(None),
595 }
596 }
597 } else if cmd.eq_ignore_ascii_case("SQUIT") {
598 match suffix {
599 Some(suffix) => {
600 if args.len() != 1 {
601 raw(cmd, args, Some(suffix))
602 } else {
603 Command::SQUIT(args[0].to_owned(), suffix.to_owned())
604 }
605 }
606 None => {
607 if args.len() != 2 {
608 raw(cmd, args, suffix)
609 } else {
610 Command::SQUIT(args[0].to_owned(), args[1].to_owned())
611 }
612 }
613 }
614 } else if cmd.eq_ignore_ascii_case("JOIN") {
615 match suffix {
616 Some(suffix) => {
617 if args.is_empty() {
618 Command::JOIN(suffix.to_owned(), None, None)
619 } else if args.len() == 1 {
620 Command::JOIN(args[0].to_owned(), Some(suffix.to_owned()), None)
621 } else if args.len() == 2 {
622 Command::JOIN(
623 args[0].to_owned(),
624 Some(args[1].to_owned()),
625 Some(suffix.to_owned()),
626 )
627 } else {
628 raw(cmd, args, Some(suffix))
629 }
630 }
631 None => {
632 if args.len() == 1 {
633 Command::JOIN(args[0].to_owned(), None, None)
634 } else if args.len() == 2 {
635 Command::JOIN(args[0].to_owned(), Some(args[1].to_owned()), None)
636 } else if args.len() == 3 {
637 Command::JOIN(
638 args[0].to_owned(),
639 Some(args[1].to_owned()),
640 Some(args[2].to_owned()),
641 )
642 } else {
643 raw(cmd, args, suffix)
644 }
645 }
646 }
647 } else if cmd.eq_ignore_ascii_case("PART") {
648 match suffix {
649 Some(suffix) => {
650 if args.is_empty() {
651 Command::PART(suffix.to_owned(), None)
652 } else if args.len() == 1 {
653 Command::PART(args[0].to_owned(), Some(suffix.to_owned()))
654 } else {
655 raw(cmd, args, Some(suffix))
656 }
657 }
658 None => {
659 if args.len() == 1 {
660 Command::PART(args[0].to_owned(), None)
661 } else if args.len() == 2 {
662 Command::PART(args[0].to_owned(), Some(args[1].to_owned()))
663 } else {
664 raw(cmd, args, suffix)
665 }
666 }
667 }
668 } else if cmd.eq_ignore_ascii_case("TOPIC") {
669 match suffix {
670 Some(suffix) => {
671 if args.is_empty() {
672 Command::TOPIC(suffix.to_owned(), None)
673 } else if args.len() == 1 {
674 Command::TOPIC(args[0].to_owned(), Some(suffix.to_owned()))
675 } else {
676 raw(cmd, args, Some(suffix))
677 }
678 }
679 None => {
680 if args.len() == 1 {
681 Command::TOPIC(args[0].to_owned(), None)
682 } else if args.len() == 2 {
683 Command::TOPIC(args[0].to_owned(), Some(args[1].to_owned()))
684 } else {
685 raw(cmd, args, suffix)
686 }
687 }
688 }
689 } else if cmd.eq_ignore_ascii_case("NAMES") {
690 match suffix {
691 Some(suffix) => {
692 if args.is_empty() {
693 Command::NAMES(Some(suffix.to_owned()), None)
694 } else if args.len() == 1 {
695 Command::NAMES(Some(args[0].to_owned()), Some(suffix.to_owned()))
696 } else {
697 raw(cmd, args, Some(suffix))
698 }
699 }
700 None => {
701 if args.is_empty() {
702 Command::NAMES(None, None)
703 } else if args.len() == 1 {
704 Command::NAMES(Some(args[0].to_owned()), None)
705 } else if args.len() == 2 {
706 Command::NAMES(Some(args[0].to_owned()), Some(args[1].to_owned()))
707 } else {
708 raw(cmd, args, suffix)
709 }
710 }
711 }
712 } else if cmd.eq_ignore_ascii_case("LIST") {
713 match suffix {
714 Some(suffix) => {
715 if args.is_empty() {
716 Command::LIST(Some(suffix.to_owned()), None)
717 } else if args.len() == 1 {
718 Command::LIST(Some(args[0].to_owned()), Some(suffix.to_owned()))
719 } else {
720 raw(cmd, args, Some(suffix))
721 }
722 }
723 None => {
724 if args.is_empty() {
725 Command::LIST(None, None)
726 } else if args.len() == 1 {
727 Command::LIST(Some(args[0].to_owned()), None)
728 } else if args.len() == 2 {
729 Command::LIST(Some(args[0].to_owned()), Some(args[1].to_owned()))
730 } else {
731 raw(cmd, args, suffix)
732 }
733 }
734 }
735 } else if cmd.eq_ignore_ascii_case("INVITE") {
736 match suffix {
737 Some(suffix) => {
738 if args.len() != 1 {
739 raw(cmd, args, Some(suffix))
740 } else {
741 Command::INVITE(args[0].to_owned(), suffix.to_owned())
742 }
743 }
744 None => {
745 if args.len() != 2 {
746 raw(cmd, args, suffix)
747 } else {
748 Command::INVITE(args[0].to_owned(), args[1].to_owned())
749 }
750 }
751 }
752 } else if cmd.eq_ignore_ascii_case("KICK") {
753 match suffix {
754 Some(suffix) => {
755 if args.len() != 2 {
756 raw(cmd, args, Some(suffix))
757 } else {
758 Command::KICK(
759 args[0].to_owned(),
760 args[1].to_owned(),
761 Some(suffix.to_owned()),
762 )
763 }
764 }
765 None => {
766 if args.len() != 2 {
767 raw(cmd, args, suffix)
768 } else {
769 Command::KICK(args[0].to_owned(), args[1].to_owned(), None)
770 }
771 }
772 }
773 } else if cmd.eq_ignore_ascii_case("PRIVMSG") {
774 match suffix {
775 Some(suffix) => {
776 if args.len() != 1 {
777 raw(cmd, args, Some(suffix))
778 } else {
779 Command::PRIVMSG(args[0].to_owned(), suffix.to_owned())
780 }
781 }
782 None => raw(cmd, args, suffix),
783 }
784 } else if cmd.eq_ignore_ascii_case("NOTICE") {
785 match suffix {
786 Some(suffix) => {
787 if args.len() != 1 {
788 raw(cmd, args, Some(suffix))
789 } else {
790 Command::NOTICE(args[0].to_owned(), suffix.to_owned())
791 }
792 }
793 None => raw(cmd, args, suffix),
794 }
795 } else if cmd.eq_ignore_ascii_case("MOTD") {
796 if !args.is_empty() {
797 raw(cmd, args, suffix)
798 } else {
799 match suffix {
800 Some(suffix) => Command::MOTD(Some(suffix.to_owned())),
801 None => Command::MOTD(None),
802 }
803 }
804 } else if cmd.eq_ignore_ascii_case("LUSERS") {
805 match suffix {
806 Some(suffix) => {
807 if args.is_empty() {
808 Command::LUSERS(Some(suffix.to_owned()), None)
809 } else if args.len() == 1 {
810 Command::LUSERS(Some(args[0].to_owned()), Some(suffix.to_owned()))
811 } else {
812 raw(cmd, args, Some(suffix))
813 }
814 }
815 None => {
816 if args.is_empty() {
817 Command::LUSERS(None, None)
818 } else if args.len() == 1 {
819 Command::LUSERS(Some(args[0].to_owned()), None)
820 } else if args.len() == 2 {
821 Command::LUSERS(Some(args[0].to_owned()), Some(args[1].to_owned()))
822 } else {
823 raw(cmd, args, suffix)
824 }
825 }
826 }
827 } else if cmd.eq_ignore_ascii_case("VERSION") {
828 if !args.is_empty() {
829 raw(cmd, args, suffix)
830 } else {
831 match suffix {
832 Some(suffix) => Command::VERSION(Some(suffix.to_owned())),
833 None => Command::VERSION(None),
834 }
835 }
836 } else if cmd.eq_ignore_ascii_case("STATS") {
837 match suffix {
838 Some(suffix) => {
839 if args.is_empty() {
840 Command::STATS(Some(suffix.to_owned()), None)
841 } else if args.len() == 1 {
842 Command::STATS(Some(args[0].to_owned()), Some(suffix.to_owned()))
843 } else {
844 raw(cmd, args, Some(suffix))
845 }
846 }
847 None => {
848 if args.is_empty() {
849 Command::STATS(None, None)
850 } else if args.len() == 1 {
851 Command::STATS(Some(args[0].to_owned()), None)
852 } else if args.len() == 2 {
853 Command::STATS(Some(args[0].to_owned()), Some(args[1].to_owned()))
854 } else {
855 raw(cmd, args, suffix)
856 }
857 }
858 }
859 } else if cmd.eq_ignore_ascii_case("LINKS") {
860 match suffix {
861 Some(suffix) => {
862 if args.is_empty() {
863 Command::LINKS(None, Some(suffix.to_owned()))
864 } else if args.len() == 1 {
865 Command::LINKS(Some(args[0].to_owned()), Some(suffix.to_owned()))
866 } else {
867 raw(cmd, args, Some(suffix))
868 }
869 }
870 None => {
871 if args.is_empty() {
872 Command::LINKS(None, None)
873 } else {
874 raw(cmd, args, suffix)
875 }
876 }
877 }
878 } else if cmd.eq_ignore_ascii_case("TIME") {
879 if !args.is_empty() {
880 raw(cmd, args, suffix)
881 } else {
882 match suffix {
883 Some(suffix) => Command::TIME(Some(suffix.to_owned())),
884 None => Command::TIME(None),
885 }
886 }
887 } else if cmd.eq_ignore_ascii_case("CONNECT") {
888 match suffix {
889 Some(suffix) => {
890 if args.len() != 2 {
891 raw(cmd, args, Some(suffix))
892 } else {
893 Command::CONNECT(
894 args[0].to_owned(),
895 args[1].to_owned(),
896 Some(suffix.to_owned()),
897 )
898 }
899 }
900 None => {
901 if args.len() != 2 {
902 raw(cmd, args, suffix)
903 } else {
904 Command::CONNECT(args[0].to_owned(), args[1].to_owned(), None)
905 }
906 }
907 }
908 } else if cmd.eq_ignore_ascii_case("TRACE") {
909 if !args.is_empty() {
910 raw(cmd, args, suffix)
911 } else {
912 match suffix {
913 Some(suffix) => Command::TRACE(Some(suffix.to_owned())),
914 None => Command::TRACE(None),
915 }
916 }
917 } else if cmd.eq_ignore_ascii_case("ADMIN") {
918 if !args.is_empty() {
919 raw(cmd, args, suffix)
920 } else {
921 match suffix {
922 Some(suffix) => Command::ADMIN(Some(suffix.to_owned())),
923 None => Command::ADMIN(None),
924 }
925 }
926 } else if cmd.eq_ignore_ascii_case("INFO") {
927 if !args.is_empty() {
928 raw(cmd, args, suffix)
929 } else {
930 match suffix {
931 Some(suffix) => Command::INFO(Some(suffix.to_owned())),
932 None => Command::INFO(None),
933 }
934 }
935 } else if cmd.eq_ignore_ascii_case("SERVLIST") {
936 match suffix {
937 Some(suffix) => {
938 if args.is_empty() {
939 Command::SERVLIST(Some(suffix.to_owned()), None)
940 } else if args.len() == 1 {
941 Command::SERVLIST(Some(args[0].to_owned()), Some(suffix.to_owned()))
942 } else {
943 raw(cmd, args, Some(suffix))
944 }
945 }
946 None => {
947 if args.is_empty() {
948 Command::SERVLIST(None, None)
949 } else if args.len() == 1 {
950 Command::SERVLIST(Some(args[0].to_owned()), None)
951 } else if args.len() == 2 {
952 Command::SERVLIST(Some(args[0].to_owned()), Some(args[1].to_owned()))
953 } else {
954 raw(cmd, args, suffix)
955 }
956 }
957 }
958 } else if cmd.eq_ignore_ascii_case("SQUERY") {
959 match suffix {
960 Some(suffix) => {
961 if args.len() != 1 {
962 raw(cmd, args, Some(suffix))
963 } else {
964 Command::SQUERY(args[0].to_owned(), suffix.to_owned())
965 }
966 }
967 None => {
968 if args.len() != 2 {
969 raw(cmd, args, suffix)
970 } else {
971 Command::SQUERY(args[0].to_owned(), args[1].to_owned())
972 }
973 }
974 }
975 } else if cmd.eq_ignore_ascii_case("WHO") {
976 match suffix {
977 Some(suffix) => {
978 if args.is_empty() {
979 Command::WHO(Some(suffix.to_owned()), None)
980 } else if args.len() == 1 {
981 Command::WHO(Some(args[0].to_owned()), Some(&suffix[..] == "o"))
982 } else {
983 raw(cmd, args, Some(suffix))
984 }
985 }
986 None => {
987 if args.is_empty() {
988 Command::WHO(None, None)
989 } else if args.len() == 1 {
990 Command::WHO(Some(args[0].to_owned()), None)
991 } else if args.len() == 2 {
992 Command::WHO(Some(args[0].to_owned()), Some(&args[1][..] == "o"))
993 } else {
994 raw(cmd, args, suffix)
995 }
996 }
997 }
998 } else if cmd.eq_ignore_ascii_case("WHOIS") {
999 match suffix {
1000 Some(suffix) => {
1001 if args.is_empty() {
1002 Command::WHOIS(None, suffix.to_owned())
1003 } else if args.len() == 1 {
1004 Command::WHOIS(Some(args[0].to_owned()), suffix.to_owned())
1005 } else {
1006 raw(cmd, args, Some(suffix))
1007 }
1008 }
1009 None => {
1010 if args.len() == 1 {
1011 Command::WHOIS(None, args[0].to_owned())
1012 } else if args.len() == 2 {
1013 Command::WHOIS(Some(args[0].to_owned()), args[1].to_owned())
1014 } else {
1015 raw(cmd, args, suffix)
1016 }
1017 }
1018 }
1019 } else if cmd.eq_ignore_ascii_case("WHOWAS") {
1020 match suffix {
1021 Some(suffix) => {
1022 if args.is_empty() {
1023 Command::WHOWAS(suffix.to_owned(), None, None)
1024 } else if args.len() == 1 {
1025 Command::WHOWAS(args[0].to_owned(), None, Some(suffix.to_owned()))
1026 } else if args.len() == 2 {
1027 Command::WHOWAS(
1028 args[0].to_owned(),
1029 Some(args[1].to_owned()),
1030 Some(suffix.to_owned()),
1031 )
1032 } else {
1033 raw(cmd, args, Some(suffix))
1034 }
1035 }
1036 None => {
1037 if args.len() == 1 {
1038 Command::WHOWAS(args[0].to_owned(), None, None)
1039 } else if args.len() == 2 {
1040 Command::WHOWAS(args[0].to_owned(), None, Some(args[1].to_owned()))
1041 } else if args.len() == 3 {
1042 Command::WHOWAS(
1043 args[0].to_owned(),
1044 Some(args[1].to_owned()),
1045 Some(args[2].to_owned()),
1046 )
1047 } else {
1048 raw(cmd, args, suffix)
1049 }
1050 }
1051 }
1052 } else if cmd.eq_ignore_ascii_case("KILL") {
1053 match suffix {
1054 Some(suffix) => {
1055 if args.len() != 1 {
1056 raw(cmd, args, Some(suffix))
1057 } else {
1058 Command::KILL(args[0].to_owned(), suffix.to_owned())
1059 }
1060 }
1061 None => {
1062 if args.len() != 2 {
1063 raw(cmd, args, suffix)
1064 } else {
1065 Command::KILL(args[0].to_owned(), args[1].to_owned())
1066 }
1067 }
1068 }
1069 } else if cmd.eq_ignore_ascii_case("PING") {
1070 match suffix {
1071 Some(suffix) => {
1072 if args.is_empty() {
1073 Command::PING(suffix.to_owned(), None)
1074 } else if args.len() == 1 {
1075 Command::PING(args[0].to_owned(), Some(suffix.to_owned()))
1076 } else {
1077 raw(cmd, args, Some(suffix))
1078 }
1079 }
1080 None => {
1081 if args.len() == 1 {
1082 Command::PING(args[0].to_owned(), None)
1083 } else if args.len() == 2 {
1084 Command::PING(args[0].to_owned(), Some(args[1].to_owned()))
1085 } else {
1086 raw(cmd, args, suffix)
1087 }
1088 }
1089 }
1090 } else if cmd.eq_ignore_ascii_case("PONG") {
1091 match suffix {
1092 Some(suffix) => {
1093 if args.is_empty() {
1094 Command::PONG(suffix.to_owned(), None)
1095 } else if args.len() == 1 {
1096 Command::PONG(args[0].to_owned(), Some(suffix.to_owned()))
1097 } else {
1098 raw(cmd, args, Some(suffix))
1099 }
1100 }
1101 None => {
1102 if args.len() == 1 {
1103 Command::PONG(args[0].to_owned(), None)
1104 } else if args.len() == 2 {
1105 Command::PONG(args[0].to_owned(), Some(args[1].to_owned()))
1106 } else {
1107 raw(cmd, args, suffix)
1108 }
1109 }
1110 }
1111 } else if cmd.eq_ignore_ascii_case("ERROR") {
1112 match suffix {
1113 Some(suffix) => {
1114 if args.is_empty() {
1115 Command::ERROR(suffix.to_owned())
1116 } else {
1117 raw(cmd, args, Some(suffix))
1118 }
1119 }
1120 None => raw(cmd, args, suffix),
1121 }
1122 } else if cmd.eq_ignore_ascii_case("AWAY") {
1123 match suffix {
1124 Some(suffix) => {
1125 if args.is_empty() {
1126 Command::AWAY(Some(suffix.to_owned()))
1127 } else {
1128 raw(cmd, args, Some(suffix))
1129 }
1130 }
1131 None => raw(cmd, args, suffix),
1132 }
1133 } else if cmd.eq_ignore_ascii_case("REHASH") {
1134 if args.is_empty() {
1135 Command::REHASH
1136 } else {
1137 raw(cmd, args, suffix)
1138 }
1139 } else if cmd.eq_ignore_ascii_case("DIE") {
1140 if args.is_empty() {
1141 Command::DIE
1142 } else {
1143 raw(cmd, args, suffix)
1144 }
1145 } else if cmd.eq_ignore_ascii_case("RESTART") {
1146 if args.is_empty() {
1147 Command::RESTART
1148 } else {
1149 raw(cmd, args, suffix)
1150 }
1151 } else if cmd.eq_ignore_ascii_case("SUMMON") {
1152 match suffix {
1153 Some(suffix) => {
1154 if args.is_empty() {
1155 Command::SUMMON(suffix.to_owned(), None, None)
1156 } else if args.len() == 1 {
1157 Command::SUMMON(args[0].to_owned(), Some(suffix.to_owned()), None)
1158 } else if args.len() == 2 {
1159 Command::SUMMON(
1160 args[0].to_owned(),
1161 Some(args[1].to_owned()),
1162 Some(suffix.to_owned()),
1163 )
1164 } else {
1165 raw(cmd, args, Some(suffix))
1166 }
1167 }
1168 None => {
1169 if args.len() == 1 {
1170 Command::SUMMON(args[0].to_owned(), None, None)
1171 } else if args.len() == 2 {
1172 Command::SUMMON(args[0].to_owned(), Some(args[1].to_owned()), None)
1173 } else if args.len() == 3 {
1174 Command::SUMMON(
1175 args[0].to_owned(),
1176 Some(args[1].to_owned()),
1177 Some(args[2].to_owned()),
1178 )
1179 } else {
1180 raw(cmd, args, suffix)
1181 }
1182 }
1183 }
1184 } else if cmd.eq_ignore_ascii_case("USERS") {
1185 match suffix {
1186 Some(suffix) => {
1187 if !args.is_empty() {
1188 raw(cmd, args, Some(suffix))
1189 } else {
1190 Command::USERS(Some(suffix.to_owned()))
1191 }
1192 }
1193 None => {
1194 if args.len() != 1 {
1195 raw(cmd, args, suffix)
1196 } else {
1197 Command::USERS(Some(args[0].to_owned()))
1198 }
1199 }
1200 }
1201 } else if cmd.eq_ignore_ascii_case("WALLOPS") {
1202 match suffix {
1203 Some(suffix) => {
1204 if !args.is_empty() {
1205 raw(cmd, args, Some(suffix))
1206 } else {
1207 Command::WALLOPS(suffix.to_owned())
1208 }
1209 }
1210 None => {
1211 if args.len() != 1 {
1212 raw(cmd, args, suffix)
1213 } else {
1214 Command::WALLOPS(args[0].to_owned())
1215 }
1216 }
1217 }
1218 } else if cmd.eq_ignore_ascii_case("USERHOST") {
1219 if suffix.is_none() {
1220 Command::USERHOST(args.into_iter().map(|s| s.to_owned()).collect())
1221 } else {
1222 raw(cmd, args, suffix)
1223 }
1224 } else if cmd.eq_ignore_ascii_case("ISON") {
1225 if suffix.is_none() {
1226 Command::USERHOST(args.into_iter().map(|s| s.to_owned()).collect())
1227 } else {
1228 raw(cmd, args, suffix)
1229 }
1230 } else if cmd.eq_ignore_ascii_case("SAJOIN") {
1231 match suffix {
1232 Some(suffix) => {
1233 if args.len() != 1 {
1234 raw(cmd, args, Some(suffix))
1235 } else {
1236 Command::SAJOIN(args[0].to_owned(), suffix.to_owned())
1237 }
1238 }
1239 None => {
1240 if args.len() != 2 {
1241 raw(cmd, args, suffix)
1242 } else {
1243 Command::SAJOIN(args[0].to_owned(), args[1].to_owned())
1244 }
1245 }
1246 }
1247 } else if cmd.eq_ignore_ascii_case("SAMODE") {
1248 match suffix {
1249 Some(suffix) => {
1250 if args.len() == 1 {
1251 Command::SAMODE(args[0].to_owned(), suffix.to_owned(), None)
1252 } else if args.len() == 2 {
1253 Command::SAMODE(
1254 args[0].to_owned(),
1255 args[1].to_owned(),
1256 Some(suffix.to_owned()),
1257 )
1258 } else {
1259 raw(cmd, args, Some(suffix))
1260 }
1261 }
1262 None => {
1263 if args.len() == 2 {
1264 Command::SAMODE(args[0].to_owned(), args[1].to_owned(), None)
1265 } else if args.len() == 3 {
1266 Command::SAMODE(
1267 args[0].to_owned(),
1268 args[1].to_owned(),
1269 Some(args[2].to_owned()),
1270 )
1271 } else {
1272 raw(cmd, args, suffix)
1273 }
1274 }
1275 }
1276 } else if cmd.eq_ignore_ascii_case("SANICK") {
1277 match suffix {
1278 Some(suffix) => {
1279 if args.len() != 1 {
1280 raw(cmd, args, Some(suffix))
1281 } else {
1282 Command::SANICK(args[0].to_owned(), suffix.to_owned())
1283 }
1284 }
1285 None => {
1286 if args.len() != 2 {
1287 raw(cmd, args, suffix)
1288 } else {
1289 Command::SANICK(args[0].to_owned(), args[1].to_owned())
1290 }
1291 }
1292 }
1293 } else if cmd.eq_ignore_ascii_case("SAPART") {
1294 match suffix {
1295 Some(suffix) => {
1296 if args.len() != 1 {
1297 raw(cmd, args, Some(suffix))
1298 } else {
1299 Command::SAPART(args[0].to_owned(), suffix.to_owned())
1300 }
1301 }
1302 None => {
1303 if args.len() != 2 {
1304 raw(cmd, args, suffix)
1305 } else {
1306 Command::SAPART(args[0].to_owned(), args[1].to_owned())
1307 }
1308 }
1309 }
1310 } else if cmd.eq_ignore_ascii_case("SAQUIT") {
1311 match suffix {
1312 Some(suffix) => {
1313 if args.len() != 1 {
1314 raw(cmd, args, Some(suffix))
1315 } else {
1316 Command::SAQUIT(args[0].to_owned(), suffix.to_owned())
1317 }
1318 }
1319 None => {
1320 if args.len() != 2 {
1321 raw(cmd, args, suffix)
1322 } else {
1323 Command::SAQUIT(args[0].to_owned(), args[1].to_owned())
1324 }
1325 }
1326 }
1327 } else if cmd.eq_ignore_ascii_case("NICKSERV") {
1328 match suffix {
1329 Some(suffix) => {
1330 if !args.is_empty() {
1331 raw(cmd, args, Some(suffix))
1332 } else {
1333 Command::NICKSERV(suffix.to_owned())
1334 }
1335 }
1336 None => {
1337 if args.len() != 1 {
1338 raw(cmd, args, suffix)
1339 } else {
1340 Command::NICKSERV(args[0].to_owned())
1341 }
1342 }
1343 }
1344 } else if cmd.eq_ignore_ascii_case("CHANSERV") {
1345 match suffix {
1346 Some(suffix) => {
1347 if !args.is_empty() {
1348 raw(cmd, args, Some(suffix))
1349 } else {
1350 Command::CHANSERV(suffix.to_owned())
1351 }
1352 }
1353 None => {
1354 if args.len() != 1 {
1355 raw(cmd, args, suffix)
1356 } else {
1357 Command::CHANSERV(args[0].to_owned())
1358 }
1359 }
1360 }
1361 } else if cmd.eq_ignore_ascii_case("OPERSERV") {
1362 match suffix {
1363 Some(suffix) => {
1364 if !args.is_empty() {
1365 raw(cmd, args, Some(suffix))
1366 } else {
1367 Command::OPERSERV(suffix.to_owned())
1368 }
1369 }
1370 None => {
1371 if args.len() != 1 {
1372 raw(cmd, args, suffix)
1373 } else {
1374 Command::OPERSERV(args[0].to_owned())
1375 }
1376 }
1377 }
1378 } else if cmd.eq_ignore_ascii_case("BOTSERV") {
1379 match suffix {
1380 Some(suffix) => {
1381 if !args.is_empty() {
1382 raw(cmd, args, Some(suffix))
1383 } else {
1384 Command::BOTSERV(suffix.to_owned())
1385 }
1386 }
1387 None => {
1388 if args.len() != 1 {
1389 raw(cmd, args, suffix)
1390 } else {
1391 Command::BOTSERV(args[0].to_owned())
1392 }
1393 }
1394 }
1395 } else if cmd.eq_ignore_ascii_case("HOSTSERV") {
1396 match suffix {
1397 Some(suffix) => {
1398 if !args.is_empty() {
1399 raw(cmd, args, Some(suffix))
1400 } else {
1401 Command::HOSTSERV(suffix.to_owned())
1402 }
1403 }
1404 None => {
1405 if args.len() != 1 {
1406 raw(cmd, args, suffix)
1407 } else {
1408 Command::HOSTSERV(args[0].to_owned())
1409 }
1410 }
1411 }
1412 } else if cmd.eq_ignore_ascii_case("MEMOSERV") {
1413 match suffix {
1414 Some(suffix) => {
1415 if !args.is_empty() {
1416 raw(cmd, args, Some(suffix))
1417 } else {
1418 Command::MEMOSERV(suffix.to_owned())
1419 }
1420 }
1421 None => {
1422 if args.len() != 1 {
1423 raw(cmd, args, suffix)
1424 } else {
1425 Command::MEMOSERV(args[0].to_owned())
1426 }
1427 }
1428 }
1429 } else if cmd.eq_ignore_ascii_case("CAP") {
1430 if args.len() == 1 {
1431 if let Ok(cmd) = args[0].parse() {
1432 match suffix {
1433 Some(suffix) => Command::CAP(None, cmd, None, Some(suffix.to_owned())),
1434 None => Command::CAP(None, cmd, None, None),
1435 }
1436 } else {
1437 raw(cmd, args, suffix)
1438 }
1439 } else if args.len() == 2 {
1440 if let Ok(cmd) = args[0].parse() {
1441 match suffix {
1442 Some(suffix) => Command::CAP(
1443 None,
1444 cmd,
1445 Some(args[1].to_owned()),
1446 Some(suffix.to_owned()),
1447 ),
1448 None => Command::CAP(None, cmd, Some(args[1].to_owned()), None),
1449 }
1450 } else if let Ok(cmd) = args[1].parse() {
1451 match suffix {
1452 Some(suffix) => Command::CAP(
1453 Some(args[0].to_owned()),
1454 cmd,
1455 None,
1456 Some(suffix.to_owned()),
1457 ),
1458 None => Command::CAP(Some(args[0].to_owned()), cmd, None, None),
1459 }
1460 } else {
1461 raw(cmd, args, suffix)
1462 }
1463 } else if args.len() == 3 {
1464 if let Ok(cmd) = args[1].parse() {
1465 match suffix {
1466 Some(suffix) => Command::CAP(
1467 Some(args[0].to_owned()),
1468 cmd,
1469 Some(args[2].to_owned()),
1470 Some(suffix.to_owned()),
1471 ),
1472 None => Command::CAP(
1473 Some(args[0].to_owned()),
1474 cmd,
1475 Some(args[2].to_owned()),
1476 None,
1477 ),
1478 }
1479 } else {
1480 raw(cmd, args, suffix)
1481 }
1482 } else {
1483 raw(cmd, args, suffix)
1484 }
1485 } else if cmd.eq_ignore_ascii_case("AUTHENTICATE") {
1486 match suffix {
1487 Some(suffix) => {
1488 if args.is_empty() {
1489 Command::AUTHENTICATE(suffix.to_owned())
1490 } else {
1491 raw(cmd, args, Some(suffix))
1492 }
1493 }
1494 None => {
1495 if args.len() == 1 {
1496 Command::AUTHENTICATE(args[0].to_owned())
1497 } else {
1498 raw(cmd, args, suffix)
1499 }
1500 }
1501 }
1502 } else if cmd.eq_ignore_ascii_case("ACCOUNT") {
1503 match suffix {
1504 Some(suffix) => {
1505 if args.is_empty() {
1506 Command::ACCOUNT(suffix.to_owned())
1507 } else {
1508 raw(cmd, args, Some(suffix))
1509 }
1510 }
1511 None => {
1512 if args.len() == 1 {
1513 Command::ACCOUNT(args[0].to_owned())
1514 } else {
1515 raw(cmd, args, suffix)
1516 }
1517 }
1518 }
1519 } else if cmd.eq_ignore_ascii_case("METADATA") {
1520 if args.len() == 2 {
1521 match suffix {
1522 Some(_) => raw(cmd, args, suffix),
1523 None => match args[1].parse() {
1524 Ok(c) => Command::METADATA(args[0].to_owned(), Some(c), None, None),
1525 Err(_) => raw(cmd, args, suffix),
1526 },
1527 }
1528 } else if args.len() > 2 {
1529 match args[1].parse() {
1530 Ok(c) => Command::METADATA(
1531 args[0].to_owned(),
1532 Some(c),
1533 Some(args.into_iter().skip(1).map(|s| s.to_owned()).collect()),
1534 suffix.map(|s| s.to_owned()),
1535 ),
1536 Err(_) => {
1537 if args.len() == 3 && suffix.is_some() {
1538 Command::METADATA(
1539 args[0].to_owned(),
1540 None,
1541 Some(args.into_iter().skip(1).map(|s| s.to_owned()).collect()),
1542 suffix.map(|s| s.to_owned()),
1543 )
1544 } else {
1545 raw(cmd, args, suffix)
1546 }
1547 }
1548 }
1549 } else {
1550 raw(cmd, args, suffix)
1551 }
1552 } else if cmd.eq_ignore_ascii_case("MONITOR") {
1553 if args.len() == 1 {
1554 Command::MONITOR(args[0].to_owned(), suffix.map(|s| s.to_owned()))
1555 } else {
1556 raw(cmd, args, suffix)
1557 }
1558 } else if cmd.eq_ignore_ascii_case("BATCH") {
1559 match suffix {
1560 Some(suffix) => {
1561 if args.is_empty() {
1562 Command::BATCH(suffix.to_owned(), None, None)
1563 } else if args.len() == 1 {
1564 Command::BATCH(args[0].to_owned(), Some(suffix.parse().unwrap()), None)
1565 } else if args.len() > 1 {
1566 Command::BATCH(
1567 args[0].to_owned(),
1568 Some(args[1].parse().unwrap()),
1569 Some(
1570 vec![suffix.to_owned()]
1571 .into_iter()
1572 .chain(args.into_iter().skip(2).map(|s| s.to_owned()))
1573 .collect(),
1574 ),
1575 )
1576 } else {
1577 raw(cmd, args, Some(suffix))
1578 }
1579 }
1580 None => {
1581 if args.len() == 1 {
1582 Command::BATCH(args[0].to_owned(), None, None)
1583 } else if args.len() == 2 {
1584 Command::BATCH(args[0].to_owned(), Some(args[1].parse().unwrap()), None)
1585 } else if args.len() > 2 {
1586 Command::BATCH(
1587 args[0].to_owned(),
1588 Some(args[1].parse().unwrap()),
1589 Some(args.iter().skip(2).map(|&s| s.to_owned()).collect()),
1590 )
1591 } else {
1592 raw(cmd, args, suffix)
1593 }
1594 }
1595 }
1596 } else if cmd.eq_ignore_ascii_case("CHGHOST") {
1597 match suffix {
1598 Some(suffix) => {
1599 if args.len() == 1 {
1600 Command::CHGHOST(args[0].to_owned(), suffix.to_owned())
1601 } else {
1602 raw(cmd, args, Some(suffix))
1603 }
1604 }
1605 None => {
1606 if args.len() == 2 {
1607 Command::CHGHOST(args[0].to_owned(), args[1].to_owned())
1608 } else {
1609 raw(cmd, args, suffix)
1610 }
1611 }
1612 }
1613 } else if let Ok(resp) = cmd.parse() {
1614 Command::Response(
1615 resp,
1616 args.into_iter().map(|s| s.to_owned()).collect(),
1617 suffix.map(|s| s.to_owned()),
1618 )
1619 } else {
1620 raw(cmd, args, suffix)
1621 })
1622 }
1623}
1624
1625fn raw(cmd: &str, args: Vec<&str>, suffix: Option<&str>) -> Command {
1627 Command::Raw(
1628 cmd.to_owned(),
1629 args.into_iter().map(|s| s.to_owned()).collect(),
1630 suffix.map(|s| s.to_owned()),
1631 )
1632}
1633
1634#[derive(Clone, Copy, Debug, PartialEq)]
1636pub enum CapSubCommand {
1637 LS,
1639 LIST,
1641 REQ,
1643 ACK,
1645 NAK,
1647 END,
1649 NEW,
1651 DEL,
1653}
1654
1655impl CapSubCommand {
1656 pub fn to_str(&self) -> &str {
1658 match *self {
1659 CapSubCommand::LS => "LS",
1660 CapSubCommand::LIST => "LIST",
1661 CapSubCommand::REQ => "REQ",
1662 CapSubCommand::ACK => "ACK",
1663 CapSubCommand::NAK => "NAK",
1664 CapSubCommand::END => "END",
1665 CapSubCommand::NEW => "NEW",
1666 CapSubCommand::DEL => "DEL",
1667 }
1668 }
1669}
1670
1671impl FromStr for CapSubCommand {
1672 type Err = MessageParseError;
1673
1674 fn from_str(s: &str) -> Result<CapSubCommand, Self::Err> {
1675 if s.eq_ignore_ascii_case("LS") {
1676 Ok(CapSubCommand::LS)
1677 } else if s.eq_ignore_ascii_case("LIST") {
1678 Ok(CapSubCommand::LIST)
1679 } else if s.eq_ignore_ascii_case("REQ") {
1680 Ok(CapSubCommand::REQ)
1681 } else if s.eq_ignore_ascii_case("ACK") {
1682 Ok(CapSubCommand::ACK)
1683 } else if s.eq_ignore_ascii_case("NAK") {
1684 Ok(CapSubCommand::NAK)
1685 } else if s.eq_ignore_ascii_case("END") {
1686 Ok(CapSubCommand::END)
1687 } else if s.eq_ignore_ascii_case("NEW") {
1688 Ok(CapSubCommand::NEW)
1689 } else if s.eq_ignore_ascii_case("DEL") {
1690 Ok(CapSubCommand::DEL)
1691 } else {
1692 Err(MessageParseError::InvalidSubcommand {
1693 cmd: "CAP",
1694 sub: s.to_owned(),
1695 })
1696 }
1697 }
1698}
1699
1700#[derive(Clone, Copy, Debug, PartialEq)]
1703pub enum MetadataSubCommand {
1704 GET,
1706 LIST,
1708 SET,
1710 CLEAR,
1712}
1713
1714impl MetadataSubCommand {
1715 pub fn to_str(&self) -> &str {
1717 match *self {
1718 MetadataSubCommand::GET => "GET",
1719 MetadataSubCommand::LIST => "LIST",
1720 MetadataSubCommand::SET => "SET",
1721 MetadataSubCommand::CLEAR => "CLEAR",
1722 }
1723 }
1724}
1725
1726impl FromStr for MetadataSubCommand {
1727 type Err = MessageParseError;
1728
1729 fn from_str(s: &str) -> Result<MetadataSubCommand, Self::Err> {
1730 if s.eq_ignore_ascii_case("GET") {
1731 Ok(MetadataSubCommand::GET)
1732 } else if s.eq_ignore_ascii_case("LIST") {
1733 Ok(MetadataSubCommand::LIST)
1734 } else if s.eq_ignore_ascii_case("SET") {
1735 Ok(MetadataSubCommand::SET)
1736 } else if s.eq_ignore_ascii_case("CLEAR") {
1737 Ok(MetadataSubCommand::CLEAR)
1738 } else {
1739 Err(MessageParseError::InvalidSubcommand {
1740 cmd: "METADATA",
1741 sub: s.to_owned(),
1742 })
1743 }
1744 }
1745}
1746
1747#[derive(Clone, Debug, PartialEq)]
1749pub enum BatchSubCommand {
1750 NETSPLIT,
1752 NETJOIN,
1754 CUSTOM(String),
1756}
1757
1758impl BatchSubCommand {
1759 pub fn to_str(&self) -> &str {
1761 match *self {
1762 BatchSubCommand::NETSPLIT => "NETSPLIT",
1763 BatchSubCommand::NETJOIN => "NETJOIN",
1764 BatchSubCommand::CUSTOM(ref s) => s,
1765 }
1766 }
1767}
1768
1769impl FromStr for BatchSubCommand {
1770 type Err = MessageParseError;
1771
1772 fn from_str(s: &str) -> Result<BatchSubCommand, Self::Err> {
1773 if s.eq_ignore_ascii_case("NETSPLIT") {
1774 Ok(BatchSubCommand::NETSPLIT)
1775 } else if s.eq_ignore_ascii_case("NETJOIN") {
1776 Ok(BatchSubCommand::NETJOIN)
1777 } else {
1778 Ok(BatchSubCommand::CUSTOM(s.to_uppercase()))
1779 }
1780 }
1781}
1782
1783#[cfg(test)]
1784mod test {
1785 use super::Command;
1786 use super::Response;
1787 use crate::proto::Message;
1788
1789 #[test]
1790 fn format_response() {
1791 assert!(
1792 String::from(&Command::Response(
1793 Response::RPL_WELCOME,
1794 vec!["foo".into()],
1795 None
1796 )) == "001 foo"
1797 );
1798 }
1799
1800 #[test]
1801 fn user_round_trip() {
1802 let cmd = Command::USER("a".to_string(), "b".to_string(), "c".to_string());
1803 let line = Message::from(cmd.clone()).to_string();
1804 let returned_cmd = line.parse::<Message>().unwrap().command;
1805 assert_eq!(cmd, returned_cmd);
1806 }
1807
1808 #[test]
1809 fn parse_user_message() {
1810 let cmd = "USER a 0 * b".parse::<Message>().unwrap().command;
1811 assert_eq!(
1812 Command::USER("a".to_string(), "0".to_string(), "b".to_string()),
1813 cmd
1814 );
1815 }
1816}