diff --git a/deluge/plugins/blocklist/blocklist/__init__.py b/deluge/plugins/blocklist/blocklist/__init__.py new file mode 100644 index 000000000..3baa6ea7e --- /dev/null +++ b/deluge/plugins/blocklist/blocklist/__init__.py @@ -0,0 +1,66 @@ +# +# blocklist/__init__.py +# +# Copyright (C) 2007 Andrew Resch ('andar') +# Copyright (C) 2008 Mark Stahler ('kramed') + +# +# 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) + diff --git a/deluge/plugins/blocklist/blocklist/core.py b/deluge/plugins/blocklist/blocklist/core.py new file mode 100644 index 000000000..51ce0af79 --- /dev/null +++ b/deluge/plugins/blocklist/blocklist/core.py @@ -0,0 +1,224 @@ +# +# core.py +# +# Copyright (C) 2008 Andrew Resch ('andar') +# +# 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 diff --git a/deluge/plugins/blocklist/blocklist/data/blocklist16.png b/deluge/plugins/blocklist/blocklist/data/blocklist16.png new file mode 100644 index 000000000..58240de7d Binary files /dev/null and b/deluge/plugins/blocklist/blocklist/data/blocklist16.png differ diff --git a/deluge/plugins/blocklist/blocklist/data/blocklist_download24.png b/deluge/plugins/blocklist/blocklist/data/blocklist_download24.png new file mode 100644 index 000000000..de73891d9 Binary files /dev/null and b/deluge/plugins/blocklist/blocklist/data/blocklist_download24.png differ diff --git a/deluge/plugins/blocklist/blocklist/data/blocklist_import24.png b/deluge/plugins/blocklist/blocklist/data/blocklist_import24.png new file mode 100644 index 000000000..ed2c75b22 Binary files /dev/null and b/deluge/plugins/blocklist/blocklist/data/blocklist_import24.png differ diff --git a/deluge/plugins/blocklist/blocklist/data/blocklist_pref.glade b/deluge/plugins/blocklist/blocklist/data/blocklist_pref.glade new file mode 100644 index 000000000..77574b2f5 --- /dev/null +++ b/deluge/plugins/blocklist/blocklist/data/blocklist_pref.glade @@ -0,0 +1,404 @@ + + + + + + + + True + 5 + + + True + 0 + GTK_SHADOW_NONE + + + True + 12 + + + True + 5 + + + True + 5 + + + True + Type: + + + False + False + + + + + True + + + False + False + 1 + + + + + False + False + + + + + True + 5 + + + True + URL: + + + False + False + + + + + True + True + + + 1 + + + + + False + False + 1 + + + + + + + + + True + 5 + <b>General</b> + True + + + label_item + + + + + False + False + + + + + True + 0 + GTK_SHADOW_NONE + + + True + 12 + + + True + 5 + + + True + 3 + 3 + 5 + 5 + + + + + + True + 0 + Check for new list every: + + + GTK_FILL + + + + + + True + 0 + Timeout to download new list: + True + + + 1 + 2 + GTK_FILL + + + + + + True + 0 + Max attempts to download list: + + + 2 + 3 + GTK_FILL + + + + + + True + True + 2 0 100 1 10 10 + + + 1 + 2 + GTK_FILL + + + + + + True + True + 180 0 9999 1 10 10 + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + + True + True + 3 1 100 1 10 10 + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + + True + 0 + Days + + + 2 + 3 + GTK_FILL + + + + + + True + 0 + Seconds + + + 2 + 3 + 1 + 2 + GTK_FILL + + + + + + False + False + + + + + True + True + Import blocklist on startup + 0 + True + + + False + False + 1 + + + + + + + + + True + 5 + <b>Settings</b> + True + + + label_item + + + + + False + False + 1 + + + + + True + 0 + GTK_SHADOW_NONE + + + True + 12 + + + True + + + True + GTK_BUTTONBOX_SPREAD + + + True + True + True + 0 + + + + True + 5 + + + True + + + False + False + + + + + True + Download List + + + False + False + 1 + + + + + + + False + False + + + + + True + True + True + 0 + + + + True + 5 + + + True + + + False + False + + + + + True + Import List + + + False + False + 1 + + + + + + + False + False + 1 + + + + + False + False + + + + + + + + + True + 5 + <b>Options</b> + True + + + label_item + + + + + False + False + 2 + + + + + + diff --git a/deluge/plugins/blocklist/blocklist/gtkui.py b/deluge/plugins/blocklist/blocklist/gtkui.py new file mode 100644 index 000000000..35e423b18 --- /dev/null +++ b/deluge/plugins/blocklist/blocklist/gtkui.py @@ -0,0 +1,165 @@ +# +# gtkui.py +# +# Copyright (C) 2008 Andrew Resch ('andar') +# +# 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")) diff --git a/deluge/plugins/blocklist/blocklist/peerguardian.py b/deluge/plugins/blocklist/blocklist/peerguardian.py new file mode 100644 index 000000000..c9f0550c6 --- /dev/null +++ b/deluge/plugins/blocklist/blocklist/peerguardian.py @@ -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() diff --git a/deluge/plugins/blocklist/blocklist/text.py b/deluge/plugins/blocklist/blocklist/text.py new file mode 100644 index 000000000..9fd0a288e --- /dev/null +++ b/deluge/plugins/blocklist/blocklist/text.py @@ -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 diff --git a/deluge/plugins/blocklist/blocklist/ui.py b/deluge/plugins/blocklist/blocklist/ui.py new file mode 100644 index 000000000..00ecab694 --- /dev/null +++ b/deluge/plugins/blocklist/blocklist/ui.py @@ -0,0 +1,48 @@ +# +# ui.py +# +# Copyright (C) 2008 Andrew Resch ('andar') +# +# 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)) diff --git a/deluge/plugins/blocklist/blocklist/webui.py b/deluge/plugins/blocklist/blocklist/webui.py new file mode 100644 index 000000000..5ce23b0bb --- /dev/null +++ b/deluge/plugins/blocklist/blocklist/webui.py @@ -0,0 +1,6 @@ +class WebUI: + def enable(self): + log.debug("Blocklist WebUI enable..") + + def disable(self): + log.debug("Blocklist WebUI disable..") diff --git a/deluge/plugins/blocklist/setup.py b/deluge/plugins/blocklist/setup.py new file mode 100644 index 000000000..1d3a7e65e --- /dev/null +++ b/deluge/plugins/blocklist/setup.py @@ -0,0 +1,56 @@ +# setup.py +# +# Copyright (C) 2007 Andrew Resch ('andar') +# Copyright (C) 2008 Mark Stahler ('kramed') + +# +# 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 + """ +)