Initial version of blocklist for 0.6
This commit is contained in:
parent
74cd111513
commit
e0c5820bf0
Binary file not shown.
After Width: | Height: | Size: 705 B |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
# 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)
|
|
@ -0,0 +1,119 @@
|
|||
#
|
||||
# blocklist/core.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 torrentblocklist import TorrentBlockList
|
||||
from deluge.log import LOG as log
|
||||
from deluge.plugins.corepluginbase import CorePluginBase
|
||||
|
||||
class Core(CorePluginBase):
|
||||
def enable(self):
|
||||
self.blocklist = TorrentBlockList(self.plugin)
|
||||
self.plugin.register_hook("post_session_load", self._post_session_load)
|
||||
log.debug('Blocklist: Plugin enabled..')
|
||||
|
||||
def disable(self):
|
||||
log.debug('Blocklist: Plugin disabled')
|
||||
self.plugin.deregister_hook("post_session_load", self._post_session_load)
|
||||
self.plugin.reset_ip_filter()
|
||||
# Delete the blocklist object
|
||||
del self.blocklist
|
||||
self.blocklist = None
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
## Hooks for core ##
|
||||
def _post_session_load(self):
|
||||
log.info('Blocklist: Session load hook caught')
|
||||
if self.blocklist.load_on_start == True or self.blocklist.load_on_start == 'True':
|
||||
# Wait until an idle time to load block list
|
||||
import gobject
|
||||
gobject.idle_add(self.blocklist.import_list)
|
||||
|
||||
## Callbacks
|
||||
def register_import_hook(self):
|
||||
self.plugin.register_hook("post_session_load", self._post_session_load)
|
||||
return False
|
||||
|
||||
# Exported functions for ui
|
||||
def export_critical_setting(self):
|
||||
if self.blocklist.old_url != self.blocklist.url or self.blocklist.old_listtype != self.blocklist.listtype:
|
||||
log.info('Blocklist: Critical setting changed')
|
||||
self.blocklist.download()
|
||||
self.blocklist.import_list()
|
||||
self.blocklist.return_count() # Return count after import
|
||||
|
||||
# New settings are now old settings
|
||||
self.blocklist.old_url = self.blocklist.url
|
||||
self.blocklist.old_listtype = self.blocklist.listtype
|
||||
|
||||
def export_count_ips(self):
|
||||
log.debug('Blocklist: Count IPs imported into blocklist')
|
||||
return self.blocklist.return_count()
|
||||
|
||||
def export_import_list(self):
|
||||
log.debug('Blocklist: Import started from GTK UI')
|
||||
self.blocklist.import_list()
|
||||
|
||||
def export_set_options(self, settings):
|
||||
log.debug("Blocklist: Set Options")
|
||||
self.blocklist.set_options(settings)
|
||||
|
||||
def export_get_options(self):
|
||||
log.debug("Blocklist: Get Options")
|
||||
settings_dict = {
|
||||
"url": self.blocklist.url,
|
||||
"listtype": self.blocklist.listtype,
|
||||
"check_after_days": self.blocklist.check_after_days,
|
||||
"load_on_start":self.blocklist.load_on_start,
|
||||
"try_times": self.blocklist.try_times,
|
||||
"timeout": self.blocklist.timeout
|
||||
}
|
||||
log.info(settings_dict)
|
||||
return settings_dict
|
||||
|
||||
def export_get_config_value(self, key):
|
||||
log.debug("Blocklist: Get configuration setting")
|
||||
return self.blocklist.get_config_value(key)
|
||||
|
||||
def export_set_config_value(self, key):
|
||||
log.debug("Blocklist: Set configuration setting")
|
||||
return self.blocklist.set_config_value(key)
|
||||
|
||||
def export_get_formats(self):
|
||||
log.debug('Blocklist: Get Reader Formats')
|
||||
return self.blocklist.return_formats()
|
||||
|
||||
|
|
@ -0,0 +1,306 @@
|
|||
#
|
||||
# blocklist/gtkui.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.
|
||||
|
||||
import pkg_resources # remove possibly, double check
|
||||
from deluge.log import LOG as log
|
||||
import deluge.common # for pixmap
|
||||
import deluge.component # for systray
|
||||
import ui
|
||||
import gtk, gobject
|
||||
|
||||
FORMATS = {
|
||||
'gzmule': ["Emule IP list (GZip)", None],
|
||||
'spzip': ["SafePeer Text (Zipped)", None],
|
||||
'pgtext': ["PeerGuardian Text (Uncompressed)", None],
|
||||
'p2bgz': ["PeerGuardian P2B (GZip)", None]
|
||||
}
|
||||
|
||||
class GtkUI(ui.UI):
|
||||
def __init__(self, plugin_api, plugin_name):
|
||||
log.debug("Calling UI init")
|
||||
# Call UI constructor
|
||||
ui.UI.__init__(self, plugin_api, plugin_name)
|
||||
log.debug("Blocklist GtkUI plugin initalized..")
|
||||
|
||||
def enable(self):
|
||||
self.plugin.register_hook("on_apply_prefs", self.apply_prefs)
|
||||
|
||||
# Import File Format Readers from TorrentBlocklist
|
||||
#ui.client.block_list_get_formats(self.callback_load_formats) # cant marshal classobj objects - wtf
|
||||
|
||||
# Update Blocked IP status bar number - BETTER METHOD TO FOLLOW
|
||||
# emit a blocklsit import signal
|
||||
gobject.timeout_add(5000, self.get_ip_count)
|
||||
gobject.timeout_add(10000, self.get_ip_count)
|
||||
gobject.timeout_add(20000, self.get_ip_count)
|
||||
|
||||
self.load_interface()
|
||||
|
||||
def disable(self):
|
||||
deluge.component.get("StatusBar").remove_item(self.blocklist_status)
|
||||
self.plugin.deregister_hook("on_apply_prefs", self.apply_prefs)
|
||||
|
||||
def add_status_icon(self, ip_count):
|
||||
try:
|
||||
deluge.component.get("StatusBar").remove_item(self.blocklist_status)
|
||||
except:
|
||||
pass
|
||||
# self, image=None, stock=None, text=None, callback=None
|
||||
self.blocklist_status = deluge.component.get("StatusBar").add_item(deluge.common.get_pixmap("blocklist16.png"), None, str(ip_count) + " Blocked IP Ranges ", None)
|
||||
|
||||
def get_ip_count(self):
|
||||
ui.client.block_list_count_ips(self.add_status_icon)
|
||||
return False
|
||||
|
||||
def start_import(self, widget, data=None):
|
||||
ui.client.block_list_import_list(None)
|
||||
log.debug('Blocklist: Import button')
|
||||
gobject.timeout_add(20000, self.get_ip_count)
|
||||
|
||||
def unload_interface(self):
|
||||
self.plugin.remove_preferences_page("Blocklist")
|
||||
|
||||
# def get_active_text(combobox):
|
||||
# model = combobox.get_model()
|
||||
# active = combobox.get_active()
|
||||
# if active < 0:
|
||||
# return None
|
||||
# return model[active][0]
|
||||
|
||||
def load_interface(self):
|
||||
log.debug("Beginning gtk pane initialization")
|
||||
self.blocklist_pref_page = gtk.VBox(False, 3)
|
||||
self.blocklist_pref_page.set_spacing(6)
|
||||
|
||||
label = gtk.Label()
|
||||
label.set_markup('<b>' + 'General' + '</b>')
|
||||
|
||||
frame = gtk.Frame()
|
||||
frame.set_shadow_type(gtk.SHADOW_NONE)
|
||||
|
||||
alignment = gtk.Alignment(0.5, 0.5, 1, 1)
|
||||
alignment.set_padding(8, 5, 5, 5)
|
||||
|
||||
table = gtk.Table(7, 2, False)
|
||||
table.set_col_spacings(8)
|
||||
table.set_row_spacings(10)
|
||||
|
||||
# First row
|
||||
label0 = gtk.Label()
|
||||
label0.set_text('Blocklist Type')
|
||||
|
||||
ls = gtk.ListStore(gobject.TYPE_STRING, # Long name
|
||||
gobject.TYPE_STRING) # Short name
|
||||
|
||||
self.listtype = gtk.ComboBox(model=ls)
|
||||
cell = gtk.CellRendererText()
|
||||
cell.set_property('xpad', 5) # padding for status text
|
||||
self.listtype.pack_start(cell, False)
|
||||
self.listtype.add_attribute(cell, 'text', 0)
|
||||
|
||||
for k in FORMATS.keys():
|
||||
i = ls.append([FORMATS[k][0], k])
|
||||
FORMATS[k][1] = ls.get_path(i)
|
||||
|
||||
self.listtype.set_active(0)
|
||||
|
||||
table.attach(label0, 0, 1, 0 , 1)
|
||||
table.attach(self.listtype, 1, 2, 0, 1)
|
||||
|
||||
# Second row
|
||||
label1 = gtk.Label()
|
||||
label1.set_text('Blocklist URL')
|
||||
|
||||
self.url = gtk.Entry()
|
||||
|
||||
table.attach(label1, 0, 1, 1, 2)
|
||||
table.attach(self.url, 1, 2, 1, 2)
|
||||
|
||||
# Third row
|
||||
label2 = gtk.Label()
|
||||
label2.set_text('Check for a new blocklist every')
|
||||
|
||||
self.check_after_days = gtk.SpinButton(None, 1.0, 0)
|
||||
self.check_after_days.set_increments(1, 3)
|
||||
self.check_after_days.set_range(-1, 14)
|
||||
|
||||
label3 = gtk.Label()
|
||||
label3.set_text('days')
|
||||
|
||||
hbox = gtk.HBox(False, 3)
|
||||
hbox.pack_start(label2, False, True)
|
||||
hbox.pack_start(self.check_after_days, False, False, 4)
|
||||
hbox.pack_start(label3)
|
||||
|
||||
alignment.add(table)
|
||||
table.attach(hbox, 0, 2, 2, 3)
|
||||
|
||||
# Fourth row
|
||||
label4 = gtk.Label()
|
||||
label4.set_text('Timeout to download new blocklist')
|
||||
|
||||
self.timeout = gtk.SpinButton(None, 5.0, 0)
|
||||
self.timeout.set_increments(5, 20)
|
||||
self.timeout.set_range(15, 360)
|
||||
|
||||
label5 = gtk.Label()
|
||||
label5.set_text('seconds')
|
||||
|
||||
hbox1 = gtk.HBox(False, 3)
|
||||
hbox1.pack_start(label4, False, True)
|
||||
hbox1.pack_start(self.timeout)
|
||||
hbox1.pack_start(label5, False, True)
|
||||
|
||||
table.attach(hbox1, 0, 2, 3, 4)
|
||||
|
||||
# Fifth row
|
||||
label5 = gtk.Label()
|
||||
label5.set_text('Times to attempt download of new list')
|
||||
|
||||
self.try_times = gtk.SpinButton(None, 1.0, 0)
|
||||
self.try_times.set_increments(1, 2)
|
||||
self.try_times.set_range(1, 5)
|
||||
|
||||
hbox2 = gtk.HBox(False, 3)
|
||||
hbox2.pack_start(label5, False, True)
|
||||
hbox2.pack_start(self.try_times)
|
||||
|
||||
table.attach(hbox2, 0, 2, 4, 5)
|
||||
|
||||
# sixth row
|
||||
self.load_on_start = gtk.CheckButton('Import blocklist on daemon startup')
|
||||
table.attach(self.load_on_start, 0, 2, 5, 6)
|
||||
|
||||
# DO I NEED THIS STILL I DONT KNOW THINK ABOUT IT AND ASK MYSELF AGAIN LATER K THX BYE
|
||||
|
||||
# # import button (Check and possibly download)
|
||||
import_button = gtk.Button("_Import Blocklist", None, True)
|
||||
import_button.connect("clicked", self.start_import, None)
|
||||
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("blocklist_import24.png"))
|
||||
image = gtk.image_new_from_pixbuf(pixbuf)
|
||||
import_button.set_image(image)
|
||||
|
||||
table.attach(import_button, 0, 2, 6, 7)
|
||||
|
||||
# finish frame
|
||||
frame.set_label_widget(label)
|
||||
frame.add(alignment)
|
||||
|
||||
self.blocklist_pref_page.pack_start(frame)
|
||||
|
||||
# Add preferences page to preferences page
|
||||
log.debug('Adding Blocklist Preferences page')
|
||||
self.plugin.add_preferences_page("Blocklist", self.blocklist_pref_page)
|
||||
|
||||
# Load settings from config and fill widgets with settings
|
||||
log.debug('Starting to load blocklist preferences')
|
||||
self.fetch_prefs()
|
||||
log.debug('Finished loading blocklist preferences')
|
||||
|
||||
|
||||
def fetch_prefs(self): # Fetch settings dictionary from plugin core and pass it to GTK ui settings
|
||||
log.info('Blocklist: Fetching and loading Preferences via GTK ui')
|
||||
ui.client.block_list_get_options(self.callback_load_prefs)
|
||||
|
||||
def apply_prefs(self):
|
||||
log.info('Blocklist: Preferences saved via Gtk ui')
|
||||
settings_dict = {
|
||||
"url": self.url.get_text(),
|
||||
"listtype": self.get_ltype(),
|
||||
"check_after_days": self.check_after_days.get_value_as_int(),
|
||||
"load_on_start":self.load_on_start.get_active(),
|
||||
"try_times": self.try_times.get_value_as_int(),
|
||||
"timeout": self.timeout.get_value_as_int()
|
||||
}
|
||||
ui.client.block_list_set_options(None, settings_dict)
|
||||
# Needs to go in another thread or wait until window is closed
|
||||
gobject.idle_add(self.call_critical_setting)
|
||||
|
||||
def call_critical_setting(self):
|
||||
ui.client.block_list_critical_setting(None) # This checks to see if url or listtype changed, if so download & import
|
||||
self.get_ip_count()
|
||||
|
||||
# GTK Gui Callback functions
|
||||
def callback_load_prefs(self, dict):
|
||||
log.info('Blocklist: Callback Load Prefs GTK ui')
|
||||
self.settings_url(dict['url'])
|
||||
self.settings_listtype(dict['listtype'])
|
||||
self.settings_load(dict['load_on_start'])
|
||||
self.settings_check_after_days(dict['check_after_days'])
|
||||
self.settings_timeout(dict['timeout'])
|
||||
self.settings_try_times(dict['try_times'])
|
||||
|
||||
# Specific function to return proper listtype so we can save and open it again
|
||||
def get_ltype(self):
|
||||
ls = self.listtype.get_model()
|
||||
log.debug(ls)
|
||||
ltype = ls[self.listtype.get_active()][1]
|
||||
log.debug(ltype)
|
||||
return ltype
|
||||
|
||||
# Settings functions
|
||||
def settings_listtype(self, setting):
|
||||
log.debug('Blocklist: listtype')
|
||||
path = FORMATS[setting][1]
|
||||
i = self.listtype.get_model().get_iter(path)
|
||||
self.listtype.set_active_iter(i)
|
||||
|
||||
def settings_url(self, setting):
|
||||
log.debug('Blocklist: url')
|
||||
self.url.set_text(setting)
|
||||
|
||||
def settings_check_after_days(self, setting):
|
||||
log.debug('Blocklist: days')
|
||||
self.check_after_days.set_value(setting)
|
||||
|
||||
def settings_load(self, setting):
|
||||
log.debug('Blocklist: load_on_start')
|
||||
log.info(setting)
|
||||
if setting == True or setting == "True":
|
||||
setting = 1
|
||||
else:
|
||||
setting = 0
|
||||
self.load_on_start.set_active(setting)
|
||||
|
||||
def settings_timeout(self, setting):
|
||||
log.debug('Blocklist: timeout')
|
||||
self.timeout.set_value(setting)
|
||||
|
||||
def settings_try_times(self, setting):
|
||||
log.debug('Blocklist: try times')
|
||||
self.try_times.set_value(setting)
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
##
|
||||
# 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
|
||||
|
||||
class PGException(Exception):
|
||||
pass
|
||||
|
||||
# Incrementally reads PeerGuardian blocklists v1 and v2.
|
||||
# See http://wiki.phoenixlabs.org/wiki/P2B_Format
|
||||
class PGReader:
|
||||
|
||||
def __init__(self, filename):
|
||||
print "PGReader loading",filename
|
||||
|
||||
try:
|
||||
self.fd = gzip.open(filename, "rb")
|
||||
except IOError, e:
|
||||
print '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:
|
||||
print "LEADER IS",hdr
|
||||
raise PGException(_("Invalid leader") + " %d"%hdr)
|
||||
|
||||
magic = self.fd.read(3)
|
||||
if magic != "P2B":
|
||||
raise PGException(_("Invalid magic code"))
|
||||
|
||||
buf = self.fd.read(1)
|
||||
ver = ord(buf)
|
||||
if ver != 1 and ver != 2:
|
||||
raise PGException(_("Invalid version") + " %d" % ver)
|
||||
|
||||
|
||||
def next(self):
|
||||
|
||||
# Skip over the string
|
||||
buf = -1
|
||||
while buf != 0:
|
||||
buf = self.fd.read(1)
|
||||
if buf == "": # EOF
|
||||
return False
|
||||
buf = ord(buf)
|
||||
|
||||
buf = self.fd.read(4)
|
||||
start = socket.inet_ntoa(buf)
|
||||
|
||||
buf = self.fd.read(4)
|
||||
end = socket.inet_ntoa(buf)
|
||||
|
||||
return (start, end)
|
||||
|
||||
def close(self):
|
||||
self.fd.close()
|
|
@ -0,0 +1,142 @@
|
|||
##
|
||||
# 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
|
||||
|
||||
class TextException(Exception):
|
||||
pass
|
||||
|
||||
class FormatException(TextException):
|
||||
pass
|
||||
|
||||
class TextBase:
|
||||
|
||||
def __init__(self, fd, regexp):
|
||||
print "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:
|
||||
print '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):
|
||||
print "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):
|
||||
print "TextReader loading",filename
|
||||
try:
|
||||
PGTextReader.__init__(self, open(filename, 'r'))
|
||||
except:
|
||||
print 'Wrong file type or corrupted blocklist file.'
|
||||
|
||||
|
||||
# Reads Emule style blocklists (aka nipfilter)
|
||||
class MuleReader(TextBase):
|
||||
|
||||
def __init__(self, fd):
|
||||
print "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):
|
||||
print "GZMuleReader loading",filename
|
||||
try:
|
||||
MuleReader.__init__(self, gzip.open(filename, "r"))
|
||||
except:
|
||||
print '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:
|
||||
print '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()
|
||||
print "Loading file",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:
|
||||
print '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,372 @@
|
|||
#
|
||||
# blocklist/blocklist.py
|
||||
#
|
||||
# Copyright (C) 2007 Andrew Resch ('andar') <andrewresch@gmail.com>
|
||||
# Copyright (C) 2008 Mark Stahler ('kramed') <markstahler@gmail.com>
|
||||
|
||||
# a snip or two used from johhnyg
|
||||
|
||||
#
|
||||
# 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.
|
||||
|
||||
# TODO:
|
||||
# - ZERO connections until after import
|
||||
# - download timeouts / retries
|
||||
|
||||
import urllib2, httplib, socket, os, datetime, sys
|
||||
import deluge.common
|
||||
import deluge.component # for libtorrent session reference to change connection number
|
||||
from deluge.log import LOG as log
|
||||
import ui # added by Mark for pausing torrents
|
||||
from peerguardian import PGReader, PGException
|
||||
from text import TextReader, GZMuleReader, PGZip
|
||||
|
||||
BLOCKLIST_PREFS = {
|
||||
"url": "http://www.bluetack.co.uk/config/pipfilter.dat.gz",
|
||||
"load_on_start": "True",
|
||||
"check_after_days": 2,
|
||||
"listtype": "gzmule",
|
||||
"timeout": 180,
|
||||
"try_times": 3
|
||||
}
|
||||
|
||||
BACKUP_PREFS = {
|
||||
"url": "http://www.bluetack.co.uk/config/pipfilter.dat.gz",
|
||||
"listtype": "gzmule",
|
||||
}
|
||||
|
||||
FORMATS = {
|
||||
'gzmule': ["Emule IP list (GZip)", GZMuleReader, None],
|
||||
'spzip': ["SafePeer Text (Zipped)", PGZip, None],
|
||||
'pgtext': ["PeerGuardian Text (Uncompressed)", TextReader, None],
|
||||
'p2bgz': ["PeerGuardian P2B (GZip)", PGReader, None]
|
||||
}
|
||||
|
||||
class HTTPConnection(httplib.HTTPConnection):
|
||||
"""A customized HTTPConnection allowing a per-connection timeout, specified at construction."""
|
||||
|
||||
def __init__(self, host, port=None, strict=None, timeout=None):
|
||||
httplib.HTTPConnection.__init__(self, host, port, strict)
|
||||
self.timeout = timeout
|
||||
|
||||
def connect(self):
|
||||
"""Override HTTPConnection.connect to connect to
|
||||
host/port specified in __init__."""
|
||||
|
||||
msg = "getaddrinfo returns an empty list"
|
||||
for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
|
||||
af, socktype, proto, canonname, sa = res
|
||||
try:
|
||||
self.sock = socket.socket(af, socktype, proto)
|
||||
if self.timeout:
|
||||
self.sock.settimeout(self.timeout)
|
||||
self.sock.connect(sa)
|
||||
except socket.error, msg:
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
continue
|
||||
break
|
||||
if not self.sock:
|
||||
raise socket.error, msg
|
||||
|
||||
|
||||
class HTTPHandler(urllib2.HTTPHandler):
|
||||
"""A customized HTTPHandler which times out connection after the duration specified at construction."""
|
||||
|
||||
def __init__(self, timeout=None):
|
||||
urllib2.HTTPHandler.__init__(self)
|
||||
self.timeout = timeout
|
||||
|
||||
def http_open(self, req):
|
||||
"""Override http_open."""
|
||||
|
||||
def makeConnection(host, port=None, strict=None):
|
||||
return HTTPConnection(host, port, strict, timeout = self.timeout)
|
||||
|
||||
#print "HTTPHandler opening", req.get_full_url()
|
||||
return self.do_open(makeConnection, req)
|
||||
|
||||
|
||||
class TorrentBlockList:
|
||||
def __init__(self, coreplugin):
|
||||
self.plugin = coreplugin # reference from plugin core
|
||||
log.info('Blocklist: TorrentBlockList instantiated')
|
||||
deluge.component.get("Core").session.set_max_connections(0)
|
||||
self.config = deluge.configmanager.ConfigManager("blocklist.conf", BLOCKLIST_PREFS)
|
||||
self.curr = 0
|
||||
self.load_options()
|
||||
|
||||
# Make sure we have a current block list file locally
|
||||
self.fetch = False
|
||||
self.local_blocklist = deluge.common.get_config_dir("blocklist.cache")
|
||||
|
||||
# Check list for modifications from online version
|
||||
self.check_update()
|
||||
|
||||
# Initialize download attempt
|
||||
self.attempt = 0
|
||||
|
||||
if self.fetch == True:
|
||||
self.download()
|
||||
|
||||
log.debug('Blocklist: TorrentBlockList Constructor finished')
|
||||
|
||||
|
||||
def load_options(self):
|
||||
#self.config.load()
|
||||
# Fill variables with settings from block list configuration file
|
||||
self.url = self.config['url']
|
||||
self.listtype = self.config['listtype']
|
||||
self.check_after_days = self.config['check_after_days']
|
||||
self.load_on_start = self.config['load_on_start']
|
||||
self.timeout = self.config['timeout']
|
||||
self.try_times = self.config['try_times']
|
||||
|
||||
self.old_url = self.url
|
||||
self.old_listtype = self.listtype
|
||||
|
||||
socket.setdefaulttimeout(self.timeout)
|
||||
|
||||
def set_options(self, options):
|
||||
log.info('Blocklist: Options saved...')
|
||||
self.config.set('url', options['url'])
|
||||
self.config.set('check_after_days', options['check_after_days'])
|
||||
self.config.set('load_on_start', options['load_on_start'])
|
||||
self.config.set('listtype', options['listtype'])
|
||||
self.config.set('timeout', options['timeout'])
|
||||
self.config.set('try_times', options['try_times'])
|
||||
# Save settings to disk
|
||||
self.config.save()
|
||||
# Load newly set options to core plugin
|
||||
self.load_options()
|
||||
|
||||
def check_update(self):
|
||||
log.info('Blocklist: Checking for updates')
|
||||
|
||||
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:
|
||||
self.fetch = True
|
||||
return
|
||||
|
||||
# If local blocklist file exists but nothing is in it
|
||||
if list_size == 0:
|
||||
self.fetch = True
|
||||
return
|
||||
|
||||
if current_time >= (list_time + datetime.timedelta(self.check_after_days)):
|
||||
check_newer = True
|
||||
log.debug('Blocklist: List may need to be replaced')
|
||||
else:
|
||||
check_newer = False
|
||||
|
||||
# If the program decides it is time to get a new list
|
||||
if check_newer == True:
|
||||
log.debug('Blocklist: Attempting check')
|
||||
|
||||
j = 0 # counter for loop
|
||||
|
||||
while j < self.try_times:
|
||||
# Get current online block lists time stamp and compare it with current
|
||||
try:
|
||||
http_handler = HTTPHandler(timeout = 15)
|
||||
opener = urllib2.build_opener(http_handler)
|
||||
request = urllib2.Request(self.url)
|
||||
|
||||
try:
|
||||
new_listinfo = opener.open(request) # Can Raise URLError
|
||||
header = new_listinfo.info()
|
||||
remote_size = int(header['content-length'])
|
||||
remote_time = datetime.datetime.strptime(header['last-modified'],"%a, %d %b %Y %H:%M:%S GMT")
|
||||
remote_type = header['content-type']
|
||||
|
||||
except Exception, e:
|
||||
log.warning(e)
|
||||
# HANDLE EXCEPTOIN
|
||||
|
||||
log.debug(self.listtype)
|
||||
|
||||
# check expected list type
|
||||
if self.listtype == "spzip":
|
||||
list_type = "application/zip"
|
||||
elif self.listtype == "gzmule" or self.listtype == "p2bgz":
|
||||
list_type = "application/x-gzip"
|
||||
else:
|
||||
list_type = "text/html"
|
||||
|
||||
# Print remote file information and local
|
||||
log.debug('Blocklist: remote')
|
||||
log.debug(remote_type)
|
||||
log.debug(remote_time)
|
||||
log.debug(remote_size)
|
||||
log.debug('Blocklist: local')
|
||||
log.debug(list_type)
|
||||
log.debug(list_time)
|
||||
log.debug(list_size)
|
||||
|
||||
# Compare MIME types of local and remote list
|
||||
if list_type == remote_type:
|
||||
log.info('Blocklist: Remote and Local have the same list type')
|
||||
# Compare last modified times and decide to download a new list or not
|
||||
if list_time < remote_time or list_size != remote_size:
|
||||
self.fetch = True
|
||||
log.info('Blocklist: Local blocklist list is out of date')
|
||||
|
||||
else:
|
||||
self.fetch = False
|
||||
log.info('Blocklist: Local block list is up to date')
|
||||
|
||||
return
|
||||
|
||||
j+=1
|
||||
log.debug('Blocklist: 6 TRY AGAIN FOO')
|
||||
|
||||
# Connection can't be made to check remote time stamps
|
||||
except: # && urllib2.URLError
|
||||
log.debug('Blocklist: Connection to remote server timed out')
|
||||
self.fetch = False
|
||||
j+=1
|
||||
|
||||
else:
|
||||
log.info('Blocklist: Not enough time has passed to check for a new list')
|
||||
return
|
||||
|
||||
def download(self):
|
||||
log.info('Blocklist: Beginning download')
|
||||
self.attempt += 1
|
||||
|
||||
i = 0
|
||||
while i < self.try_times:
|
||||
# Download a new block list
|
||||
try:
|
||||
log.info('Blocklist: Downloading new list...')
|
||||
http_handler = HTTPHandler(timeout = 15)
|
||||
opener = urllib2.build_opener(http_handler)
|
||||
request = urllib2.Request(self.url)
|
||||
new_list = opener.open(request)
|
||||
file = open(deluge.common.get_config_dir("blocklist.cache"), 'w')
|
||||
while 1:
|
||||
data = new_list.read()
|
||||
if not len(data):
|
||||
break
|
||||
file.write(data)
|
||||
file.close()
|
||||
|
||||
except OSError, e:
|
||||
log.debug('Blocklist: Unable to write blocklist file')
|
||||
return
|
||||
|
||||
except:
|
||||
if self.attempt > self.try_times:
|
||||
log.warning('Blocklist: All download attempts failed')
|
||||
return
|
||||
|
||||
else:
|
||||
log.warning('Blocklist: Try list download again')
|
||||
i += 1
|
||||
|
||||
# CHECKSUM
|
||||
|
||||
log.info('Blocklist: List downloaded sucessfully')
|
||||
|
||||
|
||||
def import_list(self):
|
||||
log.info('Blocklist: Importing list...')
|
||||
try:
|
||||
self.plugin.reset_ip_filter()
|
||||
self.curr = 0
|
||||
log.info('Blocklist: IP Filter reset')
|
||||
except:
|
||||
log.debug('Blocklist: Reset filter failed')
|
||||
pass
|
||||
|
||||
# Instantiate format class that will read the lists file format
|
||||
try:
|
||||
log.info('Blocklist: ' + str(self.listtype))
|
||||
read_list = FORMATS[self.listtype][1](self.local_blocklist)
|
||||
|
||||
except:
|
||||
log.warning('Blocklist: Error: Format read error')
|
||||
self.reset_critical_settings()
|
||||
|
||||
try:
|
||||
ips = read_list.next()
|
||||
print ips
|
||||
|
||||
while ips:
|
||||
self.plugin.block_ip_range(ips)
|
||||
ips = read_list.next()
|
||||
self.curr += 1
|
||||
# Progress measurement here
|
||||
|
||||
log.info(self.curr)
|
||||
|
||||
except IOError, e:
|
||||
log.debug('Blocklist: Problem with list, re-download')
|
||||
return
|
||||
|
||||
# Throw exception if curr = 0 reset critical settings
|
||||
if self.curr == 0:
|
||||
log.warning("Blocklist: Improper list read")
|
||||
self.reset_critical_settings()
|
||||
else:
|
||||
deluge.component.get("Core").session.set_max_connections(deluge.configmanager.ConfigManager("core.conf")["max_connections_global"])
|
||||
log.info('Blocklist: Import completed sucessfully')
|
||||
|
||||
def reset_critical_settings(self):
|
||||
log.info('Blocklist: URL and List type reset')
|
||||
reset_url = BACKUP_PREFS["url"]
|
||||
reset_listtype = BACKUP_PREFS["listtype"]
|
||||
|
||||
log.info(reset_url)
|
||||
log.info(reset_listtype)
|
||||
|
||||
self.config.set('url', reset_url)
|
||||
self.config.set('listtype', reset_listtype)
|
||||
self.config.save()
|
||||
|
||||
self.load_options()
|
||||
log.info(self.url)
|
||||
log.info(self.listtype)
|
||||
self.download()
|
||||
self.import_list()
|
||||
|
||||
def return_count(self):
|
||||
return self.curr
|
||||
|
||||
def get_config_value(self, key): # url, check_after_days, listtype
|
||||
val = self.config[key]
|
||||
log.debug('Blocklist: Get_config_val')
|
||||
return val
|
|
@ -0,0 +1,53 @@
|
|||
#
|
||||
# blocklist/ui.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.
|
||||
|
||||
import gettext
|
||||
import locale
|
||||
import pkg_resources
|
||||
import deluge.component
|
||||
from deluge.ui.client import aclient as client
|
||||
from deluge.log import LOG as log
|
||||
|
||||
class UI:
|
||||
def __init__(self, plugin_api, plugin_name):
|
||||
self.plugin = plugin_api
|
||||
|
||||
def enable(self):
|
||||
pass
|
||||
|
||||
def disable(self):
|
||||
pass
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
# 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__ = "Mark Stahler"
|
||||
|
||||
setup(
|
||||
name="Block List",
|
||||
version="1.0",
|
||||
description=__doc__,
|
||||
author=__author__,
|
||||
packages=["blocklist"],
|
||||
package_data = {"blocklist": ["glade/*.glade"]},
|
||||
entry_points="""
|
||||
[deluge.plugin.core]
|
||||
Blocklist = blocklist:CorePlugin
|
||||
[deluge.plugin.gtkui]
|
||||
Blocklist = blocklist:GtkUIPlugin
|
||||
"""
|
||||
)
|
Loading…
Reference in New Issue