Add new blocklist plugin

This commit is contained in:
Andrew Resch 2008-07-19 02:09:53 +00:00
parent 8d27c4e349
commit 237c0978f4
12 changed files with 1175 additions and 0 deletions

View File

@ -0,0 +1,66 @@
#
# blocklist/__init__.py
#
# Copyright (C) 2007 Andrew Resch ('andar') <andrewresch@gmail.com>
# Copyright (C) 2008 Mark Stahler ('kramed') <markstahler@gmail.com>
#
# Deluge is free software.
#
# You may redistribute it and/or modify it under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# deluge is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
from deluge.log import LOG as log
from deluge.plugins.init import PluginBase
class CorePlugin(PluginBase):
def __init__(self, plugin_api, plugin_name):
# Load the Core portion of the plugin
try:
from core import Core
self.plugin = Core(plugin_api, plugin_name)
except Exception, e:
log.debug("Did not load a Core plugin: %s", e)
class GtkUIPlugin(PluginBase):
def __init__(self, plugin_api, plugin_name):
# Load the GtkUI portion of the plugin
try:
from gtkui import GtkUI
self.plugin = GtkUI(plugin_api, plugin_name)
except Exception, e:
log.debug("Did not load a GtkUI plugin: %s", e)
class WebUIPlugin(PluginBase):
def __init__(self, plugin_api, plugin_name):
# Load the GtkUI portion of the plugin
try:
from webui import WebUI
self.plugin = WebUI(plugin_api, plugin_name)
except Exception, e:
log.debug("Did not load a WebUI plugin: %s", e)

View File

