Removed type combo box from gtkui (will be auto-detecting type).

Removed old format readers.
Added new format readers and decompressers.
This commit is contained in:
John Garland 2009-07-13 05:12:26 +00:00
parent c7db93e954
commit 4c9d01efe8
6 changed files with 183 additions and 249 deletions

View File

@ -49,28 +49,18 @@ import deluge.configmanager
from deluge.core.rpcserver import export
from deluge.httpdownloader import download_file
from peerguardian import PGReader, PGException
from text import TextReader, GZMuleReader, PGZip, PGTextReaderGzip
DEFAULT_PREFS = {
"url": "http://deluge-torrent.org/blocklist/nipfilter.dat.gz",
"load_on_start": False,
"check_after_days": 4,
"list_type": "gzmule",
"list_compression": "",
"list_type": "",
"last_update": "",
"list_size": 0,
"timeout": 180,
"try_times": 3,
}
FORMATS = {
'gzmule': ["Emule IP list (GZip)", GZMuleReader],
'spzip': ["SafePeer Text (Zipped)", PGZip],
'pgtext': ["PeerGuardian Text (Uncompressed)", TextReader],
'p2bgz': ["PeerGuardian P2B (GZip)", PGReader],
'pgtextgz': ["PeerGuardian Text (GZip)", PGTextReaderGzip]
}
class Core(CorePluginBase):
def enable(self):
log.debug('Blocklist: Plugin enabled..')
@ -81,6 +71,7 @@ class Core(CorePluginBase):
self.up_to_date = False
self.num_blocked = 0
self.file_progress = 0.0
self.reader = None
self.core = component.get("Core")
@ -153,13 +144,19 @@ class Core(CorePluginBase):
else:
status["state"] = "Idle"
if self.config["list_compression"]:
status["file_type"] = self.config["list_compression"] + " "
+ self.config["list_type"]
status["up_to_date"] = self.up_to_date
status["num_blocked"] = self.num_blocked
status["file_progress"] = self.file_progress
status["file_type"] = self.config["list_type"]
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"]
if self.config["list_compression"]:
status["file_type"] += " (%s)" % self.config["list_compression"]
return status
@ -237,6 +234,10 @@ class Core(CorePluginBase):
def import_list(self, force=False):
"""Imports the downloaded blocklist into the session"""
def on_read_ip_range(ip_range):
# TODO: add to lt session
self.num_blocked += 1
if self.use_cache and self.has_imported:
log.debug("Latest blocklist is already imported")
return True
@ -244,9 +245,10 @@ class Core(CorePluginBase):
self.is_importing = True
self.num_blocked = 0
# TODO: Open blocklist with appropriate reader
# TODO: Import ranges
if not self.reader:
# TODO: auto-detect reader
#return threads.deferToThread(self.reader.read(on_read_ip_range))
return defer.succeed(None)
def on_import_complete(self, result):

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Sat Feb 14 14:23:56 2009 -->
<?xml version="1.0"?>
<glade-interface>
<!-- interface-requires gtk+ 2.12 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkVBox" id="blocklist_prefs_box">
@ -11,68 +11,31 @@
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox2">
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkHBox" id="hbox1">
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Type:</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="combobox_types">
<property name="visible">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<property name="label" translatable="yes">URL:</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox2">
<widget class="GtkEntry" id="entry_url">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">URL:</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="entry_url">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</widget>
<packing>
<property name="position">1</property>
@ -96,13 +59,14 @@
</widget>
<packing>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
@ -158,14 +122,15 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="chk_import_on_start">
<property name="label" translatable="yes">Import blocklist on startup</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Import blocklist on startup</property>
<property name="response_id">0</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
@ -199,7 +164,7 @@
<widget class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
@ -218,7 +183,6 @@
<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>
<property name="response_id">0</property>
<signal name="clicked" handler="on_button_check_download_clicked"/>
<child>
<widget class="GtkHBox" id="hbox4">
@ -232,6 +196,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
@ -251,6 +216,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
@ -259,7 +225,6 @@
<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>
<property name="response_id">0</property>
<signal name="clicked" handler="on_button_force_download_clicked"/>
<child>
<widget class="GtkHBox" id="hbox5">
@ -273,6 +238,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
@ -296,6 +262,9 @@
</packing>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkImage" id="image_up_to_date">
@ -333,7 +302,7 @@
<widget class="GtkFrame" id="frame4">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
@ -346,6 +315,9 @@
<widget class="GtkProgressBar" id="progressbar">
<property name="visible">True</property>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table_info">

