Below is the file 'gtktftp.py' from this revision. You can also download the file.

#!/usr/bin/env python

# Wraps my python TFTP server in a the Gtk main loop, with
# classes that subclass gobject (and thus emit sensible
# signals)

import pygtk
pygtk.require('2.0')
import gobject
import gtk
import tftp

class gTFTPServer(gobject.GObject):
	__gproperties__ = { }
	__gsignals__ = {
		'data-received' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT)),
		'data-sent' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT)),
		'file-received' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_STRING)),
		'file-sent' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_STRING)),
		'error-received' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)),
		'error-sent' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)),
	}
	def __init__(self, port=69):
		gobject.GObject.__init__(self)
		self.tags = {}
		self.port = port
		io = tftp.TFTPIOFunctions(self.set_read, self.set_write, self.clear_read, self.clear_write, self.set_timeout, self.remove_timeout, self.notify, self.authenticate)
		self.tftp = tftp.TFTPServer(io, port=self.port, verbose=False)
	def update_io(self, fd, watch, func, user_data):
		tag = gobject.io_add_watch(fd, watch, func, user_data)
		if not self.tags.has_key(fd): self.tags[fd] = []
		self.tags[fd].append((watch, tag))
	def clear_io(self, fd, watch):
		if not self.tags.has_key(fd): return
		tags = self.tags[fd]
		if watch: tags = filter(lambda x: x[0] == watch, tags)
		map(lambda x: gobject.source_remove(x[1]), tags)
	def set_read(self, fd, func, user_data=None):
		self.update_io(fd.fileno(), gobject.IO_IN, func, user_data)
	def clear_read(self, fd):
		self.clear_io(fd.fileno(), gobject.IO_IN)
	def clear_write(self, fd):
		self.clear_io(fd.fileno(), gobject.IO_OUT)
	def set_write(self, fd, func, user_data=None):
		self.update_io(fd.fileno(), gobject.IO_OUT, func, user_data)
	def set_timeout(self, time, func, user_data=None):
		return gobject.timeout_add(3000, func, user_data)
	def remove_timeout(self, tag):
		return gobject.source_remove(tag)
	def notify(self, name, tpl):
		if name == "data_received" or name == "data_sent":
			addr_tpl, filename, bytes = tpl
			self.emit(name, addr_tpl[0], filename, bytes)
		elif name == "file_sent" or name == "file_received":
			addr_tpl, filename = tpl
			self.emit(name, addr_tpl[0], filename)
		elif name == "error_sent" or name == "error_received":
			addr_tpl, code, mesg = tpl
			self.emit(name, addr_tpl[0], code, mesg)
		else:
			print name, tpl
	def authenticate(self, request, client_addr, filename):
		if request == "WRQ":
			dialog = gtk.Dialog(title="Accept file upload?", parent=None,
						flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
						buttons=(gtk.STOCK_NO,gtk.RESPONSE_NO,
							 gtk.STOCK_YES, gtk.RESPONSE_YES))
			label = gtk.Label('<span size="large" weight="bold">The host "%s" is attempting to upload a file: "%s"</span>\n\nDo you wish to accept?' % (client_addr[0], filename))
			label.set_use_markup(True)
			dialog.set_has_separator(False)
			dialog.set_border_width(12)
			dialog.vbox.pack_start(label, True, True, 0)
			label.show()
			response = dialog.run()
			dialog.destroy()
			return response == gtk.RESPONSE_YES
		elif request == "RRQ":
			return True
			# for now we don't need access control; if it's exported, it is exported to all
			# better to have some UI where you can specify a list of hosts really.
			# many clients will ask for the same file several times (esp. with timeouts.)
		else:
			return False

gobject.type_register(gTFTPServer)