diff --git a/plugins/BlocklistImport/__init__.py b/plugins/BlocklistImport/__init__.py
new file mode 100644
index 000000000..d754fbaf6
--- /dev/null
+++ b/plugins/BlocklistImport/__init__.py
@@ -0,0 +1,95 @@
+
+
+plugin_name = "Blocklist Importer"
+plugin_author = "Steve 'Tarka' Smith"
+plugin_version = "0.1"
+plugin_description = "Downloads and import PeerGuardian blocklists"
+
+def deluge_init(deluge_path):
+ global path
+ path = deluge_path
+
+def enable(core, interface):
+ global path
+ return BlocklistImport(path, core, interface)
+
+#################### The plugin itself ####################
+
+import urllib, deluge.common, deluge.pref
+from peerguardian import PGReader, PGException
+from ui import GTKConfig, GTKProgress
+
+class BlocklistImport:
+
+ def __init__(self, path, core, interface):
+ print "Loading blocklist plugin ..."
+ # Save the path, interface, and core so they can be used later
+ self.path = path
+ self.core = core
+ self.interface = interface
+ self.gtkconf = GTKConfig(self)
+ self.gtkprog = GTKProgress(self)
+
+ self.blockfile = deluge.common.CONFIG_DIR + "/blocklist.p2b.gzip"
+
+ conffile = deluge.common.CONFIG_DIR + "/blocklist.conf"
+ self.config = deluge.pref.Preferences(filename=conffile,
+ global_defaults=False)
+ self.config.load()
+
+ if not self.config.has_key('url'):
+ self.configure()
+ else:
+ self.loadlist(fetch=self.config.get('load_on_start'))
+
+
+ def _download_update(self, curr, chunksize, size):
+ incs = float(size) / float(chunksize)
+ self.gtkprog.download_prog(curr/incs)
+
+ def loadlist(self, fetch=False):
+ # FIXME
+ #self.gtkprog.start()
+
+ # Attempt initial import
+ # FIXME: Make async
+ if fetch:
+ print "Downloading blocklist..."
+ filename, headers = urllib.urlretrieve(self.config.get('url'),
+ filename=self.blockfile,
+ reporthook=self._download_update)
+ print "Done"
+
+ self.core.reset_ip_filter()
+ reader = PGReader(self.blockfile)
+
+ ips = reader.next()
+ while ips:
+ print "Blocking",ips
+ self.core.add_range_to_ip_filter(*ips)
+ ips = reader.next()
+
+ reader.close()
+
+ # FIXME
+ #self.gtkprog.stop()
+
+ def configure(self):
+ self.gtkconf.start()
+
+ def setconfig(self, url, load_on_start):
+ self.config.set('url', url)
+ self.config.set('load_on_start', load_on_start)
+ self.config.save()
+
+ self.loadlist(fetch=True)
+
+ def disable(self):
+ self.core.reset_ip_filter()
+
+ def unload(self):
+ #self.config.save_to_file(self.config_file)
+ self.core.reset_ip_filter()
+
+ def update(self):
+ pass
diff --git a/plugins/BlocklistImport/peerguardian.py b/plugins/BlocklistImport/peerguardian.py
new file mode 100644
index 000000000..98d2c70d1
--- /dev/null
+++ b/plugins/BlocklistImport/peerguardian.py
@@ -0,0 +1,55 @@
+
+from exceptions import Exception
+from struct import unpack
+import gzip, socket
+
+class PGException(Exception):
+ pass
+
+# Incrementally reads PeerGuardian blocklists v1 and v2.
+# See http://wiki.phoenixlabs.org/wiki/P2B_Format
+class PGReader:
+
+ def __init__(self, filename):
+ print "PGReader loading",filename
+
+ # FIXME: Catch and convert exception?
+ self.fd = gzip.open(filename, "rb")
+
+ # 4 bytes, should be 0xffffffff
+ buf = self.fd.read(4)
+ hdr = unpack("l", buf)[0]
+ if hdr != -1:
+ print "LEADER IS",hdr
+ raise PGException("Invalid leader %d"%hdr)
+
+ magic = self.fd.read(3)
+ if magic != "P2B":
+ raise PGException("Invalid magic code")
+
+ buf = self.fd.read(1)
+ ver = ord(buf)
+ if ver != 1 and ver != 2:
+ raise PGException("Invalid version %d" % ver)
+
+ def next(self):
+
+ # Skip over the string
+ buf = -1
+ while buf != 0:
+ buf = self.fd.read(1)
+ if buf == "": # EOF
+ return False
+ buf = ord(buf)
+
+ buf = self.fd.read(4)
+ start = socket.inet_ntoa(buf)
+
+ buf = self.fd.read(4)
+ end = socket.inet_ntoa(buf)
+
+ return (start, end)
+
+ def close(self):
+ self.fd.close()
+
diff --git a/plugins/BlocklistImport/ui.py b/plugins/BlocklistImport/ui.py
new file mode 100644
index 000000000..e9aecab49
--- /dev/null
+++ b/plugins/BlocklistImport/ui.py
@@ -0,0 +1,92 @@
+
+import gtk
+
+class GTKConfig(gtk.Dialog):
+ def __init__(self, plugin):
+ gtk.Dialog.__init__(self, title="Blocklist Config",
+ flags=gtk.DIALOG_MODAL,
+ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
+ gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+
+ # Setup
+ self.set_border_width(12)
+ self.vbox.set_spacing(6)
+
+ # List source
+ label = gtk.Label()
+ label.set_markup('Blocklist URL')
+ self.url = gtk.Entry()
+ self.listtype = gtk.combo_box_new_text()
+ self.listtype.append_text("PeerGuardian (GZip)")
+ self.listtype.set_active(0)
+
+ hbox = gtk.HBox(False, 6)
+ hbox.pack_start(label)
+ hbox.pack_start(self.url)
+ hbox.pack_start(self.listtype)
+
+ self.vbox.pack_start(hbox)
+
+ # Load on start
+ self.load_on_start = gtk.CheckButton("Load on start")
+ self.vbox.pack_start(self.load_on_start)
+
+ self.connect('response', self.ok)
+ self.connect('close', self.cancel)
+
+ self.hide_all()
+
+ self.plugin = plugin
+
+
+ def ok(self, dialog, response):
+ self.hide_all()
+
+ if response != gtk.RESPONSE_ACCEPT:
+ self.cancel(dialog)
+ return
+
+ self.plugin.setconfig(self.url.get_text(),
+ self.load_on_start.get_active())
+
+ def cancel(self, dialog, response):
+ self.hide_all()
+
+ def start(self):
+ self.show_all()
+
+
+class GTKProgress(gtk.Dialog):
+ def __init__(self, plugin):
+ gtk.Dialog.__init__(self, title="Setting-Up Blocklist",
+ flags=gtk.DIALOG_MODAL,
+ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
+ # Setup
+ self.set_border_width(12)
+ self.vbox.set_spacing(6)
+
+ label = gtk.Label()
+ label.set_markup('Loading and installing blocklist')
+ self.vbox.pack_start(label)
+
+ self.progress = gtk.ProgressBar()
+ self.vbox.pack_start(self.progress)
+
+ self.connect('close', self.cancel)
+
+ self.hide_all()
+
+ def download_prog(self, fract):
+ if fract > 1.0:
+ fract = 1.0
+ self.progress.set_fraction(fract)
+
+ def cancel(self, dialog, response):
+ self.hide_all()
+
+ def start(self):
+ print "showing all"
+ self.show_all()
+
+ def stop(self):
+ self.hide_all()