@ -0,0 +1,224 @@
#
# core.py
#
# Copyright (C) 2008 Andrew Resch ('andar') <andrewresch@gmail.com>
#
# Deluge is free software.
#
# You may redistribute it and/or modify it under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# deluge is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
import threading
import urllib
import os
import datetime
import gobject
import time
from deluge.log import LOG as log
from deluge.plugins.corepluginbase import CorePluginBase
import deluge.component as component
import deluge.configmanager
from peerguardian import PGReader, PGException
from text import TextReader, GZMuleReader, PGZip
DEFAULT_PREFS = {
"url": "http://www.bluetack.co.uk/config/pipfilter.dat.gz",
"load_on_start": False,
"check_after_days": 2,
"listtype": "gzmule",
"timeout": 180,
"try_times": 3
}
FORMATS = {
'gzmule': ["Emule IP list (GZip)", GZMuleReader],
'spzip': ["SafePeer Text (Zipped)", PGZip],
'pgtext': ["PeerGuardian Text (Uncompressed)", TextReader],
'p2bgz': ["PeerGuardian P2B (GZip)", PGReader]
}
class Core(CorePluginBase):
def enable(self):
log.debug('Blocklist: Plugin enabled..')
self.is_downloading = False
self.is_importing = False
self.num_blocked = 0
self.file_progress = 0.0
self.core = component.get("Core")
self.config = deluge.configmanager.ConfigManager("blocklist.conf", DEFAULT_PREFS)
if self.config["load_on_start"]:
self.export_import(self.need_new_blocklist())
def disable(self):
log.debug('Blocklist: Plugin disabled')
self.config.save()
def update(self):
pass
## Exported RPC methods ###
def export_download(self):
"""Download the blocklist specified in the config as url"""
self.download_blocklist()
def export_import(self, download=False):
"""Import the blocklist from the blocklist.cache, if load is True, then
it will download the blocklist file if needed."""
threading.Thread(target=self.import_blocklist, kwargs={"download": download}).start()
def export_get_config(self):
"""Returns the config dictionary"""
return self.config.get_config()
def export_set_config(self, config):
"""Sets the config based on values in 'config'"""
for key in config.keys():
self.config[key] = config[key]
def export_get_status(self):
"""Returns the status of the plugin."""
status = {}
if self.is_downloading:
status["state"] = "Downloading"
elif self.is_importing:
status["state"] = "Importing"
else:
status["state"] = "Idle"
status["num_blocked"] = self.num_blocked
status["file_progress"] = self.file_progress
return status
####
def on_download_blocklist(self, load):
self.is_downloading = False
if load:
self.export_import()
def import_blocklist(self, download=False):
"""Imports the downloaded blocklist into the session"""
if self.is_downloading:
return
if download:
if self.need_new_blocklist():
self.download_blocklist(True)
return
self.is_importing = True
log.debug("Reset IP Filter..")
component.get("Core").export_reset_ip_filter()
self.num_blocked = 0
# Open the file for reading
try:
read_list = FORMATS[self.config["listtype"]][1](
deluge.configmanager.get_config_dir("blocklist.cache"))
except Exception, e:
log.debug("Unable to read blocklist.cache: %s", e)
return
try:
log.debug("Blocklist import starting..")
ips = read_list.next()
while ips:
self.core.export_block_ip_range(ips)
self.num_blocked += 1
ips = read_list.next()
except Exception, e:
log.debug("Exception during import: %s", e)
else:
log.debug("Blocklist import complete!")
self.is_importing = False
def download_blocklist(self, load=False):
"""Runs download_blocklist_thread() in a thread and calls on_download_blocklist
when finished. If load is True, then we will import the blocklist
upon download completion."""
if self.is_importing:
return
self.is_downloading = True
threading.Thread(
target=self.download_blocklist_thread,
args=(self.on_download_blocklist, load)).start()
def download_blocklist_thread(self, callback, load):
"""Downloads the blocklist specified by 'url' in the config"""
def _call_callback(callback, load):
callback(load)
return False
def on_retrieve_data(count, block_size, total_blocks):
self.file_progress = float(count * block_size) / total_blocks
import socket
socket.setdefaulttimeout(self.config["timeout"])
for i in xrange(self.config["try_times"]):
log.debug("Attempting to download blocklist %s", self.config["url"])
try:
urllib.urlretrieve(
self.config["url"],
deluge.configmanager.get_config_dir("blocklist.cache"),
on_retrieve_data)
except Exception, e:
log.debug("Error downloading blocklist: %s", e)
continue
else:
log.debug("Blocklist successfully downloaded..")
gobject.idle_add(_call_callback, callback, load)
return
def need_new_blocklist(self):
"""Returns True if a new blocklist file should be downloaded"""
try:
# Check current block lists time stamp and decide if it needs to be replaced
list_stats = os.stat(self.local_blocklist)
list_time = datetime.datetime.fromtimestamp(list_stats.st_mtime)
list_size = list_stats.st_size
current_time = datetime.datetime.today()
except:
return True
# If local blocklist file exists but nothing is in it
if list_size == 0:
return True
if current_time >= (list_time + datetime.timedelta(self.config["check_after_days"] * 24 * 60 * 60)):
return True
return False

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,404 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Fri Jul 18 11:06:25 2008 -->
<glade-interface>
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkVBox" id="blocklist_prefs_box">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Type:</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="combobox_types">
<property name="visible">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">URL:</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="entry_url">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">3</property>
<property name="n_columns">3</property>
<property name="column_spacing">5</property>
<property name="row_spacing">5</property>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Check for new list every:</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Timeout to download new list:</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max attempts to download list:</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_check_days">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">2 0 100 1 10 10</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_timeout">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">180 0 9999 1 10 10</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_attempts">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">3 1 100 1 10 10</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Days</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Seconds</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="chk_import_on_start">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Import blocklist on startup</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">&lt;b&gt;Settings&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<child>
<widget class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
<child>
<widget class="GtkButton" id="button_download">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="on_button_download_clicked"/>
<child>
<widget class="GtkHBox" id="hbox3">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkImage" id="image_download">
<property name="visible">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="label" translatable="yes">Download List</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button_import">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="on_button_import_clicked"/>
<child>
<widget class="GtkHBox" id="hbox4">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkImage" id="image_import">
<property name="visible">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="label" translatable="yes">Import List</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">&lt;b&gt;Options&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,165 @@
#
# gtkui.py
#
# Copyright (C) 2008 Andrew Resch ('andar') <andrewresch@gmail.com>
#
# Deluge is free software.
#
# You may redistribute it and/or modify it under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# deluge is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here
import gtk
from deluge.log import LOG as log
from deluge.ui.client import aclient as client
import deluge.component as component
import ui
from core import FORMATS
class GtkUI(ui.UI):
def enable(self):
log.debug("Blocklist GtkUI enable..")
self.load_preferences_page()
self.status_item = component.get("StatusBar").add_item(
image=self.get_resource("blocklist16.png"),
text="0",
callback=self._on_status_item_clicked,
tooltip="Blocked IP Ranges")
# Register some hooks
self.plugin.register_hook("on_apply_prefs", self._on_apply_prefs)
self.plugin.register_hook("on_show_prefs", self._on_show_prefs)
def disable(self):
log.debug("Blocklist GtkUI disable..")
# Remove the preferences page
self.plugin.remove_preferences_page("Blocklist")
# Deregister the hooks
self.plugin.deregister_hook("on_apply_prefs", self._on_apply_prefs)
self.plugin.deregister_hook("on_show_prefs", self._on_show_prefs)
del self.glade
def update(self):
def _on_get_status(status):
if status["state"] == "Downloading":
self.status_item.set_text(
"Downloading %.2f%%" % (status["file_progress"] * 100))
elif status["state"] == "Importing":
self.status_item.set_text(
"Importing " + str(status["num_blocked"]))
elif status["state"] == "Idle":
self.status_item.set_text(str(status["num_blocked"]))
client.blocklist_get_status(_on_get_status)
def _on_show_prefs(self):
def _on_get_config(config):
# Update the combo box. It's ugly, get over it.
self.glade.get_widget("combobox_types").set_active_iter(
self.glade.get_widget("combobox_types").get_model().\
get_iter(FORMATS[config["listtype"]][1]))
self.glade.get_widget("entry_url").set_text(
config["url"])
self.glade.get_widget("spin_check_days").set_value(
config["check_after_days"])
self.glade.get_widget("spin_timeout").set_value(
config["timeout"])
self.glade.get_widget("spin_attempts").set_value(
config["try_times"])
self.glade.get_widget("chk_import_on_start").set_active(
config["load_on_start"])
client.blocklist_get_config(_on_get_config)
def _on_apply_prefs(self):
config = {}
config["listtype"] = self.glade.get_widget("combobox_types").\
get_model()[self.glade.get_widget("combobox_types").get_active()][1]
config["url"] = self.glade.get_widget("entry_url").get_text()
config["check_after_days"] = self.glade.get_widget("spin_check_days").get_value_as_int()
config["timeout"] = self.glade.get_widget("spin_timeout").get_value_as_int()
config["try_times"] = self.glade.get_widget("spin_attempts").get_value_as_int()
config["load_on_start"] = self.glade.get_widget("chk_import_on_start").get_active()
client.blocklist_set_config(None, config)
def _on_button_download_clicked(self, widget):
client.blocklist_download(None)
def _on_button_import_clicked(self, widget):
client.blocklist_import(None)
def _on_status_item_clicked(self):
pass
def load_preferences_page(self):
"""Initializes the preferences page and adds it to the preferences dialog"""
# Load the preferences page
self.glade = gtk.glade.XML(self.get_resource("blocklist_pref.glade"))
self.glade.signal_autoconnect({
"on_button_download_clicked": self._on_button_download_clicked,
"on_button_import_clicked": self._on_button_import_clicked
})
# Setup types combobox
combo = self.glade.get_widget("combobox_types")
combo_list = gtk.ListStore(str, str)
combo.set_model(combo_list)
cell = gtk.CellRendererText()
combo.pack_start(cell, False)
combo.add_attribute(cell, "text", 0)
for k in FORMATS.keys():
i = combo_list.append([FORMATS[k][0], k])
FORMATS[k][1] = combo_list.get_path(i)
combo.set_active(0)
# Set button icons
self.glade.get_widget("image_download").set_from_file(
self.get_resource("blocklist_download24.png"))
self.glade.get_widget("image_import").set_from_file(
self.get_resource("blocklist_import24.png"))
# Update the preferences page with config values from the core
self._on_show_prefs()
# Add the page to the preferences dialog
self.plugin.add_preferences_page(
"Blocklist",
self.glade.get_widget("blocklist_prefs_box"))

