From 6379bd97e46e87038a0d5144f3205b08a7da7ff1 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Mon, 8 Apr 2013 19:38:15 -0400 Subject: [PATCH] Improvements to !geolocate (earwig/earwigbot#41). --- commands/geolocate.py | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/commands/geolocate.py b/commands/geolocate.py index eab4714..5c5d733 100644 --- a/commands/geolocate.py +++ b/commands/geolocate.py @@ -20,8 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import json -import urllib2 +from json import loads +from socket import (AF_INET, AF_INET6, error as socket_error, gethostbyname, + inet_pton) +from urllib2 import urlopen from earwigbot.commands import Command @@ -40,10 +42,6 @@ class Geolocate(Command): self.logger.warn(log.format(self.name)) def process(self, data): - if not data.args: - self.reply(data, "Please specify an IP to lookup.") - return - if not self.key: msg = 'I need an API key for http://ipinfodb.com/ stored as \x0303config.commands["{0}"]["apiKey"]\x0F.' log = 'Need an API key for http://ipinfodb.com/ stored as config.commands["{0}"]["apiKey"]' @@ -51,10 +49,24 @@ class Geolocate(Command): self.logger.error(log.format(self.name)) return + if data.args: + address = data.args[0] + else: + try: + address = gethostbyname(data.host) + except socket_error: + msg = "your hostname, \x0302{0}\x0F, is not an IP address!" + self.reply(data, msg.format(data.host)) + return address = data.args[0] + if not self.is_ip(address): + msg = "\x0302{0}\x0F is not an IP address!" + self.reply(data, msg.format(address)) + return + url = "http://api.ipinfodb.com/v3/ip-city/?key={0}&ip={1}&format=json" - query = urllib2.urlopen(url.format(self.key, address)).read() - res = json.loads(query) + query = urlopen(url.format(self.key, address)).read() + res = loads(query) country = res["countryName"].title() region = res["regionName"].title() @@ -72,3 +84,17 @@ class Geolocate(Command): msg = "{0}, {1}, {2} ({3}, {4}), UTC {5}" geo = msg.format(country, region, city, latitude, longitude, utcoffset) self.reply(data, geo) + + def is_ip(self, address): + """Return ``True`` if the input is an IP address, else ``False``. + + This tests for IPv4 and IPv6 using :py:func:`socket.inet_pton`. + """ + try: + inet_pton(AF_INET, address) + except socket_error: + try: + inet_pton(AF_INET6, address) + except socket_error: + return False + return True