def process(serverstring)
data = Hash.new
data[:serverstring] = serverstring
unless serverstring.chomp =~ /^(:(\S+)\s)?(\S+)(\s(.*))?$/
raise "Unparseable Server Message!!!: #{serverstring.inspect}"
end
prefix, command, params = $2, $3, $5
if prefix != nil
if prefix =~ /^#{Regexp::Irc::BANG_AT}$/
data[:source] = @server.user(prefix)
else
if @server.hostname
if @server.hostname != prefix
debug "Origin #{prefix} for message\n\t#{serverstring.inspect}\nis neither a user hostmask nor the server hostname\nI'll pretend that it's from the server anyway"
data[:source] = @server
else
data[:source] = @server
end
else
@server.instance_variable_set(:@hostname, prefix)
data[:source] = @server
end
end
end
argv = []
params.scan(/(?!:)(\S+)|:(.*)/) { argv << ($1 || $2) } if params
if command =~ /^(\d+)$/
data[:target] = argv[0]
not_us = !([@user.nick, '*'].include?(data[:target]))
if not_us
warning "Server reply #{serverstring.inspect} directed at #{data[:target]} instead of client (#{@user.nick})"
end
num=command.to_i
case num
when RPL_WELCOME
data[:message] = argv[1]
if not_us
warning "Server thinks client (#{@user.inspect}) has a different nick"
@user.nick = data[:target]
end
if data[:message] =~ /([^@!\s]+)(?:!([^@!\s]+?))?@(\S+)/
nick = $1
user = $2
host = $3
warning "Welcome message nick mismatch (#{nick} vs #{data[:target]})" if nick != data[:target]
@user.user = user if user
@user.host = host if host
end
handle(:welcome, data)
when RPL_YOURHOST
data[:message] = argv[1]
handle(:yourhost, data)
when RPL_CREATED
data[:message] = argv[1]
handle(:created, data)
when RPL_MYINFO
@server.parse_my_info(params.split(' ', 2).last)
data[:servername] = @server.hostname
data[:version] = @server.version
data[:usermodes] = @server.usermodes
data[:chanmodes] = @server.chanmodes
handle(:myinfo, data)
when RPL_ISUPPORT
@server.parse_isupport(argv[1..-2].join(' '))
handle(:isupport, data)
when ERR_NICKNAMEINUSE
data[:nick] = argv[1]
data[:message] = argv[2]
handle(:nicktaken, data)
when ERR_ERRONEUSNICKNAME
data[:nick] = argv[1]
data[:message] = argv[2]
handle(:badnick, data)
when RPL_TOPIC
data[:channel] = @server.channel(argv[1])
data[:topic] = argv[2]
data[:channel].topic.text = data[:topic]
handle(:topic, data)
when RPL_TOPIC_INFO
data[:nick] = @server.user(argv[0])
data[:channel] = @server.channel(argv[1])
data[:source] = argv[2].to_irc_netmask(:server => @server)
data[:time] = Time.at(argv[3].to_i)
data[:channel].topic.set_by = data[:source]
data[:channel].topic.set_on = data[:time]
handle(:topicinfo, data)
when RPL_NAMREPLY
data[:channeltype] = argv[1]
data[:channel] = chan = @server.channel(argv[2])
users = []
argv[3].scan(/\S+/).each { |u|
if(u =~ /^([#{@server.supports[:prefix][:prefixes].join}])?(.*)$/)
umode = $1
user = $2
users << [user, umode]
end
}
users.each { |ar|
u = @server.user(ar[0])
chan.add_user(u, :silent => true)
debug "Adding user #{u}"
if ar[1]
ms = @server.mode_for_prefix(ar[1].to_sym)
debug "\twith mode #{ar[1]} (#{ms})"
chan.mode[ms].set(u)
end
}
@tmpusers += users
when RPL_ENDOFNAMES
data[:channel] = @server.channel(argv[1])
data[:users] = @tmpusers
handle(:names, data)
@tmpusers = Array.new
when RPL_LUSERCLIENT
data[:message] = argv[1]
handle(:luserclient, data)
when RPL_LUSEROP
data[:ops] = argv[1].to_i
handle(:luserop, data)
when RPL_LUSERUNKNOWN
data[:unknown] = argv[1].to_i
handle(:luserunknown, data)
when RPL_LUSERCHANNELS
data[:channels] = argv[1].to_i
handle(:luserchannels, data)
when RPL_LUSERME
data[:message] = argv[1]
handle(:luserme, data)
when ERR_NOMOTD
data[:message] = argv[1]
handle(:motd_missing, data)
when RPL_LOCALUSERS
data[:message] = argv[1]
handle(:localusers, data)
when RPL_GLOBALUSERS
data[:message] = argv[1]
handle(:globalusers, data)
when RPL_STATSCONN
data[:message] = argv[1]
handle(:statsconn, data)
when RPL_MOTDSTART
if argv[1] =~ /^-\s+(\S+)\s/
server = $1
else
warning "Server doesn't have an RFC compliant MOTD start."
end
@motd = ""
when RPL_MOTD
if(argv[1] =~ /^-\s+(.*)$/)
@motd << $1
@motd << "\n"
end
when RPL_ENDOFMOTD
data[:motd] = @motd
handle(:motd, data)
when RPL_DATASTR
data[:text] = argv[1]
handle(:datastr, data)
when RPL_AWAY
data[:nick] = user = @server.user(argv[1])
data[:message] = argv[-1]
user.away = data[:message]
handle(:away, data)
when RPL_WHOREPLY
data[:channel] = channel = @server.channel(argv[1])
data[:user] = argv[2]
data[:host] = argv[3]
data[:userserver] = argv[4]
data[:nick] = user = @server.user(argv[5])
if argv[6] =~ /^(H|G)(\*)?(.*)?$/
data[:away] = ($1 == 'G')
data[:ircop] = $2
data[:modes] = $3.scan(/./).map { |mode|
m = @server.supports[:prefix][:prefixes].index(mode.to_sym)
@server.supports[:prefix][:modes][m]
} rescue []
else
warning "Strange WHO reply: #{serverstring.inspect}"
end
data[:hopcount], data[:real_name] = argv[7].split(" ", 2)
user.user = data[:user]
user.host = data[:host]
user.away = data[:away]
user.real_name = data[:real_name]
channel.add_user(user, :silent=>true)
data[:modes].map { |mode|
channel.mode[mode].set(user)
}
handle(:who, data)
when RPL_ENDOFWHO
handle(:eowho, data)
when RPL_WHOISUSER
@whois ||= Hash.new
@whois[:nick] = argv[1]
@whois[:user] = argv[2]
@whois[:host] = argv[3]
@whois[:real_name] = argv[-1]
user = @server.user(@whois[:nick])
user.user = @whois[:user]
user.host = @whois[:host]
user.real_name = @whois[:real_name]
when RPL_WHOISSERVER
@whois ||= Hash.new
@whois[:nick] = argv[1]
@whois[:server] = argv[2]
@whois[:server_info] = argv[-1]
when RPL_WHOISOPERATOR
@whois ||= Hash.new
@whois[:nick] = argv[1]
@whois[:operator] = argv[-1]
when RPL_WHOISIDLE
@whois ||= Hash.new
@whois[:nick] = argv[1]
user = @server.user(@whois[:nick])
@whois[:idle] = argv[2].to_i
user.idle_since = Time.now - @whois[:idle]
if argv[-1] == 'seconds idle, signon time'
@whois[:signon] = Time.at(argv[3].to_i)
user.signon = @whois[:signon]
end
when RPL_ENDOFWHOIS
@whois ||= Hash.new
@whois[:nick] = argv[1]
data[:whois] = @whois.dup
@whois.clear
handle(:whois, data)
when RPL_WHOISCHANNELS
@whois ||= Hash.new
@whois[:nick] = argv[1]
@whois[:channels] = []
user = @server.user(@whois[:nick])
argv[-1].split.each do |prechan|
pfx = prechan.scan(/[#{@server.supports[:prefix][:prefixes].join}]/)
modes = pfx.map { |p| @server.mode_for_prefix p }
chan = prechan[pfx.length..prechan.length]
channel = @server.channel(chan)
channel.add_user(user, :silent => true)
modes.map { |mode| channel.mode[mode].set(user) }
@whois[:channels] << [chan, modes]
end
when RPL_CHANNELMODEIS
parse_mode(serverstring, argv[1..-1], data)
handle(:mode, data)
when RPL_CREATIONTIME
data[:channel] = @server.channel(argv[1])
data[:time] = Time.at(argv[2].to_i)
data[:channel].creation_time=data[:time]
handle(:creationtime, data)
when RPL_CHANNEL_URL
data[:channel] = @server.channel(argv[1])
data[:url] = argv[2]
data[:channel].url=data[:url].dup
handle(:channel_url, data)
when ERR_NOSUCHNICK
data[:nick] = argv[1]
if user = @server.get_user(data[:nick])
@server.delete_user(user)
end
handle(:nosuchnick, data)
when ERR_NOSUCHCHANNEL
data[:channel] = argv[1]
if channel = @server.get_channel(data[:channel])
@server.delete_channel(channel)
end
handle(:nosuchchannel, data)
else
warning "Unknown message #{serverstring.inspect}"
handle(:unknown, data)
end
return
end
case command.to_sym
when :PING
data[:pingid] = argv[0]
handle(:ping, data)
when :PONG
data[:pingid] = argv[0]
handle(:pong, data)
when :PRIVMSG
begin
data[:target] = @server.user_or_channel(argv[0])
rescue
data[:target] = argv[0]
end
data[:message] = argv[1]
handle(:privmsg, data)
if data[:target].kind_of?(Channel)
handle(:public, data)
else
handle(:msg, data)
end
when :NOTICE
begin
data[:target] = @server.user_or_channel(argv[0])
rescue
data[:target] = argv[0]
end
data[:message] = argv[1]
case data[:source]
when User
handle(:notice, data)
else
handle(:snotice, data)
end
when :KICK
data[:channel] = @server.channel(argv[0])
data[:target] = @server.user(argv[1])
data[:message] = argv[2]
@server.delete_user_from_channel(data[:target], data[:channel])
if data[:target] == @user
@server.delete_channel(data[:channel])
end
handle(:kick, data)
when :PART
data[:channel] = @server.channel(argv[0])
data[:message] = argv[1]
@server.delete_user_from_channel(data[:source], data[:channel])
if data[:source] == @user
@server.delete_channel(data[:channel])
end
handle(:part, data)
when :QUIT
data[:message] = argv[0]
data[:was_on] = @server.channels.inject(ChannelList.new) { |list, ch|
list << ch if ch.has_user?(data[:source])
list
}
@server.delete_user(data[:source])
handle(:quit, data)
when :JOIN
data[:channel] = @server.channel(argv[0])
data[:channel].add_user(data[:source])
handle(:join, data)
when :TOPIC
data[:channel] = @server.channel(argv[0])
data[:topic] = Channel::Topic.new(argv[1], data[:source], Time.new)
data[:channel].topic.replace(data[:topic])
handle(:changetopic, data)
when :INVITE
data[:target] = @server.user(argv[0])
data[:channel] = @server.channel(argv[1])
handle(:invite, data)
when :NICK
data[:is_on] = @server.channels.inject(ChannelList.new) { |list, ch|
list << ch if ch.has_user?(data[:source])
list
}
data[:newnick] = argv[0]
data[:oldnick] = data[:source].nick.dup
data[:source].nick = data[:newnick]
debug "#{data[:oldnick]} (now #{data[:newnick]}) was on #{data[:is_on].join(', ')}"
handle(:nick, data)
when :MODE
parse_mode(serverstring, argv, data)
handle(:mode, data)
else
warning "Unknown message #{serverstring.inspect}"
handle(:unknown, data)
end
end