Below is the file 'goatpy/nmapwrapper.py' from this revision. You can also download the file.

#!/usr/bin/python

import sys
import os
import fcntl
import select
import libxml2
from goatpy import utility

class Host:
	def __init__(self):
		self.addresses = []
		self.hostnames = []
		self.tcp_ports = []
		self.udp_ports = []
	def append_hostname(self, hostname):
		self.hostnames.append(hostname)
	def port_is_open(self, protocol, id, service):
		if protocol == "tcp":
			self.tcp_ports.append((int(id)))
		elif protocol == "udp":
			self.udp_ports.append((int(id)))

class NmapException:
	def __init__(self, mesg):
		self._mesg = mesg
	def __repr__(self):
		return self._mesg

class nmap_callback:
	def __init__(self, host_list):
		self.current_host = None
		self.current_port_protocol = None
		self.current_port_id = None
		self.current_port_state = None
		self.current_port_service = None
		self.host_list = host_list
	def startDocument(self):
		pass
	def endDocument(self):
		pass
	def startElement(self, tag, attrs):
		if tag == "host":
			if self.current_host:
				raise NmapException("Woah, nested host tags aren't cool.")
			self.current_host = Host()
		if not self.current_host: return
		if tag == "hostname":
			self.current_host.append_hostname(attrs['name'])
		elif tag == "address":
			self.current_host.addresses.append((attrs['addr'], attrs['addrtype']))
		elif tag == "status":
			self.current_host.status = attrs['state']
		elif tag == "port":
			self.current_port_protocol = attrs['protocol']
			self.current_port_id = attrs['portid']
		elif tag == "state":
			self.current_port_state = attrs['state']
		elif tag == "service":
			self.current_port_service = attrs['name']
	def endElement(self, tag):
		if tag == "host" and self.current_host:
			self.host_list.append(self.current_host)
			self.current_host = None
		elif tag == "port":
			if not self.current_host: raise NmapException("Port outside of host.")
			if self.current_port_state.startswith('open'):
				self.current_host.port_is_open(self.current_port_protocol, self.current_port_id, self.current_port_service)
			self.current_port_protocol = None
			self.current_port_id = None
			self.current_port_state = None
			self.current_port_service = None

def nmap(command):
	child_stdin, child_stdout, child_stderr = os.popen3(command)
	utility.set_nonblocking(child_stdin)
	utility.set_nonblocking(child_stdout)
	utility.set_nonblocking(child_stderr)
	# ok, so we've got a stream of XML coming
	# in from the nmap process. We use libxml2's
	# progressive SAX parser to examine this XML
	# stream as it's coming in, and do sensible things
	queue = []
	handler = nmap_callback(queue)
	ctxt = libxml2.createPushParser(handler, "", 0, "")
	while 1:
		ready = select.select([child_stdout,child_stderr],[],[])
		if child_stdout in ready[0]:
			data = child_stdout.read()
			if len(data) == 0:
				break
			ctxt.parseChunk(data, len(data), 0)
		while len(queue):
			host = queue.pop()
			if host.status != "down":
				yield host
		if child_stderr in ready[0]:
			data = child_stderr.read()
			if len(data) == 0:
				break
	child_stdin.close()
	child_stdout.close()
	child_stderr.close()
	ctxt.parseChunk("", 0, 1)

if __name__ == '__main__':
	print "Please do not press this button again."
	sys.exit(1)