X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=data%2Frbot%2Fplugins%2Fgeoip.rb;h=615511728df524469571276977a16965ac1579f7;hb=7324b329dee26fd429033f85c1ec06e799b07994;hp=2fde9594b2428024d43d04a20ee45faac8f3211e;hpb=0a900b044b1920942ef99be800d7cd9bd8b60f5c;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/data/rbot/plugins/geoip.rb b/data/rbot/plugins/geoip.rb index 2fde9594..61551172 100755 --- a/data/rbot/plugins/geoip.rb +++ b/data/rbot/plugins/geoip.rb @@ -7,25 +7,93 @@ # Copyright:: (C) 2008 Raine Virta # License:: GPL v2 # -# Resolves the geographic locations of users and IP addresses +# Resolves the geographic locations of users (network-wide) and IP addresses -module GeoIP - GEO_IP = "http://www.geoiptool.com/en/?IP=" +module ::GeoIP + class InvalidHostError < RuntimeError; end + + GEO_IP_PRIMARY = "http://lakka.kapsi.fi:40086/lookup.yaml?host=" + GEO_IP_SECONDARY = "http://www.geoiptool.com/en/?IP=" + HOST_NAME_REGEX = /^[a-z0-9\-]+(?:\.[a-z0-9\-]+)*\.[a-z]{2,4}/i + + REGEX = { + :country => %r{Country:.*? (.*?)}m, + :region => %r{Region:.*?(.*?)}m, + :city => %r{City:.*?(.*?)}m, + :lat => %r{Latitude:.*?(.*?)}m, + :lon => %r{Longitude:.*?(.*?)}m + } + + def self.valid_host?(hostname) + hostname =~ HOST_NAME_REGEX || + hostname =~ Resolv::IPv4::Regex && (hostname.split(".").map { |e| e.to_i }.max <= 255) + end def self.resolve(hostname) - raw = Irc::Utils.bot.httputil.get(GEO_IP+hostname, :cache => true) + raise InvalidHostError unless valid_host?(hostname) - { - :country => raw.scan(%r{Country:.*? (.*?)}m).to_s, - :region => raw.scan(%r{Region:.*?(.*?)}m).to_s, - :city => raw.scan(%r{City:.*?(.*?)}m).to_s - } + yaml = Irc::Utils.bot.httputil.get(GEO_IP_PRIMARY+hostname) + + if yaml + return YAML::load(yaml) + else + res = {} + raw = Irc::Utils.bot.httputil.get_response(GEO_IP_SECONDARY+hostname) + raw = raw.decompress_body(raw.raw_body) + + REGEX.each { |key, regex| res[key] = Iconv.conv('utf-8', 'ISO-8859-1', raw.scan(regex).to_s) } + + return res + end + end +end + +class Stack + def initialize + @hash = {} + end + + def [](nick) + @hash[nick] = [] unless @hash[nick] + @hash[nick] + end + + def has_nick?(nick) + @hash.has_key?(nick) + end + + def clear(nick) + @hash.delete(nick) end end class GeoIpPlugin < Plugin def help(plugin, topic="") - "geoip [] => returns the geographic location of whichever has been given" + "geoip [] => returns the geographic location of whichever has been given -- note: user can be anyone on the network" + end + + def initialize + super + + @stack = Stack.new + end + + def whois(m) + nick = m.whois[:nick].downcase + + # need to see if the whois reply was invoked by this plugin + return unless @stack.has_nick?(nick) + + if m.target + msg = host2output(m.target.host, m.target.nick) + else + msg = "no such user on "+@bot.server.hostname.split(".")[-2] + end + @stack[nick].each do |source| + @bot.say source, msg + end + + @stack.clear(nick) end def geoip(m, params) @@ -33,7 +101,8 @@ class GeoIpPlugin < Plugin m.reply host2output(m.source.host, m.source.nick) else if m.replyto.class == Channel - # check if there is an user with nick same as input given + + # check if there is an user on the channel with nick same as input given user = m.replyto.users.find { |user| user.nick == params[:input] } if user @@ -42,9 +111,16 @@ class GeoIpPlugin < Plugin end end - if params[:input] =~ /[a-z0-9\-]+(?:\.[a-z0-9\-]+)*\.[a-z]{2,3}/i || - params[:input] =~ Resolv::IPv4::Regex - m.reply host2output(params[:input]) + # input is a host name or an IP + if GeoIP::valid_host?(params[:input]) + m.reply host2output(params[:input]) + + # assume input is a nick + elsif params[:input] !~ /\./ + nick = params[:input].downcase + + @stack[nick] << m.replyto + @bot.whois(nick) else m.reply "invalid input" end @@ -52,10 +128,14 @@ class GeoIpPlugin < Plugin end def host2output(host, nick=nil) - geo = GeoIP::resolve(host) + return "127.0.0.1 could not be res.. wait, what?" if host == "127.0.0.1" + + begin + geo = GeoIP::resolve(host) - if geo[:country].empty? - return _("#{host} could not be resolved") + raise if geo[:country].empty? + rescue GeoIP::InvalidHostError, RuntimeError + return _("#{nick ? "#{nick}'s location" : host} could not be resolved") end res = _("%{thing} is #{nick ? "from" : "located in"}") % { @@ -65,7 +145,7 @@ class GeoIpPlugin < Plugin res << " %{city}," % { :city => geo[:city] - } unless geo[:city].empty? + } unless geo[:city].to_s.empty? res << " %{country}" % { :country => geo[:country] @@ -73,11 +153,11 @@ class GeoIpPlugin < Plugin res << " (%{region})" % { :region => geo[:region] - } unless geo[:region].empty? || geo[:region] == geo[:city] + } unless geo[:region].to_s.empty? || geo[:region] == geo[:city] return res end end plugin = GeoIpPlugin.new -plugin.map "geoip [:input]", :action => 'geoip' +plugin.map "geoip [:input]", :action => 'geoip', :thread => true