1use std::fmt;
2use std::iter::Peekable;
3use std::str::Chars;
4use std::vec::Vec;
5
6#[derive(Default, Debug)]
7pub struct Message {
8 pub server: Option<String>,
9 pub nick: Option<String>,
10 pub user: Option<String>,
11 pub host: Option<String>,
12 pub command: String,
13 pub params: Vec<String>,
14}
15
16impl fmt::Display for Message {
17 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18 if self.server.is_some() {
19 write!(f, "Server: {} ", self.server.as_ref().unwrap())?;
20 } else if self.nick.is_some() {
21 if self.user.is_some() {
22 write!(
23 f,
24 "User: {}!{}",
25 self.nick.as_ref().unwrap(),
26 self.user.as_ref().unwrap()
27 )?;
28 } else {
29 write!(f, "User: {}", self.nick.as_ref().unwrap())?;
30 }
31
32 if self.host.is_some() {
33 write!(f, "@{}, ", self.host.as_ref().unwrap())?;
34 }
35 }
36
37 write!(f, "Command: {}, Params: {:?}", self.command, self.params)
38 }
39}
40
41pub struct Parser;
42
43impl Parser {
44 pub fn new() -> Parser {
45 Parser {}
46 }
47
48 pub fn parse<T: AsRef<str>>(&mut self, line: T) -> Option<Message> {
49 let data = line.as_ref().trim_end_matches("\r\n");
50 if data.len() > 510 {
51 return None;
52 }
53
54 let mut data = data.chars().peekable();
55 let mut message = Message {
56 ..Default::default()
57 };
58
59 let chr = data.peek()?;
60 if *chr == ':' {
61 let prefix = self.parse_prefix(&mut data);
62 if prefix.find('@').is_some() {
63 let mut chunks = prefix.split('@');
64 let name = chunks.nth(0).unwrap().to_string();
65 if name.find('!').is_some() {
66 let mut inner_chunks = name.split('!');
67 message.nick = Some(inner_chunks.nth(0).unwrap().to_string());
68 message.user = Some(inner_chunks.nth(0).unwrap().to_string());
69 } else {
70 message.nick = Some(name);
71 }
72
73 message.host = Some(chunks.nth(0).unwrap().to_string());
74 } else {
75 message.server = Some(prefix);
76 }
77 }
78
79 if let Some(command) = self.parse_command(&mut data) {
80 message.command = command;
81 } else {
82 return None;
83 }
84
85 if let Some(params) = self.parse_params(&mut data) {
86 message.params = params;
87 } else {
88 return None;
89 }
90
91 Some(message)
92 }
93
94 fn parse_prefix(&mut self, data: &mut Peekable<Chars>) -> String {
95 return data
96 .by_ref()
97 .skip(1)
98 .take_while(|c| *c != ' ')
99 .collect::<String>();
100 }
101
102 fn parse_command(&mut self, data: &mut Peekable<Chars>) -> Option<String> {
103 let chr = data.peek()?;
104 if chr.is_numeric() {
105 let numeric = data
106 .by_ref()
107 .take_while(|c| c.is_numeric())
108 .collect::<String>();
109
110 if numeric.len() == 3 {
112 return Some(numeric);
113 }
114
115 return None;
116 } else {
117 return Some(data.by_ref().take_while(|c| *c != ' ').collect::<String>());
118 }
119 }
120
121 fn parse_params(&mut self, data: &mut Peekable<Chars>) -> Option<Vec<String>> {
122 let mut params = Vec::new();
123 while let Some(chr) = data.peek() {
124 if *chr == ':' {
125 params.push(data.by_ref().skip(1).collect::<String>());
126 } else {
127 params.push(data.by_ref().take_while(|c| *c != ' ').collect::<String>());
128 }
129
130 if params.len() > 15 {
131 return None;
132 }
133 }
134
135 return Some(params);
136 }
137}