From 5f1ffd753af42357c8b074c7a8bc9be2eade002e Mon Sep 17 00:00:00 2001 From: Till Hoeppner Date: Mon, 20 Apr 2015 22:38:56 +0200 Subject: Add reply generation --- build.rs | 61 --- build_commands.rs | 61 +++ build_replies.rs | 81 +++ rfc2812_replies.txt | 1352 +++++++++++++++++++++++++-------------------------- src/command.rs | 126 +++-- src/lib.rs | 8 +- src/reply.rs | 1331 ++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 2214 insertions(+), 806 deletions(-) delete mode 100644 build.rs create mode 100644 build_commands.rs create mode 100644 build_replies.rs create mode 100644 src/reply.rs diff --git a/build.rs b/build.rs deleted file mode 100644 index 53ab74c..0000000 --- a/build.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::env; -use std::fs::File; -use std::io::{ Read, Write }; -use std::path::Path; -use std::borrow::ToOwned; - -#[derive(Debug)] -struct Command { - command: String, - params: String, - doc: String -} - -fn main() { - let mut f = File::open("rfc2812_commands.txt").unwrap(); - - let mut content = String::new(); - f.read_to_string(&mut content).unwrap(); - - let mut lines = content.lines(); - let mut line = lines.next(); - - let mut commands = Vec::new(); - - let mut command: Option<&str> = None; - let mut params: Option<&str> = None; - let mut doc = String::new(); - while let Some(l) = line { - // if is new command - if l.chars().next().map(char::is_whitespace) == Some(false) - && command.is_some() && params.is_some() { - commands.push(Command { - command: command.unwrap().to_owned(), - params: params.unwrap().to_owned(), - doc: doc.clone() - }); - command = None; - params = None; - doc.clear(); - } - if l.trim().starts_with("Command:") { - command = Some(&l.trim()["Command: ".len()..]); - } else if l.trim().starts_with("Parameters:") { - params = Some(&l.trim()["Parameters: ".len()..]); - } - doc.push_str(l); - doc.push_str("\n"); - - line = lines.next(); - } - - println!("pub enum Command {{"); - for c in commands { - for l in c.doc.lines() { - println!(" /// {}", l); - } - - println!(" {}({}),\n", c.command, c.params); - } - println!("}}"); -} diff --git a/build_commands.rs b/build_commands.rs new file mode 100644 index 0000000..53ab74c --- /dev/null +++ b/build_commands.rs @@ -0,0 +1,61 @@ +use std::env; +use std::fs::File; +use std::io::{ Read, Write }; +use std::path::Path; +use std::borrow::ToOwned; + +#[derive(Debug)] +struct Command { + command: String, + params: String, + doc: String +} + +fn main() { + let mut f = File::open("rfc2812_commands.txt").unwrap(); + + let mut content = String::new(); + f.read_to_string(&mut content).unwrap(); + + let mut lines = content.lines(); + let mut line = lines.next(); + + let mut commands = Vec::new(); + + let mut command: Option<&str> = None; + let mut params: Option<&str> = None; + let mut doc = String::new(); + while let Some(l) = line { + // if is new command + if l.chars().next().map(char::is_whitespace) == Some(false) + && command.is_some() && params.is_some() { + commands.push(Command { + command: command.unwrap().to_owned(), + params: params.unwrap().to_owned(), + doc: doc.clone() + }); + command = None; + params = None; + doc.clear(); + } + if l.trim().starts_with("Command:") { + command = Some(&l.trim()["Command: ".len()..]); + } else if l.trim().starts_with("Parameters:") { + params = Some(&l.trim()["Parameters: ".len()..]); + } + doc.push_str(l); + doc.push_str("\n"); + + line = lines.next(); + } + + println!("pub enum Command {{"); + for c in commands { + for l in c.doc.lines() { + println!(" /// {}", l); + } + + println!(" {}({}),\n", c.command, c.params); + } + println!("}}"); +} diff --git a/build_replies.rs b/build_replies.rs new file mode 100644 index 0000000..a9c00e4 --- /dev/null +++ b/build_replies.rs @@ -0,0 +1,81 @@ +use std::fs::File; +use std::io::{ Read }; +use std::borrow::ToOwned; + +#[derive(Debug)] +struct Reply { + number: String, + reply: String, + doc: String +} + +fn main() { + let mut f = File::open("rfc2812_replies.txt").unwrap(); + + let mut content = String::new(); + f.read_to_string(&mut content).unwrap(); + + let mut lines = content.lines(); + let mut line = lines.next(); + + let mut replies = Vec::new(); + + while let Some(l) = line { + // if is new command + if l.chars().next().map(char::is_whitespace) == Some(false) { + let t = l.split(" ").filter(|s| !s.is_empty()).collect::>(); + assert_eq!(t.len(), 2); + replies.push(Reply { + number: t[0].to_owned(), + reply: t[1].to_owned(), + doc: String::new() + }); + } + + let len = replies.len(); + replies[len - 1].doc.push_str(l); + replies[len - 1].doc.push_str("\n"); + + line = lines.next(); + } + + println!("use ::{{ Result, IrscError }};"); + println!("use std::str::FromStr;"); + println!("use std::borrow::ToOwned;"); + + println!("#[allow(non_camel_case_types)]"); + println!("#[derive(Debug, Hash, PartialEq, Eq)]"); + println!("pub enum Reply {{"); + for r in &replies { + for l in r.doc.lines() { + println!(" /// {}", l); + } + + println!(" {} = {},\n", r.reply, r.number); + } + println!("}}\n\n"); + + println!("impl FromStr for Reply {{"); + println!(" type Err = IrscError;"); + println!(" fn from_str(s: &str) -> Result {{"); + println!(" use self::Reply::*;"); + println!(" match s {{"); + for r in &replies { + println!(" \"{}\" => Ok({}),", r.number, r.reply); + } + println!(" _ => Err(IrscError::NotFound)"); + println!(" }}"); + println!(" }}"); + println!("}}"); + + println!("impl ToString for Reply {{"); + println!(" fn to_string(&self) -> String {{"); + println!(" use self::Reply::*;"); + println!(" match *self {{"); + for r in &replies { + println!(" {} => \"{}\".to_owned(),", r.reply, r.number); + } + println!(" }}"); + println!(" }}"); + println!("}}"); +} diff --git a/rfc2812_replies.txt b/rfc2812_replies.txt index 52fd99c..4367fcc 100644 --- a/rfc2812_replies.txt +++ b/rfc2812_replies.txt @@ -1,760 +1,758 @@ - 001 RPL_WELCOME - "Welcome to the Internet Relay Network - !@" - 002 RPL_YOURHOST - "Your host is , running version " - 003 RPL_CREATED - "This server was created " - 004 RPL_MYINFO - " - " - - - The server sends Replies 001 to 004 to a user upon - successful registration. - 005 RPL_BOUNCE - "Try server , port " - - - Sent by the server to a user to suggest an alternative - server. This is often used when the connection is - refused because the server is already full. - - 302 RPL_USERHOST - ":*1 *( " " )" - - - Reply format used by USERHOST to list replies to - the query list. The reply string is composed as - follows: - - reply = nickname [ "*" ] "=" ( "+" / "-" ) hostname - - The '*' indicates whether the client has registered - as an Operator. The '-' or '+' characters represent - whether the client has set an AWAY message or not - respectively. - - 303 RPL_ISON - ":*1 *( " " )" - - - Reply format used by ISON to list replies to the - query list. - - 301 RPL_AWAY - " :" - 305 RPL_UNAWAY - ":You are no longer marked as being away" - 306 RPL_NOWAWAY - ":You have been marked as being away" - - - These replies are used with the AWAY command (if - allowed). RPL_AWAY is sent to any client sending a - PRIVMSG to a client which is away. RPL_AWAY is only - sent by the server to which the client is connected. - Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the - client removes and sets an AWAY message. - - 311 RPL_WHOISUSER - " * :" - 312 RPL_WHOISSERVER - " :" - 313 RPL_WHOISOPERATOR - " :is an IRC operator" - 317 RPL_WHOISIDLE - " :seconds idle" - 318 RPL_ENDOFWHOIS - " :End of WHOIS list" - 319 RPL_WHOISCHANNELS - " :*( ( "@" / "+" ) " " )" - - - Replies 311 - 313, 317 - 319 are all replies - generated in response to a WHOIS message. Given that - there are enough parameters present, the answering - server MUST either formulate a reply out of the above - numerics (if the query nick is found) or return an - error reply. The '*' in RPL_WHOISUSER is there as - the literal character and not as a wild card. For - each reply set, only RPL_WHOISCHANNELS may appear - more than once (for long lists of channel names). - The '@' and '+' characters next to the channel name - indicate whether a client is a channel operator or - has been granted permission to speak on a moderated - channel. The RPL_ENDOFWHOIS reply is used to mark - the end of processing a WHOIS message. - - 314 RPL_WHOWASUSER - " * :" - 369 RPL_ENDOFWHOWAS - " :End of WHOWAS" - - - When replying to a WHOWAS message, a server MUST use - the replies RPL_WHOWASUSER, RPL_WHOISSERVER or - ERR_WASNOSUCHNICK for each nickname in the presented - list. At the end of all reply batches, there MUST - be RPL_ENDOFWHOWAS (even if there was only one reply - and it was an error). - - 321 RPL_LISTSTART - Obsolete. Not used. - - 322 RPL_LIST - " <# visible> :" - 323 RPL_LISTEND - ":End of LIST" - - - Replies RPL_LIST, RPL_LISTEND mark the actual replies - with data and end of the server's response to a LIST - command. If there are no channels available to return, - only the end reply MUST be sent. - - 325 RPL_UNIQOPIS - " " - - 324 RPL_CHANNELMODEIS - " " - - 331 RPL_NOTOPIC - " :No topic is set" - 332 RPL_TOPIC - " :" - - - When sending a TOPIC message to determine the - channel topic, one of two replies is sent. If - the topic is set, RPL_TOPIC is sent back else - RPL_NOTOPIC. - - 341 RPL_INVITING - " " - - - Returned by the server to indicate that the - attempted INVITE message was successful and is - being passed onto the end client. - - 342 RPL_SUMMONING - " :Summoning user to IRC" - - - Returned by a server answering a SUMMON message to - indicate that it is summoning that user. - - 346 RPL_INVITELIST - " " - 347 RPL_ENDOFINVITELIST - " :End of channel invite list" - - - When listing the 'invitations masks' for a given channel, - a server is required to send the list back using the - RPL_INVITELIST and RPL_ENDOFINVITELIST messages. A - separate RPL_INVITELIST is sent for each active mask. - After the masks have been listed (or if none present) a - RPL_ENDOFINVITELIST MUST be sent. - - 348 RPL_EXCEPTLIST - " " - 349 RPL_ENDOFEXCEPTLIST - " :End of channel exception list" - - - When listing the 'exception masks' for a given channel, - a server is required to send the list back using the - RPL_EXCEPTLIST and RPL_ENDOFEXCEPTLIST messages. A - separate RPL_EXCEPTLIST is sent for each active mask. - After the masks have been listed (or if none present) - a RPL_ENDOFEXCEPTLIST MUST be sent. - - 351 RPL_VERSION - ". :" - - - Reply by the server showing its version details. - The is the version of the software being - used (including any patchlevel revisions) and the - is used to indicate if the server is - running in "debug mode". - - The "comments" field may contain any comments about - the version or further version details. - - 352 RPL_WHOREPLY - " - ( "H" / "G" > ["*"] [ ( "@" / "+" ) ] - : " - - 315 RPL_ENDOFWHO - " :End of WHO list" - - - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used - to answer a WHO message. The RPL_WHOREPLY is only - sent if there is an appropriate match to the WHO - query. If there is a list of parameters supplied - with a WHO message, a RPL_ENDOFWHO MUST be sent - after processing each list item with being - the item. - - 353 RPL_NAMREPLY - "( "=" / "*" / "@" ) - :[ "@" / "+" ] *( " " [ "@" / "+" ] ) - - "@" is used for secret channels, "*" for private - channels, and "=" for others (public channels). - - 366 RPL_ENDOFNAMES - " :End of NAMES list" - - - To reply to a NAMES message, a reply pair consisting - of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the - server back to the client. If there is no channel - found as in the query, then only RPL_ENDOFNAMES is - returned. The exception to this is when a NAMES - message is sent with no parameters and all visible - channels and contents are sent back in a series of - RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark - the end. - - 364 RPL_LINKS - " : " - 365 RPL_ENDOFLINKS - " :End of LINKS list" - - - In replying to the LINKS message, a server MUST send - replies back using the RPL_LINKS numeric and mark the - end of the list using an RPL_ENDOFLINKS reply. - - 367 RPL_BANLIST - " " - 368 RPL_ENDOFBANLIST - " :End of channel ban list" - - - When listing the active 'bans' for a given channel, - a server is required to send the list back using the - RPL_BANLIST and RPL_ENDOFBANLIST messages. A separate - RPL_BANLIST is sent for each active banmask. After the - banmasks have been listed (or if none present) a - RPL_ENDOFBANLIST MUST be sent. - - 371 RPL_INFO - ":" - 374 RPL_ENDOFINFO - ":End of INFO list" - - - A server responding to an INFO message is required to - send all its 'info' in a series of RPL_INFO messages - with a RPL_ENDOFINFO reply to indicate the end of the - replies. - - 375 RPL_MOTDSTART - ":- Message of the day - " - 372 RPL_MOTD - ":- " - 376 RPL_ENDOFMOTD - ":End of MOTD command" - - - When responding to the MOTD message and the MOTD file - is found, the file is displayed line by line, with - each line no longer than 80 characters, using - RPL_MOTD format replies. These MUST be surrounded - by a RPL_MOTDSTART (before the RPL_MOTDs) and an - RPL_ENDOFMOTD (after). - - 381 RPL_YOUREOPER - ":You are now an IRC operator" - - - RPL_YOUREOPER is sent back to a client which has - just successfully issued an OPER message and gained - operator status. - - 382 RPL_REHASHING - " :Rehashing" - - - If the REHASH option is used and an operator sends - a REHASH message, an RPL_REHASHING is sent back to - the operator. - - 383 RPL_YOURESERVICE - "You are service " - - - Sent by the server to a service upon successful - registration. - - 391 RPL_TIME - " :" - - - When replying to the TIME message, a server MUST send - the reply using the RPL_TIME format above. The string - showing the time need only contain the correct day and - time there. There is no further requirement for the - time string. - - 392 RPL_USERSSTART - ":UserID Terminal Host" - 393 RPL_USERS - ": " - 394 RPL_ENDOFUSERS - ":End of users" - 395 RPL_NOUSERS - ":Nobody logged in" - - - If the USERS message is handled by a server, the - replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and - RPL_NOUSERS are used. RPL_USERSSTART MUST be sent - first, following by either a sequence of RPL_USERS - or a single RPL_NOUSER. Following this is - RPL_ENDOFUSERS. - - 200 RPL_TRACELINK - "Link - V - - " - 201 RPL_TRACECONNECTING - "Try. " - 202 RPL_TRACEHANDSHAKE - "H.S. " - 203 RPL_TRACEUNKNOWN - "???? []" - 204 RPL_TRACEOPERATOR - "Oper " - 205 RPL_TRACEUSER - "User " - 206 RPL_TRACESERVER - "Serv S C - @ V" - 207 RPL_TRACESERVICE - "Service " - 208 RPL_TRACENEWTYPE - " 0 " - 209 RPL_TRACECLASS - "Class " - 210 RPL_TRACERECONNECT - Unused. - 261 RPL_TRACELOG - "File " - 262 RPL_TRACEEND - " :End of TRACE" - - - The RPL_TRACE* are all returned by the server in - response to the TRACE message. How many are - returned is dependent on the TRACE message and - whether it was sent by an operator or not. There - is no predefined order for which occurs first. - Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and - RPL_TRACEHANDSHAKE are all used for connections - which have not been fully established and are either - unknown, still attempting to connect or in the - process of completing the 'server handshake'. - RPL_TRACELINK is sent by any server which handles - a TRACE message and has to pass it on to another - server. The list of RPL_TRACELINKs sent in - response to a TRACE command traversing the IRC - network should reflect the actual connectivity of - the servers themselves along that path. - - RPL_TRACENEWTYPE is to be used for any connection - which does not fit in the other categories but is - being displayed anyway. - RPL_TRACEEND is sent to indicate the end of the list. - - 211 RPL_STATSLINKINFO - " - -