diff --git a/.travis.yml b/.travis.yml index 57a5e38..cc60af0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ script: - cargo test --verbose --features "toml yaml" - cargo test --doc - cargo test --verbose --no-default-features + - cargo run --bin build-bot notifications: email: false irc: diff --git a/Cargo.toml b/Cargo.toml index 81f28ca..3b5e45d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "irc" -version = "0.13.5" +version = "0.13.6" description = "the irc crate – usable, async IRC for Rust " authors = ["Aaron Weiss "] license = "MPL-2.0" -keywords = ["irc", "client", "thread-safe", "async", "tokio", "protocol"] +keywords = ["irc", "client", "thread-safe", "async", "tokio"] categories = ["asynchronous", "network-programming"] documentation = "https://docs.rs/irc/" repository = "https://github.com/aatxe/irc" diff --git a/README.md b/README.md index 8e611fc..84007cf 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ projects: - [irc-bot.rs][ircbot] — a library for writing IRC bots - [playbot_ng][playbot_ng] — a Rust-evaluating IRC bot in Rust - [bunnybutt-rs][bunnybutt] — an IRC bot for the [Feed The Beast Wiki][ftb-wiki] +- [url-bot-rs][url-bot-rs] — a URL-fetching IRC bot [alectro]: https://github.com/aatxe/alectro [spilo]: https://github.com/aatxe/spilo @@ -34,6 +35,7 @@ projects: [bunnybutt]: https://github.com/FTB-Gamepedia/bunnybutt-rs [playbot_ng]: https://github.com/panicbit/playbot_ng [ftb-wiki]: https://ftb.gamepedia.com/FTB_Wiki +[url-bot-rs]: https://github.com/nuxeh/url-bot-rs Making your own project? [Submit a pull request](https://github.com/aatxe/irc/pulls) to add it! diff --git a/irc-proto/src/command.rs b/irc-proto/src/command.rs index b7f8948..cb31821 100644 --- a/irc-proto/src/command.rs +++ b/irc-proto/src/command.rs @@ -505,17 +505,17 @@ impl Command { } else if cmd.eq_ignore_ascii_case("USER") { match suffix { Some(suffix) => { - if args.len() != 2 { + if args.len() != 3 { raw(cmd, args, Some(suffix)) } else { Command::USER(args[0].to_owned(), args[1].to_owned(), suffix.to_owned()) } } None => { - if args.len() != 3 { + if args.len() != 4 { raw(cmd, args, suffix) } else { - Command::USER(args[0].to_owned(), args[1].to_owned(), args[2].to_owned()) + Command::USER(args[0].to_owned(), args[1].to_owned(), args[3].to_owned()) } } } @@ -1787,6 +1787,7 @@ impl FromStr for BatchSubCommand { #[cfg(test)] mod test { + use proto::Message; use super::Response; use super::Command; @@ -1796,4 +1797,18 @@ mod test { vec!["foo".into()], None)) == "001 foo"); } + + #[test] + fn user_round_trip() { + let cmd = Command::USER("a".to_string(), "b".to_string(), "c".to_string()); + let line = Message::from(cmd.clone()).to_string(); + let returned_cmd = line.parse::().unwrap().command; + assert_eq!(cmd, returned_cmd); + } + + #[test] + fn parse_user_message() { + let cmd = "USER a 0 * b".parse::().unwrap().command; + assert_eq!(Command::USER("a".to_string(), "0".to_string(), "b".to_string()), cmd); + } } diff --git a/src/bin/build-bot.rs b/src/bin/build-bot.rs new file mode 100644 index 0000000..effde57 --- /dev/null +++ b/src/bin/build-bot.rs @@ -0,0 +1,46 @@ +extern crate irc; + +use irc::client::prelude::*; +use std::default::Default; +use std::env; + +fn main() { + let repository_slug = env::var("TRAVIS_REPO_SLUG").unwrap(); + let branch = env::var("TRAVIS_BRANCH").unwrap(); + let commit = env::var("TRAVIS_COMMIT").unwrap(); + let commit_message = env::var("TRAVIS_COMMIT_MESSAGE").unwrap(); + + let config = Config { + nickname: Some("irc-crate-ci".to_owned()), + server: Some("irc.pdgn.co".to_owned()), + use_ssl: Some(true), + ..Default::default() + }; + + let mut reactor = IrcReactor::new().unwrap(); + let client = reactor.prepare_client_and_connect(&config).unwrap(); + client.identify().unwrap(); + + reactor.register_client_with_handler(client, move |client, message| { + match message.command { + Command::Response(Response::RPL_ISUPPORT, _, _) => { + client.send_privmsg( + "#commits", + format!( + "[{}/{}] ({}) {}", + repository_slug, + branch, + &commit[..7], + commit_message + ), + )?; + client.send_quit("QUIT")?; + } + _ => (), + }; + + Ok(()) + }); + + reactor.run().unwrap(); +} diff --git a/src/client/mod.rs b/src/client/mod.rs index 79d14ed..38843e2 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -336,7 +336,7 @@ impl ClientState { PRIVMSG(ref target, ref body) => { if body.starts_with('\u{001}') { let tokens: Vec<_> = { - let end = if body.ends_with('\u{001}') { + let end = if body.ends_with('\u{001}') && body.len() > 1 { body.len() - 1 } else { body.len() @@ -550,8 +550,7 @@ impl ClientState { self.send_ctcp_internal( resp, &format!("SOURCE {}", self.config().source()), - )?; - self.send_ctcp_internal(resp, "SOURCE") + ) } else if tokens[0].eq_ignore_ascii_case("PING") && tokens.len() > 1 { self.send_ctcp_internal(resp, &format!("PING {}", tokens[1])) } else if tokens[0].eq_ignore_ascii_case("TIME") { @@ -828,7 +827,8 @@ impl Future for IrcClientFuture { /// This type should only be used by advanced users who are familiar with the implementation of this /// crate. An easy to use abstraction that does not require this knowledge is available via /// [`IrcReactors`](./reactor/struct.IrcReactor.html). -pub struct PackedIrcClient(pub IrcClient, pub Box + Send>); +pub struct PackedIrcClient(pub IrcClient, pub Box + Send + 'static>); +>>>>>>> develop #[cfg(test)] mod test { @@ -1231,6 +1231,21 @@ mod test { assert!(client.list_users("#test").is_none()) } + #[test] + fn handle_single_soh() { + let value = ":test!test@test PRIVMSG #test :\u{001}\r\n"; + let client = IrcClient::from_config(Config { + mock_initial_value: Some(value.to_owned()), + nickname: Some(format!("test")), + channels: Some(vec![format!("#test"), format!("#test2")]), + ..test_config() + }).unwrap(); + client.for_each_incoming(|message| { + println!("{:?}", message); + }).unwrap(); + } + + #[test] #[cfg(feature = "ctcp")] fn finger_response() { @@ -1281,8 +1296,7 @@ mod test { }).unwrap(); assert_eq!( &get_client_value(client)[..], - "NOTICE test :\u{001}SOURCE https://github.com/aatxe/irc\u{001}\r\n\ - NOTICE test :\u{001}SOURCE\u{001}\r\n" + "NOTICE test :\u{001}SOURCE https://github.com/aatxe/irc\u{001}\r\n" ); } diff --git a/src/client/reactor.rs b/src/client/reactor.rs index 7ab18f7..7b8e53f 100644 --- a/src/client/reactor.rs +++ b/src/client/reactor.rs @@ -138,8 +138,11 @@ impl IrcReactor { &mut self, client: IrcClient, mut handler: F ) where F: FnMut(&IrcClient, Message) -> U + 'static, U: IntoFuture + 'static { + let handle = self.inner.handle().clone(); self.handlers.push(Box::new(client.stream().for_each(move |message| { - handler(&client, message) + handle.spawn(handler(&client, message).into_future().map_err(|_| (()))); + + Ok(()) }))); }