View File

@ -0,0 +1,59 @@
#
# decompressers.py
#
# Copyright (C) 2009 John Garland <johnnybg@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 3 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 gzip, zipfile, bz2
import new
def Zip(reader):
"""Blocklist reader for zipped blocklists"""
def open(self):
z = zipfile.ZipFile(self.file)
return z.open(z.namelist()[0])
setattr(reader, "open", new.instancemethod(open, reader))
return reader
def GZip(reader):
"""Blocklist reader for gzipped blocklists"""
def open(self):
return gzip.open(self.file)
setattr(reader, "open", new.instancemethod(open, reader))
return reader
def BZip2(reader):
"""Blocklist reader for bzipped2 blocklists"""
def open(self):
return bz2.BZ2File(self.file)
setattr(reader, "open", new.instancemethod(open, reader))
return reader

View File

@ -42,8 +42,6 @@ import deluge.common
from deluge.plugins.pluginbase import GtkPluginBase
import common
from core import FORMATS
class GtkUI(GtkPluginBase):
def enable(self):
log.debug("Blocklist GtkUI enable..")
@ -118,11 +116,6 @@ class GtkUI(GtkPluginBase):
deluge.common.fsize(status["file_size"]))
self.glade.get_widget("label_modified").set_text(
str(status["file_date"]))
try:
self.glade.get_widget("label_type").set_text(
FORMATS[status["file_type"]][0])
except KeyError:
self.glade.get_widget("label_type").set_text("")
self.glade.get_widget("label_url").set_text(
status["file_url"])
@ -131,11 +124,6 @@ class GtkUI(GtkPluginBase):
def _on_show_prefs(self):
def _on_get_config(config):
# Update the combo box. It's ugly, get over it.
self.glade.get_widget("combobox_types").set_active_iter(
self.glade.get_widget("combobox_types").get_model().\
get_iter(FORMATS[config["list_type"]][1]))
self.glade.get_widget("entry_url").set_text(
config["url"])
@ -149,8 +137,6 @@ class GtkUI(GtkPluginBase):
def _on_apply_prefs(self):
config = {}
config["list_type"] = self.glade.get_widget("combobox_types").\
get_model()[self.glade.get_widget("combobox_types").get_active()][1]
config["url"] = self.glade.get_widget("entry_url").get_text()
config["check_after_days"] = self.glade.get_widget("spin_check_days").get_value_as_int()
config["load_on_start"] = self.glade.get_widget("chk_import_on_start").get_active()
@ -184,20 +170,6 @@ class GtkUI(GtkPluginBase):
"on_button_force_download_clicked": self._on_button_force_download_clicked
})
# Setup types combobox
combo = self.glade.get_widget("combobox_types")
combo_list = gtk.ListStore(str, str)
combo.set_model(combo_list)
cell = gtk.CellRendererText()
combo.pack_start(cell, False)
combo.add_attribute(cell, "text", 0)
for k in FORMATS.keys():
i = combo_list.append([FORMATS[k][0], k])
FORMATS[k][1] = combo_list.get_path(i)
combo.set_active(0)
# Set button icons
self.glade.get_widget("image_download").set_from_file(
common.get_resource("blocklist_download24.png"))

View File

@ -0,0 +1,80 @@
#
# readers.py
#
# Copyright (C) 2009 John Garland <johnnybg@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 3 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
class BaseReader(object):
"""Base reader for blocklist files"""
def __init__(self, file):
"""Creates a new BaseReader given a file"""
self.file = file
def open(self):
"""Opens the associated file for reading"""
return open(self.file)
def parse(self, line):
"""Extracts ip range from given line"""
raise NotYetImplemented
def read(self, callback):
"""Calls callback on each ip range in the file"""
for ip_range in self.readranges():
callback(ip_range)
def is_valid(self, line):
return not line.startswith('#') and line.strip() != ""
def readranges(self):
"""Yields each ip range from the file"""
blocklist = self.open()
for line in blocklist:
if self.is_valid(line):
yield self.parse(line)
blocklist.close()
class EmuleReader(BaseReader):
"""Blocklist reader for emule style blocklists"""
def parse(self, line):
return line.strip().split(" , ")[0].split(" - ")
class SafePeerReader(BaseReader):
"""Blocklist reader for SafePeer style blocklists"""
def parse(self, line):
return line.strip().split(":")[1].split("-")
class PeerGuardianReader(SafePeerReader):
"""Blocklist reader for PeerGuardian style blocklists"""
pass

