aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTill Hoeppner2015-04-20 20:54:13 +0200
committerTill Hoeppner2015-04-20 20:57:04 +0200
commitcabbd084f89908e91b81300a776cbeb5034396b8 (patch)
treec29bb2aca28b2827133d54bdb64b131da21e2a4a
parent3cee55e3bfd1c853e1ff4fa71a690f1ad1d6e37e (diff)
downloadirsc-cabbd084f89908e91b81300a776cbeb5034396b8.tar.gz
irsc-cabbd084f89908e91b81300a776cbeb5034396b8.tar.xz
irsc-cabbd084f89908e91b81300a776cbeb5034396b8.zip
Something inbetween working and broken
-rw-r--r--examples/01.rs8
-rw-r--r--src/command.rs1760
-rw-r--r--src/lib.rs3
-rw-r--r--src/message.rs1102
-rw-r--r--src/server.rs11
5 files changed, 1884 insertions, 1000 deletions
diff --git a/examples/01.rs b/examples/01.rs
index 6b95be2..eb662ca 100644
--- a/examples/01.rs
+++ b/examples/01.rs
@@ -1,7 +1,7 @@
#![feature(plugin)]
#![plugin(regex_macros)]
-extern crate irsc;
+/*extern crate irsc;
use std::borrow::ToOwned;
@@ -33,14 +33,14 @@ fn callback(server: &mut Server, msg: &Message) {
_ => ()
}*/
}
-
+*/
fn main() {
- let mut s = Server::new();
+ /*let mut s = Server::new();
s.connect("irc.mozilla.org".to_owned(), 6667).unwrap();
s.nick(NAME).unwrap();
s.user(NAME, "*", "*", DESC).unwrap();
s.join("#botzoo").unwrap();
// Dedicate this thread to listening and event processing
- s.listen(&[callback]).unwrap();
+ s.listen(&[callback]).unwrap();*/
}
diff --git a/src/command.rs b/src/command.rs
new file mode 100644
index 0000000..828c7a5
--- /dev/null
+++ b/src/command.rs
@@ -0,0 +1,1760 @@
+use std::borrow::{ ToOwned, Cow };
+
+use message::{ Message, MsgType };
+
+#[derive(Debug, Hash, PartialEq, Eq)]
+pub enum Command<'a> {
+ /// 3.1.1 Password message
+ ///
+ /// Command: PASS
+ /// Parameters: <password>
+ ///
+ /// The PASS command is used to set a 'connection password'. The
+ /// optional password can and MUST be set before any attempt to register
+ /// the connection is made. Currently this requires that user send a
+ /// PASS command before sending the NICK/USER combination.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_ALREADYREGISTRED
+ ///
+ /// Example:
+ ///
+ /// PASS secretpasswordhere
+ ///
+ PASS(&'a str),
+
+ /// 3.1.2 Nick message
+ ///
+ ///
+ /// Command: NICK
+ /// Parameters: <nickname>
+ ///
+ /// NICK command is used to give user a nickname or change the existing
+ /// one.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NONICKNAMEGIVEN ERR_ERRONEUSNICKNAME
+ /// ERR_NICKNAMEINUSE ERR_NICKCOLLISION
+ /// ERR_UNAVAILRESOURCE ERR_RESTRICTED
+ ///
+ /// Examples:
+ ///
+ /// NICK Wiz ; Introducing new nick "Wiz" if session is
+ /// still unregistered, or user changing his
+ /// nickname to "Wiz"
+ ///
+ /// :WiZ!jto@tolsun.oulu.fi NICK Kilroy
+ /// ; Server telling that WiZ changed his
+ /// nickname to Kilroy.
+ ///
+ NICK(&'a str),
+
+ /// 3.1.3 User message
+ ///
+ /// Command: USER
+ /// Parameters: <user> <mode> <unused> <realname>
+ ///
+ /// The USER command is used at the beginning of connection to specify
+ /// the username, hostname and realname of a new user.
+ ///
+ /// The <mode> parameter should be a numeric, and can be used to
+ /// automatically set user modes when registering with the server. This
+ /// parameter is a bitmask, with only 2 bits having any signification: if
+ /// the bit 2 is set, the user mode 'w' will be set and if the bit 3 is
+ /// set, the user mode 'i' will be set. (See Section 3.1.5 "User
+ /// Modes").
+ ///
+ /// The <realname> may contain space characters.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_ALREADYREGISTRED
+ ///
+ /// Example:
+ ///
+ /// USER guest 0 * :Ronnie Reagan ; User registering themselves with a
+ /// username of "guest" and real name
+ /// "Ronnie Reagan".
+ ///
+ /// USER guest 8 * :Ronnie Reagan ; User registering themselves with a
+ /// username of "guest" and real name
+ /// "Ronnie Reagan", and asking to be set
+ /// invisible.
+ ///
+ USER(&'a str, &'a str, &'a str, &'a str),
+
+ /// 3.1.4 Oper message
+ ///
+ /// Command: OPER
+ /// Parameters: <name> <password>
+ ///
+ /// A normal user uses the OPER command to obtain operator privileges.
+ /// The combination of <name> and <password> are REQUIRED to gain
+ /// Operator privileges. Upon success, the user will receive a MODE
+ /// message (see section 3.1.5) indicating the new user modes.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS RPL_YOUREOPER
+ /// ERR_NOOPERHOST ERR_PASSWDMISMATCH
+ ///
+ /// Example:
+ ///
+ /// OPER foo bar ; Attempt to register as an operator
+ /// using a username of "foo" and "bar"
+ /// as the password.
+ ///
+ OPER(&'a str, &'a str),
+
+ /// 3.1.5 User mode message
+ ///
+ /// Command: UMODE
+ /// Parameters: <nickname>
+ /// *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )
+ ///
+ /// The user MODE's are typically changes which affect either how the
+ /// client is seen by others or what 'extra' messages the client is sent.
+ ///
+ /// A user MODE command MUST only be accepted if both the sender of the
+ /// message and the nickname given as a parameter are both the same. If
+ /// no other parameter is given, then the server will return the current
+ /// settings for the nick.
+ ///
+ /// The available modes are as follows:
+ ///
+ /// a - user is flagged as away;
+ /// i - marks a users as invisible;
+ /// w - user receives wallops;
+ /// r - restricted user connection;
+ /// o - operator flag;
+ /// O - local operator flag;
+ /// s - marks a user for receipt of server notices.
+ ///
+ /// Additional modes may be available later on.
+ ///
+ /// The flag 'a' SHALL NOT be toggled by the user using the MODE command,
+ /// instead use of the AWAY command is REQUIRED.
+ ///
+ /// If a user attempts to make themselves an operator using the "+o" or
+ /// "+O" flag, the attempt SHOULD be ignored as users could bypass the
+ /// authentication mechanisms of the OPER command. There is no
+ /// restriction, however, on anyone `deopping' themselves (using "-o" or
+ /// "-O").
+ ///
+ /// On the other hand, if a user attempts to make themselves unrestricted
+ /// using the "-r" flag, the attempt SHOULD be ignored. There is no
+ /// restriction, however, on anyone `deopping' themselves (using "+r").
+ /// This flag is typically set by the server upon connection for
+ /// administrative reasons. While the restrictions imposed are left up
+ /// to the implementation, it is typical that a restricted user not be
+ /// allowed to change nicknames, nor make use of the channel operator
+ /// status on channels.
+ ///
+ /// The flag 's' is obsolete but MAY still be used.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_USERSDONTMATCH
+ /// ERR_UMODEUNKNOWNFLAG RPL_UMODEIS
+ ///
+ /// Examples:
+ ///
+ /// MODE WiZ -w ; Command by WiZ to turn off
+ /// reception of WALLOPS messages.
+ ///
+ /// MODE Angel +i ; Command from Angel to make herself
+ /// invisible.
+ ///
+ /// MODE WiZ -o ; WiZ 'deopping' (removing operator
+ /// status).
+ ///
+ UMODE(&'a str),
+
+ /// 3.1.6 Service message
+ ///
+ /// Command: SERVICE
+ /// Parameters: <nickname> <reserved> <distribution> <type>
+ /// <reserved> <info>
+ ///
+ /// The SERVICE command to register a new service. Command parameters
+ /// specify the service nickname, distribution, type and info of a new
+ /// service.
+ ///
+ /// The <distribution> parameter is used to specify the visibility of a
+ /// service. The service may only be known to servers which have a name
+ /// matching the distribution. For a matching server to have knowledge
+ /// of the service, the network path between that server and the server
+ /// on which the service is connected MUST be composed of servers which
+ /// names all match the mask.
+ ///
+ /// The <type> parameter is currently reserved for future usage.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_ALREADYREGISTRED ERR_NEEDMOREPARAMS
+ /// ERR_ERRONEUSNICKNAME
+ /// RPL_YOURESERVICE RPL_YOURHOST
+ /// RPL_MYINFO
+ ///
+ /// Example:
+ ///
+ /// SERVICE dict * *.fr 0 0 :French Dictionary ; Service registering
+ /// itself with a name of "dict". This
+ /// service will only be available on
+ /// servers which name matches "*.fr".
+ ///
+ SERVICE(&'a str, &'a str, &'a str, &'a str, &'a str, &'a str),
+
+ /// 3.1.7 Quit
+ ///
+ /// Command: QUIT
+ /// Parameters: [ <Quit Message> ]
+ ///
+ /// A client session is terminated with a quit message. The server
+ /// acknowledges this by sending an ERROR message to the client.
+ ///
+ /// Numeric Replies:
+ ///
+ /// None.
+ ///
+ /// Example:
+ ///
+ /// QUIT :Gone to have lunch ; Preferred message format.
+ ///
+ /// :syrk!kalt@millennium.stealth.net QUIT :Gone to have lunch ; User
+ /// syrk has quit IRC to have lunch.
+ ///
+ QUIT(Option<&'a str>),
+
+ /// 3.1.8 Squit
+ ///
+ /// Command: SQUIT
+ /// Parameters: <server> <comment>
+ ///
+ /// The SQUIT command is available only to operators. It is used to
+ /// disconnect server links. Also servers can generate SQUIT messages on
+ /// error conditions. A SQUIT message may also target a remote server
+ /// connection. In this case, the SQUIT message will simply be sent to
+ /// the remote server without affecting the servers in between the
+ /// operator and the remote server.
+ ///
+ /// The <comment> SHOULD be supplied by all operators who execute a SQUIT
+ /// for a remote server. The server ordered to disconnect its peer
+ /// generates a WALLOPS message with <comment> included, so that other
+ /// users may be aware of the reason of this action.
+ ///
+ /// Numeric replies:
+ ///
+ /// ERR_NOPRIVILEGES ERR_NOSUCHSERVER
+ /// ERR_NEEDMOREPARAMS
+ ///
+ /// Examples:
+ ///
+ /// SQUIT tolsun.oulu.fi :Bad Link ? ; Command to uplink of the server
+ /// tolson.oulu.fi to terminate its
+ /// connection with comment "Bad Link".
+ ///
+ /// :Trillian SQUIT cm22.eng.umd.edu :Server out of control ; Command
+ /// from Trillian from to disconnect
+ /// "cm22.eng.umd.edu" from the net with
+ /// comment "Server out of control".
+ ///
+ SQUIT(&'a str, &'a str),
+
+ /// 3.2.1 Join message
+ ///
+ /// Command: JOIN
+ /// Parameters: ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] )
+ /// / "0"
+ ///
+ /// The JOIN command is used by a user to request to start listening to
+ /// the specific channel. Servers MUST be able to parse arguments in the
+ /// form of a list of target, but SHOULD NOT use lists when sending JOIN
+ /// messages to clients.
+ ///
+ /// Once a user has joined a channel, he receives information about
+ /// all commands his server receives affecting the channel. This
+ /// includes JOIN, MODE, KICK, PART, QUIT and of course PRIVMSG/NOTICE.
+ /// This allows channel members to keep track of the other channel
+ /// members, as well as channel modes.
+ ///
+ /// If a JOIN is successful, the user receives a JOIN message as
+ /// confirmation and is then sent the channel's topic (using RPL_TOPIC) and
+ /// the list of users who are on the channel (using RPL_NAMREPLY), which
+ /// MUST include the user joining.
+ ///
+ /// Note that this message accepts a special argument ("0"), which is
+ /// a special request to leave all channels the user is currently a member
+ /// of. The server will process this message as if the user had sent
+ /// a PART command (See Section 3.2.2) for each channel he is a member
+ /// of.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_BANNEDFROMCHAN
+ /// ERR_INVITEONLYCHAN ERR_BADCHANNELKEY
+ /// ERR_CHANNELISFULL ERR_BADCHANMASK
+ /// ERR_NOSUCHCHANNEL ERR_TOOMANYCHANNELS
+ /// ERR_TOOMANYTARGETS ERR_UNAVAILRESOURCE
+ /// RPL_TOPIC
+ ///
+ /// Examples:
+ ///
+ /// JOIN #foobar ; Command to join channel #foobar.
+ ///
+ /// JOIN &foo fubar ; Command to join channel &foo using
+ /// key "fubar".
+ ///
+ /// JOIN #foo,&bar fubar ; Command to join channel #foo using
+ /// key "fubar" and &bar using no key.
+ ///
+ /// JOIN #foo,#bar fubar,foobar ; Command to join channel #foo using
+ /// key "fubar", and channel #bar using
+ /// key "foobar".
+ ///
+ /// JOIN #foo,#bar ; Command to join channels #foo and
+ /// #bar.
+ ///
+ /// JOIN 0 ; Leave all currently joined
+ /// channels.
+ ///
+ /// :WiZ!jto@tolsun.oulu.fi JOIN #Twilight_zone ; JOIN message from WiZ
+ /// on channel #Twilight_zone
+ ///
+ JOIN(Vec<&'a str>, Vec<&'a str>),
+
+ /// 3.2.2 Part message
+ ///
+ /// Command: PART
+ /// Parameters: <channel> *( "," <channel> ) [ <Part Message> ]
+ ///
+ /// The PART command causes the user sending the message to be removed
+ /// from the list of active members for all given channels listed in the
+ /// parameter string. If a "Part Message" is given, this will be sent
+ /// instead of the default message, the nickname. This request is always
+ /// granted by the server.
+ ///
+ /// Servers MUST be able to parse arguments in the form of a list of
+ /// target, but SHOULD NOT use lists when sending PART messages to
+ /// clients.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_NOSUCHCHANNEL
+ /// ERR_NOTONCHANNEL
+ ///
+ /// Examples:
+ ///
+ /// PART #twilight_zone ; Command to leave channel
+ /// "#twilight_zone"
+ ///
+ /// PART #oz-ops,&group5 ; Command to leave both channels
+ /// "&group5" and "#oz-ops".
+ ///
+ /// :WiZ!jto@tolsun.oulu.fi PART #playzone :I lost
+ /// ; User WiZ leaving channel
+ /// "#playzone" with the message "I
+ /// lost".
+ ///
+ PART(Vec<&'a str>, Option<&'a str>),
+
+ /// 3.2.3 Channel mode message
+ ///
+ /// Command: MODE
+ /// Parameters: <channel> *( ( "-" / "+" ) *<modes> *<modeparams> )
+ ///
+ /// The MODE command is provided so that users may query and change the
+ /// characteristics of a channel. For more details on available modes
+ /// and their uses, see "Internet Relay Chat: Channel Management" [IRC-
+ /// CHAN]. Note that there is a maximum limit of three (3) changes per
+ /// command for modes that take a parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_KEYSET
+ /// ERR_NOCHANMODES ERR_CHANOPRIVSNEEDED
+ /// ERR_USERNOTINCHANNEL ERR_UNKNOWNMODE
+ /// RPL_CHANNELMODEIS
+ /// RPL_BANLIST RPL_ENDOFBANLIST
+ /// RPL_EXCEPTLIST RPL_ENDOFEXCEPTLIST
+ /// RPL_INVITELIST RPL_ENDOFINVITELIST
+ /// RPL_UNIQOPIS
+ ///
+ /// The following examples are given to help understanding the syntax of
+ /// the MODE command, but refer to modes defined in "Internet Relay Chat:
+ /// Channel Management" [IRC-CHAN].
+ ///
+ /// Examples:
+ ///
+ /// MODE #Finnish +imI *!*@*.fi ; Command to make #Finnish channel
+ /// moderated and 'invite-only' with user
+ /// with a hostname matching *.fi
+ /// automatically invited.
+ ///
+ /// MODE #Finnish +o Kilroy ; Command to give 'chanop' privileges
+ /// to Kilroy on channel #Finnish.
+ ///
+ /// MODE #Finnish +v Wiz ; Command to allow WiZ to speak on
+ /// #Finnish.
+ ///
+ /// MODE #Fins -s ; Command to remove 'secret' flag
+ /// from channel #Fins.
+ ///
+ /// MODE #42 +k oulu ; Command to set the channel key to
+ /// "oulu".
+ ///
+ /// MODE #42 -k oulu ; Command to remove the "oulu"
+ /// channel key on channel "#42".
+ ///
+ /// MODE #eu-opers +l 10 ; Command to set the limit for the
+ /// number of users on channel
+ /// "#eu-opers" to 10.
+ ///
+ /// :WiZ!jto@tolsun.oulu.fi MODE #eu-opers -l
+ /// ; User "WiZ" removing the limit for
+ /// the number of users on channel "#eu-
+ /// opers".
+ ///
+ /// MODE &oulu +b ; Command to list ban masks set for
+ /// the channel "&oulu".
+ ///
+ /// MODE &oulu +b *!*@* ; Command to prevent all users from
+ /// joining.
+ ///
+ /// MODE &oulu +b *!*@*.edu +e *!*@*.bu.edu
+ /// ; Command to prevent any user from a
+ /// hostname matching *.edu from joining,
+ /// except if matching *.bu.edu
+ ///
+ /// MODE #bu +be *!*@*.edu *!*@*.bu.edu
+ /// ; Comment to prevent any user from a
+ /// hostname matching *.edu from joining,
+ /// except if matching *.bu.edu
+ ///
+ /// MODE #meditation e ; Command to list exception masks set
+ /// for the channel "#meditation".
+ ///
+ /// MODE #meditation I ; Command to list invitations masks
+ /// set for the channel "#meditation".
+ ///
+ /// MODE !12345ircd O ; Command to ask who the channel
+ /// creator for "!12345ircd" is
+ ///
+ MODE(&'a str, &'a str /* *( ( "-" / "+" ) *<modes> *<modeparams> ) */),
+
+ /// 3.2.4 Topic message
+ ///
+ /// Command: TOPIC
+ /// Parameters: <channel> [ <topic> ]
+ ///
+ /// The TOPIC command is used to change or view the topic of a channel.
+ /// The topic for channel <channel> is returned if there is no <topic>
+ /// given. If the <topic> parameter is present, the topic for that
+ /// channel will be changed, if this action is allowed for the user
+ /// requesting it. If the <topic> parameter is an empty string, the
+ /// topic for that channel will be removed.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_NOTONCHANNEL
+ /// RPL_NOTOPIC RPL_TOPIC
+ /// ERR_CHANOPRIVSNEEDED ERR_NOCHANMODES
+ ///
+ /// Examples:
+ ///
+ /// :WiZ!jto@tolsun.oulu.fi TOPIC #test :New topic ; User Wiz setting the
+ /// topic.
+ ///
+ /// TOPIC #test :another topic ; Command to set the topic on #test
+ /// to "another topic".
+ ///
+ /// TOPIC #test : ; Command to clear the topic on
+ /// #test.
+ ///
+ /// TOPIC #test ; Command to check the topic for
+ /// #test.
+ ///
+ TOPIC(&'a str, Option<&'a str>),
+
+ /// 3.2.5 Names message
+ ///
+ /// Command: NAMES
+ /// Parameters: [ <channel> *( "," <channel> ) [ <target> ] ]
+ ///
+ /// By using the NAMES command, a user can list all nicknames that are
+ /// visible to him. For more details on what is visible and what is not,
+ /// see "Internet Relay Chat: Channel Management" [IRC-CHAN]. The
+ /// <channel> parameter specifies which channel(s) to return information
+ /// about. There is no error reply for bad channel names.
+ ///
+ /// If no <channel> parameter is given, a list of all channels and their
+ /// occupants is returned. At the end of this list, a list of users who
+ /// are visible but either not on any channel or not on a visible channel
+ /// are listed as being on `channel' "*".
+ ///
+ /// If the <target> parameter is specified, the request is forwarded to
+ /// that server which will generate the reply.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numerics:
+ ///
+ /// ERR_TOOMANYMATCHES ERR_NOSUCHSERVER
+ /// RPL_NAMREPLY RPL_ENDOFNAMES
+ ///
+ /// Examples:
+ ///
+ /// NAMES #twilight_zone,#42 ; Command to list visible users on
+ /// #twilight_zone and #42
+ ///
+ /// NAMES ; Command to list all visible
+ /// channels and users
+ ///
+ NAMES(Option<(Vec<&'a str>, Option<&'a str>)>),
+
+ /// 3.2.6 List message
+ ///
+ /// Command: LIST
+ /// Parameters: [ <channel> *( "," <channel> ) [ <target> ] ]
+ ///
+ /// The list command is used to list channels and their topics. If the
+ /// <channel> parameter is used, only the status of that channel is
+ /// displayed.
+ ///
+ /// If the <target> parameter is specified, the request is forwarded to
+ /// that server which will generate the reply.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_TOOMANYMATCHES ERR_NOSUCHSERVER
+ /// RPL_LIST RPL_LISTEND
+ ///
+ /// Examples:
+ ///
+ /// LIST ; Command to list all channels.
+ ///
+ /// LIST #twilight_zone,#42 ; Command to list channels
+ /// #twilight_zone and #42
+ ///
+ LIST(Option<(Vec<&'a str>, Option<&'a str>)>),
+
+ /// 3.2.7 Invite message
+ ///
+ /// Command: INVITE
+ /// Parameters: <nickname> <channel>
+ ///
+ /// The INVITE command is used to invite a user to a channel. The
+ /// parameter <nickname> is the nickname of the person to be invited to
+ /// the target channel <channel>. There is no requirement that the
+ /// channel the target user is being invited to must exist or be a valid
+ /// channel. However, if the channel exists, only members of the channel
+ /// are allowed to invite other users. When the channel has invite-only
+ /// flag set, only channel operators may issue INVITE command.
+ ///
+ /// Only the user inviting and the user being invited will receive
+ /// notification of the invitation. Other channel members are not
+ /// notified. (This is unlike the MODE changes, and is occasionally the
+ /// source of trouble for users.)
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_NOSUCHNICK
+ /// ERR_NOTONCHANNEL ERR_USERONCHANNEL
+ /// ERR_CHANOPRIVSNEEDED
+ /// RPL_INVITING RPL_AWAY
+ ///
+ /// Examples:
+ ///
+ /// :Angel!wings@irc.org INVITE Wiz #Dust
+ ///
+ /// ; Message to WiZ when he has been
+ /// invited by user Angel to channel
+ /// #Dust
+ ///
+ /// INVITE Wiz #Twilight_Zone ; Command to invite WiZ to
+ /// #Twilight_zone
+ ///
+ INVITE(&'a str, &'a str),
+
+ /// 3.2.8 Kick command
+ ///
+ /// Command: KICK
+ /// Parameters: <channel> *( "," <channel> ) <user> *( "," <user> )
+ /// [<comment>]
+ ///
+ /// The KICK command can be used to request the forced removal of a user
+ /// from a channel. It causes the <user> to PART from the <channel> by
+ /// force. For the message to be syntactically correct, there MUST be
+ /// either one channel parameter and multiple user parameter, or as many
+ /// channel parameters as there are user parameters. If a "comment" is
+ /// given, this will be sent instead of the default message, the nickname
+ /// of the user issuing the KICK.
+ ///
+ /// The server MUST NOT send KICK messages with multiple channels or
+ /// users to clients. This is necessarily to maintain backward
+ /// compatibility with old client software.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS ERR_NOSUCHCHANNEL
+ /// ERR_BADCHANMASK ERR_CHANOPRIVSNEEDED
+ /// ERR_USERNOTINCHANNEL ERR_NOTONCHANNEL
+ ///
+ /// Examples:
+ ///
+ /// KICK &Melbourne Matthew ; Command to kick Matthew from
+ /// &Melbourne
+ ///
+ /// KICK #Finnish John :Speaking English
+ /// ; Command to kick John from #Finnish
+ /// using "Speaking English" as the
+ /// reason (comment).
+ ///
+ /// :WiZ!jto@tolsun.oulu.fi KICK #Finnish John
+ /// ; KICK message on channel #Finnish
+ /// from WiZ to remove John from channel
+ ///
+ KICK(Vec<&'a str>, Vec<&'a str>, Option<&'a str>),
+
+ /// 3.3.1 Private messages
+ ///
+ /// Command: PRIVMSG
+ /// Parameters: <msgtarget> <text to be sent>
+ ///
+ /// PRIVMSG is used to send private messages between users, as well as to
+ /// send messages to channels. <msgtarget> is usually the nickname of
+ /// the recipient of the message, or a channel name.
+ ///
+ /// The <msgtarget> parameter may also be a host mask (#<mask>) or server
+ /// mask ($<mask>). In both cases the server will only send the PRIVMSG
+ /// to those who have a server or host matching the mask. The mask MUST
+ /// have at least 1 (one) "." in it and no wildcards following the last
+ /// ".". This requirement exists to prevent people sending messages to
+ /// "#*" or "$*", which would broadcast to all users. Wildcards are the
+ /// '*' and '?' characters. This extension to the PRIVMSG command is
+ /// only available to operators.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NORECIPIENT ERR_NOTEXTTOSEND
+ /// ERR_CANNOTSENDTOCHAN ERR_NOTOPLEVEL
+ /// ERR_WILDTOPLEVEL ERR_TOOMANYTARGETS
+ /// ERR_NOSUCHNICK
+ /// RPL_AWAY
+ ///
+ /// Examples:
+ ///
+ /// :Angel!wings@irc.org PRIVMSG Wiz :Are you receiving this message ?
+ /// ; Message from Angel to Wiz.
+ ///
+ /// PRIVMSG Angel :yes I'm receiving it !
+ /// ; Command to send a message to Angel.
+ ///
+ /// PRIVMSG jto@tolsun.oulu.fi :Hello !
+ /// ; Command to send a message to a user
+ /// on server tolsun.oulu.fi with
+ /// username of "jto".
+ ///
+ /// PRIVMSG kalt%millennium.stealth.net@irc.stealth.net :Are you a frog?
+ /// ; Message to a user on server
+ /// irc.stealth.net with username of
+ /// "kalt", and connected from the host
+ /// millennium.stealth.net.
+ ///
+ /// PRIVMSG kalt%millennium.stealth.net :Do you like cheese?
+ /// ; Message to a user on the local
+ /// server with username of "kalt", and
+ /// connected from the host
+ /// millennium.stealth.net.
+ ///
+ /// PRIVMSG Wiz!jto@tolsun.oulu.fi :Hello !
+ /// ; Message to the user with nickname
+ /// Wiz who is connected from the host
+ /// tolsun.oulu.fi and has the username
+ /// "jto".
+ ///
+ /// PRIVMSG $*.fi :Server tolsun.oulu.fi rebooting.
+ /// ; Message to everyone on a server
+ /// which has a name matching *.fi.
+ ///
+ /// PRIVMSG #*.edu :NSFNet is undergoing work, expect interruptions
+ /// ; Message to all users who come from
+ /// a host which has a name matching
+ /// *.edu.
+ ///
+ PRIVMSG(&'a str, &'a str),
+
+ /// 3.3.2 Notice
+ ///
+ /// Command: NOTICE
+ /// Parameters: <msgtarget> <text>
+ ///
+ /// The NOTICE command is used similarly to PRIVMSG. The difference
+ /// between NOTICE and PRIVMSG is that automatic replies MUST NEVER be
+ /// sent in response to a NOTICE message. This rule applies to servers
+ /// too - they MUST NOT send any error reply back to the client on
+ /// receipt of a notice. The object of this rule is to avoid loops
+ /// between clients automatically sending something in response to
+ /// something it received.
+ ///
+ /// This command is available to services as well as users.
+ ///
+ /// This is typically used by services, and automatons (clients with
+ /// either an AI or other interactive program controlling their actions).
+ ///
+ /// See PRIVMSG for more details on replies and examples.
+ ///
+ NOTICE(&'a str, &'a str),
+
+ /// 3.4.1 Motd message
+ ///
+ /// Command: MOTD
+ /// Parameters: [ <target> ]
+ ///
+ /// The MOTD command is used to get the "Message Of The Day" of the given
+ /// server, or current server if <target> is omitted.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ /// RPL_MOTDSTART RPL_MOTD
+ /// RPL_ENDOFMOTD ERR_NOMOTD
+ ///
+ MOTD(Option<&'a str>),
+
+ /// 3.4.2 Lusers message
+ ///
+ /// Command: LUSERS
+ /// Parameters: [ <mask> [ <target> ] ]
+ ///
+ /// The LUSERS command is used to get statistics about the size of the
+ /// IRC network. If no parameter is given, the reply will be about the
+ /// whole net. If a <mask> is specified, then the reply will only
+ /// concern the part of the network formed by the servers matching the
+ /// mask. Finally, if the <target> parameter is specified, the request
+ /// is forwarded to that server which will generate the reply.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// RPL_LUSERCLIENT RPL_LUSEROP
+ /// RPL_LUSERUNKOWN RPL_LUSERCHANNELS
+ /// RPL_LUSERME ERR_NOSUCHSERVER
+ ///
+ LUSERS(Option<(&'a str, Option<&'a str>)>),
+
+ /// 3.4.3 Version message
+ ///
+ /// Command: VERSION
+ /// Parameters: [ <target> ]
+ ///
+ /// The VERSION command is used to query the version of the server
+ /// program. An optional parameter <target> is used to query the version
+ /// of the server program which a client is not directly connected to.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER RPL_VERSION
+ ///
+ /// Examples:
+ ///
+ /// VERSION tolsun.oulu.fi ; Command to check the version of
+ /// server "tolsun.oulu.fi".
+ ///
+ VERSION(Option<&'a str>),
+
+ /// 3.4.4 Stats message
+ ///
+ /// Command: STATS
+ /// Parameters: [ <query> [ <target> ] ]
+ ///
+ /// The stats command is used to query statistics of certain server. If
+ /// <query> parameter is omitted, only the end of stats reply is sent
+ /// back.
+ ///
+ /// A query may be given for any single letter which is only checked by
+ /// the destination server and is otherwise passed on by intermediate
+ /// servers, ignored and unaltered.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Except for the ones below, the list of valid queries is
+ /// implementation dependent. The standard queries below SHOULD be
+ /// supported by the server:
+ ///
+ /// l - returns a list of the server's connections, showing how
+ /// long each connection has been established and the
+ /// traffic over that connection in Kbytes and messages for
+ /// each direction;
+ /// m - returns the usage count for each of commands supported
+ /// by the server; commands for which the usage count is
+ /// zero MAY be omitted;
+ /// o - returns a list of configured privileged users,
+ /// operators;
+ /// u - returns a string showing how long the server has been
+ /// up.
+ ///
+ /// It is also RECOMMENDED that client and server access configuration be
+ /// published this way.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER
+ /// RPL_STATSLINKINFO RPL_STATSUPTIME
+ /// RPL_STATSCOMMANDS RPL_STATSOLINE
+ /// RPL_ENDOFSTATS
+ ///
+ /// Examples:
+ ///
+ /// STATS m ; Command to check the command usage
+ /// for the server you are connected to
+ ///
+ STATS(Option<(&'a str, Option<&'a str>)>),
+
+ /// 3.4.5 Links message
+ ///
+ /// Command: LINKS
+ /// Parameters: [ [ <remote server> ] <server mask> ]
+ ///
+ /// With LINKS, a user can list all servernames, which are known by the
+ /// server answering the query. The returned list of servers MUST match
+ /// the mask, or if no mask is given, the full list is returned.
+ ///
+ /// If <remote server> is given in addition to <server mask>, the LINKS
+ /// command is forwarded to the first server found that matches that name
+ /// (if any), and that server is then required to answer the query.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER
+ /// RPL_LINKS RPL_ENDOFLINKS
+ ///
+ /// Examples:
+ ///
+ /// LINKS *.au ; Command to list all servers which
+ /// have a name that matches *.au;
+ ///
+ /// LINKS *.edu *.bu.edu ; Command to list servers matching
+ /// *.bu.edu as seen by the first server
+ /// matching *.edu.
+ ///
+ LINKS(Option<(Option<&'a str>, &'a str)>),
+
+ /// 3.4.6 Time message
+ ///
+ /// Command: TIME
+ /// Parameters: [ <target> ]
+ ///
+ /// The time command is used to query local time from the specified
+ /// server. If the <target> parameter is not given, the server receiving
+ /// the command must reply to the query.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER RPL_TIME
+ ///
+ /// Examples:
+ /// TIME tolsun.oulu.fi ; check the time on the server
+ /// "tolson.oulu.fi"
+ ///
+ TIME(Option<&'a str>),
+
+ /// 3.4.7 Connect message
+ ///
+ /// Command: CONNECT
+ /// Parameters: <target server> <port> [ <remote server> ]
+ ///
+ /// The CONNECT command can be used to request a server to try to
+ /// establish a new connection to another server immediately. CONNECT is
+ /// a privileged command and SHOULD be available only to IRC Operators.
+ /// If a <remote server> is given and its mask doesn't match name of the
+ /// parsing server, the CONNECT attempt is sent to the first match of
+ /// remote server. Otherwise the CONNECT attempt is made by the server
+ /// processing the request.
+ ///
+ /// The server receiving a remote CONNECT command SHOULD generate a
+ /// WALLOPS message describing the source and target of the request.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER ERR_NOPRIVILEGES
+ /// ERR_NEEDMOREPARAMS
+ ///
+ /// Examples:
+ ///
+ /// CONNECT tolsun.oulu.fi 6667 ; Command to attempt to connect local
+ /// server to tolsun.oulu.fi on port 6667
+ ///
+ CONNECT(&'a str, i16, Option<&'a str>),
+
+ /// 3.4.8 Trace message
+ ///
+ /// Command: TRACE
+ /// Parameters: [ <target> ]
+ ///
+ /// TRACE command is used to find the route to specific server and
+ /// information about its peers. Each server that processes this command
+ /// MUST report to the sender about it. The replies from pass-through
+ /// links form a chain, which shows route to destination. After sending
+ /// this reply back, the query MUST be sent to the next server until
+ /// given <target> server is reached.
+ ///
+ /// TRACE command is used to find the route to specific server. Each
+ /// server that processes this message MUST tell the sender about it by
+ /// sending a reply indicating it is a pass-through link, forming a chain
+ /// of replies. After sending this reply back, it MUST then send the
+ /// TRACE message to the next server until given server is reached. If
+ /// the <target> parameter is omitted, it is RECOMMENDED that TRACE
+ /// command sends a message to the sender telling which servers the local
+ /// server has direct connection to.
+ ///
+ /// If the destination given by <target> is an actual server, the
+ /// destination server is REQUIRED to report all servers, services and
+ /// operators which are connected to it; if the command was issued by an
+ /// operator, the server MAY also report all users which are connected to
+ /// it. If the destination given by <target> is a nickname, then only a
+ /// reply for that nickname is given. If the <target> parameter is
+ /// omitted, it is RECOMMENDED that the TRACE command is parsed as
+ /// targeted to the processing server.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER
+ ///
+ /// If the TRACE message is destined for another server, all
+ /// intermediate servers must return a RPL_TRACELINK reply to indicate
+ /// that the TRACE passed through it and where it is going next.
+ ///
+ /// RPL_TRACELINK
+ ///
+ /// A TRACE reply may be composed of any number of the following
+ /// numeric replies.
+ ///
+ /// RPL_TRACECONNECTING RPL_TRACEHANDSHAKE
+ /// RPL_TRACEUNKNOWN RPL_TRACEOPERATOR
+ /// RPL_TRACEUSER RPL_TRACESERVER
+ /// RPL_TRACESERVICE RPL_TRACENEWTYPE
+ /// RPL_TRACECLASS RPL_TRACELOG
+ /// RPL_TRACEEND
+ ///
+ /// Examples:
+ ///
+ /// TRACE *.oulu.fi ; TRACE to a server matching
+ /// *.oulu.fi
+ ///
+ TRACE(Option<&'a str>),
+
+ /// 3.4.9 Admin command
+ ///
+ /// Command: ADMIN
+ /// Parameters: [ <target> ]
+ ///
+ /// The admin command is used to find information about the administrator
+ /// of the given server, or current server if <target> parameter is
+ /// omitted. Each server MUST have the ability to forward ADMIN messages
+ /// to other servers.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER
+ /// RPL_ADMINME RPL_ADMINLOC1
+ /// RPL_ADMINLOC2 RPL_ADMINEMAIL
+ ///
+ /// Examples:
+ ///
+ /// ADMIN tolsun.oulu.fi ; request an ADMIN reply from
+ /// tolsun.oulu.fi
+ ///
+ /// ADMIN syrk ; ADMIN request for the server to
+ /// which the user syrk is connected
+ ///
+ ADMIN(Option<&'a str>),
+
+ /// 3.4.10 Info command
+ ///
+ /// Command: INFO
+ /// Parameters: [ <target> ]
+ ///
+ /// The INFO command is REQUIRED to return information describing the
+ /// server: its version, when it was compiled, the patchlevel, when it
+ /// was started, and any other miscellaneous information which may be
+ /// considered to be relevant.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER
+ /// RPL_INFO RPL_ENDOFINFO
+ ///
+ /// Examples:
+ ///
+ /// INFO csd.bu.edu ; request an INFO reply from
+ /// csd.bu.edu
+ ///
+ /// INFO Angel ; request info from the server that
+ /// Angel is connected to.
+ ///
+ INFO(Option<&'a str>),
+
+ /// 3.5.1 Servlist message
+ ///
+ /// Command: SERVLIST
+ /// Parameters: [ <mask> [ <type> ] ]
+ ///
+ /// The SERVLIST command is used to list services currently connected to
+ /// the network and visible to the user issuing the command. The
+ /// optional parameters may be used to restrict the result of the query
+ /// (to matching services names, and services type).
+ ///
+ /// Numeric Replies:
+ ///
+ /// RPL_SERVLIST RPL_SERVLISTEND
+ ///
+ SERVLIST(Option<(&'a str, Option<&'a str>)>),
+
+ /// 3.5.2 Squery
+ ///
+ /// Command: SQUERY
+ /// Parameters: <servicename> <text>
+ ///
+ /// The SQUERY command is used similarly to PRIVMSG. The only difference
+ /// is that the recipient MUST be a service. This is the only way for a
+ /// text message to be delivered to a service.
+ ///
+ /// See PRIVMSG for more details on replies and example.
+ ///
+ /// Examples:
+ ///
+ /// SQUERY irchelp :HELP privmsg
+ /// ; Message to the service with
+ /// nickname irchelp.
+ ///
+ /// SQUERY dict@irc.fr :fr2en blaireau
+ /// ; Message to the service with name
+ /// dict@irc.fr.
+ ///
+ SQUERY(&'a str, &'a str),
+
+ /// 3.6.1 Who query
+ ///
+ /// Command: WHO
+ /// Parameters: [ <mask> [ "o" ] ]
+ ///
+ /// The WHO command is used by a client to generate a query which returns
+ /// a list of information which 'matches' the <mask> parameter given by
+ /// the client. In the absence of the <mask> parameter, all visible
+ /// (users who aren't invisible (user mode +i) and who don't have a
+ /// common channel with the requesting client) are listed. The same
+ /// result can be achieved by using a <mask> of "0" or any wildcard which
+ /// will end up matching every visible user.
+ ///
+ /// The <mask> passed to WHO is matched against users' host, server, real
+ /// name and nickname if the channel <mask> cannot be found.
+ ///
+ /// If the "o" parameter is passed only operators are returned according
+ /// to the <mask> supplied.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER
+ /// RPL_WHOREPLY RPL_ENDOFWHO
+ ///
+ /// Examples:
+ ///
+ /// WHO *.fi ; Command to list all users who match
+ /// against "*.fi".
+ ///
+ /// WHO jto* o ; Command to list all users with a
+ /// match against "jto*" if they are an
+ /// operator.
+ ///
+ WHO(&'a str, bool),
+
+ /// 3.6.2 Whois query
+ ///
+ /// Command: WHOIS
+ /// Parameters: [ <target> ] <mask> *( "," <mask> )
+ ///
+ /// This command is used to query information about particular user.
+ /// The server will answer this command with several numeric messages
+ /// indicating different statuses of each user which matches the mask (if
+ /// you are entitled to see them). If no wildcard is present in the
+ /// <mask>, any information about that nick which you are allowed to see
+ /// is presented.
+ ///
+ /// If the <target> parameter is specified, it sends the query to a
+ /// specific server. It is useful if you want to know how long the user
+ /// in question has been idle as only local server (i.e., the server the
+ /// user is directly connected to) knows that information, while
+ /// everything else is globally known.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER ERR_NONICKNAMEGIVEN
+ /// RPL_WHOISUSER RPL_WHOISCHANNELS
+ /// RPL_WHOISCHANNELS RPL_WHOISSERVER
+ /// RPL_AWAY RPL_WHOISOPERATOR
+ /// RPL_WHOISIDLE ERR_NOSUCHNICK
+ /// RPL_ENDOFWHOIS
+ ///
+ /// Examples:
+ ///
+ /// WHOIS wiz ; return available user information
+ /// about nick WiZ
+ ///
+ /// WHOIS eff.org trillian ; ask server eff.org for user
+ /// information about trillian
+ ///
+ WHOIS(Option<&'a str>, Vec<&'a str>),
+
+ /// 3.6.3 Whowas
+ ///
+ /// Command: WHOWAS
+ /// Parameters: <nickname> *( "," <nickname> ) [ <count> [ <target> ] ]
+ ///
+ /// Whowas asks for information about a nickname which no longer exists.
+ /// This may either be due to a nickname change or the user leaving IRC.
+ /// In response to this query, the server searches through its nickname
+ /// history, looking for any nicks which are lexically the same (no wild
+ /// card matching here). The history is searched backward, returning the
+ /// most recent entry first. If there are multiple entries, up to
+ /// <count> replies will be returned (or all of them if no <count>
+ /// parameter is given). If a non-positive number is passed as being
+ /// <count>, then a full search is done.
+ ///
+ /// Wildcards are allowed in the <target> parameter.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NONICKNAMEGIVEN ERR_WASNOSUCHNICK
+ /// RPL_WHOWASUSER RPL_WHOISSERVER
+ /// RPL_ENDOFWHOWAS
+ ///
+ /// Examples:
+ ///
+ /// WHOWAS Wiz ; return all information in the nick
+ /// history about nick "WiZ";
+ ///
+ /// WHOWAS Mermaid 9 ; return at most, the 9 most recent
+ /// entries in the nick history for
+ /// "Mermaid";
+ ///
+ /// WHOWAS Trillian 1 *.edu ; return the most recent history for
+ /// "Trillian" from the first server
+ /// found to match "*.edu".
+ ///
+ WHOWAS(Vec<&'a str>, Option<(&'a str, Option<&'a str>)>),
+
+ /// 3.7.1 Kill message
+ ///
+ /// Command: KILL
+ /// Parameters: <nickname> <comment>
+ ///
+ /// The KILL command is used to cause a client-server connection to be
+ /// closed by the server which has the actual connection. Servers
+ /// generate KILL messages on nickname collisions. It MAY also be
+ /// available available to users who have the operator status.
+ ///
+ /// Clients which have automatic reconnect algorithms effectively make
+ /// this command useless since the disconnection is only brief. It does
+ /// however break the flow of data and can be used to stop large amounts
+ /// of 'flooding' from abusive users or accidents. Abusive users usually
+ /// don't care as they will reconnect promptly and resume their abusive
+ /// behaviour. To prevent this command from being abused, any user may
+ /// elect to receive KILL messages generated for others to keep an 'eye'
+ /// on would be trouble spots.
+ ///
+ /// In an arena where nicknames are REQUIRED to be globally unique at all
+ /// times, KILL messages are sent whenever 'duplicates' are detected
+ /// (that is an attempt to register two users with the same nickname) in
+ /// the hope that both of them will disappear and only 1 reappear.
+ ///
+ /// When a client is removed as the result of a KILL message, the server
+ /// SHOULD add the nickname to the list of unavailable nicknames in an
+ /// attempt to avoid clients to reuse this name immediately which is
+ /// usually the pattern of abusive behaviour often leading to useless
+ /// "KILL loops". See the "IRC Server Protocol" document [IRC-SERVER]
+ /// for more information on this procedure.
+ ///
+ /// The comment given MUST reflect the actual reason for the KILL. For
+ /// server-generated KILLs it usually is made up of details concerning
+ /// the origins of the two conflicting nicknames. For users it is left
+ /// up to them to provide an adequate reason to satisfy others who see
+ /// it. To prevent/discourage fake KILLs from being generated to hide
+ /// the identify of the KILLer, the comment also shows a 'kill-path'
+ /// which is updated by each server it passes through, each prepending
+ /// its name to the path.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOPRIVILEGES ERR_NEEDMOREPARAMS
+ /// ERR_NOSUCHNICK ERR_CANTKILLSERVER
+ ///
+ /// NOTE:
+ /// It is RECOMMENDED that only Operators be allowed to kill other users
+ /// with KILL command. This command has been the subject of many
+ /// controversies over the years, and along with the above
+ /// recommendation, it is also widely recognized that not even operators
+ /// should be allowed to kill users on remote servers.
+ ///
+ KILL(&'a str, &'a str),
+
+ /// 3.7.2 Ping message
+ ///
+ /// Command: PING
+ /// Parameters: <server1> [ <server2> ]
+ ///
+ /// The PING command is used to test the presence of an active client or
+ /// server at the other end of the connection. Servers send a PING
+ /// message at regular intervals if no other activity detected coming
+ /// from a connection. If a connection fails to respond to a PING
+ /// message within a set amount of time, that connection is closed. A
+ /// PING message MAY be sent even if the connection is active.
+ ///
+ /// When a PING message is received, the appropriate PONG message MUST be
+ /// sent as reply to <server1> (server which sent the PING message out)
+ /// as soon as possible. If the <server2> parameter is specified, it
+ /// represents the target of the ping, and the message gets forwarded
+ /// there.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOORIGIN ERR_NOSUCHSERVER
+ ///
+ /// Examples:
+ ///
+ /// PING tolsun.oulu.fi ; Command to send a PING message to
+ /// server
+ ///
+ /// PING WiZ tolsun.oulu.fi ; Command from WiZ to send a PING
+ /// message to server "tolsun.oulu.fi"
+ ///
+ /// PING :irc.funet.fi ; Ping message sent by server
+ /// "irc.funet.fi"
+ ///
+ PING(&'a str, Option<&'a str>),
+
+ /// 3.7.3 Pong message
+ ///
+ /// Command: PONG
+ /// Parameters: <server> [ <server2> ]
+ ///
+ /// PONG message is a reply to ping message. If parameter <server2> is
+ /// given, this message MUST be forwarded to given target. The <server>
+ /// parameter is the name of the entity who has responded to PING message
+ /// and generated this message.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOORIGIN ERR_NOSUCHSERVER
+ ///
+ /// Example:
+ ///
+ /// PONG csd.bu.edu tolsun.oulu.fi ; PONG message from csd.bu.edu to
+ /// tolsun.oulu.fi
+ ///
+ PONG(&'a str, Option<&'a str>),
+
+ /// 3.7.4 Error
+ ///
+ /// Command: ERROR
+ /// Parameters: <error message>
+ ///
+ /// The ERROR command is for use by servers when reporting a serious or
+ /// fatal error to its peers. It may also be sent from one server to
+ /// another but MUST NOT be accepted from any normal unknown clients.
+ ///
+ /// Only an ERROR message SHOULD be used for reporting errors which occur
+ /// with a server-to-server link. An ERROR message is sent to the server
+ /// at the other end (which reports it to appropriate local users and
+ /// logs) and to appropriate local users and logs. It is not to be
+ /// passed onto any other servers by a server if it is received from a
+ /// server.
+ ///
+ /// The ERROR message is also used before terminating a client
+ /// connection.
+ ///
+ /// When a server sends a received ERROR message to its operators, the
+ /// message SHOULD be encapsulated inside a NOTICE message, indicating
+ /// that the client was not responsible for the error.
+ ///
+ /// Numerics:
+ ///
+ /// None.
+ ///
+ /// Examples:
+ ///
+ /// ERROR :Server *.fi already exists ; ERROR message to the other server
+ /// which caused this error.
+ ///
+ /// NOTICE WiZ :ERROR from csd.bu.edu -- Server *.fi already exists
+ /// ; Same ERROR message as above but
+ /// sent to user WiZ on the other server.
+ ///
+ ERROR(&'a str),
+
+ /// 4.1 Away
+ ///
+ /// Command: AWAY
+ /// Parameters: [ <text> ]
+ ///
+ /// With the AWAY command, clients can set an automatic reply string for
+ /// any PRIVMSG commands directed at them (not to a channel they are on).
+ /// The server sends an automatic reply to the client sending the PRIVMSG
+ /// command. The only replying server is the one to which the sending
+ /// client is connected to.
+ ///
+ /// The AWAY command is used either with one parameter, to set an AWAY
+ /// message, or with no parameters, to remove the AWAY message.
+ ///
+ /// Because of its high cost (memory and bandwidth wise), the AWAY
+ /// message SHOULD only be used for client-server communication. A
+ /// server MAY choose to silently ignore AWAY messages received from
+ /// other servers. To update the away status of a client across servers,
+ /// the user mode 'a' SHOULD be used instead. (See Section 3.1.5)
+ ///
+ /// Numeric Replies:
+ ///
+ /// RPL_UNAWAY RPL_NOWAWAY
+ ///
+ /// Example:
+ ///
+ /// AWAY :Gone to lunch. Back in 5 ; Command to set away message to
+ /// "Gone to lunch. Back in 5".
+ ///
+ AWAY(Option<&'a str>),
+
+ /// 4.2 Rehash message
+ ///
+ /// Command: REHASH
+ /// Parameters: None
+ ///
+ /// The rehash command is an administrative command which can be used by
+ /// an operator to force the server to re-read and process its
+ /// configuration file.
+ ///
+ /// Numeric Replies:
+ ///
+ /// RPL_REHASHING ERR_NOPRIVILEGES
+ ///
+ ///
+ /// Example:
+ ///
+ /// REHASH ; message from user with operator
+ /// status to server asking it to reread
+ /// its configuration file.
+ ///
+ REHASH,
+
+ /// 4.3 Die message
+ ///
+ /// Command: DIE
+ /// Parameters: None
+ ///
+ /// An operator can use the DIE command to shutdown the server. This
+ /// message is optional since it may be viewed as a risk to allow
+ /// arbitrary people to connect to a server as an operator and execute
+ /// this command.
+ ///
+ /// The DIE command MUST always be fully processed by the server to which
+ /// the sending client is connected and MUST NOT be passed onto other
+ /// connected servers.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOPRIVILEGES
+ ///
+ /// Example:
+ ///
+ /// DIE ; no parameters required.
+ ///
+ DIE,
+
+ /// 4.4 Restart message
+ ///
+ /// Command: RESTART
+ /// Parameters: None
+ ///
+ /// An operator can use the restart command to force the server to
+ /// restart itself. This message is optional since it may be viewed as a
+ /// risk to allow arbitrary people to connect to a server as an operator
+ /// and execute this command, causing (at least) a disruption to service.
+ ///
+ /// The RESTART command MUST always be fully processed by the server to
+ /// which the sending client is connected and MUST NOT be passed onto
+ /// other connected servers.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOPRIVILEGES
+ ///
+ /// Example:
+ ///
+ /// RESTART ; no parameters required.
+ ///
+ RESTART,
+
+ /// 4.5 Summon message
+ ///
+ /// Command: SUMMON
+ /// Parameters: <user> [ <target> [ <channel> ] ]
+ ///
+ /// The SUMMON command can be used to give users who are on a host
+ /// running an IRC server a message asking them to please join IRC. This
+ /// message is only sent if the target server (a) has SUMMON enabled, (b)
+ /// the user is logged in and (c) the server process can write to the
+ /// user's tty (or similar).
+ ///
+ /// If no <server> parameter is given it tries to summon <user> from the
+ /// server the client is connected to is assumed as the target.
+ ///
+ /// If summon is not enabled in a server, it MUST return the
+ /// ERR_SUMMONDISABLED numeric.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NORECIPIENT ERR_FILEERROR
+ /// ERR_NOLOGIN ERR_NOSUCHSERVER
+ /// ERR_SUMMONDISABLED RPL_SUMMONING
+ ///
+ /// Examples:
+ ///
+ /// SUMMON jto ; summon user jto on the server's
+ /// host
+ ///
+ /// SUMMON jto tolsun.oulu.fi ; summon user jto on the host which a
+ /// server named "tolsun.oulu.fi" is
+ /// running.
+ ///
+ SUMMON(&'a str, Option<(&'a str, Option<&'a str>)>),
+
+ /// 4.6 Users
+ ///
+ /// Command: USERS
+ /// Parameters: [ <target> ]
+ ///
+ /// The USERS command returns a list of users logged into the server in a
+ /// format similar to the UNIX commands who(1), rusers(1) and finger(1).
+ /// If disabled, the correct numeric MUST be returned to indicate this.
+ ///
+ /// Because of the security implications of such a command, it SHOULD be
+ /// disabled by default in server implementations. Enabling it SHOULD
+ /// require recompiling the server or some equivalent change rather than
+ /// simply toggling an option and restarting the server. The procedure
+ /// to enable this command SHOULD also include suitable large comments.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NOSUCHSERVER ERR_FILEERROR
+ /// RPL_USERSSTART RPL_USERS
+ /// RPL_NOUSERS RPL_ENDOFUSERS
+ /// ERR_USERSDISABLED
+ ///
+ /// Disabled Reply:
+ ///
+ /// ERR_USERSDISABLED
+ ///
+ /// Example:
+ ///
+ /// USERS eff.org ; request a list of users logged in
+ /// on server eff.org
+ ///
+ USERS(Option<&'a str>),
+
+ /// 4.7 Operwall message
+ ///
+ /// Command: WALLOPS
+ /// Parameters: <Text to be sent>
+ ///
+ /// The WALLOPS command is used to send a message to all currently
+ /// connected users who have set the 'w' user mode for themselves. (See
+ /// Section 3.1.5 "User modes").
+ ///
+ /// After implementing WALLOPS as a user command it was found that it was
+ /// often and commonly abused as a means of sending a message to a lot of
+ /// people. Due to this, it is RECOMMENDED that the implementation of
+ /// WALLOPS allows and recognizes only servers as the originators of
+ /// WALLOPS.
+ ///
+ /// Numeric Replies:
+ ///
+ /// ERR_NEEDMOREPARAMS
+ ///
+ /// Example:
+ ///
+ /// :csd.bu.edu WALLOPS :Connect '*.uiuc.edu 6667' from Joshua ; WALLOPS
+ /// message from csd.bu.edu announcing a
+ /// CONNECT message it received from
+ /// Joshua and acted upon.
+ ///
+ WALLOPS(&'a str),
+
+ /// 4.8 Userhost message
+ ///
+ /// Command: USERHOST
+ /// Parameters: <nickname> *( SPACE <nickname> )
+ ///
+ /// The USERHOST command takes a list of up to 5 nicknames, each
+ /// separated by a space character and returns a list of information
+ /// about each nickname that it found. The returned list has each reply
+ /// separated by a space.
+ ///
+ /// Numeric Replies:
+ ///
+ /// RPL_USERHOST ERR_NEEDMOREPARAMS
+ ///
+ /// Example:
+ ///
+ /// USERHOST Wiz Michael syrk ; USERHOST request for information on
+ /// nicks "Wiz", "Michael", and "syrk"
+ ///
+ /// :ircd.stealth.net 302 yournick :syrk=+syrk@millennium.stealth.net
+ /// ; Reply for user syrk
+ ///
+ USERHOST(Vec<&'a str>),
+}
+
+impl<'a> Command<'a> {
+ fn to_name(&self) -> &'static str {
+ match self {
+ PASS => "PING",
+ NICK => "NICK",
+ USER => "USER",
+ OPER => "1004",
+ MODE => "1005",
+ SERVICE => "1006",
+ QUIT => "1007",
+ SQUIT => "1008",
+ JOIN => "1009",
+ PART => "1010",
+ TOPIC => "1011",
+ NAMES => "1012",
+ LIST => "1013",
+ INVITE => "1014",
+ KICK => "1015",
+ PRIVMSG => "1016",
+ NOTICE => "1017",
+ MOTD => "1018",
+ LUSERS => "1019",
+ VERSION => "1020",
+ STATS => "1021",
+ LINKS => "1022",
+ TIME => "1023",
+ CONNECT => "1024",
+ TRACE => "1025",
+ ADMIN => "1026",
+ INFO => "1027",
+ SERVLIST => "1028",
+ SQUERY => "1029",
+ WHO => "1030",
+ WHOIS => "1031",
+ WHOWAS => "1032",
+ KILL => "1033",
+ PING => "1034",
+ PONG => "1035",
+ ERROR => "1036",
+ AWAY => "1037",
+ REHASH => "1038",
+ DIE => "1039",
+ RESTART => "1040",
+ SUMMON => "1041",
+ USERS => "1042",
+ WALLOPS => "1043",
+ USERHOST => "1044",
+ ISON => "1045",
+/*
+ RPL_WELCOME => "001",
+ RPL_YOURHOST => "002",
+ RPL_CREATED => "003",
+ RPL_MYINFO => "004",
+ RPL_BOUNCE => "005",
+ RPL_USERHOST => "302",
+ RPL_ISON => "303",
+ RPL_AWAY => "301",
+ RPL_UNAWAY => "305",
+ RPL_NOWAWAY => "306",
+ RPL_WHOISUSER => "311",
+ RPL_WHOISSERVER => "312",
+ RPL_WHOISOPERATOR => "313",
+ RPL_WHOISIDLE => "317",
+ RPL_ENDOFWHOIS => "318",
+ RPL_WHOISCHANNELS => "319",
+ RPL_WHOWASUSER => "314",
+ RPL_ENDOFWHOWAS => "369",
+ RPL_LISTSTART => "321",
+ RPL_LIST => "322",
+ RPL_LISTEND => "323",
+ RPL_UNIQOPIS => "325",
+ RPL_CHANNELMODEIS => "324",
+ RPL_NOTOPIC => "331",
+ RPL_TOPIC => "332",
+ RPL_INVITING => "341",
+ RPL_SUMMONING => "342",
+ RPL_INVITELIST => "346",
+ RPL_ENDOFINVITELIST => "347",
+ RPL_EXCEPTLIST => "348",
+ RPL_ENDOFEXCEPTLIST => "349",
+ RPL_VERSION => "351",
+ RPL_WHOREPLY => "352",
+ RPL_ENDOFWHO => "315",
+ RPL_NAMREPLY => "353",
+ RPL_ENDOFNAMES => "366",
+ RPL_LINKS => "364",
+ RPL_ENDOFLINKS => "365",
+ RPL_BANLIST => "367",
+ RPL_ENDOFBANLIST => "368",
+ RPL_INFO => "371",
+ RPL_ENDOFINFO => "374",
+ RPL_MOTDSTART => "375",
+ RPL_MOTD => "372",
+ RPL_ENDOFMOTD => "376",
+ RPL_YOUREOPER => "381",
+ RPL_REHASHING => "382",
+ RPL_YOURESERVICE => "383",
+ RPL_TIME => "391",
+ RPL_USERSSTART => "392",
+ RPL_USERS => "393",
+ RPL_ENDOFUSERS => "394",
+ RPL_NOUSERS => "395",
+ RPL_TRACELINK => "200",
+ RPL_TRACECONNECTING => "201",
+ RPL_TRACEHANDSHAKE => "202",
+ RPL_TRACEUNKNOWN => "203",
+ RPL_TRACEOPERATOR => "204",
+ RPL_TRACEUSER => "205",
+ RPL_TRACESERVER => "206",
+ RPL_TRACESERVICE => "207",
+ RPL_TRACENEWTYPE => "208",
+ RPL_TRACECLASS => "209",
+ RPL_TRACERECONNECT => "210",
+ RPL_TRACELOG => "261",
+ RPL_TRACEEND => "262",
+ RPL_STATSLINKINFO => "211",
+ RPL_STATSCOMMAND => "212",
+ RPL_ENDOFSTATS => "219",
+ RPL_STATSUPTIME => "242",
+ RPL_STATSOLINE => "243",
+ RPL_UMODEIS => "221",
+ RPL_SERVLIST => "234",
+ RPL_SERVLISTEND => "235",
+ RPL_LUSERCLIENT => "251",
+ RPL_LUSEROP => "252",
+ RPL_LUSERUNKNOWN => "253",
+ RPL_LUSERCHANNELS => "254",
+ RPL_LUSERME => "255",
+ RPL_ADMINME => "256",
+ RPL_ADMINLOC1 => "257",
+ RPL_ADMINLOC2 => "258",
+ RPL_ADMINEMAIL => "259",
+ RPL_TRYAGAIN => "263",
+
+ ERR_NOSUCHNICK => "401",
+ ERR_NOSUCHSERVER => "402",
+ ERR_NOSUCHCHANNEL => "403",
+ ERR_CANNOTSENDTOCHAN => "404",
+ ERR_TOOMANYCHANNELS => "405",
+ ERR_WASNOSUCHNICK => "406",
+ ERR_TOOMANYTARGETS => "407",
+ ERR_NOSUCHSERVICE => "408",
+ ERR_NOORIGIN => "409",
+ ERR_NORECIPIENT => "411",
+ ERR_NOTEXTTOSEND => "412",
+ ERR_NOTOPLEVEL => "413",
+ ERR_WILDTOPLEVEL => "414",
+ ERR_BADMASK => "415",
+ ERR_UNKNOWNCOMMAND => "421",
+ ERR_NOMOTD => "422",
+ ERR_NOADMININFO => "423",
+ ERR_FILEERROR => "424",
+ ERR_NONICKNAMEGIVEN => "431",
+ ERR_ERRONEUSNICKNAME => "432",
+ ERR_NICKNAMEINUSE => "433",
+ ERR_NICKCOLLISION => "436",
+ ERR_UNAVAILRESOURCE => "437",
+ ERR_USERNOTINCHANNEL => "441",
+ ERR_NOTONCHANNEL => "442",
+ ERR_USERONCHANNEL => "443",
+ ERR_NOLOGIN => "444",
+ ERR_SUMMONDISABLED => "445",
+ ERR_USERSDISABLED => "446",
+ ERR_NOTREGISTERED => "451",
+ ERR_NEEDMOREPARAMS => "461",
+ ERR_ALREADYREGISTERED => "462",
+ ERR_NOPERMFORHOST => "463",
+ ERR_PASSWDMISMATCH => "464",
+ ERR_YOUREBANNEDCREEP => "465",
+ ERR_YOUWILLBEBANNED => "466",
+ ERR_KEYSET => "467",
+ ERR_CHANNELISFULL => "471",
+ ERR_UNKNOWNMODE => "472",
+ ERR_INVITEONLYCHAN => "473",
+ ERR_BANNEDFROMCHAN => "474",
+ ERR_BADCHANNELKEY => "475",
+ ERR_BADCHANMASK => "476",
+ ERR_NOCHANMODES => "477",
+ ERR_BANLISTFULL => "478",
+ ERR_NOPRIVILEGES => "481",
+ ERR_CHANOPRIVSNEEDED => "482",
+ ERR_CANTKILLSERVER => "483",
+ ERR_RESTRICTED => "484",
+ ERR_UNIQOPPRIVSNEEDED => "485",
+ ERR_NOOPERHOST => "491",
+ ERR_UMODEUNKNOWNFLAG => "501",*/
+ }
+ }
+}
+
+impl<'a> Command<'a> {
+ pub fn from_message(msg: &'a Message) -> Option<Command<'a>> {
+ match &msg.command.as_ref()[..] {
+ "NOTICE" => msg.content.get(0).and_then(|c| msg.content.get(1).map(|t|
+ Command::NOTICE { to: Cow::Borrowed(&t), content: Cow::Borrowed(&c) })),
+ "PING" => msg.content.get(0).and_then(|s1| msg.content.get(1).map(|s2|
+ Command::PING { server1: Some(Cow::Borrowed(&s1)), server2: Some(Cow::Borrowed(&s2)) })),
+ "001" => Some(Command::RPL_WELCOME),
+ "002" => Some(Command::RPL_YOURHOST),
+ "003" => Some(Command::RPL_CREATED),
+ "004" => Some(Command::RPL_MYINFO),
+ "451" => Some(Command::ErrNotRegistered),
+ _ => unimplemented!()
+ }
+ }
+
+ pub fn to_message(&'a self) -> Message {
+ match self {
+ &Command::PING { ref server1, ref server2 } => {
+ let mut c = Vec::new();
+ if let &Some(ref s) = server1 { c.push(s.clone()) }
+ if let &Some(ref s) = server2 { c.push(s.clone()) }
+ Message::new(None, Cow::Owned("PING".to_owned()), c, None, MsgType::Irc)
+ },
+ &Command::PONG { ref server1, ref server2 } => {
+ let mut c = Vec::new();
+ if let &Some(ref s) = server1 { c.push(s.clone()) }
+ if let &Some(ref s) = server2 { c.push(s.clone()) }
+ Message::new(None, Cow::Owned("PONG".to_owned()), c, None, MsgType::Irc)
+ },
+ _ => unimplemented!()
+ }
+ }
+
+ //pub fn is_reply(&self) -> bool { let i = *self as uint; i >= 200 && i <= 399 }
+ //pub fn is_error(&self) -> bool { let i = *self as uint; i >= 400 && i <= 599 }
+}
+
diff --git a/src/lib.rs b/src/lib.rs
index 577770d..f37c9a4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,11 +6,12 @@ extern crate regex;
extern crate log;
extern crate eventual;
-pub mod server;
+// pub mod server;
pub mod color;
pub mod ident;
pub mod callback;
pub mod message;
+// pub mod command;
use std::io;
use std::result;
diff --git a/src/message.rs b/src/message.rs
index f2cd9d3..2341609 100644
--- a/src/message.rs
+++ b/src/message.rs
@@ -2,7 +2,10 @@
use std::str::FromStr;
use std::string::{ ToString };
-use std::borrow::{ Cow, ToOwned };
+use std::borrow::{ ToOwned };
+use std::ops::Range;
+
+use ::IrscError;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum MsgType {
@@ -13,18 +16,20 @@ pub enum MsgType {
Ctcp
}
-#[derive(Debug, PartialEq, Eq, Hash, Clone)]
-pub struct Message<'a> {
- pub prefix: Option<Cow<'a, String>>,
- pub command: Cow<'a, String>,
- pub content: Vec<Cow<'a, String>>,
- pub suffix: Option<Cow<'a, String>>,
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct Message {
+ pub source: String,
+ prefix: Option<Range<u16>>,
+ command: Range<u16>,
+ content: Vec<Range<u16>>,
+ suffix: Option<Range<u16>>,
pub msg_type: MsgType
}
-impl<'a> Message<'a> {
- pub fn new(prefix: Option<Cow<'a, String>>, command: Cow<'a, String>, content: Vec<Cow<'a, String>>, suffix: Option<Cow<'a, String>>, msg_type: MsgType) -> Message<'a> {
+impl Message {
+ pub fn new(source: String, prefix: Option<Range<u16>>, command: Range<u16>, content: Vec<Range<u16>>, suffix: Option<Range<u16>>, msg_type: MsgType) -> Message {
Message {
+ source: source,
prefix: prefix,
command: command,
content: content,
@@ -32,60 +37,111 @@ impl<'a> Message<'a> {
msg_type: msg_type
}
}
+
+ #[allow(unused_assignments)]
+ pub fn format(prefix: Option<&str>, command: &str, content: Vec<&str>, suffix: Option<&str>, msg_type: MsgType) -> Message {
+ let mut s = String::with_capacity(512);
+ let mut i = 0;
+
+ let mut i_prefix = None;
+ if let Some(ref p) = prefix {
+ i_prefix = Some((i + 1) as u16..(i + 2 + p.len()) as u16);
+ s.push(':');
+ s.push_str(p);
+ s.push(' ');
+ i += 2 + p.len();
+ }
+
+ let i_command = i as u16..(i + command.len()) as u16;
+ s.push_str(command);
+ s.push(' ');
+ i += 1 + command.len();
+
+ let mut i_content = Vec::new();
+ for part in content.iter() {
+ i_content.push(i as u16..(i + part.len()) as u16);
+ s.push_str(part);
+ s.push(' ');
+ i += 1 + part.len();
+ }
+
+ let mut i_suffix = None;
+ if let Some(ref p) = suffix {
+ s.push(':');
+ if let MsgType::Ctcp = msg_type { s.push('\u{1}'); i += 1; }
+ let n = i;
+ s.push_str(p);
+ if let MsgType::Ctcp = msg_type { s.push('\u{1}'); i += 1; }
+ i_suffix = Some(n as u16..(n + p.len()) as u16);
+ i += 1 + p.len();
+ }
+
+ s.push_str("\r\n");
+ i += 2;
+
+ Message::new(s, i_prefix, i_command, i_content, i_suffix, msg_type)
+ }
+
+ pub fn range(&self, r: &Range<u16>) -> &str {
+ self.source.slice_chars(r.start as usize, r.end as usize)
+ }
+
+ pub fn prefix(&self) -> Option<&str> { self.prefix.as_ref().map(|r| self.range(r)) }
+ pub fn command(&self) -> &str { self.range(&self.command) }
+ pub fn content(&self) -> Vec<&str> { self.content.iter().map(|r| self.range(&r)).collect() }
+ pub fn suffix(&self) -> Option<&str> { self.suffix.as_ref().map(|r| self.range(r)) }
}
-impl<'a> FromStr for Message<'a> {
- type Err = ::IrscError;
- fn from_str(i: &str) -> Result<Message<'a>, ::IrscError> {
+impl FromStr for Message {
+ type Err = IrscError;
+ fn from_str(i: &str) -> Result<Message, IrscError> {
info!("Attempting to parse message: {}", i);
let len = i.len();
- let mut s = i;
+ let mut s = 0;
- let prefix = if len >= 1 && s.chars().next() == Some(':') {
- s.find(' ').map(|i| {
- let p = s.slice_chars(1, i).to_owned();
- s = &s[i + 1..];
- p
- })
+ let prefix = if len >= 1 && i[s..].chars().next() == Some(':') {
+ i[s..].find(' ').map(|i| 1u16..i as u16)
} else { None };
- let command = s.find(' ').map(|i| {
- let p = s.slice_chars(0, i).to_owned();
- s = &s[i..];
+ let command = i[s..].find(' ').map(|n| {
+ let p = s as u16..n as u16;
+ s = n;
p
- }).map(|c| c.parse()).map(|c| Some(Cow::Owned(c.unwrap())));
+ });
// TODO: Parse last non-suffix argument as suffix if no suffix
// with colon is available.
let mut content = Vec::with_capacity(15);
let mut suffix = None;
- while s.len() > 0 {
- if s.chars().next() == Some(':') {
- suffix = Some(s[1..].to_owned());
+ while i[s..].len() > 0 {
+ if i[s..].chars().next() == Some(':') {
+ suffix = Some(s as u16 + 1 as u16..i.len() as u16);
break
}
- s.find(' ').map(|i| {
+ i[s..].find(' ').map(|i| {
if i > 0 {
- content.push(Cow::Owned(s.slice_chars(0, i).to_owned()));
- s = &s[i..];
+ content.push(s as u16..(s + i) as u16);
+ s = i;
}
});
// if s.chars().next() == Some(' ') { s = &s[1..] };
- s = &s[1..]
+ s += 1;
}
let msg_type = if suffix.as_ref()
- .and_then(|s| s.chars().next()) == Some('\u{1}') { MsgType::Ctcp } else { MsgType::Irc };
+ .and_then(|s| i[s.start as usize..].chars().next()) == Some('\u{1}') { MsgType::Ctcp } else { MsgType::Irc };
command.map(move |c|
- Ok(Message::new(prefix.map(Cow::Owned),
- c.unwrap(),
+ Ok(Message::new(
+ i.to_owned(),
+ prefix,
+ c,
content,
// strip \{1} if CTCP message
// strip \r\n for each line, relying on their existence
match msg_type {
- MsgType::Irc => suffix.map(|s| s[0..s.len() - 2].to_string()).map(Cow::Owned),
- MsgType::Ctcp => suffix.map(|s| s[1..s.len() - 3].to_string()).map(Cow::Owned)
+ MsgType::Irc => suffix.map(|s| s.start..s.end - 2),
+ MsgType::Ctcp => suffix.map(|s| s.start + 1..s.end - 3)
},
msg_type
))
@@ -94,32 +150,34 @@ impl<'a> FromStr for Message<'a> {
}
}
-impl<'a> ToString for Message<'a> {
+impl ToString for Message {
fn to_string(&self) -> String {
+ self.source.clone()
+ /*
let mut s = String::with_capacity(512);
- if let Some(ref p) = self.prefix {
+ if let Some(ref p) = self.prefix() {
s.push(':');
- s.push_str(&p);
+ s.push_str(p);
s.push(' ');
}
- s.push_str(&self.command);
+ s.push_str(self.command());
s.push(' ');
for part in self.content.iter() {
- s.push_str(&part);
+ s.push_str(self.range(&part));
s.push(' ');
}
- if let Some(ref p) = self.suffix {
+ if let Some(ref p) = self.suffix() {
s.push(':');
if let MsgType::Ctcp = self.msg_type { s.push('\u{1}') }
- s.push_str(&p);
+ s.push_str(p);
if let MsgType::Ctcp = self.msg_type { s.push('\u{1}') }
}
s.push_str("\r\n");
- s
+ s*/
}
}
@@ -204,906 +262,6 @@ pub enum SetMode {
Minus
}
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub enum Command<'a> {
- Pass { password: Cow<'a, String> },
- Nick { nickname: Cow<'a, String> },
- User { user: Cow<'a, String>, mode: Cow<'a, String>, unused: Cow<'a, String>, realname: Cow<'a, String> },
- Oper { name: Cow<'a, String>, password: Cow<'a, String> },
- Mode { nickname: Cow<'a, String>, mode: &'a [(SetMode, Mode)] },
- Service { nickname: Cow<'a, String>, reserved: Cow<'a, String>, distribution: Cow<'a, String>, service_type: Cow<'a, String>, reserved2: Cow<'a, String>, info: Cow<'a, String> },
- Quit { message: Option<Cow<'a, String>> },
- SQuit { server: Cow<'a, String>, comment: Cow<'a, String> },
- Join { channels: &'a [(Cow<'a, String>, Option<Cow<'a, String>>)] },
- Join_leave_all,
- Part { channels: &'a [Cow<'a, String>], message: Cow<'a, String> },
- /*
- Topic = 1011,
- Names = 1012,
- List = 1013,
- Invite = 1014,
- Kick = 1015,
- */
- PrivMsg { from: Option<Cow<'a, String>>, to: Cow<'a, String>, content: Cow<'a, String> },
- Notice { to: Cow<'a, String>, content: Cow<'a, String> },
- /*
- Motd = 1018,
- LUsers = 1019,
- Version = 1020,
- Stats = 1021,
- Links = 1022,
- Time = 1023,
- Connect = 1024,
- Trace = 1025,
- Admin = 1026,
- Info = 1027,
- ServList = 1028,
- SQuery = 1029,
- Who = 1030,
- WhoIs = 1031,
- WhoWas = 1032,
- Kill = 1033,
- */
- Ping { server1: Option<Cow<'a, String>>, server2: Option<Cow<'a, String>> },
- Pong { server1: Option<Cow<'a, String>>, server2: Option<Cow<'a, String>> },
- /*
- Error = 1036,
- Away = 1037,
- Rehash = 1038,
- Die = 1039,
- Restart = 1040,
- Summon = 1041,
- Users = 1042,
- Wallops = 1043,
- Userhost = 1044,
- Ison = 1045,*/
-
- Ctcp { command: Cow<'a, String> },
-
-
- /// "Welcome to the Internet Relay Network <nick>!<user>@<host>"
- RPL_WELCOME,
- /// "Your host is <servername>, running version <ver>"
- RPL_YOURHOST,
- /// "This server was created <date>"
- RPL_CREATED,
- /// "<servername> <version> <available user modes> <available channel modes>"
- RPL_MYINFO,
- /*/// "Try server <server name>, port <port number>"
- /// 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.
- RPL_BOUNCE = 005,
- /// ":*1<reply> *( " " <reply> )"
- /// - 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.
- RPL_USERHOST = 302,
- /// ":*1<nick> *( " " <nick> )"
- /// - Reply format used by ISON to list replies to the query list.
- RPL_ISON = 303,
- /// "<nick> :<away message>"
- RPL_AWAY = 301,
- /// ":You are no longer marked as being away"
- RPL_UNAWAY = 305,
- /// ":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./
- RPL_NOWAWAY = 306,
- /// "<nick> <user> <host> * :<real name>"
- RPL_WHOISUSER = 311,
- /// "<nick> <server> :<server info>"
- RPL_WHOISSERVER = 312,
- /// "<nick> :is an IRC operator"
- RPL_WHOISOPERATOR = 313,
- /// "<nick> <integer> :seconds idle"
- RPL_WHOISIDLE = 317,
- /// "<nick> :End of WHOIS list"
- RPL_ENDOFWHOIS = 318,
- /// "<nick> :*( ( "@" / "+" ) <channel> " " )"
- /// - 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.
- RPL_WHOISCHANNELS = 319,
- /// "<nick> <user> <host> * :<real name>"
- RPL_WHOWASUSER = 314,
- /// "<nick> :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).
- RPL_ENDOFWHOWAS = 369,
- /// Obsolete. Not used.
- #[deprecated = "Obsolete. Not used."]
- RPL_LISTSTART = 321,
- /// "<channel> <# visible> :<topic>"
- RPL_LIST = 322,
- /// ":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.
- RPL_LISTEND = 323,
- /// "<channel> <nickname>"
- RPL_UNIQOPIS = 325,
- /// "<channel> <mode> <mode params>"
- RPL_CHANNELMODEIS = 324,
- /// "<channel> :No topic is set"
- RPL_NOTOPIC = 331,
- /// "<channel> :<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.
- RPL_TOPIC = 332,
- /// "<channel> <nick>"
- /// - Returned by the server to indicate that the
- /// attempted INVITE message was successful and is
- /// being passed onto the end client.
- RPL_INVITING = 341,
- /// "<user> :Summoning user to IRC"
- /// - Returned by a server answering a SUMMON message to
- /// indicate that it is summoning that user.
- RPL_SUMMONING = 342,
- /// "<channel> <invitemask>"
- RPL_INVITELIST = 346,
- /// "<channel> :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.
- RPL_ENDOFINVITELIST = 347,
- /// "<channel> <exceptionmask>"
- RPL_EXCEPTLIST = 348,
- /// "<channel> :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./
- RPL_ENDOFEXCEPTLIST = 349,
- /// "<version>.<debuglevel> <server> :<comments>"
- /// - Reply by the server showing its version details.
- /// The <version> is the version of the software being
- /// used (including any patchlevel revisions) and the
- /// <debuglevel> 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.
- RPL_VERSION = 351,
- /// "<channel> <user> <host> <server> <nick>
- /// ( "H" / "G" > ["*"] [ ( "@" / "+" ) ]
- /// :<hopcount> <real name>"
- RPL_WHOREPLY = 352,
- /// "<name> :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 <name> being
- /// the item.
- RPL_ENDOFWHO = 315,
- /// "( "=" / "*" / "@" ) <channel>
- /// :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
- /// - "@" is used for secret channels, "*" for private
- /// channels, and "=" for others (public channels).
- RPL_NAMREPLY = 353,
- /// "<channel> :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.
- RPL_ENDOFNAMES = 366,
- /// "<mask> <server> :<hopcount> <server info>"
- RPL_LINKS = 364,
- /// "<mask> :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.
- RPL_ENDOFLINKS = 365,
- /// "<channel> <banmask>"
- RPL_BANLIST = 367,
- /// "<channel> :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.
- RPL_ENDOFBANLIST = 368,
- /// ":<string>"
- RPL_INFO = 371,
- /// ":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.
- RPL_ENDOFINFO = 374,
- /// ":- <server> Message of the day - "
- RPL_MOTDSTART = 375,
- /// ":- <text>"
- RPL_MOTD = 372,
- /// ":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).
- RPL_ENDOFMOTD = 376,
- /// ":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.
- RPL_YOUREOPER = 381,
- /// "<config file> :Rehashing"
- /// - If the REHASH option is used and an operator sends
- /// a REHASH message, an RPL_REHASHING is sent back to
- /// the operator.
- RPL_REHASHING = 382,
- /// "You are service <servicename>"
- /// - Sent by the server to a service upon successful
- /// registration.
- RPL_YOURESERVICE = 383,
- /// "<server> :<string showing server's local 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.
- RPL_TIME = 391,
- /// ":UserID Terminal Host"
- RPL_USERSSTART = 392,
- /// ":<username> <ttyline> <hostname>"
- RPL_USERS = 393,
- /// ":End of users"
- RPL_ENDOFUSERS = 394,
- /// ":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.
- RPL_NOUSERS = 395,
- /// "Link <version & debug level> <destination>
- /// <next server> V<protocol version>
- /// <link uptime in seconds> <backstream sendq>
- /// <upstream sendq>"
- RPL_TRACELINK = 200,
- /// "Try. <class> <server>"
- RPL_TRACECONNECTING = 201,
- /// "H.S. <class> <server>"
- RPL_TRACEHANDSHAKE = 202,
- /// "???? <class> [<client IP address in dot form>]"
- RPL_TRACEUNKNOWN = 203,
- /// "Oper <class> <nick>"
- RPL_TRACEOPERATOR = 204,
- /// "User <class> <nick>"
- RPL_TRACEUSER = 205,
- /// "Serv <class> <int>S <int>C <server>
- /// <nick!user|*!*>@<host|server> V<protocol version>"
- RPL_TRACESERVER = 206,
- /// "Service <class> <name> <type> <active type>"
- RPL_TRACESERVICE = 207,
- /// "<newtype> 0 <client name>"
- RPL_TRACENEWTYPE = 208,
- /// "Class <class> <count>"
- RPL_TRACECLASS = 209,
- /// Unused.
- #[deprecated = "Unused."]
- RPL_TRACERECONNECT = 210,
- /// "File <logfile> <debug level>"
- RPL_TRACELOG = 261,
- /// "<server name> <version & debug level> :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./
- RPL_TRACEEND = 262,
- /// "<linkname> <sendq> <sent messages>
- /// <sent Kbytes> <received messages>
- /// <received Kbytes> <time open>"
- /// - reports statistics on a connection. <linkname>
- /// identifies the particular connection, <sendq> is
- /// the amount of data that is queued and waiting to be
- /// sent <sent messages> the number of messages sent,
- /// and <sent Kbytes> the amount of data sent, in
- /// Kbytes. <received messages> and <received Kbytes>
- /// are the equivalent of <sent messages> and <sent
- /// Kbytes> for received data, respectively. <time
- /// open> indicates how long ago the connection was
- /// opened, in seconds.
- RPL_STATSLINKINFO = 211,
- /// "<command> <count> <byte count> <remote count>"
- /// - reports statistics on commands usage.
- RPL_STATSCOMMAND = 212,
- /// "<stats letter> :End of STATS report"
- RPL_ENDOFSTATS = 219,
- /// ":Server Up %d days %d:%02d:%02d"
- /// - reports the server uptime.
- RPL_STATSUPTIME = 242,
- /// "O <hostmask> * <name>"
- /// - reports the allowed hosts from where user may become IRC
- /// operators.
- RPL_STATSOLINE = 243,
- /// "<user mode string>"
- /// - To answer a query about a client's own mode,
- /// RPL_UMODEIS is sent back.
- RPL_UMODEIS = 221,
- /// "<name> <server> <mask> <type> <hopcount> <info>"
- RPL_SERVLIST = 234,
- /// "<mask> <type> :End of service listing"
- /// - When listing services in reply to a SERVLIST message,
- /// a server is required to send the list back using the
- /// RPL_SERVLIST and RPL_SERVLISTEND messages. A separate
- /// RPL_SERVLIST is sent for each service. After the
- /// services have been listed (or if none present) a
- /// RPL_SERVLISTEND MUST be sent./
- RPL_SERVLISTEND = 235,
- /// ":There are <integer> users and <integer>
- /// services on <integer> servers"
- RPL_LUSERCLIENT = 251,
- /// "<integer> :operator(s) online"
- RPL_LUSEROP = 252,
- /// "<integer> :unknown connection(s)"
- RPL_LUSERUNKNOWN = 253,
- /// "<integer> :channels formed"
- RPL_LUSERCHANNELS = 254,
- /// ":I have <integer> clients and <integer>
- /// servers"
- /// - In processing an LUSERS message, the server
- /// sends a set of replies from RPL_LUSERCLIENT,
- /// RPL_LUSEROP, RPL_USERUNKNOWN,
- /// RPL_LUSERCHANNELS and RPL_LUSERME. When
- /// replying, a server MUST send back
- /// RPL_LUSERCLIENT and RPL_LUSERME. The other
- /// replies are only sent back if a non-zero count
- /// is found for them.
- RPL_LUSERME = 255,
- /// "<server> :Administrative info"
- RPL_ADMINME = 256,
- /// ":<admin info>"
- RPL_ADMINLOC1 = 257,
- /// ":<admin info>"
- RPL_ADMINLOC2 = 258,
- /// ":<admin info>"
- /// - When replying to an ADMIN message, a server
- /// is expected to use replies RPL_ADMINME
- /// through to RPL_ADMINEMAIL and provide a text
- /// message with each. For RPL_ADMINLOC1 a
- /// description of what city, state and country
- /// the server is in is expected, followed by
- /// details of the institution (RPL_ADMINLOC2)
- /// and finally the administrative contact for the
- /// server (an email address here is REQUIRED)
- /// in RPL_ADMINEMAIL.
- RPL_ADMINEMAIL = 259,
- /// "<command> :Please wait a while and try again."
- /// - When a server drops a command without processing it,
- /// it MUST use the reply RPL_TRYAGAIN to inform the
- /// originating client.
- RPL_TRYAGAIN = 263,
-
- /// "<nickname> :No such nick/channel"
- /// - Used to indicate the nickname parameter supplied to a
- /// command is currently unused.
- ERR_NOSUCHNICK = 401,
- /// "<server name> :No such server"
- /// - Used to indicate the server name given currently
- /// does not exist.
- ERR_NOSUCHSERVER = 402,
- /// "<channel name> :No such channel"
- /// - Used to indicate the given channel name is invalid.
- ERR_NOSUCHCHANNEL = 403,
- /// "<channel name> :Cannot send to channel"
- /// - Sent to a user who is either (a) not on a channel
- /// which is mode +n or (b) not a chanop (or mode +v) on
- /// a channel which has mode +m set or where the user is
- /// banned and is trying to send a PRIVMSG message to
- /// that channel.
- ERR_CANNOTSENDTOCHAN = 404,
- /// "<channel name> :You have joined too many channels"
- /// - Sent to a user when they have joined the maximum
- /// number of allowed channels and they try to join
- /// another channel.
- ERR_TOOMANYCHANNELS = 405,
- /// "<nickname> :There was no such nickname"
- /// - Returned by WHOWAS to indicate there is no history
- /// information for that nickname.
- ERR_WASNOSUCHNICK = 406,
- /// "<target> :<error code> recipients. <abort message>"
- /// - Returned to a client which is attempting to send a
- /// PRIVMSG/NOTICE using the user@host destination format
- /// and for a user@host which has several occurrences.
- /// - Returned to a client which trying to send a
- /// PRIVMSG/NOTICE to too many recipients.
- /// - Returned to a client which is attempting to JOIN a safe
- /// channel using the shortname when there are more than one
- /// such channel.
- ERR_TOOMANYTARGETS = 407,
- /// "<service name> :No such service"
- /// - Returned to a client which is attempting to send a SQUERY
- /// to a service which does not exist.
- ERR_NOSUCHSERVICE = 408,
- /// ":No origin specified"
- /// - PING or PONG message missing the originator parameter.
- ERR_NOORIGIN = 409,
- /// ":No recipient given (<command>)"
- ERR_NORECIPIENT = 411,
- /// ":No text to send"
- ERR_NOTEXTTOSEND = 412,
- /// "<mask> :No toplevel domain specified"
- ERR_NOTOPLEVEL = 413,
- /// "<mask> :Wildcard in toplevel domain"
- ERR_WILDTOPLEVEL = 414,
- /// "<mask> :Bad Server/host mask"
- /// - 412 - 415 are returned by PRIVMSG to indicate that
- /// the message wasn't delivered for some reason.
- /// ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
- /// are returned when an invalid use of
- /// "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
- ERR_BADMASK = 415,
- /// "<command> :Unknown command"
- /// - Returned to a registered client to indicate that the
- /// command sent is unknown by the server.
- ERR_UNKNOWNCOMMAND = 421,
- /// ":MOTD File is missing"
- /// - Server's MOTD file could not be opened by the server.
- ERR_NOMOTD = 422,
- /// "<server> :No administrative info available"
- /// - Returned by a server in response to an ADMIN message
- /// when there is an error in finding the appropriate
- /// information.
- ERR_NOADMININFO = 423,
- /// ":File error doing <file op> on <file>"
- /// - Generic error message used to report a failed file
- /// operation during the processing of a message.
- ERR_FILEERROR = 424,
- /// ":No nickname given"
- /// - Returned when a nickname parameter expected for a
- /// command and isn't found.
- ERR_NONICKNAMEGIVEN = 431,
- /// "<nick> :Erroneous nickname"
- /// - Returned after receiving a NICK message which contains
- /// characters which do not fall in the defined set. See
- /// section 2.3.1 for details on valid nicknames.
- ERR_ERRONEUSNICKNAME = 432,
- /// "<nick> :Nickname is already in use"
- /// - Returned when a NICK message is processed that results
- /// in an attempt to change to a currently existing
- /// nickname.
- ERR_NICKNAMEINUSE = 433,
- /// "<nick> :Nickname collision KILL from <user>@<host>"
- /// - Returned by a server to a client when it detects a
- /// nickname collision (registered of a NICK that
- /// already exists by another server).
- ERR_NICKCOLLISION = 436,
- /// "<nick/channel> :Nick/channel is temporarily unavailable"
- /// - Returned by a server to a user trying to join a channel
- /// currently blocked by the channel delay mechanism.
- /// - Returned by a server to a user trying to change nickname
- /// when the desired nickname is blocked by the nick delay
- /// mechanism.
- ERR_UNAVAILRESOURCE = 437,
- /// "<nick> <channel> :They aren't on that channel"
- /// - Returned by the server to indicate that the target
- /// user of the command is not on the given channel.
- ERR_USERNOTINCHANNEL = 441,
- /// "<channel> :You're not on that channel"
- /// - Returned by the server whenever a client tries to
- /// perform a channel affecting command for which the
- /// client isn't a member.
- ERR_NOTONCHANNEL = 442,
- /// "<user> <channel> :is already on channel"
- /// - Returned when a client tries to invite a user to a
- /// channel they are already on.
- ERR_USERONCHANNEL = 443,
- /// "<user> :User not logged in"
- /// - Returned by the summon after a SUMMON command for a
- /// user was unable to be performed since they were not
- /// logged in.
- ERR_NOLOGIN = 444,
- /// ":SUMMON has been disabled"
- /// - Returned as a response to the SUMMON command. MUST be
- /// returned by any server which doesn't implement it.
- ERR_SUMMONDISABLED = 445,
- /// ":USERS has been disabled"
- /// - Returned as a response to the USERS command. MUST be
- /// returned by any server which does not implement it.
- ERR_USERSDISABLED = 446,*/
- /// ":You have not registered"
- /// - Returned by the server to indicate that the client
- /// MUST be registered before the server will allow it
- /// to be parsed in detail.
- ErrNotRegistered,/*
- /// "<command> :Not enough parameters"
- /// - Returned by the server by numerous commands to
- /// indicate to the client that it didn't supply enough
- /// parameters.
- ERR_NEEDMOREPARAMS = 461,
- /// ":Unauthorized command (already registered)"
- /// - Returned by the server to any link which tries to
- /// change part of the registered details (such as
- /// password or user details from second USER message).
- ERR_ALREADYREGISTERED = 462,
- /// ":Your host isn't among the privileged"
- /// - Returned to a client which attempts to register with
- /// a server which does not been setup to allow
- /// connections from the host the attempted connection
- /// is tried.
- ERR_NOPERMFORHOST = 463,
- /// ":Password incorrect"
- /// - Returned to indicate a failed attempt at registering
- /// a connection for which a password was required and
- /// was either not given or incorrect.
- ERR_PASSWDMISMATCH = 464,
- /// ":You are banned from this server"
- /// - Returned after an attempt to connect and register
- /// yourself with a server which has been setup to
- /// explicitly deny connections to you.
- ERR_YOUREBANNEDCREEP = 465,
- /// - Sent by a server to a user to inform that access to the
- /// server will soon be denied.
- ERR_YOUWILLBEBANNED = 466,
- /// "<channel> :Channel key already set"
- ERR_KEYSET = 467,
- /// "<channel> :Cannot join channel (+l)"
- ERR_CHANNELISFULL = 471,
- /// "<char> :is unknown mode char to me for <channel>"
- ERR_UNKNOWNMODE = 472,
- /// "<channel> :Cannot join channel (+i)"
- ERR_INVITEONLYCHAN = 473,
- /// "<channel> :Cannot join channel (+b)"
- ERR_BANNEDFROMCHAN = 474,
- /// "<channel> :Cannot join channel (+k)"
- ERR_BADCHANNELKEY = 475,
- /// "<channel> :Bad Channel Mask"
- ERR_BADCHANMASK = 476,
- /// "<channel> :Channel doesn't support modes"
- ERR_NOCHANMODES = 477,
- /// "<channel> <char> :Channel list is full"
- ERR_BANLISTFULL = 478,
- /// ":Permission Denied- You're not an IRC operator"
- /// - Any command requiring operator privileges to operate
- /// MUST return this error to indicate the attempt was
- /// unsuccessful.
- ERR_NOPRIVILEGES = 481,
- /// "<channel> :You're not channel operator"
- /// - Any command requiring 'chanop' privileges (such as
- /// MODE messages) MUST return this error if the client
- /// making the attempt is not a chanop on the specified
- /// channel.
- ERR_CHANOPRIVSNEEDED = 482,
- /// ":You can't kill a server!"
- /// - Any attempts to use the KILL command on a server
- /// are to be refused and this error returned directly
- /// to the client.
- ERR_CANTKILLSERVER = 483,
- /// ":Your connection is restricted!"
- /// - Sent by the server to a user upon connection to indicate
- /// the restricted nature of the connection (user mode "+r").
- ERR_RESTRICTED = 484,
- /// ":You're not the original channel operator"
- /// - Any MODE requiring "channel creator" privileges MUST
- /// return this error if the client making the attempt is not
- /// a chanop on the specified channel.
- ERR_UNIQOPPRIVSNEEDED = 485,
- /// ":No O-lines for your host"
- /// - If a client sends an OPER message and the server has
- /// not been configured to allow connections from the
- /// client's host as an operator, this error MUST be
- /// returned.
- ERR_NOOPERHOST = 491,
- /// ":Unknown MODE flag"
- /// - Returned by the server to indicate that a MODE
- /// message was sent with a nickname parameter and that
- /// the a mode flag sent was not recognized.
- ERR_UMODEUNKNOWNFLAG = 501,
- /// ":Cannot change mode for other users"
- /// - Error sent to any user trying to view or change the
- /// user mode for a user other than themselves.
- ERR_USERSDONTMATCH = 502
- */
-}
-
-/*
-impl ToString for Command {
- fn to_string(&self) -> String {
- match self {
- PASS => "PING",
- NICK => "NICK",
- USER => "USER",
- OPER => "1004",
- MODE => "1005",
- SERVICE => "1006",
- QUIT => "1007",
- SQUIT => "1008",
- JOIN => "1009",
- PART => "1010",
- TOPIC => "1011",
- NAMES => "1012",
- LIST => "1013",
- INVITE => "1014",
- KICK => "1015",
- PRIVMSG => "1016",
- NOTICE => "1017",
- MOTD => "1018",
- LUSERS => "1019",
- VERSION => "1020",
- STATS => "1021",
- LINKS => "1022",
- TIME => "1023",
- CONNECT => "1024",
- TRACE => "1025",
- ADMIN => "1026",
- INFO => "1027",
- SERVLIST => "1028",
- SQUERY => "1029",
- WHO => "1030",
- WHOIS => "1031",
- WHOWAS => "1032",
- KILL => "1033",
- PING => "1034",
- PONG => "1035",
- ERROR => "1036",
- AWAY => "1037",
- REHASH => "1038",
- DIE => "1039",
- RESTART => "1040",
- SUMMON => "1041",
- USERS => "1042",
- WALLOPS => "1043",
- USERHOST => "1044",
- ISON => "1045",
-
- RPL_WELCOME => "001",
- RPL_YOURHOST => "002",
- RPL_CREATED => "003",
- RPL_MYINFO => "004",
- RPL_BOUNCE => "005",
- RPL_USERHOST => "302",
- RPL_ISON => "303",
- RPL_AWAY => "301",
- RPL_UNAWAY => "305",
- RPL_NOWAWAY => "306",
- RPL_WHOISUSER => "311",
- RPL_WHOISSERVER => "312",
- RPL_WHOISOPERATOR => "313",
- RPL_WHOISIDLE => "317",
- RPL_ENDOFWHOIS => "318",
- RPL_WHOISCHANNELS => "319",
- RPL_WHOWASUSER => "314",
- RPL_ENDOFWHOWAS => "369",
- RPL_LISTSTART => "321",
- RPL_LIST => "322",
- RPL_LISTEND => "323",
- RPL_UNIQOPIS => "325",
- RPL_CHANNELMODEIS => "324",
- RPL_NOTOPIC => "331",
- RPL_TOPIC => "332",
- RPL_INVITING => "341",
- RPL_SUMMONING => "342",
- RPL_INVITELIST => "346",
- RPL_ENDOFINVITELIST => "347",
- RPL_EXCEPTLIST => "348",
- RPL_ENDOFEXCEPTLIST => "349",
- RPL_VERSION => "351",
- RPL_WHOREPLY => "352",
- RPL_ENDOFWHO => "315",
- RPL_NAMREPLY => "353",
- RPL_ENDOFNAMES => "366",
- RPL_LINKS => "364",
- RPL_ENDOFLINKS => "365",
- RPL_BANLIST => "367",
- RPL_ENDOFBANLIST => "368",
- RPL_INFO => "371",
- RPL_ENDOFINFO => "374",
- RPL_MOTDSTART => "375",
- RPL_MOTD => "372",
- RPL_ENDOFMOTD => "376",
- RPL_YOUREOPER => "381",
- RPL_REHASHING => "382",
- RPL_YOURESERVICE => "383",
- RPL_TIME => "391",
- RPL_USERSSTART => "392",
- RPL_USERS => "393",
- RPL_ENDOFUSERS => "394",
- RPL_NOUSERS => "395",
- RPL_TRACELINK => "200",
- RPL_TRACECONNECTING => "201",
- RPL_TRACEHANDSHAKE => "202",
- RPL_TRACEUNKNOWN => "203",
- RPL_TRACEOPERATOR => "204",
- RPL_TRACEUSER => "205",
- RPL_TRACESERVER => "206",
- RPL_TRACESERVICE => "207",
- RPL_TRACENEWTYPE => "208",
- RPL_TRACECLASS => "209",
- RPL_TRACERECONNECT => "210",
- RPL_TRACELOG => "261",
- RPL_TRACEEND => "262",
- RPL_STATSLINKINFO => "211",
- RPL_STATSCOMMAND => "212",
- RPL_ENDOFSTATS => "219",
- RPL_STATSUPTIME => "242",
- RPL_STATSOLINE => "243",
- RPL_UMODEIS => "221",
- RPL_SERVLIST => "234",
- RPL_SERVLISTEND => "235",
- RPL_LUSERCLIENT => "251",
- RPL_LUSEROP => "252",
- RPL_LUSERUNKNOWN => "253",
- RPL_LUSERCHANNELS => "254",
- RPL_LUSERME => "255",
- RPL_ADMINME => "256",
- RPL_ADMINLOC1 => "257",
- RPL_ADMINLOC2 => "258",
- RPL_ADMINEMAIL => "259",
- RPL_TRYAGAIN => "263",
-
- ERR_NOSUCHNICK => "401",
- ERR_NOSUCHSERVER => "402",
- ERR_NOSUCHCHANNEL => "403",
- ERR_CANNOTSENDTOCHAN => "404",
- ERR_TOOMANYCHANNELS => "405",
- ERR_WASNOSUCHNICK => "406",
- ERR_TOOMANYTARGETS => "407",
- ERR_NOSUCHSERVICE => "408",
- ERR_NOORIGIN => "409",
- ERR_NORECIPIENT => "411",
- ERR_NOTEXTTOSEND => "412",
- ERR_NOTOPLEVEL => "413",
- ERR_WILDTOPLEVEL => "414",
- ERR_BADMASK => "415",
- ERR_UNKNOWNCOMMAND => "421",
- ERR_NOMOTD => "422",
- ERR_NOADMININFO => "423",
- ERR_FILEERROR => "424",
- ERR_NONICKNAMEGIVEN => "431",
- ERR_ERRONEUSNICKNAME => "432",
- ERR_NICKNAMEINUSE => "433",
- ERR_NICKCOLLISION => "436",
- ERR_UNAVAILRESOURCE => "437",
- ERR_USERNOTINCHANNEL => "441",
- ERR_NOTONCHANNEL => "442",
- ERR_USERONCHANNEL => "443",
- ERR_NOLOGIN => "444",
- ERR_SUMMONDISABLED => "445",
- ERR_USERSDISABLED => "446",
- ERR_NOTREGISTERED => "451",
- ERR_NEEDMOREPARAMS => "461",
- ERR_ALREADYREGISTERED => "462",
- ERR_NOPERMFORHOST => "463",
- ERR_PASSWDMISMATCH => "464",
- ERR_YOUREBANNEDCREEP => "465",
- ERR_YOUWILLBEBANNED => "466",
- ERR_KEYSET => "467",
- ERR_CHANNELISFULL => "471",
- ERR_UNKNOWNMODE => "472",
- ERR_INVITEONLYCHAN => "473",
- ERR_BANNEDFROMCHAN => "474",
- ERR_BADCHANNELKEY => "475",
- ERR_BADCHANMASK => "476",
- ERR_NOCHANMODES => "477",
- ERR_BANLISTFULL => "478",
- ERR_NOPRIVILEGES => "481",
- ERR_CHANOPRIVSNEEDED => "482",
- ERR_CANTKILLSERVER => "483",
- ERR_RESTRICTED => "484",
- ERR_UNIQOPPRIVSNEEDED => "485",
- ERR_NOOPERHOST => "491",
- ERR_UMODEUNKNOWNFLAG => "501",
- }.to_owned()
- }
-}*/
-
-
-/*
-impl FromStr for Command {
- fn from_str(s: &str) -> Option<Command> {
- use self::Command::*;
- match s {
- "PASS" => Some(PASS),
- "NICK" => Some(NICK),
- "USER" => Some(USER),
- "OPER" => Some(OPER),
- "MODE" => Some(MODE),
- "SERVICE" => Some(SERVICE),
- "QUIT" => Some(QUIT),
- "SQUIT" => Some(SQUIT),
- "JOIN" => Some(JOIN),
- "PART" => Some(PART),
- "TOPIC" => Some(TOPIC),
- "NAMES" => Some(NAMES),
- "LIST" => Some(LIST),
- "INVITE" => Some(INVITE),
- "KICK" => Some(KICK),
- "PRIVMSG" => Some(PRIVMSG),
- "NOTICE" => Some(NOTICE),
- "MOTD" => Some(MOTD),
- "LUSERS" => Some(LUSERS),
- "VERSION" => Some(VERSION),
- "STATS" => Some(STATS),
- "LINKS" => Some(LINKS),
- "TIME" => Some(TIME),
- "CONNECT" => Some(CONNECT),
- "TRACE" => Some(TRACE),
- "ADMIN" => Some(ADMIN),
- "INFO" => Some(INFO),
- "SERVLIST" => Some(SERVLIST),
- "SQUERY" => Some(SQUERY),
- "WHO" => Some(WHO),
- "WHOIS" => Some(WHOIS),
- "WHOWAS" => Some(WHOWAS),
- "KILL" => Some(KILL),
- "PING" => Some(PING),
- "PONG" => Some(PONG),
- "ERROR" => Some(ERROR),
- "AWAY" => Some(AWAY),
- "REHASH" => Some(REHASH),
- "DIE" => Some(DIE),
- "RESTART" => Some(RESTART),
- "SUMMON" => Some(SUMMON),
- "USERS" => Some(USERS),
- "WALLOPS" => Some(WALLOPS),
- "USERHOST" => Some(USERHOST),
- "ISON" => Some(ISON),
- _ => None
- }
- }
-}*/
-
/// If you hoped it couldn't get any uglier... I'm sorry, it does.
/// Why a giant match? API.
///
@@ -1116,44 +274,7 @@ impl FromStr for Command {
///
/// Please don't cry.
-impl<'a> Command<'a> {
- pub fn from_message(msg: &'a Message) -> Option<Command<'a>> {
- match &msg.command.as_ref()[..] {
- "NOTICE" => msg.content.get(0).and_then(|c| msg.content.get(1).map(|t|
- Command::Notice { to: Cow::Borrowed(&t), content: Cow::Borrowed(&c) })),
- "PING" => msg.content.get(0).and_then(|s1| msg.content.get(1).map(|s2|
- Command::Ping { server1: Some(Cow::Borrowed(&s1)), server2: Some(Cow::Borrowed(&s2)) })),
- "001" => Some(Command::RPL_WELCOME),
- "002" => Some(Command::RPL_YOURHOST),
- "003" => Some(Command::RPL_CREATED),
- "004" => Some(Command::RPL_MYINFO),
- "451" => Some(Command::ErrNotRegistered),
- _ => unimplemented!()
- }
- }
- pub fn to_message(&'a self) -> Message {
- match self {
- &Command::Ping { ref server1, ref server2 } => {
- let mut c = Vec::new();
- if let &Some(ref s) = server1 { c.push(s.clone()) }
- if let &Some(ref s) = server2 { c.push(s.clone()) }
- Message::new(None, Cow::Owned("PING".to_owned()), c, None, MsgType::Irc)
- },
- &Command::Pong { ref server1, ref server2 } => {
- let mut c = Vec::new();
- if let &Some(ref s) = server1 { c.push(s.clone()) }
- if let &Some(ref s) = server2 { c.push(s.clone()) }
- Message::new(None, Cow::Owned("PONG".to_owned()), c, None, MsgType::Irc)
- },
- _ => unimplemented!()
- }
- }
-
- //pub fn is_reply(&self) -> bool { let i = *self as uint; i >= 200 && i <= 399 }
- //pub fn is_error(&self) -> bool { let i = *self as uint; i >= 400 && i <= 599 }
-}
-
-pub fn join(v: Vec<String>, from: usize) -> String {
+/*pub fn join(v: Vec<String>, from: usize) -> String {
let mut msg = if v[from].chars().next().unwrap() == ':' {
v[from][1..].to_owned()
} else { v[from].clone() };
@@ -1162,7 +283,7 @@ pub fn join(v: Vec<String>, from: usize) -> String {
msg.push_str(m.trim_right());
}
msg
-}
+}*/
/*pub struct PrivMsg {
pub from: Ident,
@@ -1187,14 +308,15 @@ impl ParseResult for PrivMsg {
#[cfg(test)]
mod test {
- use std::borrow::{ Cow, ToOwned };
+ use std::borrow::{ ToOwned };
use message::{ Message, MsgType };
#[test]
fn parse_message() {
- let a = ":a.b.c NOTICE AUTH :*** Looking up your hostname...\r\n";
+ /*let a = ":a.b.c NOTICE AUTH :*** Looking up your hostname...\r\n";
// I'm not even kidding...
let a2 = Message::new(
+ a.to_owned(),
Some(Cow::Owned("a.b.c".to_owned())),
Cow::Owned("NOTICE".to_owned()),
vec![Cow::Owned("AUTH".to_owned())],
@@ -1202,16 +324,18 @@ mod test {
MsgType::Irc
);
assert_eq!(a.parse::<Message>().unwrap(), a2.clone());
- assert_eq!(a2.to_string(), a);
+ assert_eq!(a2.to_string(), a);*/
let b = ":d PRIVMSG You :\u{1}ACTION sends you funny pictures of cats!\u{1}\r\n";
let b2 = Message::new(
- Some(Cow::Owned("d".to_owned())),
- Cow::Owned("PRIVMSG".to_owned()),
- vec![Cow::Owned("You".to_owned())],
- Some(Cow::Owned("ACTION sends you funny pictures of cats!".to_owned())),
+ b.to_owned(),
+ Some(1..2),
+ 3..10,
+ vec![11..14],
+ Some(17..57),
MsgType::Ctcp
);
+
assert_eq!(b.parse::<Message>().unwrap(), b2.clone());
assert_eq!(b2.to_string(), b);
}
diff --git a/src/server.rs b/src/server.rs
index a8c2819..e5548ef 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -8,11 +8,10 @@ use std::io::{
use std::net::TcpStream;
-use message;
-use message::{ Command, Message };
+use message::Message;
+use command::Command;
use ::{ DEBUG, Result, IrscError };
-
#[cfg(feature = "ssl")]
use openssl::ssl::{ SslContext, SslMethod, SslStream };
@@ -62,9 +61,9 @@ impl Server {
}
}
- fn handle_event(&mut self, msg: &message::Message) {
+ fn handle_event(&mut self, msg: &Message) {
if *msg.command == "PING" {
- let _ = self.send(Command::Pong { server1: msg.suffix.clone(), server2: None }.to_message());
+ let _ = self.send(Command::PONG(msg.suffix, None).to_message());
}
}
@@ -109,7 +108,7 @@ impl Server {
.map_err(IrscError::Io))
}
- pub fn send(&mut self, msg: message::Message) -> Result<()> {
+ pub fn send(&mut self, msg: Message) -> Result<()> {
self.sendraw(&msg.to_string())
}