Implemented #1382:

* Implemented whitelist support to both core and GTK UI.
* Implemented ip filter cleaning before each update. Restarting the deluge
  daemon is no longer needed.
* If "check_after_days" is 0(zero), the timer is not started anymore. It would
  keep updating one call after the other. If the value changed, the timer is
  now stopped and restarted using the new value.
This commit is contained in:
Pedro Algarvio 2012-02-15 14:21:02 +00:00
parent da868347cf
commit c8718ad643
9 changed files with 472 additions and 38 deletions

View File

@ -33,6 +33,14 @@
* #378: Allow showing a pieces bar instead of a regular progress bar in a
torrent's status tab.
=== Blocklist Plugin ===
* #1382: Implemented whitelist support to both core and GTK UI.
* Implemented ip filter cleaning before each update. Restarting the deluge
daemon is no longer needed.
* If "check_after_days" is 0(zero), the timer is not started anymore. It
would keep updating one call after the other. If the value changed, the
timer is now stopped and restarted using the new value.
=== Deluge 1.3.4 (In Development) ===
==== Core ====
* #1921: Free disk space reporting incorrectly in FreeBSD

View File

@ -1,3 +1,2 @@
# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)
__import__('pkg_resources').declare_namespace(__name__)

View File

@ -1,3 +1,2 @@
# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)
__import__('pkg_resources').declare_namespace(__name__)

View File

