Add new blocklist plugin
This commit is contained in:
parent
8d27c4e349
commit
237c0978f4
|
@ -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)
|
||||
|
|
@ -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 |
|
@ -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"><b>General</b></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"><b>Settings</b></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"><b>Options</b></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>
|
|
@ -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"))
|
|
@ -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()
|
|
@ -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
|
|
@ -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))
|
|
@ -0,0 +1,6 @@
|
|||
class WebUI:
|
||||
def enable(self):
|
||||
log.debug("Blocklist WebUI enable..")
|
||||
|
||||
def disable(self):
|
||||
log.debug("Blocklist WebUI disable..")
|
|
@ -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
|
||||
"""
|
||||
)
|
Loading…
Reference in New Issue