View File

@ -0,0 +1,62 @@
##
# Copyright 2007 Steve 'Tarka' Smith (tarka@internode.on.net)
# Distributed under the same terms as Deluge
##
from exceptions import Exception
from struct import unpack
import gzip, socket
from deluge.log import LOG as log
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):
log.debug("PGReader loading: %s", filename)
try:
self.fd = gzip.open(filename, "rb")
except IOError, e:
log.debug("Blocklist: PGReader: Incorrect file type or list is corrupt")
# 4 bytes, should be 0xffffffff
buf = self.fd.read(4)
hdr = unpack("l", buf)[0]
if hdr != -1:
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()

View File

@ -0,0 +1,144 @@
##
# Copyright 2007 Steve 'Tarka' Smith (tarka@internode.on.net)
# Distributed under the same terms as Deluge
##
from exceptions import Exception
import re, gzip, os
from socket import inet_aton
from struct import unpack
from zipfile import ZipFile
from deluge.log import LOG as log
class TextException(Exception):
pass
class FormatException(TextException):
pass
class TextBase:
def __init__(self, fd, regexp):
log.debug("TextBase loading")
self.count = 0
self.fd = fd
self.re = re.compile(regexp)
def next(self):
self.count += 1
txt = self.fd.readline()
if txt == "":
return False
match = self.re.search(txt)
if not match:
log.debug("Blocklist: TextBase: Wrong file type or corrupted blocklist file.")
try:
g = match.groups()
except AttributeError:
pass
else:
start = ".".join(g[0:4])
end = ".".join(g[4:8])
return (start, end)
def close(self):
self.fd.close()
# This reads PeerGuardian text-formatted block-lists
class PGTextReader(TextBase):
def __init__(self, fd):
log.debug("PGTextReader loading")
regexp = ':(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)\s*$'
TextBase.__init__(self, fd, regexp)
# This reads uncompressed PG text list
class TextReader(PGTextReader):
def __init__(self, filename):
log.debug("TextReader loading: %s", filename)
try:
PGTextReader.__init__(self, open(filename, 'r'))
except:
log.debug("Wrong file type or corrupted blocklist file.")
# Reads Emule style blocklists (aka nipfilter)
class MuleReader(TextBase):
def __init__(self, fd):
log.debug("MuleReader loading")
regexp = '0*(\d+)\.0*(\d+)\.0*(\d+)\.0*(\d+)\s*-\s*0*(\d+)\.0*(\d+)\.0*(\d+)\.0*(\d+)\s*,'
TextBase.__init__(self, fd, regexp)
class GZMuleReader(MuleReader):
def __init__(self, filename):
log.debug("GZMuleReader loading: %s", filename)
try:
MuleReader.__init__(self, gzip.open(filename, "r"))
except:
log.debug("Wrong file type or corrupted blocklist file.")
# Reads zip files from SafePeer style files
class PGZip(TextBase):
def __init__(self, filename):
# Open zip and extract first file
try:
self.zfd = ZipFile(filename, 'r')
except:
log.debug("Blocklist: PGZip: Wrong file type or corrupted blocklist file.")
else:
self.files = self.zfd.namelist()
self.opennext()
def opennext(self):
self.tmp = os.tmpfile()
f = self.files.pop()
log.debug("Loading file: %s", f)
self.tmp.write(self.zfd.read(f))
self.tmp.seek(0)
self.reader = PGTextReader(self.tmp)
def next(self):
try:
ret = self.reader.next()
if ret == False:
# This bit is repeated below and could be moved into a
# new procedure. However I'm not clear on how this
# would effect tail recursion, so it remains
# broken-out for now.
if len(self.files) > 0:
self.opennext()
return self.next()
else:
# End of zip
return False
return ret
except FormatException, e:
log.debug("Blocklist: PGZip: Got format exception for zipfile")
# Just skip
if len(self.files) > 0:
self.opennext()
return self.next()
else:
return False
except AttributeError:
pass
def close(self):
try:
self.zfd.close()
except AttributeError:
pass

