#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""PyHostIP - PyGTK interface to hostip.info online database"""
import pygtk
pygtk.require("2.0")
import gtk, gobject, pango
from re import findall
from socket import gethostbyname, gethostbyaddr
from string import maketrans
from threading import Thread
from urllib import FancyURLopener
import webbrowser
class Background(Thread):
def __init__(self, parent, list_poll, progress, dialog):
Thread.__init__(self)
self.parent = parent
self.list_poll = list_poll
self.progress = progress
self.dialog = dialog
self.quit = False
def run(self):
total = float(len(self.list_poll))
step = 0.0
iter = self.parent.tbuffer_input.get_start_iter()
for item in self.list_poll:
if self.quit: return
fraction = step / total
gtk.gdk.threads_enter()
self.progress.set_fraction(fraction)
self.progress.set_text(str(int(100 * fraction)) + "%")
gtk.gdk.threads_leave()
start, end = iter.forward_search(item, gtk.TEXT_SEARCH_TEXT_ONLY)
self.parent.tmarks.append(self.parent.tbuffer_input.create_mark(None, start))
try:
gethostbyname(item)
try: dns = "\n\nDNS name: " + gethostbyaddr(item)[0]
except: dns = "\n\nDNS name: unknown"
info = "IP Address: " + item + "\n\n" + self.parent.opener.open("http://api.hostip.info/rough.php?ip=" + item + "&position=true").read().translate(self.parent.chars_all, self.parent.chars_drop) + dns
if not info.find("Guessed: true") == -1:
color = "yellow"
order = 1
elif not info.find("(Private Address)") == -1:
color = "red"
order = 3
elif not info.find("Country Code: XX") == -1:
color = "orange"
order = 2
else:
color = "green"
order = 0
self.parent.tbuffer_input.apply_tag_by_name(color, start, end)
self.parent.lstore_output.append([" ", item, info, order, int(step)])
except:
self.parent.tbuffer_input.apply_tag_by_name("grey", start, end)
self.parent.lstore_output.append([" ", item, "", 4, int(step)])
gtk.gdk.threads_enter()
self.parent.txview_input.scroll_to_iter(start, False)
self.parent.txview_input.scroll_to_iter(end, False)
gtk.gdk.threads_leave()
step += 1.0
self.dialog.destroy()
def stop(self):
self.quit = True
class PyHostIp(gtk.Window):
def __switch(self, widget, path=None, column=None):
model, iter = self.tview_output.get_selection().get_selected()
if iter:
item = model[iter]
self.txview_input.scroll_to_mark(self.tmarks[item[4]], False)
self.tbuffer_output.set_text(item[2])
if item[3] == 3 or item[3] == 4: self.button_fix.set_sensitive(False)
else: self.button_fix.set_sensitive(True)
def __fix(self, widget):
model, iter = self.tview_output.get_selection().get_selected()
if iter:
item = model[iter]
webbrowser.open("http://www.hostip.info/correct.php?spip=" + item[1])
def __click(self, widget, event):
if self.firstrun:
self.tbuffer_input.set_text("")
self.firstrun = False
def __init__(self):
self.opener = FancyURLopener({})
self.firstrun = True
self.chars_all = maketrans("", "")
self.chars_drop = self.chars_all[0] * 127 + self.chars_all[127:]
gtk.gdk.threads_init()
gtk.Window.__init__(self)
self.connect("destroy", gtk.main_quit)
self.set_title("PyHostIP")
self.set_default_size(500, 500)
toolbar = gtk.Toolbar()
toolbar.set_style(gtk.TOOLBAR_BOTH)
toolitem = gtk.Action(None, "Execute", None, "gtk-apply").create_tool_item()
toolbar.add(toolitem)
toolitem.connect("clicked", self.execute)
toolitem = gtk.Action(None, "DNS Name...", None, "gtk-jump-to").create_tool_item()
toolbar.add(toolitem)
toolitem.connect("clicked", self.dns)
toolitem = gtk.Action(None, "Clear Input", None, "gtk-clear").create_tool_item()
toolbar.add(toolitem)
toolitem.connect("clicked", lambda widget: self.tbuffer_input.set_text(""))
toolbar.add(gtk.SeparatorToolItem())
toolitem = gtk.Action(None, "About...", None, "gtk-about").create_tool_item()
toolbar.add(toolitem)
toolitem.connect("clicked", self.about)
toolitem = gtk.Action(None, "Quit", None, "gtk-quit").create_tool_item()
toolbar.add(toolitem)
toolitem.connect("clicked", gtk.main_quit)
tagtable = gtk.TextTagTable()
tag = gtk.TextTag("green")
tagtable.add(tag)
tag.set_property("background", "green")
tag = gtk.TextTag("yellow")
tagtable.add(tag)
tag.set_property("background", "yellow")
tag = gtk.TextTag("orange")
tagtable.add(tag)
tag.set_property("background", "orange")
tag = gtk.TextTag("red")
tagtable.add(tag)
tag.set_property("background", "red")
tag = gtk.TextTag("grey")
tagtable.add(tag)
tag.set_property("background", "grey")
self.tbuffer_input = gtk.TextBuffer(tagtable)
self.txview_input = gtk.TextView(self.tbuffer_input)
self.txview_input.set_wrap_mode(gtk.WRAP_WORD_CHAR)
self.tbuffer_input.insert_at_cursor("Welcome to PyHostIP!\n\nClick anywhere here and type or paste text containing IPv4 addresses.\n\n\
Program will obtain their geographic location using hostip.info online database.\n\nFollowing colors describe the result \"hit score\":\n")
self.tbuffer_input.insert_with_tags_by_name(self.tbuffer_input.get_end_iter(), "Grey", "grey")
self.tbuffer_input.insert_at_cursor(":\tInvalid IPv4 address\n")
self.tbuffer_input.insert_with_tags_by_name(self.tbuffer_input.get_end_iter(), "Red", "red")
self.tbuffer_input.insert_at_cursor(":\t\tPrivate / localhost address\n")
self.tbuffer_input.insert_with_tags_by_name(self.tbuffer_input.get_end_iter(), "Orange", "orange")
self.tbuffer_input.insert_at_cursor(":\tUnknown address (not in database)\n")
self.tbuffer_input.insert_with_tags_by_name(self.tbuffer_input.get_end_iter(), "Yellow", "yellow")
self.tbuffer_input.insert_at_cursor(":\tKnown address, location guessed\n")
self.tbuffer_input.insert_with_tags_by_name(self.tbuffer_input.get_end_iter(), "Green", "green")
self.tbuffer_input.insert_at_cursor(":\tKnown address, known location\n\n")
self.tbuffer_input.insert_at_cursor("You may want to fix the Orange and Yellow results by clicking the button below the information area. \
It will lead you to hostip.info subpage, holding form to set correct country and city values.\n\nhostip.info is a free service.\nAny donations to it's authors will be appreciated.")
self.txview_input.connect("button-press-event", self.__click)
self.tmarks = []
self.lstore_output = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_INT)
self.tview_output = gtk.TreeView(self.lstore_output)
self.tview_output.set_enable_search(False)
self.tview_output.set_rules_hint(True)
column = gtk.TreeViewColumn("Status", gtk.CellRendererText(), markup=0)
self.tview_output.append_column(column)
column.set_sort_column_id(4)
column = gtk.TreeViewColumn("Address", gtk.CellRendererText(), text=1)
self.tview_output.append_column(column)
column.set_sort_column_id(1)
self.tview_output.get_selection().connect("changed", self.__switch)
self.tview_output.connect("row-activated", self.__switch)
self.tbuffer_output = gtk.TextBuffer()
self.txview_output = gtk.TextView(self.tbuffer_output)
self.txview_output.set_editable(False)
self.txview_output.set_wrap_mode(gtk.WRAP_CHAR)
vbox = gtk.VBox(False, 5)
self.add(vbox)
vbox.pack_start(toolbar, False, False)
hbox = gtk.HBox(False, 5)
vbox.pack_start(hbox)
frame = gtk.Frame("Input text")
hbox.pack_start(frame)
sw = gtk.ScrolledWindow()
frame.add(sw)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
sw.add(self.txview_input)
vpaned = gtk.VPaned()
hbox.pack_start(vpaned, False, False)
frame = gtk.Frame("Adresses")
vpaned.pack1(frame, True, False)
sw = gtk.ScrolledWindow()
frame.add(sw)
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
sw.add(self.tview_output)
vbox = gtk.VBox(False, 5)
vpaned.pack2(vbox, True, False)
frame = gtk.Frame("Information")
vbox.pack_start(frame)
frame.add(self.txview_output)
self.button_fix = gtk.Button("Change location...")
vbox.pack_start(self.button_fix, False, False)
self.button_fix.set_sensitive(False)
self.button_fix.connect("clicked", self.__fix)
self.show_all()
def execute(self, widget):
list_find = findall("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", self.tbuffer_input.get_text(self.tbuffer_input.get_start_iter(), self.tbuffer_input.get_end_iter()))
if len(list_find):
del self.tmarks[:]
self.lstore_output.clear()
self.tbuffer_output.set_text("")
list_poll = []
for item in list_find:
if item not in list_poll: list_poll.append(item)
self.tbuffer_input.remove_all_tags(self.tbuffer_input.get_start_iter(), self.tbuffer_input.get_end_iter())
dialog = gtk.Dialog("Processing", self, 0, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
dialog.set_resizable(False)
dialog.vbox.set_spacing(5)
dialog.vbox.pack_start(gtk.Label("Processing " + str(len(list_poll)) + " addresses"))
progress = gtk.ProgressBar()
dialog.vbox.pack_start(progress)
background = Background(self, list_poll, progress, dialog)
background.start()
dialog.show_all()
if dialog.run() == gtk.RESPONSE_CANCEL: background.stop()
dialog.destroy()
self.txview_input.scroll_to_iter(self.tbuffer_input.get_start_iter(), False)
def dns(self, widget):
dialog = gtk.Dialog("Add DNS Name", self, 0, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
dialog.set_resizable(False)
dialog.vbox.set_spacing(5)
dialog.vbox.pack_start(gtk.Label("Enter DNS name to be resolved into IP address"))
entry = gtk.Entry()
dialog.vbox.pack_start(entry)
entry.connect("activate", lambda widget: dialog.response(gtk.RESPONSE_OK))
dialog.show_all()
if dialog.run() == gtk.RESPONSE_OK and len(entry.get_text()):
if self.firstrun:
self.tbuffer_input.set_text("")
self.firstrun = False
try: self.tbuffer_input.insert_at_cursor(" " + gethostbyname(entry.get_text()))
except: pass
dialog.destroy()
def about(self, widget):
dialog = gtk.AboutDialog()
dialog.set_name("PyHostIP")
dialog.set_version("2.1")
button = gtk.LinkButton("http://www.hostip.info")
dialog.vbox.pack_start(button, False, False)
button.connect("clicked", lambda widget: webbrowser.open("http://www.hostip.info"))
dialog.set_license("Public domain")
dialog.show_all()
dialog.run()
dialog.destroy()
if __name__ == "__main__":
PyHostIp()
gtk.main()