X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Frbot%2Frfc2812.rb;h=ac44888330d6b10726fa11be5a2eba04ff464d15;hb=2f2644f03203b36fd6aa105e62f4cd15070e1cbe;hp=f4487bdb8eaf5576454c8f4af2828c7e79013546;hpb=bded1f0382aeb691aa33ca312eea7f068dbcde99;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/lib/rbot/rfc2812.rb b/lib/rbot/rfc2812.rb index f4487bdb..ac448883 100644 --- a/lib/rbot/rfc2812.rb +++ b/lib/rbot/rfc2812.rb @@ -144,6 +144,12 @@ module Irc # " " RPL_CHANNELMODEIS=324 + # " " + RPL_CREATIONTIME=329 + + # " " + RPL_CHANNEL_URL=328 + # " :No topic is set" RPL_NOTOPIC=331 @@ -1122,19 +1128,14 @@ module Irc data[:message] = argv[2] handle(:badnick, data) when RPL_TOPIC - data[:channel] = @server.get_channel(argv[1]) + data[:channel] = @server.channel(argv[1]) data[:topic] = argv[2] - - if data[:channel] - data[:channel].topic.text = data[:topic] - else - warning "Received topic #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on" - end + data[:channel].topic.text = data[:topic] handle(:topic, data) when RPL_TOPIC_INFO data[:nick] = @server.user(argv[0]) - data[:channel] = @server.get_channel(argv[1]) + data[:channel] = @server.channel(argv[1]) # This must not be an IRC::User because it might not be an actual User, # and we risk overwriting valid User data @@ -1142,12 +1143,8 @@ module Irc data[:time] = Time.at(argv[3].to_i) - if data[:channel] - data[:channel].topic.set_by = data[:source] - data[:channel].topic.set_on = data[:time] - else - warning "Received topic #{data[:topic].inspect} for channel #{data[:channel].inspect} I was not on" - end + data[:channel].topic.set_by = data[:source] + data[:channel].topic.set_on = data[:time] handle(:topicinfo, data) when RPL_NAMREPLY @@ -1285,7 +1282,21 @@ module Irc handle(:who, data) when RPL_ENDOFWHO handle(:eowho, data) + when RPL_CHANNELMODEIS + parse_mode(serverstring, argv[1..-1], data) + handle(:mode, data) + when RPL_CREATIONTIME + data[:channel] = argv[1] + data[:time] = Time.at(argv[2].to_i) + @server.get_channel(data[:channel]).creation_time=data[:time] + handle(:creationtime, data) + when RPL_CHANNEL_URL + data[:channel] = argv[1] + data[:url] = argv[2] + @server.get_channel(data[:channel]).url=data[:url].dup + handle(:channel_url, data) else + warning "Unknown message #{serverstring.inspect}" handle(:unknown, data) end return # We've processed the numeric reply @@ -1401,108 +1412,7 @@ module Irc handle(:nick, data) when :MODE - # MODE ([+-] ()*)* - # When a MODE message is received by a server, - # Type C will have parameters too, so we must - # be able to consume parameters for all - # but Type D modes - - data[:target] = @server.user_or_channel(argv[0]) - data[:modestring] = argv[1..-1].join(" ") - # data[:modes] is an array where each element - # is an array with two elements, the first of which - # is either :set or :reset, and the second symbol - # is the mode letter. An optional third element - # is present e.g. for channel modes that need - # a parameter - data[:modes] = [] - case data[:target] - when User - # User modes aren't currently handled internally, - # but we still parse them and delegate to the client - warning "Unhandled user mode message '#{serverstring}'" - argv[1..-1].each { |arg| - setting = arg[0].chr - if "+-".include?(setting) - setting = setting == "+" ? :set : :reset - arg[1..-1].each_byte { |b| - m = b.chr.intern - data[:modes] << [setting, m] - } - else - # Although typically User modes don't take an argument, - # this is not true for all modes on all servers. Since - # we have no knowledge of which modes take parameters - # and which don't we just assign it to the last - # mode. This is not going to do strange things often, - # as usually User modes are only set one at a time - warning "Unhandled user mode parameter #{arg} found" - data[:modes].last << arg - end - } - else - # array of indices in data[:modes] where parameters - # are needed - who_wants_params = [] - - modes = argv[1..-1].dup - debug modes - getting_args = false - while arg = modes.shift - debug arg - if getting_args - # getting args for previously set modes - idx = who_wants_params.shift - if idx.nil? - warning "Oops, problems parsing #{serverstring.inspect}" - break - end - data[:modes][idx] << arg - getting_args = false if who_wants_params.empty? - else - debug @server.supports[:chanmodes] - setting = :set - arg.each_byte do |c| - m = c.chr.intern - case m - when :+ - setting = :set - when :- - setting = :reset - else - data[:modes] << [setting, m] - case m - when *@server.supports[:chanmodes][:typea] - who_wants_params << data[:modes].length - 1 - when *@server.supports[:chanmodes][:typeb] - who_wants_params << data[:modes].length - 1 - when *@server.supports[:chanmodes][:typec] - if setting == :set - who_wants_params << data[:modes].length - 1 - end - when *@server.supports[:chanmodes][:typed] - # Nothing to do - when *@server.supports[:prefix][:modes] - who_wants_params << data[:modes].length - 1 - else - warning "Unknown mode #{m} in #{serverstring.inspect}" - end - end - end - getting_args = true unless who_wants_params.empty? - end - end - - data[:modes].each { |mode| - set, key, val = mode - if val - data[:target].mode[key].send(set, val) - else - data[:target].mode[key].send(set) - end - } - end - + parse_mode(serverstring, argv, data) handle(:mode, data) else warning "Unknown message #{serverstring.inspect}" @@ -1520,5 +1430,110 @@ module Irc @handlers[key].call(data) end end + + # RPL_CHANNELMODEIS + # MODE ([+-] ()*)* + # When a MODE message is received by a server, + # Type C will have parameters too, so we must + # be able to consume parameters for all + # but Type D modes + def parse_mode(serverstring, argv, data) + data[:target] = @server.user_or_channel(argv[0]) + data[:modestring] = argv[1..-1].join(" ") + # data[:modes] is an array where each element + # is an array with two elements, the first of which + # is either :set or :reset, and the second symbol + # is the mode letter. An optional third element + # is present e.g. for channel modes that need + # a parameter + data[:modes] = [] + case data[:target] + when User + # User modes aren't currently handled internally, + # but we still parse them and delegate to the client + warning "Unhandled user mode message '#{serverstring}'" + argv[1..-1].each { |arg| + setting = arg[0].chr + if "+-".include?(setting) + setting = setting == "+" ? :set : :reset + arg[1..-1].each_byte { |b| + m = b.chr.intern + data[:modes] << [setting, m] + } + else + # Although typically User modes don't take an argument, + # this is not true for all modes on all servers. Since + # we have no knowledge of which modes take parameters + # and which don't we just assign it to the last + # mode. This is not going to do strange things often, + # as usually User modes are only set one at a time + warning "Unhandled user mode parameter #{arg} found" + data[:modes].last << arg + end + } + else + # array of indices in data[:modes] where parameters + # are needed + who_wants_params = [] + + modes = argv[1..-1].dup + debug modes + getting_args = false + while arg = modes.shift + debug arg + if getting_args + # getting args for previously set modes + idx = who_wants_params.shift + if idx.nil? + warning "Oops, problems parsing #{serverstring.inspect}" + break + end + data[:modes][idx] << arg + getting_args = false if who_wants_params.empty? + else + debug @server.supports[:chanmodes] + setting = :set + arg.each_byte do |c| + m = c.chr.intern + case m + when :+ + setting = :set + when :- + setting = :reset + else + data[:modes] << [setting, m] + case m + when *@server.supports[:chanmodes][:typea] + who_wants_params << data[:modes].length - 1 + when *@server.supports[:chanmodes][:typeb] + who_wants_params << data[:modes].length - 1 + when *@server.supports[:chanmodes][:typec] + if setting == :set + who_wants_params << data[:modes].length - 1 + end + when *@server.supports[:chanmodes][:typed] + # Nothing to do + when *@server.supports[:prefix][:modes] + who_wants_params << data[:modes].length - 1 + else + warning "Ignoring unknown mode #{m} in #{serverstring.inspect}" + data[:modes].pop + end + end + end + getting_args = true unless who_wants_params.empty? + end + end + + data[:modes].each { |mode| + set, key, val = mode + if val + data[:target].mode[key].send(set, val) + else + data[:target].mode[key].send(set) + end + } + end + end end end