4 # :title: Geo IP Plugin
6 # Author:: Raine Virta <rane@kapsi.fi>
7 # Copyright:: (C) 2008 Raine Virta
10 # Resolves the geographic locations of users (network-wide) and IP addresses
13 GEO_IP = "http://www.geoiptool.com/en/?IP="
15 :country => %r{Country:.*?<a href=".*?" target="_blank"> (.*?)</a>}m,
16 :region => %r{Region:.*?<a href=".*?" target="_blank">(.*?)</a>}m,
17 :city => %r{City:.*?<td align="left" class="arial_bold">(.*?)</td>}m
21 def self.resolve(hostname)
23 raw = Irc::Utils.bot.httputil.get_response(GEO_IP+hostname)
24 raw = raw.decompress_body(raw.raw_body)
26 REGEX.each { |key, regex| res[key] = Iconv.conv('utf-8', 'ISO-8859-1', raw.scan(regex).to_s) }
32 class GeoIpPlugin < Plugin
33 def help(plugin, topic="")
34 "geoip [<user|hostname|ip>] => returns the geographic location of whichever has been given -- note: user can be anyone on the network"
38 # need to see if the whois reply was invoked by this plugin
39 return unless m.whois[:nick] == @nick
42 @bot.say @source, host2output(m.target.host, m.target.nick)
44 @bot.say @source, "no such user on "+@bot.server.hostname.split(".")[-2]
52 m.reply host2output(m.source.host, m.source.nick)
54 if m.replyto.class == Channel
56 # check if there is an user on the channel with nick same as input given
57 user = m.replyto.users.find { |user| user.nick == params[:input] }
60 m.reply host2output(user.host, user.nick)
65 # input is a host name or an IP
66 if params[:input] =~ /[a-z0-9\-]+(?:\.[a-z0-9\-]+)*\.[a-z]{2,3}/i ||
67 params[:input] =~ Resolv::IPv4::Regex
68 m.reply host2output(params[:input])
70 # assume input is a nick
73 @nick = params[:input]
80 def host2output(host, nick=nil)
81 geo = GeoIP::resolve(host)
83 if geo[:country].empty?
84 return _("#{nick ? "#{nick}'s location" : host} could not be resolved")
87 res = _("%{thing} is #{nick ? "from" : "located in"}") % {
88 :thing => (nick ? nick : Resolv::getaddress(host)),
89 :country => geo[:country]
92 res << " %{city}," % {
94 } unless geo[:city].empty?
96 res << " %{country}" % {
97 :country => geo[:country]
100 res << " (%{region})" % {
101 :region => geo[:region]
102 } unless geo[:region].empty? || geo[:region] == geo[:city]
108 plugin = GeoIpPlugin.new
109 plugin.map "geoip [:input]", :action => 'geoip'