+class ::String
+ # Calculate the penalty which will be assigned to this message
+ # by the IRCd
+ def irc_send_penalty
+ # According to eggrdop, the initial penalty is
+ penalty = 1 + self.length/100
+ # on everything but UnderNET where it's
+ # penalty = 2 + self.length/120
+
+ cmd, pars = self.split($;,2)
+ debug "cmd: #{cmd}, pars: #{pars.inspect}"
+ case cmd.to_sym
+ when :KICK
+ chan, nick, msg = pars.split
+ chan = chan.split(',')
+ nick = nick.split(',')
+ penalty += nick.length
+ penalty *= chan.length
+ when :MODE
+ chan, modes, argument = pars.split
+ extra = 0
+ if modes
+ extra = 1
+ if argument
+ extra += modes.split(/\+|-/).length
+ else
+ extra += 3 * modes.split(/\+|-/).length
+ end
+ end
+ if argument
+ extra += 2 * argument.split.length
+ end
+ penalty += extra * chan.split.length
+ when :TOPIC
+ penalty += 1
+ penalty += 2 unless pars.split.length < 2
+ when :PRIVMSG, :NOTICE
+ dests = pars.split($;,2).first
+ penalty += dests.split(',').length
+ when :WHO
+ # I'm too lazy to implement this one correctly
+ penalty += 5
+ when :AWAY, :JOIN, :VERSION, :TIME, :TRACE, :WHOIS, :DNS
+ penalty += 2
+ when :INVITE, :NICK
+ penalty += 3
+ when :ISON
+ penalty += 1
+ else # Unknown messages
+ penalty += 1
+ end
+ if penalty > 99
+ debug "Wow, more than 99 secs of penalty!"
+ penalty = 99
+ end
+ if penalty < 2
+ debug "Wow, less than 2 secs of penalty!"
+ penalty = 2
+ end
+ debug "penalty: #{penalty}"
+ return penalty
+ end
+end
+
module Irc
# RFC 2812 Internet Relay Chat: Client Protocol
#
# create a new IrcClient instance
def initialize
- @server = Server.new # The Server
- @client = User.new # The User representing the client on this Server
+ @server = Server.new # The Server
+ @client = @server.user("") # The User representing the client on this Server
@handlers = Hash.new
data[:nick] = $2
data[:address] = $3
@client = @server.user(data[:netmask])
+ set = true
when /Welcome to the Internet Relay Network\s(\S+)/
data[:nick] = $1
when /Welcome.*\s+(\S+)$/
when /^(\S+)$/
data[:nick] = $1
end
- @user ||= @server.user(data[:nick])
+ @client = @server.user(data[:nick]) unless set
handle(:welcome, data)
when RPL_YOURHOST
# "Your host is <servername>, running version <ver>"
chan = @server.get_channel(data[:channel])
unless chan
- warning "Received topic #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on"
+ warning "Received names #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on"
return
end
users = []
argv[3].scan(/\S+/).each { |u|
+ # FIXME beware of servers that allow multiple prefixes
if(u =~ /^(#{@server.supports[:prefix][:prefixes].join})?(.*)$/)
umode = $1
user = $2
users.each { |ar|
u = @server.user(ar[0])
- chan.users << u
+ chan.users << u unless chan.users.include?(u)
if ar[1]
m = @server.supports[:prefix][:prefixes].index(ar[1].to_sym)
m = @server.supports[:prefix][:modes][m]
# parse it yourself, or you can bind to 'MSG', 'PUBLIC',
# etc and get it all nicely split up for you.
- data[:target] = @server.user_or_channel(argv[0])
+ begin
+ data[:target] = @server.user_or_channel(argv[0])
+ rescue
+ # The previous may fail e.g. when the target is a server or something
+ # like that (e.g. $<mask>). In any of these cases, we just use the
+ # String as a target
+ # FIXME we probably want to explicitly check for the #<mask> $<mask>
+ data[:target] = argv[0]
+ end
data[:message] = argv[1]
handle(:privmsg, data)
# Now we split it
- if(data[:target].class <= Channel)
+ if data[:target].kind_of?(Channel)
handle(:public, data)
else
handle(:msg, data)
end
when 'NOTICE'
- data[:target] = @server.user_or_channel(argv[0])
+ begin
+ data[:target] = @server.user_or_channel(argv[0])
+ rescue
+ # The previous may fail e.g. when the target is a server or something
+ # like that (e.g. $<mask>). In any of these cases, we just use the
+ # String as a target
+ # FIXME we probably want to explicitly check for the #<mask> $<mask>
+ data[:target] = argv[0]
+ end
data[:message] = argv[1]
case data[:source]
when User
handle(:notice, data)
else
- # "server notice" (not from user, noone to reply to
+ # "server notice" (not from user, noone to reply to)
handle(:snotice, data)
end
when 'KICK'
data[:message] = argv[0]
data[:was_on] = @server.channels.inject(ChannelList.new) { |list, ch|
list << ch if ch.users.include?(data[:source])
+ list
}
@server.delete_user(data[:source])
handle(:join, data)
when 'TOPIC'
data[:channel] = @server.channel(argv[0])
- data[:topic] = ChannelTopic.new(argv[1], data[:source], Time.new)
+ data[:topic] = Channel::Topic.new(argv[1], data[:source], Time.new)
data[:channel].topic.replace(data[:topic])
handle(:changetopic, data)
when 'NICK'
data[:is_on] = @server.channels.inject(ChannelList.new) { |list, ch|
list << ch if ch.users.include?(data[:source])
+ list
}
data[:newnick] = argv[0]
data[:oldnick] = data[:source].nick.dup
- data[:source].nick = data[:nick]
+ data[:source].nick = data[:newnick]
+
debug "#{data[:oldnick]} (now #{data[:newnick]}) was on #{data[:is_on].join(', ')}"
handle(:nick, data)