@ -85,3 +85,103 @@ def remove_zeros(ip):
"""
return ".".join([part.lstrip("0").zfill(1) for part in ip.split(".")])
class BadIP(Exception):
_message = None
def __init__(self, message):
self.message = message
def __set_message(self, message):
self._message = message
def __get_message(self):
return self._message
message = property(__get_message, __set_message)
del __get_message, __set_message
class IP(object):
__slots__ = ('q1', 'q2', 'q3', 'q4', '_long')
def __init__(self, q1, q2, q3, q4):
self.q1 = q1
self.q2 = q2
self.q3 = q3
self.q4 = q4
self._long = 0
for q in self.quadrants():
self._long = (self._long << 8) | int(q)
@property
def address(self):
return '.'.join([str(q) for q in [self.q1, self.q2, self.q3, self.q4]])
@property
def long(self):
return self._long
@classmethod
def parse(cls, ip):
try:
q1, q2, q3, q4 = [int(q) for q in ip.split('.')]
except ValueError:
raise BadIP(_("The IP address \"%s\" is badly formed" % ip))
if q1<0 or q2<0 or q3<0 or q4<0:
raise BadIP(_("The IP address \"%s\" is badly formed" % ip))
elif q1>255 or q2>255 or q3>255 or q4>255:
raise BadIP(_("The IP address \"%s\" is badly formed" % ip))
return cls(q1, q2, q3, q4)
def quadrants(self):
return (self.q1, self.q2, self.q3, self.q4)
# def next_ip(self):
# (q1, q2, q3, q4) = self.quadrants()
# if q4 >= 255:
# if q3 >= 255:
# if q2 >= 255:
# if q1 >= 255:
# raise BadIP(_("There ain't a next IP address"))
# q1 += 1
# else:
# q2 += 1
# else:
# q3 += 1
# else:
# q4 += 1
# return IP(q1, q2, q3, q4)
#
# def previous_ip(self):
# (q1, q2, q3, q4) = self.quadrants()
# if q4 <= 1:
# if q3 <= 1:
# if q2 <= 1:
# if q1 <= 1:
# raise BadIP(_("There ain't a previous IP address"))
# q1 -= 1
# else:
# q2 -= 1
# else:
# q3 -= 1
# else:
# q4 -= 1
# return IP(q1, q2, q3, q4)
def __lt__(self, other):
if isinstance(other, basestring):
other = IP.parse(other)
return self.long < other.long
def __gt__(self, other):
if isinstance(other, basestring):
other = IP.parse(other)
return self.long > other.long
def __eq__(self, other):
if isinstance(other, basestring):
other = IP.parse(other)
return self.long == other.long
def __repr__(self):
return '<%s long=%s address="%s">' % (
self.__class__.__name__, self.long, self.address
)

View File

@ -46,13 +46,13 @@ from twisted.internet.task import LoopingCall
from twisted.internet import threads, defer
from twisted.web import error
from deluge.plugins.pluginbase import CorePluginBase
import deluge.component as component
import deluge.configmanager
from deluge.common import is_url
from deluge.core.rpcserver import export
from deluge.httpdownloader import download_file
from common import IP, BadIP
from detect import detect_compression, detect_format, create_reader, UnknownFormatError
from readers import ReaderParseError
@ -71,14 +71,16 @@ DEFAULT_PREFS = {
"list_size": 0,
"timeout": 180,
"try_times": 3,
"whitelisted": [],
}
# Constants
ALLOW_RANGE = 0
BLOCK_RANGE = 1
class Core(CorePluginBase):
def enable(self):
log.debug('Blocklist: Plugin enabled..')
log.debug('Blocklist: Plugin enabled...')
self.is_url = True
self.is_downloading = False
@ -86,11 +88,14 @@ class Core(CorePluginBase):
self.has_imported = False
self.up_to_date = False
self.need_to_resume_session = False
self.num_whited = 0
self.num_blocked = 0
self.file_progress = 0.0
self.core = component.get("Core")
self.config = deluge.configmanager.ConfigManager("blocklist.conf", DEFAULT_PREFS)
if "whitelisted" not in self.config:
self.config["whitelisted"] = []
self.reader = create_reader(self.config["list_type"], self.config["list_compression"])
@ -114,10 +119,17 @@ class Core(CorePluginBase):
# This function is called every 'check_after_days' days, to download
# and import a new list if needed.
self.update_timer = LoopingCall(self.check_import)
self.update_timer.start(self.config["check_after_days"] * 24 * 60 * 60, update_now)
if self.config["check_after_days"] > 0:
self.update_timer.start(
self.config["check_after_days"] * 24 * 60 * 60, update_now
)
def disable(self):
self.config.save()
log.debug("Reset IP filter")
self.core.session.get_ip_filter().add_rule(
"0.0.0.0", "255.255.255.255", ALLOW_RANGE
)
log.debug('Blocklist: Plugin disabled')
def update(self):
@ -136,7 +148,6 @@ class Core(CorePluginBase):
:rtype: Deferred
"""
# Reset variables
self.filename = None
self.force_download = force
@ -178,9 +189,67 @@ class Core(CorePluginBase):
:param config: config to set
:type config: dictionary
"""
needs_blocklist_import = False
for key in config.keys():
if key == 'whitelisted':
saved = set(self.config[key])
update = set(config[key])
diff = saved.symmetric_difference(update)
if diff:
log.debug("Whitelist changed. Updating...")
added = update.intersection(diff)
removed = saved.intersection(diff)
if added:
for ip in added:
try:
ip = IP.parse(ip)
self.blocklist.add_rule(
ip.address, ip.address, ALLOW_RANGE
)
saved.add(ip.address)
log.debug("Added %s to whitelisted", ip)
self.num_whited += 1
except BadIP, e:
log.error("Bad IP: %s", e)
continue
if removed:
needs_blocklist_import = True
for ip in removed:
try:
ip = IP.parse(ip)
saved.remove(ip.address)
log.debug("Removed %s from whitelisted", ip)
except BadIP, e:
log.error("Bad IP: %s", e)
continue
self.config[key] = list(saved)
continue
elif key == "check_after_days":
if self.config[key] != config[key]:
self.config[key] = config[key]
update_now = False
if self.config["last_update"]:
last_update = datetime.fromtimestamp(self.config["last_update"])
check_period = timedelta(days=self.config["check_after_days"])
if not self.config["last_update"] or last_update + check_period < datetime.now():
update_now = True
self.update_timer.running and self.update_timer.stop()
if self.config["check_after_days"] > 0:
self.update_timer.start(
self.config["check_after_days"] * 24 * 60 * 60, update_now
)
continue
self.config[key] = config[key]
if needs_blocklist_import:
log.debug("IP addresses were removed from the whitelist. Since we "
"don't know if they were blocked before. Re-import "
"current blocklist and re-add whitelisted.")
self.has_imported = False
d = self.import_list(deluge.configmanager.get_config_dir("blocklist.cache"))
d.addCallbacks(self.on_import_complete, self.on_import_error)
@export
def get_status(self):
"""
@ -198,15 +267,16 @@ class Core(CorePluginBase):
status["state"] = "Idle"
status["up_to_date"] = self.up_to_date
status["num_whited"] = self.num_whited
status["num_blocked"] = self.num_blocked
status["file_progress"] = self.file_progress
status["file_url"] = self.config["url"]
status["file_size"] = self.config["list_size"]
status["file_date"] = self.config["last_update"]
status["file_type"] = self.config["list_type"]
status["whitelisted"] = self.config["whitelisted"]
if self.config["list_compression"]:
status["file_type"] += " (%s)" % self.config["list_compression"]
return status
####
@ -258,7 +328,10 @@ class Core(CorePluginBase):
log.debug("Attempting to download blocklist %s", url)
log.debug("Sending headers: %s", headers)
self.is_downloading = True
return download_file(url, deluge.configmanager.get_config_dir("blocklist.download"), on_retrieve_data, headers)
return download_file(
url, deluge.configmanager.get_config_dir("blocklist.download"),
on_retrieve_data, headers
)
def on_download_complete(self, blocklist):
"""
@ -318,13 +391,24 @@ class Core(CorePluginBase):
:returns: a Deferred that fires when the blocklist has been imported
:rtype: Deferred
"""
log.trace("on import_list")
def on_read_ip_range(start, end):
"""Add ip range to blocklist"""
self.blocklist.add_rule(start, end, BLOCK_RANGE)
# log.trace("Adding ip range %s - %s to ipfilter as blocked", start, end)
self.blocklist.add_rule(start.address, end.address, BLOCK_RANGE)
self.num_blocked += 1
def on_finish_read(result):
"""Add blocklist to session"""
"""Add any whitelisted IP's and add the blocklist to session"""
# White listing happens last because the last rules added have
# priority
log.info("Added %d ranges to ipfilter as blocked", self.num_blocked)
for ip in self.config["whitelisted"]:
ip = IP.parse(ip)
self.blocklist.add_rule(ip.address, ip.address, ALLOW_RANGE)
self.num_whited += 1
log.trace("Added %s to the ipfiler as white-listed", ip.address)
log.info("Added %d ranges to ipfilter as white-listed", self.num_whited)
self.core.session.set_ip_filter(self.blocklist)
return result
@ -335,6 +419,7 @@ class Core(CorePluginBase):
self.is_importing = True
self.num_blocked = 0
self.num_whited = 0
self.blocklist = self.core.session.get_ip_filter()
if not blocklist:
@ -344,10 +429,16 @@ class Core(CorePluginBase):
self.auto_detect(blocklist)
self.auto_detected = True
def on_reader_failure(failure):
log.error("Failed to read!!!!!!")
log.exception(failure)
log.debug("Importing using reader: %s", self.reader)
log.debug("Reader type: %s compression: %s", self.config["list_type"], self.config["list_compression"])
log.debug("Clearing current ip filtering")
# self.blocklist.add_rule("0.0.0.0", "255.255.255.255", ALLOW_RANGE)
d = threads.deferToThread(self.reader(blocklist).read, on_read_ip_range)
d.addCallback(on_finish_read)
d.addCallback(on_finish_read).addErrback(on_reader_failure)
return d
@ -360,6 +451,7 @@ class Core(CorePluginBase):
:returns: a Deferred that fires when clean up is done
:rtype: Deferred
"""
log.trace("on_import_list_complete")
d = blocklist
self.is_importing = False
self.has_imported = True
@ -384,6 +476,7 @@ class Core(CorePluginBase):
else the original failure
:rtype: Deferred or Failure
"""
log.trace("on_import_error: %s", f)
d = f
self.is_importing = False
try_again = False
@ -424,6 +517,7 @@ class Core(CorePluginBase):
else:
self.reader = create_reader(self.config["list_type"], self.config["list_compression"])
def pause_session(self):
if not self.core.session.is_paused():
self.core.session.pause()