View File

@ -0,0 +1,48 @@
#
# ui.py
#
# Copyright (C) 2008 Andrew Resch ('andar') <andrewresch@gmail.com>
#
# Deluge is free software.
#
# You may redistribute it and/or modify it under the terms of the
# GNU General Public License, as published by the Free Software
# Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# deluge is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
import pkg_resources
import os.path
class UI:
def __init__(self, plugin_api, plugin_name):
self.plugin = plugin_api
def enable(self):
pass
def disable(self):
pass
def get_resource(self, filename):
return pkg_resources.resource_filename("blocklist", os.path.join("data", filename))

View File

@ -0,0 +1,6 @@
class WebUI:
def enable(self):
log.debug("Blocklist WebUI enable..")
def disable(self):
log.debug("Blocklist WebUI disable..")

View File

@ -0,0 +1,56 @@
# setup.py
#
# Copyright (C) 2007 Andrew Resch ('andar') <andrewresch@gmail.com>
# Copyright (C) 2008 Mark Stahler ('kramed') <markstahler@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
"""
Download and import IP Blocklists
"""
from setuptools import setup
__author__ = "Andrew Resch"
setup(
name="Blocklist",
version="1.0",
description=__doc__,
author=__author__,
packages=["blocklist"],
package_data = {"blocklist": ["data/*"]},
entry_points="""
[deluge.plugin.core]
Blocklist = blocklist:CorePlugin
[deluge.plugin.gtkui]
Blocklist = blocklist:GtkUIPlugin
[deluge.plugin.webui]
Blocklist = blocklist:WebUIPlugin
"""
)