Added CTCP feature with automatic responses to a set of CTCP commands
as per #7.
This commit is contained in:
parent
0967ece14a
commit
1b51c69a23
6 changed files with 81 additions and 2 deletions
|
@ -12,9 +12,15 @@ readme = "README.md"
|
|||
|
||||
[features]
|
||||
|
||||
ctcp = ["time"]
|
||||
encode = ["encoding"]
|
||||
ssl = ["openssl"]
|
||||
|
||||
[dependencies.time]
|
||||
|
||||
time = "~0.1.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.encoding]
|
||||
|
||||
encoding = "~0.2.8"
|
||||
|
|
|
@ -24,7 +24,7 @@ fn main() {
|
|||
if message.command[] == "PRIVMSG" {
|
||||
if let Some(msg) = message.suffix {
|
||||
if msg.contains("pickles") {
|
||||
server.send_privmsg(message.args[0][], "Hi!").unwrap();
|
||||
server.send_action(message.args[0][], "Hi!").unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ pub struct Config {
|
|||
pub encoding: Option<String>,
|
||||
/// A list of channels to join on connection.
|
||||
pub channels: Option<Vec<String>>,
|
||||
/// The text that'll be sent in response to CTCP USERINFO requests.
|
||||
pub user_info: Option<String>,
|
||||
/// A map of additional options to be stored in config.
|
||||
pub options: Option<HashMap<String, String>>,
|
||||
}
|
||||
|
@ -146,6 +148,13 @@ impl Config {
|
|||
self.channels.as_ref().map(|v| v.iter().map(|s| s[]).collect()).unwrap_or(vec![])
|
||||
}
|
||||
|
||||
/// Gets the string to be sent in response to CTCP USERINFO requests.
|
||||
/// This defaults to an empty string when not specified.
|
||||
#[experimental]
|
||||
pub fn user_info(&self) -> &str {
|
||||
self.user_info.as_ref().map(|s| s[]).unwrap_or("")
|
||||
}
|
||||
|
||||
/// Looks up the specified string in the options map.
|
||||
/// This uses indexing, and thus panics when the string is not present.
|
||||
/// This will also panic if used and there are no options.
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#![warn(missing_docs)]
|
||||
|
||||
#![feature(slicing_syntax)]
|
||||
#[cfg(feature = "ctcp")] extern crate time;
|
||||
#[cfg(feature = "encode")] extern crate encoding;
|
||||
extern crate serialize;
|
||||
#[cfg(feature = "ssl")] extern crate openssl;
|
||||
|
|
|
@ -5,8 +5,9 @@ use std::io::{BufferedReader, BufferedWriter, IoError, IoErrorKind, IoResult};
|
|||
use std::sync::{Mutex, RWLock};
|
||||
use conn::{Connection, NetStream};
|
||||
use data::{Command, Config, Message, Response, User};
|
||||
use data::Command::{JOIN, NICK, NICKSERV, PONG};
|
||||
use data::Command::{JOIN, NICK, NICKSERV, NOTICE, PONG};
|
||||
use data::kinds::{IrcReader, IrcWriter};
|
||||
#[cfg(feature = "ctcp")] use time::now;
|
||||
|
||||
pub mod utils;
|
||||
|
||||
|
@ -170,8 +171,63 @@ impl<T: IrcReader, U: IrcWriter> IrcServer<T, U> {
|
|||
vec[n].update_access_level(mode[]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.handle_ctcp(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles CTCP requests if the CTCP feature is enabled.
|
||||
#[experimental]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn handle_ctcp(&self, msg: &Message) {
|
||||
let source = match msg.prefix {
|
||||
Some(ref source) => source.find('!').map_or(source[], |i| source[..i]),
|
||||
None => "",
|
||||
};
|
||||
if let ("PRIVMSG", [ref target]) = (msg.command[], msg.args[]) {
|
||||
let resp = if target.starts_with("#") { target[] } else { source };
|
||||
match msg.suffix {
|
||||
Some(ref msg) if msg.starts_with("\u{001}") => {
|
||||
let tokens: Vec<_> = {
|
||||
let end = if msg.ends_with("\u{001}") {
|
||||
msg.len() - 1
|
||||
} else {
|
||||
msg.len()
|
||||
};
|
||||
msg[1..end].split_str(" ").collect()
|
||||
};
|
||||
match tokens[0] {
|
||||
"FINGER" => self.send_ctcp(resp, format!("FINGER :{} ({})",
|
||||
self.config.real_name(),
|
||||
self.config.username())[]),
|
||||
"VERSION" => self.send_ctcp(resp, "VERSION irc v0.6.0 Rust"),
|
||||
"SOURCE" => {
|
||||
self.send_ctcp(resp, "SOURCE https://github.com/aatxe/irc");
|
||||
self.send_ctcp(resp, "SOURCE");
|
||||
},
|
||||
"PING" => self.send_ctcp(resp, format!("PING {}", tokens[1])[]),
|
||||
"TIME" => self.send_ctcp(resp, format!("TIME :{}", now().rfc822z())[]),
|
||||
"USERINFO" => self.send_ctcp(resp, format!("USERINFO :{}",
|
||||
self.config.user_info())[]),
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a CTCP-escaped message.
|
||||
#[experimental]
|
||||
#[cfg(feature = "ctcp")]
|
||||
fn send_ctcp(&self, target: &str, msg: &str) {
|
||||
self.send(NOTICE(target, format!("\u{001}{}\u{001}", msg)[])).unwrap();
|
||||
}
|
||||
|
||||
/// Handles CTCP requests if the CTCP feature is enabled.
|
||||
#[experimental]
|
||||
#[cfg(not(feature = "ctcp"))]
|
||||
fn handle_ctcp(&self, msg: &Message) {}
|
||||
}
|
||||
|
||||
/// An Iterator over an IrcServer's incoming Messages.
|
||||
|
|
|
@ -164,6 +164,13 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
|
|||
msg
|
||||
})))
|
||||
}
|
||||
|
||||
/// Sends an action command to the specified target.
|
||||
#[experimental]
|
||||
#[cfg(feature = "ctcp")]
|
||||
pub fn send_action(&self, target: &str, msg: &str) -> IoResult<()> {
|
||||
self.send_privmsg(target, format!("\u{001}ACTION {}\u{001}", msg )[])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Add table
Reference in a new issue