View File

@ -1,29 +1,34 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<glade-interface>
<!-- interface-requires gtk+ 2.12 -->
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<widget class="GtkVBox" id="blocklist_prefs_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">URL:</property>
</widget>
<packing>
@ -36,9 +41,15 @@
<widget class="GtkEntry" id="entry_url">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="invisible_char">●</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</widget>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
@ -49,6 +60,7 @@
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
<property name="use_markup">True</property>
@ -67,26 +79,30 @@
<child>
<widget class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_columns">3</property>
<property name="column_spacing">5</property>
<property name="row_spacing">5</property>
<child>
<widget class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Days</property>
</widget>
@ -101,7 +117,11 @@
<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 0</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">1 1 100 1 10 0</property>
</widget>
<packing>
<property name="left_attach">1</property>
@ -113,6 +133,7 @@
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Check for new list every:</property>
</widget>
@ -134,6 +155,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
@ -149,6 +171,7 @@
<child>
<widget class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">&lt;b&gt;Settings&lt;/b&gt;</property>
<property name="use_markup">True</property>
@ -167,35 +190,41 @@
<child>
<widget class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="xscale">0</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkHBox" id="hbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<widget class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="can_focus">False</property>
<child>
<widget class="GtkButton" id="button_check_download">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip" translatable="yes">Download the blocklist file if necessary and import the file.</property>
<signal name="clicked" handler="on_button_check_download_clicked"/>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_button_check_download_clicked" />
<child>
<widget class="GtkHBox" id="hbox4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<widget class="GtkImage" id="image_download">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
</widget>
<packing>
@ -207,6 +236,7 @@
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Check Download and Import</property>
</widget>
<packing>
@ -230,14 +260,17 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip" translatable="yes">Download a new blocklist file and import it.</property>
<signal name="clicked" handler="on_button_force_download_clicked"/>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_button_force_download_clicked" />
<child>
<widget class="GtkHBox" id="hbox5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<widget class="GtkImage" id="image_import">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
</widget>
<packing>
@ -249,6 +282,7 @@
<child>
<widget class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Force Download and Import</property>
</widget>
<packing>
@ -268,17 +302,22 @@
</child>
</widget>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkImage" id="image_up_to_date">
<property name="can_focus">False</property>
<property name="tooltip" translatable="yes">Blocklist is up to date</property>
<property name="yalign">0.15000000596046448</property>
<property name="xpad">2</property>
<property name="stock">gtk-yes</property>
</widget>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
@ -289,6 +328,7 @@
<child>
<widget class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">&lt;b&gt;Options&lt;/b&gt;</property>
<property name="use_markup">True</property>
@ -307,34 +347,41 @@
<child>
<widget class="GtkFrame" id="frame4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="top_padding">5</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox4">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="can_focus">False</property>
<child>
<widget class="GtkProgressBar" id="progressbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
</widget>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table_info">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<property name="column_spacing">5</property>
<child>
<widget class="GtkLabel" id="label_url">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
</widget>
<packing>
@ -347,6 +394,7 @@
<child>
<widget class="GtkLabel" id="label_type">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
</widget>
<packing>
@ -359,6 +407,7 @@
<child>
<widget class="GtkLabel" id="label_modified">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
</widget>
<packing>
@ -371,6 +420,7 @@
<child>
<widget class="GtkLabel" id="label_filesize">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
</widget>
<packing>
@ -381,6 +431,7 @@
<child>
<widget class="GtkLabel" id="label17">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">URL:</property>
</widget>
@ -393,6 +444,7 @@
<child>
<widget class="GtkLabel" id="label16">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Type:</property>
</widget>
@ -405,6 +457,7 @@
<child>
<widget class="GtkLabel" id="label15">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Date:</property>
</widget>
@ -417,6 +470,7 @@
<child>
<widget class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">File Size:</property>
</widget>
@ -438,6 +492,7 @@
<child>
<widget class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Info&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
@ -452,6 +507,109 @@
<property name="position">3</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="whitelist_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<widget class="GtkTreeView" id="whitelist_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<property name="headers_clickable">False</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkVButtonBox" id="vbuttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<property name="layout_style">start</property>
<child>
<widget class="GtkButton" id="whitelist_add">
<property name="label">gtk-add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_whitelist_add_clicked" />
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="whitelist_delete">
<property name="label">gtk-delete</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_whitelist_remove_clicked" />
</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">True</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Whitelist&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</widget>
</child>
</widget>