View File

@ -1,151 +0,0 @@
##
# Copyright 2007 Steve 'Tarka' Smith (tarka@internode.on.net)
# Distributed under the same terms as Deluge
##
from exceptions import Exception
import re, gzip, os
from socket import inet_aton
from struct import unpack
from zipfile import ZipFile
from deluge.log import LOG as log
class TextException(Exception):
pass
class FormatException(TextException):
pass
class TextBase:
def __init__(self, fd, regexp):
log.debug("TextBase loading")
self.count = 0
self.fd = fd
self.re = re.compile(regexp)
def next(self):
self.count += 1
txt = self.fd.readline()
if txt == "":
return False
match = self.re.search(txt)
if not match:
log.debug("Blocklist: TextBase: Wrong file type or corrupted blocklist file.")
try:
g = match.groups()
except AttributeError:
pass
else:
start = ".".join(g[0:4])
end = ".".join(g[4:8])
return (start, end)
def close(self):
self.fd.close()
# This reads PeerGuardian text-formatted block-lists
class PGTextReader(TextBase):
def __init__(self, fd):
log.debug("PGTextReader loading")
regexp = ':(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)\s*$'
TextBase.__init__(self, fd, regexp)
class PGTextReaderGzip(PGTextReader):
def __init__(self, filename):
log.debug("PGTextReaderGzip loading")
try:
PGTextReader.__init__(self, gzip.open(filename, "r"))
except:
log.debug("Wrong file type or corrupted blocklist file.")
# This reads uncompressed PG text list
class TextReader(PGTextReader):
def __init__(self, filename):
log.debug("TextReader loading: %s", filename)
try:
PGTextReader.__init__(self, open(filename, 'r'))
except:
log.debug("Wrong file type or corrupted blocklist file.")
# Reads Emule style blocklists (aka nipfilter)
class MuleReader(TextBase):
def __init__(self, fd):
log.debug("MuleReader loading")
regexp = '0*(\d+)\.0*(\d+)\.0*(\d+)\.0*(\d+)\s*-\s*0*(\d+)\.0*(\d+)\.0*(\d+)\.0*(\d+)\s*,'
TextBase.__init__(self, fd, regexp)
class GZMuleReader(MuleReader):
def __init__(self, filename):
log.debug("GZMuleReader loading: %s", filename)
try:
MuleReader.__init__(self, gzip.open(filename, "r"))
except:
log.debug("Wrong file type or corrupted blocklist file.")
# Reads zip files from SafePeer style files
class PGZip(TextBase):
def __init__(self, filename):
# Open zip and extract first file
try:
self.zfd = ZipFile(filename, 'r')
except:
log.debug("Blocklist: PGZip: Wrong file type or corrupted blocklist file.")
else:
self.files = self.zfd.namelist()
self.opennext()
def opennext(self):
self.tmp = os.tmpfile()
f = self.files.pop()
log.debug("Loading file: %s", f)
self.tmp.write(self.zfd.read(f))
self.tmp.seek(0)
self.reader = PGTextReader(self.tmp)
def next(self):
try:
ret = self.reader.next()
if not ret:
# This bit is repeated below and could be moved into a
# new procedure. However I'm not clear on how this
# would effect tail recursion, so it remains
# broken-out for now.
if len(self.files) > 0:
self.opennext()
return self.next()
else:
# End of zip
return False
return ret
except FormatException, e:
log.debug("Blocklist: PGZip: Got format exception for zipfile")
# Just skip
if len(self.files) > 0:
self.opennext()
return self.next()
else:
return False
except AttributeError:
pass
def close(self):
try:
self.zfd.close()
except AttributeError:
pass