aboutsummaryrefslogtreecommitdiffstats
path: root/libirc/msg.rs
diff options
context:
space:
mode:
Diffstat (limited to 'libirc/msg.rs')
-rw-r--r--libirc/msg.rs185
1 files changed, 185 insertions, 0 deletions
diff --git a/libirc/msg.rs b/libirc/msg.rs
new file mode 100644
index 0000000..3471d75
--- /dev/null
+++ b/libirc/msg.rs
@@ -0,0 +1,185 @@
+use std::fmt;
+use std::from_str::FromStr;
+use std::ascii::OwnedStrAsciiExt;
+
+pub mod cmd {
+ #[deriving(Clone, Show)]
+ pub enum Command {
+ Nick(String),
+ User(String, u8, String),
+ Quit(Option<String>),
+ Join(String),
+ Part(String, Option<String>),
+ PrivMsg(String, String),
+ Notice(String, String),
+ //Motd(Option<String>),
+ Ping(String),
+ Pong(String),
+ Error(String),
+ Away(Option<String>),
+ Numeric(u16, Option<String>),
+ UnknownCmd(String, Vec<String>)
+ }
+}
+
+pub struct PrefixHost {
+ hostname: String,
+ user: Option<String>,
+}
+
+pub enum Prefix {
+ PrefixServer(String),
+ PrefixUser(String, Option<PrefixHost>),
+}
+
+#[deriving(Clone)]
+pub struct Message {
+ pub prefix: Option<String>,
+ pub command: cmd::Command,
+}
+
+impl Message {
+ pub fn new(command: cmd::Command) -> Message {
+ Message { prefix: None, command: command }
+ }
+
+ pub fn with_prefix(prefix: String, command: cmd::Command) -> Message {
+ Message { prefix: Some(prefix), command: command }
+ }
+}
+
+impl<'a> fmt::Show for Message {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ if self.prefix.is_some() {
+ try!(write!(formatter, ":{} ", self.prefix.get_ref()));
+ }
+
+ match self.command {
+ cmd::Nick(ref nickname) => write!(formatter, "NICK {}", nickname),
+ cmd::User(ref username, mode, ref real_name) => write!(formatter, "USER {} {} * :{}", username, mode, real_name),
+ cmd::Quit(ref msg) => if msg.is_some() { write!(formatter, "QUIT :{}", *msg.get_ref()) } else { write!(formatter, "QUIT") },
+ cmd::Join(ref channel) => write!(formatter, "JOIN :{}", channel),
+ cmd::Part(ref channel, ref msg) => if msg.is_some() { write!(formatter, "PART {} :{}", channel, *msg.get_ref()) } else { write!(formatter, "PART {}", channel) },
+ cmd::PrivMsg(ref target, ref msg) => write!(formatter, "PRIVMSG {} :{}", target, msg),
+ cmd::Notice(ref target, ref msg) => write!(formatter, "NOTICE {} :{}", target, msg),
+ cmd::Ping(ref msg) => write!(formatter, "PING :{}", msg),
+ cmd::Pong(ref msg) => write!(formatter, "PONG :{}", msg),
+ cmd::Error(ref msg) => write!(formatter, "ERROR :{}", msg),
+ cmd::Away(ref msg) => if msg.is_some() { write!(formatter, "AWAY :{}", msg.get_ref()) } else { write!(formatter, "AWAY") },
+ cmd::Numeric(i, ref msg) => if msg.is_some() { write!(formatter, "{:03u} :{}", i, msg.get_ref()) } else { write!(formatter, "{:03u}", i) },
+ cmd::UnknownCmd(ref cmd, ref args) => {
+ try!(write!(formatter, "{}", cmd));
+ let mut iter = args.iter().peekable();
+ loop {
+ match iter.next() {
+ Some(arg) => {
+ try!(
+ if iter.peek().is_some() {
+ write!(formatter, " {}", arg)
+ }
+ else {
+ write!(formatter, " :{}", arg)
+ }
+ )
+ }
+ None => break
+ }
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
+impl FromStr for Message {
+ fn from_str(s: &str) -> Option<Message> {
+ let mut prefix = None;
+ let mut cmd = None;
+ let mut args = Vec::new();
+ let mut current_str: Option<String> = None;
+ let mut is_prefix = false;
+ let mut is_final = false;
+
+ for c in s.chars() {
+ match c {
+ c if is_final => {
+ current_str.get_mut_ref().push_char(c);
+ }
+ ' ' => {
+ if is_prefix {
+ prefix = current_str.take();
+ }
+ else if cmd.is_none() {
+ cmd = current_str.take();
+ }
+ else {
+ args.push(current_str.take_unwrap());
+ }
+ is_prefix = false;
+ }
+ ':' if current_str.is_none() => {
+ current_str = Some(String::new());
+ if cmd.is_none() {
+ is_prefix = true;
+ }
+ else {
+ is_final = true;
+ }
+ }
+ c => {
+ if current_str.is_none() {
+ current_str = Some(String::new());
+ }
+ current_str.get_mut_ref().push_char(c)
+ }
+ }
+ }
+
+ args.push(current_str.take_unwrap());
+
+ let cmd = match cmd.map(|s| s.into_ascii_upper()).as_ref().map(|s| s.as_slice()) {
+ Some("NICK") => {
+ if args.len() == 1 { Some(cmd::Nick(args.pop().unwrap())) }
+ else { None }
+ }
+ Some("USER") => {
+ if args.len() == 4 {
+ let mut iter = args.move_iter();
+ let uname = iter.next().unwrap();
+ let opt_mode: Option<u8> = from_str(iter.next().unwrap().as_slice());
+ iter.next();
+ let fullname = iter.next().unwrap();
+ if opt_mode.is_some() {
+ Some(cmd::User(uname, opt_mode.unwrap(), fullname))
+ }
+ else {
+ None
+ }
+ }
+ else { None }
+ }
+ Some("NOTICE") => {
+ if args.len() == 2 {
+ let mut iter = args.move_iter();
+ Some(cmd::Notice(iter.next().unwrap(), iter.next().unwrap()))
+ }
+ else { None }
+ }
+ Some("PRIVMSG") => {
+ if args.len() == 2 {
+ let mut iter = args.move_iter();
+ Some(cmd::PrivMsg(iter.next().unwrap(), iter.next().unwrap()))
+ }
+ else { None }
+ }
+ Some(other) => {
+ Some(cmd::UnknownCmd(other.to_string(), args))
+ }
+ None => {
+ None
+ }
+ };
+
+ cmd.map(|c| Message { prefix: prefix.take(), command: c })
+ }
+}