View File

@ -51,13 +51,18 @@ class GtkUI(GtkPluginBase):
log.debug("Blocklist GtkUI enable..")
self.plugin = component.get("PluginManager")
self.load_preferences_page()
try:
self.load_preferences_page()
except Exception, err:
log.exception(err)
raise
self.status_item = component.get("StatusBar").add_item(
image=common.get_resource("blocklist16.png"),
text="",
callback=self._on_status_item_clicked,
tooltip="Blocked IP Ranges")
tooltip=_("Blocked IP Ranges /Whitelisted IP Ranges")
)
# Register some hooks
self.plugin.register_hook("on_apply_prefs", self._on_apply_prefs)
@ -115,7 +120,8 @@ class GtkUI(GtkPluginBase):
self.glade.get_widget("image_up_to_date").hide()
self.table_info.show()
self.status_item.set_text(str(status["num_blocked"]))
self.status_item.set_text("%(num_blocked)s/%(num_whited)s" % status)
self.glade.get_widget("label_filesize").set_text(
deluge.common.fsize(status["file_size"]))
self.glade.get_widget("label_modified").set_text(
@ -128,14 +134,11 @@ class GtkUI(GtkPluginBase):
def _on_show_prefs(self):
def _on_get_config(config):
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("chk_import_on_start").set_active(
config["load_on_start"])
log.trace("Loaded config: %s", config)
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("chk_import_on_start").set_active(config["load_on_start"])
self.populate_whitelist(config["whitelisted"])
client.blocklist.get_config().addCallback(_on_get_config)
@ -144,6 +147,7 @@ class GtkUI(GtkPluginBase):
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["load_on_start"] = self.glade.get_widget("chk_import_on_start").get_active()
config["whitelisted"] = [ip[0] for ip in self.whitelist_model if ip[0]!='IP HERE']
client.blocklist.set_config(config)
def _on_button_check_download_clicked(self, widget):
@ -162,6 +166,7 @@ class GtkUI(GtkPluginBase):
# Load the preferences page
self.glade = gtk.glade.XML(common.get_resource("blocklist_pref.glade"))
self.whitelist_frame = self.glade.get_widget("whitelist_frame")
self.progress_bar = self.glade.get_widget("progressbar")
self.table_info = self.glade.get_widget("table_info")
@ -169,9 +174,16 @@ class GtkUI(GtkPluginBase):
self.progress_bar.hide()
self.table_info.show()
# Create the whitelisted model
self.build_whitelist_model_treeview()
self.glade.signal_autoconnect({
"on_button_check_download_clicked": self._on_button_check_download_clicked,
"on_button_force_download_clicked": self._on_button_force_download_clicked
"on_button_force_download_clicked": self._on_button_force_download_clicked,
'on_whitelist_add_clicked': (self.on_add_button_clicked,
self.whitelist_treeview),
'on_whitelist_remove_clicked': (self.on_delete_button_clicked,
self.whitelist_treeview),
})
# Set button icons
@ -188,3 +200,59 @@ class GtkUI(GtkPluginBase):
self.plugin.add_preferences_page(
_("Blocklist"),
self.glade.get_widget("blocklist_prefs_box"))
def build_whitelist_model_treeview(self):
self.whitelist_treeview = self.glade.get_widget("whitelist_treeview")
treeview_selection = self.whitelist_treeview.get_selection()
treeview_selection.connect(
"changed", self.on_whitelist_treeview_selection_changed
)
self.whitelist_model = gtk.ListStore(str, bool)
renderer = gtk.CellRendererText()
renderer.connect("edited", self.on_cell_edited, self.whitelist_model)
renderer.set_data("ip", 0)
column = gtk.TreeViewColumn("IPs", renderer, text=0, editable=1)
column.set_expand(True)
self.whitelist_treeview.append_column(column)
self.whitelist_treeview.set_model(self.whitelist_model)
def on_cell_edited(self, cell, path_string, new_text, model):
# iter = model.get_iter_from_string(path_string)
# path = model.get_path(iter)[0]
try:
ip = common.IP.parse(new_text)
model.set(model.get_iter_from_string(path_string), 0, ip.address)
except common.BadIP, e:
model.remove(model.get_iter_from_string(path_string))
from deluge.ui.gtkui import dialogs
d = dialogs.ErrorDialog(_("Bad IP address"), e.message)
d.run()
def on_whitelist_treeview_selection_changed(self, selection):
model, selected_connection_iter = selection.get_selected()
if selected_connection_iter:
self.glade.get_widget("whitelist_delete").set_property('sensitive',
True)
else:
self.glade.get_widget("whitelist_delete").set_property('sensitive',
False)
def on_add_button_clicked(self, widget, treeview):
model = treeview.get_model()
model.set(model.append(), 0, "IP HERE", 1, True)
def on_delete_button_clicked(self, widget, treeview):
selection = treeview.get_selection()
model, iter = selection.get_selected()
if iter:
# path = model.get_path(iter)[0]
model.remove(iter)
def populate_whitelist(self, whitelist):
self.whitelist_model.clear()
for ip in whitelist:
self.whitelist_model.set(
self.whitelist_model.append(),0, ip, 1, True
)

View File

@ -33,9 +33,12 @@
#
#
from common import raisesErrorsAs, remove_zeros
import logging
from common import raisesErrorsAs, IP, BadIP
import re
log = logging.getLogger(__name__)
class ReaderParseError(Exception):
pass
@ -51,12 +54,16 @@ class BaseReader(object):
def parse(self, line):
"""Extracts ip range from given line"""
raise NotYetImplemented
raise NotImplementedError
def read(self, callback):
"""Calls callback on each ip range in the file"""
for start, end in self.readranges():
callback(remove_zeros(start), remove_zeros(end))
try:
callback(IP.parse(start), IP.parse(end))
except BadIP, e:
log.error("Failed to parse IP: %s", e)
# log.exception(e)
return self.file
def is_ignored(self, line):

View File

@ -51,6 +51,7 @@ setup(
author_email=__author_email__,
url=__url__,
license=__license__,
zip_safe=False,
long_description=__long_description__,
packages=find_packages(),