From 5b8f320050726e3a4fc762344d0f89e609bfb268 Mon Sep 17 00:00:00 2001 From: Aaron Weiss Date: Tue, 5 Jul 2016 16:21:21 -0400 Subject: [PATCH] Implemented channel keys for autojoined channels (fixes #51). --- src/client/data/config.rs | 10 ++++++++++ src/client/server/mod.rs | 25 ++++++++++++++++++++++++- src/client/server/utils.rs | 5 +++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/client/data/config.rs b/src/client/data/config.rs index e2b6d32..088adfc 100644 --- a/src/client/data/config.rs +++ b/src/client/data/config.rs @@ -36,6 +36,8 @@ pub struct Config { pub encoding: Option, /// A list of channels to join on connection. pub channels: Option>, + /// A mapping of channel names to keys for join-on-connect. + pub channel_keys: Option>, /// User modes to set on connect. Example: "+RB-x" pub umodes: Option, /// The text that'll be sent in response to CTCP USERINFO requests. @@ -149,6 +151,12 @@ impl Config { self.channels.as_ref().map_or(vec![], |v| v.iter().map(|s| &s[..]).collect()) } + + /// Gets the key for the specified channel if it exists in the configuration. + pub fn channel_key(&self, chan: &str) -> Option<&str> { + self.channel_keys.as_ref().and_then(|m| m.get(&chan.to_owned()).map(|s| &s[..])) + } + /// Gets the user modes to set on connect specified in the configuration. /// This defaults to an empty string when not specified. pub fn umodes(&self) -> &str { @@ -217,6 +225,7 @@ mod test { use_ssl: Some(false), encoding: Some(format!("UTF-8")), channels: Some(vec![format!("#test"), format!("#test2")]), + channel_keys: None, user_info: None, ping_time: None, ping_timeout: None, @@ -243,6 +252,7 @@ mod test { use_ssl: Some(false), encoding: Some(format!("UTF-8")), channels: Some(vec![format!("#test"), format!("#test2")]), + channel_keys: None, user_info: None, ping_time: None, ping_timeout: None, diff --git a/src/client/server/mod.rs b/src/client/server/mod.rs index 96b2e5d..067cefe 100644 --- a/src/client/server/mod.rs +++ b/src/client/server/mod.rs @@ -346,7 +346,10 @@ impl IrcServer { try!(self.send_nick_password()); try!(self.send_umodes()); for chan in self.config().channels().into_iter() { - try!(self.send_join(chan)) + match self.config().channel_key(chan) { + Some(key) => try!(self.send_join_with_keys(chan, key)), + None => try!(self.send_join(chan)) + } } }, Command::Response(Response::ERR_NICKNAMEINUSE, _, _) | @@ -538,6 +541,7 @@ impl<'a> Iterator for ServerIterator<'a> { #[cfg(test)] mod test { use super::{IrcServer, Server}; + use std::collections::HashMap; use std::default::Default; use client::conn::MockConnection; use client::data::Config; @@ -604,6 +608,25 @@ mod test { JOIN #test2\r\n"); } + #[test] + fn handle_end_motd_with_chan_keys() { + let value = ":irc.test.net 376 test :End of /MOTD command\r\n"; + let server = IrcServer::from_connection(Config { + nickname: Some(format!("test")), + channels: Some(vec![format!("#test"), format!("#test2")]), + channel_keys: { + let mut map = HashMap::new(); + map.insert(format!("#test2"), format!("password")); + Some(map) + }, + .. Default::default() + }, MockConnection::new(value)); + for message in server.iter() { + println!("{:?}", message); + } + assert_eq!(&get_server_value(server)[..], "JOIN #test\r\nJOIN #test2 password\r\n"); + } + #[test] fn handle_end_motd_with_ghost() { let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n\ diff --git a/src/client/server/utils.rs b/src/client/server/utils.rs index c6a2931..6ef5307 100644 --- a/src/client/server/utils.rs +++ b/src/client/server/utils.rs @@ -71,6 +71,11 @@ pub trait ServerExt: Server { self.send(JOIN(chanlist.to_owned(), None, None)) } + /// Joins the specified channel or chanlist using the specified key or keylist. + fn send_join_with_keys(&self, chanlist: &str, keylist: &str) -> Result<()> where Self: Sized { + self.send(JOIN(chanlist.to_owned(), Some(keylist.to_owned()), None)) + } + /// Attempts to oper up using the specified username and password. fn send_oper(&self, username: &str, password: &str) -> Result<()> where Self: Sized { self.send(OPER(username.to_owned(), password.to_owned()))