lib/net/irc.rb in net-irc-0.0.1 vs lib/net/irc.rb in net-irc-0.0.2

- old
+ new

@@ -2,15 +2,16 @@ require "ostruct" require "socket" require "thread" require "logger" +require "monitor" module Net; end module Net::IRC - VERSION = "0.0.1" + VERSION = "0.0.2" class IRCException < StandardError; end module PATTERN # :nodoc: # letter = %x41-5A / %x61-7A ; A-Z / a-z # digit = %x30-39 ; 0-9 @@ -307,11 +308,11 @@ extract[2] end # Extract prefix string to [nick, user, host] Array. def extract - _, *ret = *self.match(/^([^\s!]+)!([^\s@]+)@(\S+)$/) + _, *ret = *self.match(/^([^\s!]+)(?:!([^\s@]+)@(\S+))?$/) ret end end # Encoding to CTCP message. Prefix and postfix \x01. @@ -447,10 +448,11 @@ # "#channel" => { # :modes => [], # :users => [], # } } + @channels.extend(MonitorMixin) end # Connect to server and start loop. def start @socket = TCPSocket.open(@host, @port) @@ -493,138 +495,152 @@ end # Default RPL_WELCOME callback. # This sets @prefix from the message. def on_rpl_welcome(m) - @prefix = Prefix.new(m[1][/\S+!\S+@\S+/]) + @prefix = Prefix.new(m[1][/\S+$/]) end # Default PING callback. Response PONG. def on_ping(m) - post PONG, @nick + post PONG, @prefix ? @prefix.nick : "" end # For managing channel def on_rpl_namreply(m) type = m[1] channel = m[2] init_channel(channel) - m[3].split(/\s+/).each do |u| - _, mode, nick = *u.match(/^([@+]?)(.+)/) + @channels.synchronize do + m[3].split(/\s+/).each do |u| + _, mode, nick = *u.match(/^([@+]?)(.+)/) - @channels[channel][:users] << nick - @channels[channel][:users].uniq! + @channels[channel][:users] << nick + @channels[channel][:users].uniq! - case mode - when "@" # channel operator - @channels[channel][:modes] << ["o", nick] - when "+" # voiced (under moderating mode) - @channels[channel][:modes] << ["v", nick] + case mode + when "@" # channel operator + @channels[channel][:modes] << ["o", nick] + when "+" # voiced (under moderating mode) + @channels[channel][:modes] << ["v", nick] + end end - end - case type - when "@" # secret - @channels[channel][:modes] << ["s", nil] - when "*" # private - @channels[channel][:modes] << ["p", nil] - when "=" # public - end + case type + when "@" # secret + @channels[channel][:modes] << ["s", nil] + when "*" # private + @channels[channel][:modes] << ["p", nil] + when "=" # public + end - @channels[channel][:modes].uniq! + @channels[channel][:modes].uniq! + end end # For managing channel def on_part(m) nick = m.prefix.nick channel = m[0] init_channel(channel) - info = @channels[channel] - if info - info[:users].delete(nick) - info[:modes].delete_if {|u| - u[1] == nick - } + @channels.synchronize do + info = @channels[channel] + if info + info[:users].delete(nick) + info[:modes].delete_if {|u| + u[1] == nick + } + end end end # For managing channel def on_quit(m) nick = m.prefix.nick - @channels.each do |channel, info| - info[:users].delete(nick) - info[:modes].delete_if {|u| - u[1] == nick - } + @channels.synchronize do + @channels.each do |channel, info| + info[:users].delete(nick) + info[:modes].delete_if {|u| + u[1] == nick + } + end end end # For managing channel def on_kick(m) users = m[1].split(/,/) - m[0].split(/,/).each do |chan| - init_channel(chan) - info = @channels[chan] - if info - users.each do |nick| - info[:users].delete(nick) - info[:modes].delete_if {|u| - u[1] == nick - } + + @channels.synchronize do + m[0].split(/,/).each do |chan| + init_channel(chan) + info = @channels[chan] + if info + users.each do |nick| + info[:users].delete(nick) + info[:modes].delete_if {|u| + u[1] == nick + } + end end end end end # For managing channel def on_join(m) nick = m.prefix.nick channel = m[0] - init_channel(channel) - @channels[channel][:users] << nick - @channels[channel][:users].uniq! + @channels.synchronize do + init_channel(channel) + + @channels[channel][:users] << nick + @channels[channel][:users].uniq! + end end # For managing channel def on_mode(m) channel = m[0] - init_channel(channel) + @channels.synchronize do + init_channel(channel) - positive_mode = [] - negative_mode = [] + positive_mode = [] + negative_mode = [] - mode = positive_mode - arg_pos = 0 - m[1].each_byte do |c| - case c - when ?+ - mode = positive_mode - when ?- - mode = negative_mode - when ?o, ?v, ?k, ?l, ?b, ?e, ?I - mode << [c.chr, m[arg_pos + 2]] - arg_pos += 1 - else - mode << [c.chr, nil] + mode = positive_mode + arg_pos = 0 + m[1].each_byte do |c| + case c + when ?+ + mode = positive_mode + when ?- + mode = negative_mode + when ?o, ?v, ?k, ?l, ?b, ?e, ?I + mode << [c.chr, m[arg_pos + 2]] + arg_pos += 1 + else + mode << [c.chr, nil] + end end - end - mode = nil + mode = nil - negative_mode.each do |m| - @channels[channel][:modes].delete(m) - end + negative_mode.each do |m| + @channels[channel][:modes].delete(m) + end - positive_mode.each do |m| - @channels[channel][:modes] << m - end + positive_mode.each do |m| + @channels[channel][:modes] << m + end - @channels[channel][:modes].uniq! - [negative_mode, positive_mode] + @channels[channel][:modes].uniq! + [negative_mode, positive_mode] + end end # For managing channel def init_channel(channel) @channels[channel] ||= { @@ -717,11 +733,11 @@ attr_reader :prefix, :nick, :real, :host # Override subclass. def server_name - "Net::IRC::Server::Session" + "net-irc" end # Override subclass. def server_version "0.0.0" @@ -828,17 +844,19 @@ m = Message.new(prefix, command, params.map {|s| s.gsub(/[\r\n]/, " ") }) @log.debug "SEND: #{m.to_s.chomp}" @socket << m + rescue IOError + finish end # Call when client connected. # Send RPL_WELCOME sequence. If you want to customize, override this method at subclass. def inital_message - post nil, RPL_WELCOME, @nick, "Welcome to the Internet Relay Network #{@prefix}" - post nil, RPL_YOURHOST, @nick, "Your host is #{server_name}, running version #{server_version}" - post nil, RPL_CREATED, @nick, "This server was created #{Time.now}" - post nil, RPL_MYINFO, @nick, "#{server_name} #{server_version} #{avaiable_user_modes} #{avaiable_channel_modes}" + post server_name, RPL_WELCOME, @nick, "Welcome to the Internet Relay Network #{@prefix}" + post server_name, RPL_YOURHOST, @nick, "Your host is #{server_name}, running version #{server_version}" + post server_name, RPL_CREATED, @nick, "This server was created #{Time.now}" + post server_name, RPL_MYINFO, @nick, "#{server_name} #{server_version} #{avaiable_user_modes} #{avaiable_channel_modes}" end end end # Server