mirror of
https://github.com/codex-storage/deluge.git
synced 2025-01-11 12:04:10 +00:00
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:
parent
da868347cf
commit
c8718ad643
@ -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
|
||||
|
@ -1,3 +1,2 @@
|
||||
# this is a namespace package
|
||||
import pkg_resources
|
||||
pkg_resources.declare_namespace(__name__)
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
|
@ -1,3 +1,2 @@
|
||||
# this is a namespace package
|
||||
import pkg_resources
|
||||
pkg_resources.declare_namespace(__name__)
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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()
|
||||
|
@ -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">●</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"><b>General</b></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"><b>Settings</b></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"><b>Options</b></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"><b>Info</b></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"><b>Whitelist</b></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>
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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):
|
||||
|
@ -51,6 +51,7 @@ setup(
|
||||
author_email=__author_email__,
|
||||
url=__url__,
|
||||
license=__license__,
|
||||
zip_safe=False,
|
||||
long_description=__long_description__,
|
||||
|
||||
packages=find_packages(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user