Updated to 0.7.9 and re-evaluated library stabilization.

This commit is contained in:
Aaron Weiss 2015-01-09 18:36:22 -05:00
parent d0b54f8119
commit 768c6f556f
10 changed files with 128 additions and 129 deletions

View file

@ -1,7 +1,7 @@
[package]
name = "irc"
version = "0.7.8"
version = "0.7.9"
description = "A simple, thread-safe IRC client library."
authors = ["Aaron Weiss <aaronweiss74@gmail.com>"]
license = "Unlicense"
@ -18,19 +18,19 @@ encode = ["encoding"]
ssl = ["openssl"]
[dependencies.rustc-serialize]
rustc-serialize = "~0.2.5"
rustc-serialize = "~0.2.7"
[dependencies.time]
time = "~0.1.10"
time = "~0.1.12"
optional = true
[dependencies.encoding]
encoding = "~0.2.16"
encoding = "~0.2.18"
optional = true
[dependencies.openssl]
openssl = "~0.2.13"
openssl = "~0.2.15"
optional = true

View file

@ -1,5 +1,5 @@
//! Thread-safe connections on IrcStreams.
#![experimental]
#![stable]
use std::error::Error;
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
#[cfg(any(feature = "encode", feature = "ssl"))] use std::io::{IoError, IoErrorKind};
@ -12,7 +12,7 @@ use data::message::ToMessage;
#[cfg(feature = "ssl")] use openssl::ssl::error::SslError;
/// A thread-safe connection.
#[experimental]
#[stable]
pub struct Connection<T: IrcReader, U: IrcWriter> {
reader: Mutex<T>,
writer: Mutex<U>,
@ -26,7 +26,7 @@ type NetReaderWriterPair = (BufferedReader<NetStream>, BufferedWriter<NetStream>
impl Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
/// Creates a thread-safe TCP connection to the specified server.
#[experimental]
#[stable]
pub fn connect(host: &str, port: u16) -> IoResult<NetConnection> {
let (reader, writer) = try!(Connection::connect_internal(host, port));
Ok(Connection::new(reader, writer))
@ -41,7 +41,7 @@ impl Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
/// Creates a thread-safe TCP connection to the specified server over SSL.
/// If the library is compiled without SSL support, this method panics.
#[experimental]
#[stable]
pub fn connect_ssl(host: &str, port: u16) -> IoResult<NetConnection> {
let (reader, writer) = try!(Connection::connect_ssl_internal(host, port));
Ok(Connection::new(reader, writer))
@ -64,6 +64,7 @@ impl Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
}
/// Reconnects to the specified server, dropping the current connection.
#[unstable = "Feature is relatively new."]
pub fn reconnect(&self, host: &str, port: u16) -> IoResult<()> {
let use_ssl = match self.reader.lock().unwrap().get_ref() {
&NetStream::UnsecuredTcpStream(_) => false,
@ -81,13 +82,13 @@ impl Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
}
/// Sets the keepalive for the network stream.
#[experimental]
#[unstable = "Feature is relatively new."]
pub fn set_keepalive(&self, delay_in_seconds: Option<usize>) -> IoResult<()> {
self.mod_stream(|tcp| tcp.set_keepalive(delay_in_seconds))
}
/// Sets the timeout for the network stream.
#[experimental]
#[unstable = "Feature is relatively new."]
pub fn set_timeout(&self, timeout_ms: Option<u64>) {
self.mod_stream(|tcp| Ok(tcp.set_timeout(timeout_ms))).unwrap(); // this cannot fail.
}
@ -104,7 +105,7 @@ impl Connection<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
impl<T: IrcReader, U: IrcWriter> Connection<T, U> {
/// Creates a new connection from an IrcReader and an IrcWriter.
#[experimental]
#[stable]
pub fn new(reader: T, writer: U) -> Connection<T, U> {
Connection {
reader: Mutex::new(reader),
@ -113,7 +114,7 @@ impl<T: IrcReader, U: IrcWriter> Connection<T, U> {
}
/// Sends a Message over this connection.
#[experimental]
#[experimental = "Design is very new."]
#[cfg(feature = "encode")]
pub fn send<M: ToMessage>(&self, to_msg: M, encoding: &str) -> IoResult<()> {
let encoding = match encoding_from_whatwg_label(encoding) {
@ -139,7 +140,7 @@ impl<T: IrcReader, U: IrcWriter> Connection<T, U> {
}
/// Sends a message over this connection.
#[experimental]
#[experimental = "Design is very new."]
#[cfg(not(feature = "encode"))]
pub fn send<T: ToMessage>(&self, to_msg: T) -> IoResult<()> {
let mut writer = self.writer.lock().unwrap();
@ -148,7 +149,7 @@ impl<T: IrcReader, U: IrcWriter> Connection<T, U> {
}
/// Receives a single line from this connection.
#[experimental]
#[stable]
#[cfg(feature = "encoding")]
pub fn recv(&self, encoding: &str) -> IoResult<String> {
let encoding = match encoding_from_whatwg_label(encoding) {
@ -172,20 +173,20 @@ impl<T: IrcReader, U: IrcWriter> Connection<T, U> {
}
/// Receives a single line from this connection.
#[experimental]
#[stable]
#[cfg(not(feature = "encoding"))]
pub fn recv(&self) -> IoResult<String> {
self.reader.lock().unwrap().read_line()
}
/// Acquires the Reader lock.
#[experimental]
#[stable]
pub fn reader<'a>(&'a self) -> MutexGuard<'a, T> {
self.reader.lock().unwrap()
}
/// Acquires the Writer lock.
#[experimental]
#[stable]
pub fn writer<'a>(&'a self) -> MutexGuard<'a, U> {
self.writer.lock().unwrap()
}
@ -205,7 +206,7 @@ fn ssl_to_io<T>(res: Result<T, SslError>) -> IoResult<T> {
}
/// An abstraction over different networked streams.
#[experimental]
#[stable]
pub enum NetStream {
/// An unsecured TcpStream.
UnsecuredTcpStream(TcpStream),

View file

@ -12,72 +12,72 @@ use data::message::{Message, ToMessage};
#[derive(Show, PartialEq)]
pub enum Command<'a> {
// 3.1 Connection Registration
/// PASS password
/// PASS :password
PASS(&'a str),
/// NICK nickname
/// NICK :nickname
NICK(&'a str),
/// USER user mode * realname
/// USER user mode * :realname
USER(&'a str, &'a str, &'a str),
/// OPER name password
/// OPER name :password
OPER(&'a str, &'a str),
/// MODE nickname modes
/// MODE channel modes [modeparams]
MODE(&'a str, &'a str, Option<&'a str>),
/// SERVICE nickname reserved distribution type reserved info
/// SERVICE nickname reserved distribution type reserved :info
SERVICE(&'a str, &'a str, &'a str, &'a str, &'a str, &'a str),
/// QUIT Quit Message
/// QUIT :comment
QUIT(Option<&'a str>),
/// SQUIT server comment
/// SQUIT server :comment
SQUIT(&'a str, &'a str),
// 3.2 Channel operations
/// JOIN chanlist [chankeys]
JOIN(&'a str, Option<&'a str>),
/// PART chanlist [Part Message]
/// PART chanlist :[comment]
PART(&'a str, Option<&'a str>),
// MODE is already defined.
// MODE(&'a str, &'a str, Option<&'a str>),
/// TOPIC channel [topic]
/// TOPIC channel :[topic]
TOPIC(&'a str, Option<&'a str>),
/// NAMES [chanlist [target]]
/// NAMES [chanlist :[target]]
NAMES(Option<&'a str>, Option<&'a str>),
/// LIST [chanlist [target]]
/// LIST [chanlist :[target]]
LIST(Option<&'a str>, Option<&'a str>),
/// INVITE nickname channel
INVITE(&'a str, &'a str),
/// KICK chanlist userlist [comment]
/// KICK chanlist userlist :[comment]
KICK(&'a str, &'a str, Option<&'a str>),
// 3.3 Sending messages
/// PRIVMSG msgtarget text to be sent
/// PRIVMSG msgtarget :message
PRIVMSG(&'a str, &'a str),
/// NOTICE msgtarget text
/// NOTICE msgtarget :message
NOTICE(&'a str, &'a str),
// 3.4 Server queries and commands
/// MOTD [target]
/// MOTD :[target]
MOTD(Option<&'a str>),
/// LUSERS [mask [target]]
/// LUSERS [mask :[target]]
LUSERS(Option<&'a str>, Option<&'a str>),
/// VERSION [target]
/// VERSION :[target]
VERSION(Option<&'a str>),
/// STATS [query [target]]
/// STATS [query :[target]]
STATS(Option<&'a str>, Option<&'a str>),
/// LINKS [[remote server] server mask]
/// LINKS [[remote server] server :mask]
LINKS(Option<&'a str>, Option<&'a str>),
/// TIME [target]
/// TIME :[target]
TIME(Option<&'a str>),
/// CONNECT target server port [remote server]
/// CONNECT target server port :[remote server]
CONNECT(&'a str, &'a str, Option<&'a str>),
/// TRACE [target]
/// TRACE :[target]
TRACE(Option<&'a str>),
/// ADMIN [target]
/// ADMIN :[target]
ADMIN(Option<&'a str>),
/// INFO [target]
/// INFO :[target]
INFO(Option<&'a str>),
// 3.5 Service Query and Commands
/// SERVLIST [mask [type]]
/// SERVLIST [mask :[type]]
SERVLIST(Option<&'a str>, Option<&'a str>),
/// SQUERY servicename text
SQUERY(&'a str, &'a str),
@ -87,22 +87,22 @@ pub enum Command<'a> {
WHO(Option<&'a str>, Option<bool>),
/// WHOIS [target] masklist
WHOIS(Option<&'a str>, &'a str),
/// WHOWAS nicklist [count [target]]
/// WHOWAS nicklist [count :[target]]
WHOWAS(&'a str, Option<&'a str>, Option<&'a str>),
// 3.7 Miscellaneous messages
/// KILL nickname comment
/// KILL nickname :comment
KILL(&'a str, &'a str),
/// PING server1 [server2]
/// PING server1 :[server2]
PING(&'a str, Option<&'a str>),
/// PONG server [server2]
/// PONG server :[server2]
PONG(&'a str, Option<&'a str>),
/// ERROR error message
/// ERROR :message
ERROR(&'a str),
// 4 Optional Features
/// AWAY [text]
/// AWAY :[message]
AWAY(Option<&'a str>),
/// REHASH
REHASH,
@ -110,11 +110,11 @@ pub enum Command<'a> {
DIE,
/// RESTART
RESTART,
/// SUMMON user [target [channel]]
/// SUMMON user [target :[channel]]
SUMMON(&'a str, Option<&'a str>, Option<&'a str>),
/// USERS [target]
/// USERS :[target]
USERS(Option<&'a str>),
/// WALLOPS Text to be sent
/// WALLOPS :Text to be sent
WALLOPS(&'a str),
/// USERHOST space-separated nicklist
USERHOST(Vec<&'a str>),
@ -128,9 +128,9 @@ pub enum Command<'a> {
SAMODE(&'a str, &'a str, Option<&'a str>),
/// SANICK old nickname new nickname
SANICK(&'a str, &'a str),
/// SAPART nickname reason
/// SAPART nickname :comment
SAPART(&'a str, &'a str),
/// SAQUIT nickname reason
/// SAQUIT nickname :comment
SAQUIT(&'a str, &'a str),
/// NICKSERV message
NICKSERV(&'a str),
@ -146,7 +146,8 @@ pub enum Command<'a> {
MEMOSERV(&'a str),
// Capabilities extension to IRCv3
/// CAP COMMAND [param]
/// CAP COMMAND :[param]
#[experimental = "This command is not entirely specification compliant."]
CAP(CapSubCommand, Option<&'a str>),
}

View file

@ -9,7 +9,7 @@ use rustc_serialize::json::decode;
/// Configuration data.
#[derive(Clone, RustcDecodable, Default, PartialEq, Show)]
#[unstable]
#[stable]
pub struct Config {
/// A list of the owners of the bot by nickname.
pub owners: Option<Vec<String>>,
@ -70,21 +70,21 @@ impl Config {
/// Gets the nickname specified in the configuration.
/// This will panic if not specified.
#[experimental]
#[stable]
pub fn nickname(&self) -> &str {
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]
#[stable]
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]
#[stable]
pub fn get_alternate_nicknames(&self) -> Vec<&str> {
self.alt_nicks.as_ref().map(|v| v.iter().map(|s| &s[]).collect()).unwrap_or(vec![])
}
@ -92,28 +92,28 @@ impl Config {
/// Gets the username specified in the configuration.
/// This defaults to the user's nickname when not specified.
#[experimental]
#[stable]
pub fn username(&self) -> &str {
self.username.as_ref().map(|s| &s[]).unwrap_or(self.nickname())
}
/// Gets the real name specified in the configuration.
/// This defaults to the user's nickname when not specified.
#[experimental]
#[stable]
pub fn real_name(&self) -> &str {
self.realname.as_ref().map(|s| &s[]).unwrap_or(self.nickname())
}
/// Gets the address of the server specified in the configuration.
/// This panics when not specified.
#[experimental]
#[stable]
pub fn server(&self) -> &str {
self.server.as_ref().map(|s| &s[]).unwrap()
}
/// Gets the port of the server specified in the configuration.
/// This defaults to 6667 (or 6697 if use_ssl is specified as true) when not specified.
#[experimental]
#[stable]
pub fn port(&self) -> u16 {
self.port.as_ref().map(|p| *p).unwrap_or(if self.use_ssl() {
6697
@ -124,35 +124,35 @@ impl Config {
/// Gets the server password specified in the configuration.
/// This defaults to a blank string when not specified.
#[experimental]
#[stable]
pub fn password(&self) -> &str {
self.password.as_ref().map(|s| &s[]).unwrap_or("")
}
/// Gets whether or not to use SSL with this connection.
/// This defaults to false when not specified.
#[experimental]
#[stable]
pub fn use_ssl(&self) -> bool {
self.use_ssl.as_ref().map(|u| *u).unwrap_or(false)
}
/// Gets the encoding to use for this connection. This requires the encode feature to work.
/// This defaults to UTF-8 when not specified.
#[experimental]
#[stable]
pub fn encoding(&self) -> &str {
self.encoding.as_ref().map(|s| &s[]).unwrap_or("UTF-8")
}
/// Gets the channels to join upon connection.
/// This defaults to an empty vector if it's not specified.
#[experimental]
#[stable]
pub fn channels(&self) -> Vec<&str> {
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]
#[unstable = "Feature is still relatively new."]
pub fn user_info(&self) -> &str {
self.user_info.as_ref().map(|s| &s[]).unwrap_or("")
}
@ -160,7 +160,7 @@ impl Config {
/// 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.
#[experimental]
#[stable]
pub fn get_option(&self, option: &str) -> &str {
self.options.as_ref().map(|o| &o[option.to_owned()][]).unwrap()
}

View file

@ -4,7 +4,7 @@ use std::borrow::ToOwned;
use std::str::FromStr;
/// IRC Message data.
#[experimental]
#[stable]
#[derive(Clone, PartialEq, Show)]
pub struct Message {
/// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812).
@ -20,7 +20,7 @@ pub struct Message {
impl Message {
/// Creates a new Message.
#[experimental]
#[stable]
pub fn new(prefix: Option<&str>, command: &str, args: Option<Vec<&str>>, suffix: Option<&str>)
-> Message {
Message {
@ -32,13 +32,13 @@ impl Message {
}
/// Gets the nickname of the message source, if it exists.
#[experimental]
#[experimental = "Feature is new."]
pub fn get_source_nickname(&self) -> Option<&str> {
self.prefix.as_ref().and_then(|s| s.find('!').map(|i| &s[..i]))
}
/// Converts a Message into a String according to the IRC protocol.
#[experimental]
#[stable]
pub fn into_string(&self) -> String {
let mut ret = String::new();
if let Some(ref prefix) = self.prefix {
@ -98,6 +98,7 @@ impl FromStr for Message {
}
/// A trait representing the ability to be converted into a Message.
#[experimental = "Design is new."]
pub trait ToMessage {
/// Converts this to a Message.
fn to_message(&self) -> Message;

View file

@ -1,5 +1,5 @@
//! Data related to IRC functionality.
#![unstable]
#![stable]
pub use data::command::Command;
pub use data::config::Config;
@ -9,18 +9,18 @@ pub use data::user::{AccessLevel, User};
pub mod kinds {
//! Trait definitions of appropriate Writers and Buffers for use with this library.
#![unstable]
#![stable]
/// Trait describing all possible Writers for this library.
#[unstable]
#[stable]
pub trait IrcWriter: Writer + Sized + Send + 'static {}
impl<T> IrcWriter for T where T: Writer + Sized + Send + 'static {}
/// Trait describing all possible Readers for this library.
#[unstable]
#[stable]
pub trait IrcReader: Buffer + Sized + Send + 'static {}
impl<T> IrcReader for T where T: Buffer + Sized + Send + 'static {}
/// Trait describing all possible Streams for this library.
#[unstable]
#[unstable = "May be removed."]
pub trait IrcStream: IrcWriter + IrcReader {}
impl<T> IrcStream for T where T: IrcWriter + IrcReader {}
}

View file

@ -1,5 +1,5 @@
//! Enumeration of all the possible server responses.
#![unstable]
#![stable]
#![allow(non_camel_case_types)]
use std::num::FromPrimitive;
use std::str::FromStr;
@ -9,7 +9,7 @@ use data::message::Message;
/// All commands are documented with their expected form from the RFC.
#[derive(Copy, Show, PartialEq, FromPrimitive)]
#[repr(u16)]
#[unstable]
#[stable]
pub enum Response {
// Expected replies
/// 001 Welcome to the Internet Relay Network <nick>!<user>@<host>

View file

@ -6,7 +6,7 @@ use std::cmp::Ordering::{Less, Equal, Greater};
use std::str::FromStr;
/// IRC User data.
#[unstable]
#[stable]
#[derive(Clone, Show)]
pub struct User {
/// The user's nickname.
@ -48,19 +48,19 @@ impl User {
}
/// Gets the user's highest access level.
#[experimental]
#[unstable = "API may change."]
pub fn highest_access_level(&self) -> AccessLevel {
self.highest_access_level
}
/// Gets all the user's access levels.
#[experimental]
#[unstable = "API may change."]
pub fn access_levels(&self) -> Vec<AccessLevel> {
self.access_levels.clone()
}
/// Updates the user's access level.
#[unstable]
#[unstable = "API may change."]
pub fn update_access_level(&mut self, mode: &str) {
match mode {
"+q" => self.add_access_level(AccessLevel::Owner),
@ -77,6 +77,7 @@ impl User {
}
}
/// Adds an access level to the list, and updates the highest level if necessary.
fn add_access_level(&mut self, level: AccessLevel) {
if level > self.highest_access_level() {
self.highest_access_level = level
@ -84,6 +85,7 @@ impl User {
self.access_levels.push(level.clone())
}
/// Removes an access level from the list, and updates the highest level if necessary.
fn sub_access_level(&mut self, level: AccessLevel) {
if let Some(n) = self.access_levels[].position_elem(&level) {
self.access_levels.swap_remove(n);
@ -179,6 +181,7 @@ impl FromStr for AccessLevel {
}
}
/// An iterator used to parse access levels from strings.
struct AccessLevelIterator<'a> {
value: &'a str,
}

View file

@ -1,5 +1,5 @@
//! Interface for working with IRC Servers
#![experimental]
#![stable]
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, IoError, IoErrorKind, IoResult};
@ -13,7 +13,7 @@ use data::kinds::{IrcReader, IrcWriter};
pub mod utils;
/// Trait describing core Server functionality.
#[experimental]
#[stable]
pub trait Server<'a, T, U> {
/// Gets the configuration being used with this Server.
fn config(&self) -> &Config;
@ -26,7 +26,7 @@ pub trait Server<'a, T, U> {
}
/// A thread-safe implementation of an IRC Server connection.
#[experimental]
#[stable]
pub struct IrcServer<T: IrcReader, U: IrcWriter> {
/// The thread-safe IRC connection.
conn: Connection<T, U>,
@ -44,14 +44,14 @@ pub type NetIrcServer = IrcServer<BufferedReader<NetStream>, BufferedWriter<NetS
impl IrcServer<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
/// Creates a new IRC Server connection from the configuration at the specified path,
/// connecting immediately.
#[experimental]
#[stable]
pub fn new(config: &str) -> IoResult<NetIrcServer> {
IrcServer::from_config(try!(Config::load_utf8(config)))
}
/// Creates a new IRC server connection from the specified configuration, connecting
/// immediately.
#[experimental]
#[stable]
pub fn from_config(config: Config) -> IoResult<NetIrcServer> {
let conn = try!(if config.use_ssl() {
Connection::connect_ssl(config.server(), config.port())
@ -63,7 +63,7 @@ impl IrcServer<BufferedReader<NetStream>, BufferedWriter<NetStream>> {
}
/// Reconnects to the IRC server.
#[experimental]
#[unstable = "Feature is relatively new."]
pub fn reconnect(&self) -> IoResult<()> {
self.conn.reconnect(self.config().server(), self.config.port())
}
@ -95,20 +95,19 @@ impl<'a, T: IrcReader, U: IrcWriter> Server<'a, T, U> for IrcServer<T, U> {
impl<T: IrcReader, U: IrcWriter> IrcServer<T, U> {
/// Creates an IRC server from the specified configuration, and any arbitrary Connection.
#[experimental]
#[stable]
pub fn from_connection(config: Config, conn: Connection<T, U>) -> IrcServer<T, U> {
IrcServer { conn: conn, config: config, chanlists: Mutex::new(HashMap::new()),
alt_nick_index: RwLock::new(0) }
}
/// Gets a reference to the IRC server's connection.
#[experimental]
#[stable]
pub fn conn(&self) -> &Connection<T, U> {
&self.conn
}
/// Handles messages internally for basic bot functionality.
#[experimental]
fn handle_message(&self, msg: &Message) {
if let Some(resp) = Response::from_message(msg) {
if resp == Response::RPL_NAMREPLY {
@ -179,7 +178,6 @@ impl<T: IrcReader, U: IrcWriter> IrcServer<T, U> {
}
/// Handles CTCP requests if the CTCP feature is enabled.
#[experimental]
#[cfg(feature = "ctcp")]
fn handle_ctcp(&self, msg: &Message) {
let source = match msg.prefix {
@ -220,31 +218,26 @@ impl<T: IrcReader, U: IrcWriter> IrcServer<T, U> {
}
/// Sends a CTCP-escaped message.
#[experimental]
#[cfg(feature = "ctcp")]
fn send_ctcp(&self, target: &str, msg: &str) {
self.send(Command::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, _: &Message) {}
#[cfg(not(feature = "ctcp"))] fn handle_ctcp(&self, _: &Message) {}
}
/// An Iterator over an IrcServer's incoming Messages.
#[experimental]
#[stable]
pub struct ServerIterator<'a, T: IrcReader, U: IrcWriter> {
server: &'a IrcServer<T, U>
}
impl<'a, T: IrcReader, U: IrcWriter> ServerIterator<'a, T, U> {
/// Creates a new ServerIterator for the desired IrcServer.
#[experimental]
#[experimental = "Design will change to accomodate new behavior."]
pub fn new(server: &IrcServer<T, U>) -> ServerIterator<T, U> {
ServerIterator {
server: server
}
ServerIterator { server: server }
}
/// Gets the next line from the connection.

View file

@ -1,5 +1,5 @@
//! Utilities and shortcuts for working with IRC servers.
#![experimental]
#![stable]
use std::io::IoResult;
use data::{Command, Config, User};
@ -12,7 +12,7 @@ use server::{Server, ServerIterator};
/// Functionality-providing wrapper for Server.
/// Wrappers are currently not thread-safe, and should be created per-thread, as needed.
#[experimental]
#[stable]
pub struct Wrapper<'a, T: IrcReader, U: IrcWriter> {
server: &'a (Server<'a, T, U> + 'a)
}
@ -37,13 +37,13 @@ impl<'a, T: IrcReader, U: IrcWriter> Server<'a, T, U> for Wrapper<'a, T, U> {
impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Creates a new Wrapper from the given Server.
#[experimental]
#[stable]
pub fn new(server: &'a Server<'a, T, U>) -> Wrapper<'a, T, U> {
Wrapper { server: server }
}
/// Sends a NICK and USER to identify.
#[experimental]
#[unstable = "Capabilities requests may be moved outside of identify."]
pub fn identify(&self) -> IoResult<()> {
// We'll issue a CAP REQ for multi-prefix support to improve access level tracking.
try!(self.server.send(CAP(REQ, Some("multi-prefix"))));
@ -58,25 +58,25 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
}
/// Sends a PONG with the specified message.
#[experimental]
#[stable]
pub fn send_pong(&self, msg: &str) -> IoResult<()> {
self.server.send(PONG(msg, None))
}
/// Joins the specified channel or chanlist.
#[experimental]
#[stable]
pub fn send_join(&self, chanlist: &str) -> IoResult<()> {
self.server.send(JOIN(chanlist, None))
}
/// Attempts to oper up using the specified username and password.
#[experimental]
#[stable]
pub fn send_oper(&self, username: &str, password: &str) -> IoResult<()> {
self.server.send(OPER(username, password))
}
/// Sends a message to the specified target.
#[experimental]
#[stable]
pub fn send_privmsg(&self, target: &str, message: &str) -> IoResult<()> {
for line in message.split_str("\r\n") {
try!(self.server.send(PRIVMSG(target, line)))
@ -85,7 +85,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
}
/// Sends a notice to the specified target.
#[experimental]
#[stable]
pub fn send_notice(&self, target: &str, message: &str) -> IoResult<()> {
for line in message.split_str("\r\n") {
try!(self.server.send(NOTICE(target, line)))
@ -95,7 +95,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sets the topic of a channel or requests the current one.
/// If `topic` is an empty string, it won't be included in the message.
#[experimental]
#[unstable = "Design may change."]
pub fn send_topic(&self, channel: &str, topic: &str) -> IoResult<()> {
self.server.send(TOPIC(channel, if topic.len() == 0 {
None
@ -105,7 +105,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
}
/// Kills the target with the provided message.
#[experimental]
#[stable]
pub fn send_kill(&self, target: &str, message: &str) -> IoResult<()> {
self.server.send(KILL(target, message))
}
@ -123,7 +123,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Changes the mode of the target.
/// If `modeparmas` is an empty string, it won't be included in the message.
#[experimental]
#[unstable = "Design may change."]
pub fn send_mode(&self, target: &str, mode: &str, modeparams: &str) -> IoResult<()> {
self.server.send(MODE(target, mode, if modeparams.len() == 0 {
None
@ -134,7 +134,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Changes the mode of the target by force.
/// If `modeparams` is an empty string, it won't be included in the message.
#[experimental]
#[unstable = "Design may change."]
pub fn send_samode(&self, target: &str, mode: &str, modeparams: &str) -> IoResult<()> {
self.server.send(SAMODE(target, mode, if modeparams.len() == 0 {
None
@ -144,20 +144,20 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
}
/// Forces a user to change from the old nickname to the new nickname.
#[experimental]
#[stable]
pub fn send_sanick(&self, old_nick: &str, new_nick: &str) -> IoResult<()> {
self.server.send(SANICK(old_nick, new_nick))
}
/// Invites a user to the specified channel.
#[experimental]
#[stable]
pub fn send_invite(&self, nick: &str, chan: &str) -> IoResult<()> {
self.server.send(INVITE(nick, chan))
}
/// Quits the server entirely with a message.
/// This defaults to `Powered by Rust.` if none is specified.
#[experimental]
#[unstable = "Design may change."]
pub fn send_quit(&self, msg: &str) -> IoResult<()> {
self.server.send(QUIT(Some(if msg.len() == 0 {
"Powered by Rust."
@ -168,7 +168,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sends a CTCP-escaped message to the specified target.
/// This requires the CTCP feature to be enabled.
#[experimental]
#[unstable = "Feature is relatively new."]
#[cfg(feature = "ctcp")]
pub fn send_ctcp(&self, target: &str, msg: &str) -> IoResult<()> {
self.send_privmsg(target, &format!("\u{001}{}\u{001}", msg)[])
@ -176,7 +176,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sends an action command to the specified target.
/// This requires the CTCP feature to be enabled.
#[experimental]
#[unstable = "Feature is relatively new."]
#[cfg(feature = "ctcp")]
pub fn send_action(&self, target: &str, msg: &str) -> IoResult<()> {
self.send_ctcp(target, &format!("ACTION {}", msg)[])
@ -184,7 +184,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sends a finger request to the specified target.
/// This requires the CTCP feature to be enabled.
#[experimental]
#[unstable = "Feature is relatively new."]
#[cfg(feature = "ctcp")]
pub fn send_finger(&self, target: &str) -> IoResult<()> {
self.send_ctcp(target, "FINGER")
@ -192,7 +192,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sends a version request to the specified target.
/// This requires the CTCP feature to be enabled.
#[experimental]
#[unstable = "Feature is relatively new."]
#[cfg(feature = "ctcp")]
pub fn send_version(&self, target: &str) -> IoResult<()> {
self.send_ctcp(target, "VERSION")
@ -200,7 +200,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sends a source request to the specified target.
/// This requires the CTCP feature to be enabled.
#[experimental]
#[unstable = "Feature is relatively new."]
#[cfg(feature = "ctcp")]
pub fn send_source(&self, target: &str) -> IoResult<()> {
self.send_ctcp(target, "SOURCE")
@ -208,7 +208,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sends a user info request to the specified target.
/// This requires the CTCP feature to be enabled.
#[experimental]
#[unstable = "Feature is relatively new."]
#[cfg(feature = "ctcp")]
pub fn send_user_info(&self, target: &str) -> IoResult<()> {
self.send_ctcp(target, "USERINFO")
@ -216,7 +216,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sends a finger request to the specified target.
/// This requires the CTCP feature to be enabled.
#[experimental]
#[unstable = "Feature is relatively new."]
#[cfg(feature = "ctcp")]
pub fn send_ctcp_ping(&self, target: &str) -> IoResult<()> {
let time = get_time();
@ -225,7 +225,7 @@ impl<'a, T: IrcReader, U: IrcWriter> Wrapper<'a, T, U> {
/// Sends a time request to the specified target.
/// This requires the CTCP feature to be enabled.
#[experimental]
#[unstable = "Feature is relatively new."]
#[cfg(feature = "ctcp")]
pub fn send_time(&self, target: &str) -> IoResult<()> {
self.send_ctcp(target, "TIME")