Implemented password support for nickservs as per #9.
This commit is contained in:
parent
31281d2820
commit
398cda4af6
3 changed files with 147 additions and 6 deletions
|
@ -4,9 +4,10 @@ use std::io::{InvalidInput, IoError, IoResult};
|
|||
use std::str::FromStr;
|
||||
use data::message::Message;
|
||||
|
||||
/// List of all client commands as defined in [RFC 2812](http://tools.ietf.org/html/rfc2812).
|
||||
/// This also includes commands from the
|
||||
/// List of all client commands as defined in [RFC 2812](http://tools.ietf.org/html/rfc2812). This
|
||||
/// also includes commands from the
|
||||
/// [capabilities extension](https://tools.ietf.org/html/draft-mitchell-irc-capabilities-01).
|
||||
/// Additionally, this includes some common additional commands from popular IRCds.
|
||||
#[stable]
|
||||
#[deriving(Show, PartialEq)]
|
||||
pub enum Command<'a> {
|
||||
|
@ -131,6 +132,18 @@ pub enum Command<'a> {
|
|||
SAPART(&'a str, &'a str),
|
||||
/// SAQUIT nickname reason
|
||||
SAQUIT(&'a str, &'a str),
|
||||
/// NICKSERV :message
|
||||
NICKSERV(&'a str),
|
||||
/// CHANSERV :message
|
||||
CHANSERV(&'a str),
|
||||
/// OPERSERV :message
|
||||
OPERSERV(&'a str),
|
||||
/// BOTSERV :message
|
||||
BOTSERV(&'a str),
|
||||
/// HOSTSERV :message
|
||||
HOSTSERV(&'a str),
|
||||
/// MEMOSERV :message
|
||||
MEMOSERV(&'a str),
|
||||
|
||||
// Capabilities extension to IRCv3
|
||||
/// CAP COMMAND [param]
|
||||
|
@ -239,7 +252,12 @@ impl<'a> Command<'a> {
|
|||
Command::SANICK(o, n) => Message::new(None, "SANICK", Some(vec![o, n]), None),
|
||||
Command::SAPART(c, r) => Message::new(None, "SAPART", Some(vec![c]), Some(r)),
|
||||
Command::SAQUIT(c, r) => Message::new(None, "SAQUIT", Some(vec![c]), Some(r)),
|
||||
|
||||
Command::NICKSERV(m) => Message::new(None, "NICKSERV", None, Some(m)),
|
||||
Command::CHANSERV(m) => Message::new(None, "CHANSERV", None, Some(m)),
|
||||
Command::OPERSERV(m) => Message::new(None, "OPERSERV", None, Some(m)),
|
||||
Command::BOTSERV(m) => Message::new(None, "BOTSERV", None, Some(m)),
|
||||
Command::HOSTSERV(m) => Message::new(None, "HOSTSERV", None, Some(m)),
|
||||
Command::MEMOSERV(m) => Message::new(None, "MEMOSERV", None, Some(m)),
|
||||
Command::CAP(s, p) => Message::new(None, "CAP", Some(vec![s.to_str()]), p),
|
||||
}
|
||||
}
|
||||
|
@ -846,6 +864,72 @@ impl<'a> Command<'a> {
|
|||
Command::SAQUIT(m.args[0][], m.args[1][])
|
||||
}
|
||||
}
|
||||
} else if let "NICKSERV" = m.command[] {
|
||||
match m.suffix {
|
||||
Some(ref suffix) => {
|
||||
if m.args.len() != 0 { return Err(invalid_input()) }
|
||||
Command::NICKSERV(suffix[])
|
||||
},
|
||||
None => {
|
||||
if m.args.len() != 1 { return Err(invalid_input()) }
|
||||
Command::NICKSERV(m.args[0][])
|
||||
}
|
||||
}
|
||||
} else if let "CHANSERV" = m.command[] {
|
||||
match m.suffix {
|
||||
Some(ref suffix) => {
|
||||
if m.args.len() != 0 { return Err(invalid_input()) }
|
||||
Command::CHANSERV(suffix[])
|
||||
},
|
||||
None => {
|
||||
if m.args.len() != 1 { return Err(invalid_input()) }
|
||||
Command::CHANSERV(m.args[0][])
|
||||
}
|
||||
}
|
||||
} else if let "OPERSERV" = m.command[] {
|
||||
match m.suffix {
|
||||
Some(ref suffix) => {
|
||||
if m.args.len() != 0 { return Err(invalid_input()) }
|
||||
Command::OPERSERV(suffix[])
|
||||
},
|
||||
None => {
|
||||
if m.args.len() != 1 { return Err(invalid_input()) }
|
||||
Command::OPERSERV(m.args[0][])
|
||||
}
|
||||
}
|
||||
} else if let "BOTSERV" = m.command[] {
|
||||
match m.suffix {
|
||||
Some(ref suffix) => {
|
||||
if m.args.len() != 0 { return Err(invalid_input()) }
|
||||
Command::BOTSERV(suffix[])
|
||||
},
|
||||
None => {
|
||||
if m.args.len() != 1 { return Err(invalid_input()) }
|
||||
Command::BOTSERV(m.args[0][])
|
||||
}
|
||||
}
|
||||
} else if let "HOSTSERV" = m.command[] {
|
||||
match m.suffix {
|
||||
Some(ref suffix) => {
|
||||
if m.args.len() != 0 { return Err(invalid_input()) }
|
||||
Command::HOSTSERV(suffix[])
|
||||
},
|
||||
None => {
|
||||
if m.args.len() != 1 { return Err(invalid_input()) }
|
||||
Command::HOSTSERV(m.args[0][])
|
||||
}
|
||||
}
|
||||
} else if let "MEMOSERV" = m.command[] {
|
||||
match m.suffix {
|
||||
Some(ref suffix) => {
|
||||
if m.args.len() != 0 { return Err(invalid_input()) }
|
||||
Command::MEMOSERV(suffix[])
|
||||
},
|
||||
None => {
|
||||
if m.args.len() != 1 { return Err(invalid_input()) }
|
||||
Command::MEMOSERV(m.args[0][])
|
||||
}
|
||||
}
|
||||
} else if let "CAP" = m.command[] {
|
||||
if m.args.len() != 1 { return Err(invalid_input()) }
|
||||
if let Some(cmd) = from_str(m.args[0][]) {
|
||||
|
|
|
@ -13,6 +13,8 @@ pub struct Config {
|
|||
pub owners: Option<Vec<String>>,
|
||||
/// The bot's nickname.
|
||||
pub nickname: Option<String>,
|
||||
/// The bot's NICKSERV password.
|
||||
pub nick_password: Option<String>,
|
||||
/// Alternative nicknames for the bots, if the default is taken.
|
||||
pub alt_nicks: Option<Vec<String>>,
|
||||
/// The bot's username.
|
||||
|
@ -69,6 +71,13 @@ impl Config {
|
|||
self.nickname.as_ref().map(|s| s[]).unwrap()
|
||||
}
|
||||
|
||||
/// Gets the bot's nickserv password specified in the configuration.
|
||||
/// This defaults to an empty string when not specified.
|
||||
#[experimental]
|
||||
pub fn nick_password(&self) -> &str {
|
||||
self.nick_password.as_ref().map(|s| s[]).unwrap_or("")
|
||||
}
|
||||
|
||||
/// Gets the alternate nicknames specified in the configuration.
|
||||
/// This defaults to an empty vector when not specified.
|
||||
#[experimental]
|
||||
|
@ -157,6 +166,7 @@ mod test {
|
|||
let cfg = Config {
|
||||
owners: Some(vec![format!("test")]),
|
||||
nickname: Some(format!("test")),
|
||||
nick_password: None,
|
||||
alt_nicks: None,
|
||||
username: Some(format!("test")),
|
||||
realname: Some(format!("test")),
|
||||
|
@ -176,6 +186,7 @@ mod test {
|
|||
let cfg = Config {
|
||||
owners: Some(vec![format!("test")]),
|
||||
nickname: Some(format!("test")),
|
||||
nick_password: None,
|
||||
alt_nicks: None,
|
||||
username: Some(format!("test")),
|
||||
realname: Some(format!("test")),
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use std::io::IoResult;
|
||||
use data::{Command, Config, User};
|
||||
use data::Command::{CAP, INVITE, JOIN, KICK, KILL, MODE, NICK, NOTICE};
|
||||
use data::Command::{CAP, INVITE, JOIN, KICK, KILL, MODE, NICK, NICKSERV, NOTICE};
|
||||
use data::Command::{OPER, PASS, PONG, PRIVMSG, SAMODE, SANICK, TOPIC, USER};
|
||||
use data::command::CapSubCommand::{END, REQ};
|
||||
use data::kinds::{IrcReader, IrcWriter};
|
||||
|
@ -51,8 +51,14 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
|
|||
try!(self.server.send(PASS(self.server.config().password())));
|
||||
}
|
||||
try!(self.server.send(NICK(self.server.config().nickname())));
|
||||
self.server.send(USER(self.server.config().username(), "0",
|
||||
self.server.config().real_name()))
|
||||
try!(self.server.send(USER(self.server.config().username(), "0",
|
||||
self.server.config().real_name())));
|
||||
if self.server.config().nick_password() != "" {
|
||||
try!(self.server.send(NICKSERV(
|
||||
format!("IDENTIFY {}", self.server.config().nick_password())[]
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sends a PONG with the specified message.
|
||||
|
@ -157,9 +163,11 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Wrapper;
|
||||
use std::default::Default;
|
||||
use std::io::MemWriter;
|
||||
use std::io::util::NullReader;
|
||||
use conn::Connection;
|
||||
use data::Config;
|
||||
use server::IrcServer;
|
||||
use server::test::{get_server_value, test_config};
|
||||
|
||||
|
@ -175,6 +183,44 @@ mod test {
|
|||
"CAP REQ :multi-prefix\r\nCAP END\r\nNICK :test\r\nUSER test 0 * :test\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn identify_with_password() {
|
||||
let server = IrcServer::from_connection(Config {
|
||||
owners: Some(vec![format!("test")]),
|
||||
nickname: Some(format!("test")),
|
||||
alt_nicks: Some(vec![format!("test2")]),
|
||||
server: Some(format!("irc.test.net")),
|
||||
password: Some(format!("password")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
.. Default::default()
|
||||
}, Connection::new(NullReader, MemWriter::new()));
|
||||
{
|
||||
let wrapper = Wrapper::new(&server);
|
||||
wrapper.identify().unwrap();
|
||||
}
|
||||
assert_eq!(get_server_value(server)[], "CAP REQ :multi-prefix\r\nCAP END\r\n\
|
||||
PASS :password\r\nNICK :test\r\nUSER test 0 * :test\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn identify_with_nick_password() {
|
||||
let server = IrcServer::from_config(Config {
|
||||
owners: Some(vec![format!("test")]),
|
||||
nickname: Some(format!("test")),
|
||||
alt_nicks: Some(vec![format!("test2")]),
|
||||
server: Some(format!("irc.test.net")),
|
||||
nick_password: Some(format!("password")),
|
||||
channels: Some(vec![format!("#test"), format!("#test2")]),
|
||||
.. Default::default()
|
||||
}, Connection::new(NullReader, MemWriter::new()));
|
||||
{
|
||||
let wrapper = Wrapper::new(&server);
|
||||
wrapper.identify().unwrap();
|
||||
}
|
||||
assert_eq!(get_server_value(server)[], "CAP REQ :multi-prefix\r\nCAP END\r\nNICK :test\r\n\
|
||||
USER test 0 * :test\r\nNICKSERV :IDENTIFY password\r\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn send_pong() {
|
||||
let server = IrcServer::from_connection(test_config(),
|
||||
|
|
Loading…
Reference in a new issue