(trunk) #3697 "make blocklist URL configurable" -- implemented in GTK+, Qt, and RPC

This commit is contained in:
Charles Kerr 2010-10-31 17:16:12 +00:00
parent 22c622a92f
commit 92620b72b0
14 changed files with 169 additions and 71 deletions

View File

@ -409,6 +409,7 @@
"alt-speed-time-end" | number | when to turn off alt speeds (units: same)
"alt-speed-time-day" | number | what day(s) to turn on alt speeds (look at tr_sched_day)
"alt-speed-up" | number | max global upload speed (KBps)
"blocklist-url" | string | location of the blocklist to use for "blocklist-update"
"blocklist-enabled" | boolean | true means enabled
"blocklist-size" | number | number of rules in the blocklist
"cache-size" | number | maximum size of the disk cache (MB)
@ -636,3 +637,6 @@
| | yes | session-get | new arg "units"
| | yes | torrent-set | new arg "seedIdleLimit"
| | yes | torrent-set | new arg "seedIdleMode"
------+---------+-----------+----------------+-------------------------------
11 | 2.12 | yes | session-get | new arg "blocklist-url"
| | yes | session-set | new arg "blocklist-url"

View File

@ -1196,6 +1196,10 @@ prefschanged( TrCore * core UNUSED, const char * key, gpointer data )
{
tr_blocklistSetEnabled( tr, pref_flag_get( key ) );
}
else if( !strcmp( key, TR_PREFS_KEY_BLOCKLIST_URL ) )
{
tr_blocklistSetURL( tr, pref_string_get( key ) );
}
else if( !strcmp( key, PREF_KEY_SHOW_TRAY_ICON ) )
{
const int show = pref_flag_get( key );

View File

@ -2,5 +2,5 @@
export G_SLICE=always-malloc
export G_DEBUG=gc-friendly
export GLIBCXX_FORCE_NEW=1
#valgrind --tool=cachegrind ./transmission -p -g /tmp/transmission-test/what 2>&1 | tee runlog
valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=48 --log-file=x-valgrind --show-reachable=yes ./transmission-gtk -p 2>&1 | tee runlog
#valgrind --tool=cachegrind ./transmission-gtk -p -g /tmp/transmission-test 2>&1 | tee runlog
valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=48 --log-file=x-valgrind --show-reachable=yes ./transmission-gtk -g /tmp/transmission-test -p 2>&1 | tee runlog

View File

@ -245,8 +245,7 @@ new_file_chooser_button( const char * key, gpointer core )
}
static void
target_cb( GtkWidget * tb,
gpointer target )
target_cb( GtkWidget * tb, gpointer target )
{
const gboolean b = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( tb ) );
@ -383,6 +382,7 @@ struct blocklist_data
gulong updateBlocklistTag;
GtkWidget * updateBlocklistButton;
GtkWidget * updateBlocklistDialog;
GtkWidget * label;
GtkWidget * check;
TrCore * core;
};
@ -390,12 +390,14 @@ struct blocklist_data
static void
updateBlocklistText( GtkWidget * w, TrCore * core )
{
char buf1[512];
char buf2[512];
const int n = tr_blocklistGetRuleCount( tr_core_session( core ) );
char buf[512];
g_snprintf( buf, sizeof( buf ),
gtr_ngettext( "Enable _blocklist (contains %'d rule)",
"Enable _blocklist (contains %'d rules)", n ), n );
gtk_button_set_label( GTK_BUTTON( w ), buf );
g_snprintf( buf1, sizeof( buf1 ),
gtr_ngettext( "Blocklist contains %'d rule",
"Blocklist contains %'d rules", n ), n );
g_snprintf( buf2, sizeof( buf2 ), "<i>%s</i>", buf1 );
gtk_label_set_markup( GTK_LABEL( w ), buf2 );
}
/* prefs dialog is being destroyed, so stop listening to blocklist updates */
@ -429,7 +431,7 @@ onBlocklistUpdated( TrCore * core, int n, gpointer gdata )
gtk_widget_set_sensitive( data->updateBlocklistButton, TRUE );
gtk_message_dialog_set_markup( d, _( "<b>Update succeeded!</b>" ) );
gtk_message_dialog_format_secondary_text( d, s, n );
updateBlocklistText( data->check, core );
updateBlocklistText( data->label, core );
}
/* user pushed a button to update the blocklist */
@ -476,12 +478,13 @@ new_encryption_combo( GObject * core, const char * key )
static GtkWidget*
privacyPage( GObject * core )
{
int row = 0;
const char * s;
GtkWidget * t;
GtkWidget * w;
GtkWidget * b;
GtkWidget * h;
int row = 0;
const char * s;
GtkWidget * t;
GtkWidget * w;
GtkWidget * b;
GtkWidget * h;
GtkWidget * e;
struct blocklist_data * data;
data = g_new0( struct blocklist_data, 1 );
@ -490,25 +493,32 @@ privacyPage( GObject * core )
t = hig_workarea_create( );
hig_workarea_add_section_title( t, &row, _( "Blocklist" ) );
w = new_check_button( "", TR_PREFS_KEY_BLOCKLIST_ENABLED, core );
b = new_check_button( _( "Enable _blocklist:" ), TR_PREFS_KEY_BLOCKLIST_ENABLED, core );
e = new_entry( TR_PREFS_KEY_BLOCKLIST_URL, core );
gtk_widget_set_size_request( e, 300, -1 );
hig_workarea_add_row_w( t, &row, b, e, NULL );
data->check = b;
g_signal_connect( b, "toggled", G_CALLBACK( target_cb ), e );
target_cb( b, e );
w = gtk_label_new( "" );
gtk_misc_set_alignment( GTK_MISC( w ), 0.0f, 0.5f );
updateBlocklistText( w, TR_CORE( core ) );
data->label = w;
h = gtk_hbox_new( FALSE, GUI_PAD_BIG );
gtk_box_pack_start( GTK_BOX( h ), w, TRUE, TRUE, 0 );
b = data->updateBlocklistButton = gtk_button_new_with_mnemonic( _( "_Update" ) );
data->check = w;
g_object_set_data( G_OBJECT( b ), "session",
tr_core_session( TR_CORE( core ) ) );
g_object_set_data( G_OBJECT( b ), "session", tr_core_session( TR_CORE( core ) ) );
g_signal_connect( b, "clicked", G_CALLBACK( onBlocklistUpdate ), data );
g_signal_connect( data->check, "toggled", G_CALLBACK( target_cb ), b ); target_cb( data->check, b );
gtk_box_pack_start( GTK_BOX( h ), b, FALSE, FALSE, 0 );
g_signal_connect( w, "toggled", G_CALLBACK( target_cb ), b );
target_cb( w, b );
g_signal_connect( data->check, "toggled", G_CALLBACK( target_cb ), w ); target_cb( data->check, w );
hig_workarea_add_wide_control( t, &row, h );
s = _( "Enable _automatic updates" );
w = new_check_button( s, PREF_KEY_BLOCKLIST_UPDATES_ENABLED, core );
hig_workarea_add_wide_control( t, &row, w );
g_signal_connect( data->check, "toggled", G_CALLBACK( target_cb ), w );
target_cb( data->check, w );
g_signal_connect( data->check, "toggled", G_CALLBACK( target_cb ), w ); target_cb( data->check, w );
hig_workarea_add_section_divider( t, &row );
hig_workarea_add_section_title ( t, &row, _( "Privacy" ) );

View File

@ -231,7 +231,7 @@ _tr_blocklistHasAddress( tr_blocklist * b,
}
/*
* level1 format: "comment:x.x.x.x-y.y.y.y"
* bluetack format: "comment:x.x.x.x-y.y.y.y"
*/
static tr_bool
parseLine1( const char * line, struct tr_ip_range * range )

View File

@ -17,11 +17,16 @@
#include <string.h> /* strcmp */
#include <unistd.h> /* unlink */
#ifdef HAVE_ZLIB
#include <zlib.h>
#endif
#include <event.h> /* evbuffer */
#include "transmission.h"
#include "bencode.h"
#include "completion.h"
#include "fdlimit.h"
#include "json.h"
#include "rpcimpl.h"
#include "session.h"
@ -1112,42 +1117,74 @@ gotNewBlocklist( tr_session * session,
}
else /* successfully fetched the blocklist... */
{
int fd;
const char * configDir = tr_sessionGetConfigDir( session );
char * filename = tr_buildPath( configDir, "blocklist.tmp", NULL );
FILE * fp = fopen( filename, "wb+" );
if( fp == NULL )
{
tr_snprintf( result, sizeof( result ),
_( "Couldn't save file \"%1$s\": %2$s" ),
filename, tr_strerror( errno ) );
errno = 0;
if( !errno ) {
fd = tr_open_file_for_writing( filename );
if( fd < 0 )
tr_snprintf( result, sizeof( result ), _( "Couldn't save file \"%1$s\": %2$s" ), filename, tr_strerror( errno ) );
}
else
if( !errno ) {
const char * buf = response;
size_t buflen = response_byte_count;
while( buflen > 0 ) {
int n = write( fd, buf, buflen );
if( n < 0 ) {
tr_snprintf( result, sizeof( result ), _( "Couldn't save file \"%1$s\": %2$s" ), filename, tr_strerror( errno ) );
break;
}
buf += n;
buflen -= n;
}
tr_close_file( fd );
}
#ifdef HAVE_ZLIB
if( !errno )
{
const size_t n = fwrite( response, 1, response_byte_count, fp );
fclose( fp );
if( n != response_byte_count )
{
tr_snprintf( result, sizeof( result ),
_( "Couldn't save file \"%1$s\": %2$s" ),
filename, tr_strerror( errno ) );
}
else
{
/* feed it to the session */
const int ruleCount = tr_blocklistSetContent( session, filename );
/* give the client a response */
tr_bencDictAddInt( data->args_out, "blocklist-size", ruleCount );
tr_snprintf( result, sizeof( result ), "success" );
char * filename2 = tr_buildPath( configDir, "blocklist.txt.tmp", NULL );
fd = tr_open_file_for_writing( filename2 );
if( fd < 0 )
tr_snprintf( result, sizeof( result ), _( "Couldn't save file \"%1$s\": %2$s" ), filename2, tr_strerror( errno ) );
else {
gzFile gzf = gzopen( filename, "r" );
if( gzf ) {
const size_t buflen = 1024 * 128; /* 128 KiB buffer */
uint8_t * buf = tr_valloc( buflen );
for( ;; ) {
int n = gzread( gzf, buf, buflen );
if( n < 0 ) /* error */
tr_snprintf( result, sizeof( result ), _( "Error reading \"%1$s\": %2$s" ), filename, gzerror( gzf, NULL ) );
if( n < 1 ) /* error or EOF */
break;
if( write( fd, buf, n ) < 0 )
tr_snprintf( result, sizeof( result ), _( "Couldn't save file \"%1$s\": %2$s" ), filename2, tr_strerror( errno ) );
}
tr_free( buf );
gzclose( gzf );
}
tr_close_file( fd );
}
/* cleanup */
unlink( filename );
tr_free( filename );
filename = filename2;
}
#endif
if( !errno ) {
/* feed it to the session and give the client a response */
const int rule_count = tr_blocklistSetContent( session, filename );
tr_bencDictAddInt( data->args_out, "blocklist-size", rule_count );
tr_snprintf( result, sizeof( result ), "success" );
}
/* cleanup */
unlink( filename );
tr_free( filename );
}
@ -1160,8 +1197,7 @@ blocklistUpdate( tr_session * session,
tr_benc * args_out UNUSED,
struct tr_rpc_idle_data * idle_data )
{
const char * url = "http://update.transmissionbt.com/level1";
tr_webRun( session, url, NULL, gotNewBlocklist, idle_data );
tr_webRun( session, session->blocklist_url, NULL, gotNewBlocklist, idle_data );
return NULL;
}
@ -1408,6 +1444,8 @@ sessionSet( tr_session * session,
tr_sessionUseAltSpeedTime( session, boolVal );
if( tr_bencDictFindBool( args_in, TR_PREFS_KEY_BLOCKLIST_ENABLED, &boolVal ) )
tr_blocklistSetEnabled( session, boolVal );
if( tr_bencDictFindStr( args_in, TR_PREFS_KEY_BLOCKLIST_URL, &str ) )
tr_blocklistSetURL( session, str );
if( tr_bencDictFindStr( args_in, TR_PREFS_KEY_DOWNLOAD_DIR, &str ) )
tr_sessionSetDownloadDir( session, str );
if( tr_bencDictFindStr( args_in, TR_PREFS_KEY_INCOMPLETE_DIR, &str ) )
@ -1535,6 +1573,7 @@ sessionGet( tr_session * s,
tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_DAY,tr_sessionGetAltSpeedDay(s) );
tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, tr_sessionUsesAltSpeedTime(s) );
tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, tr_blocklistIsEnabled( s ) );
tr_bencDictAddStr ( d, TR_PREFS_KEY_BLOCKLIST_URL, tr_blocklistGetURL( s ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, tr_sessionGetCacheLimit_MB( s ) );
tr_bencDictAddInt ( d, "blocklist-size", tr_blocklistGetRuleCount( s ) );
tr_bencDictAddStr ( d, "config-dir", tr_sessionGetConfigDir( s ) );

View File

@ -248,6 +248,7 @@ tr_sessionGetDefaultSettings( const char * configDir UNUSED, tr_benc * d )
tr_bencDictReserve( d, 60 );
tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, FALSE );
tr_bencDictAddStr ( d, TR_PREFS_KEY_BLOCKLIST_URL, "http://www.example.com/blocklist" );
tr_bencDictAddInt ( d, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, DEFAULT_CACHE_SIZE_MB );
tr_bencDictAddBool( d, TR_PREFS_KEY_DHT_ENABLED, TRUE );
tr_bencDictAddBool( d, TR_PREFS_KEY_LPD_ENABLED, FALSE );
@ -309,6 +310,7 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
tr_bencDictReserve( d, 60 );
tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, tr_blocklistIsEnabled( s ) );
tr_bencDictAddStr ( d, TR_PREFS_KEY_BLOCKLIST_URL, tr_blocklistGetURL( s ) );
tr_bencDictAddInt ( d, TR_PREFS_KEY_MAX_CACHE_SIZE_MB, tr_sessionGetCacheLimit_MB( s ) );
tr_bencDictAddBool( d, TR_PREFS_KEY_DHT_ENABLED, s->isDHTEnabled );
tr_bencDictAddBool( d, TR_PREFS_KEY_LPD_ENABLED, s->isLPDEnabled );
@ -685,6 +687,8 @@ sessionSetImpl( void * vdata )
session->peer_congestion_algorithm = tr_strdup(str);
if( tr_bencDictFindBool( settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, &boolVal ) )
tr_blocklistSetEnabled( session, boolVal );
if( tr_bencDictFindStr( settings, TR_PREFS_KEY_BLOCKLIST_URL, &str ) )
tr_blocklistSetURL( session, str );
if( tr_bencDictFindBool( settings, TR_PREFS_KEY_START, &boolVal ) )
tr_sessionSetPaused( session, !boolVal );
if( tr_bencDictFindBool( settings, TR_PREFS_KEY_TRASH_ORIGINAL, &boolVal) )
@ -1755,6 +1759,7 @@ tr_sessionClose( tr_session * session )
tr_free( session->torrentDir );
tr_free( session->downloadDir );
tr_free( session->incompleteDir );
tr_free( session->blocklist_url );
tr_free( session->peer_congestion_algorithm );
tr_free( session );
}
@ -2141,7 +2146,7 @@ tr_blocklistSetContent( tr_session * session,
tr_list * l;
int ruleCount;
tr_blocklist * b;
const char * defaultName = "level1.bin";
const char * defaultName = "blocklist.bin";
tr_sessionLock( session );
for( b = NULL, l = session->blocklists; !b && l; l = l->next )
@ -2176,6 +2181,23 @@ tr_sessionIsAddressBlocked( const tr_session * session,
return FALSE;
}
void
tr_blocklistSetURL( tr_session * session, const char * url )
{
if( session->blocklist_url != url )
{
tr_free( session->blocklist_url );
session->blocklist_url = tr_strdup( url );
}
}
const char *
tr_blocklistGetURL ( const tr_session * session )
{
return session->blocklist_url;
}
/***
****
***/

View File

@ -150,6 +150,8 @@ struct tr_session
char * torrentDir;
char * incompleteDir;
char * blocklist_url;
struct tr_list * blocklists;
struct tr_peerMgr * peerMgr;
struct tr_shared * shared;

View File

@ -157,6 +157,7 @@ const char* tr_getDefaultDownloadDir( void );
#define TR_PREFS_KEY_BIND_ADDRESS_IPV4 "bind-address-ipv4"
#define TR_PREFS_KEY_BIND_ADDRESS_IPV6 "bind-address-ipv6"
#define TR_PREFS_KEY_BLOCKLIST_ENABLED "blocklist-enabled"
#define TR_PREFS_KEY_BLOCKLIST_URL "blocklist-url"
#define TR_PREFS_KEY_MAX_CACHE_SIZE_MB "cache-size-mb"
#define TR_PREFS_KEY_DHT_ENABLED "dht-enabled"
#define TR_PREFS_KEY_LPD_ENABLED "lpd-enabled"
@ -778,14 +779,13 @@ void tr_freeMessageList( tr_msg_list * freeme );
/**
* Specify a range of IPs for Transmission to block.
*
* filename must be an uncompressed ascii file,
* using the same format as the bluetack level1 file.
* Filename must be an uncompressed ascii file.
*
* libtransmission does not keep a handle to `filename'
* after this call returns, so the caller is free to
* keep or delete `filename' as it wishes.
* libtransmission makes its own copy of the file
* massaged into a format easier to search.
* massaged into a binary format easier to search.
*
* The caller only needs to invoke this when the blocklist
* has changed.
@ -804,6 +804,12 @@ tr_bool tr_blocklistIsEnabled ( const tr_session * session );
void tr_blocklistSetEnabled ( tr_session * session,
tr_bool isEnabled );
/** @brief The blocklist that ges updated when an RPC client
invokes the "blocklist-update" method */
void tr_blocklistSetURL ( tr_session *, const char * url );
const char * tr_blocklistGetURL ( const tr_session * );
/** @} */

View File

@ -458,21 +458,34 @@ PrefsDialog :: encryptionEdited( int i )
QWidget *
PrefsDialog :: createPrivacyTab( )
{
QWidget * w;
HIG * hig = new HIG( this );
hig->addSectionTitle( tr( "Blocklist" ) );
QHBoxLayout * h = new QHBoxLayout( );
QWidget * w = new QPushButton( tr( "&Update" ) );
QWidget * l = checkBoxNew( "Enable &blocklist:", Prefs::BLOCKLIST_ENABLED );
QWidget * e = lineEditNew( Prefs::BLOCKLIST_URL );
myBlockWidgets << e;
hig->addRow( l, e );
l = myBlocklistLabel = new QLabel( "" );
myBlockWidgets << l;
w = new QPushButton( tr( "&Update" ) );
connect( w, SIGNAL(clicked(bool)), this, SLOT(onUpdateBlocklistClicked()));
myBlockWidgets << w;
QWidget * l = checkBoxNew( "", Prefs::BLOCKLIST_ENABLED );
QHBoxLayout * h = new QHBoxLayout( );
h->addWidget( l );
h->addStretch( 1 );
h->addWidget( w );
hig->addWideControl( h );
l = checkBoxNew( tr( "Enable &automatic updates" ), Prefs::BLOCKLIST_UPDATES_ENABLED );
myBlockWidgets << l;
hig->addWideControl( l );
hig->addSectionDivider( );
hig->addSectionTitle( tr( "Privacy" ) );
QComboBox * box = new QComboBox( );
box->addItem( tr( "Allow encryption" ), 0 );
box->addItem( tr( "Prefer encryption" ), 1 );
@ -480,8 +493,6 @@ PrefsDialog :: createPrivacyTab( )
myWidgets.insert( Prefs :: ENCRYPTION, box );
connect( box, SIGNAL(activated(int)), this, SLOT(encryptionEdited(int)));
hig->addSectionDivider( );
hig->addSectionTitle( tr( "Privacy" ) );
hig->addRow( tr( "&Encryption mode:" ), box );
hig->addWideControl( w = checkBoxNew( tr( "Use PE&X to find more peers" ), Prefs::PEX_ENABLED ) );
w->setToolTip( tr( "PEX is a tool for exchanging peer lists with the peers you're connected to." ) );
@ -491,7 +502,7 @@ PrefsDialog :: createPrivacyTab( )
w->setToolTip( tr( "LPD is a tool for finding peers on your local network." ) );
hig->finish( );
updateBlocklistCheckBox( );
updateBlocklistLabel( );
return hig;
}
@ -691,18 +702,14 @@ PrefsDialog :: setPref( int key, const QVariant& v )
void
PrefsDialog :: sessionUpdated( )
{
updateBlocklistCheckBox( );
updateBlocklistLabel( );
}
void
PrefsDialog :: updateBlocklistCheckBox( )
PrefsDialog :: updateBlocklistLabel( )
{
QCheckBox * box = qobject_cast<QCheckBox*>( myWidgets[Prefs::BLOCKLIST_ENABLED] );
const int n = mySession.blocklistSize( );
if( n < 0 ) // unknown
box->setText( tr( "Enable &blocklist" ) );
else
box->setText( tr( "Enable &blocklist (%Ln rules)", 0, n ) );
myBlocklistLabel->setText( tr( "<i>Blocklist contains %Ln rules)", 0, n ) );
}
void

View File

@ -70,7 +70,7 @@ class PrefsDialog: public QDialog
QTimeEdit * timeEditNew( int key );
QLineEdit * lineEditNew( int key, int mode = 0 );
void enableBuddyWhenChecked( QCheckBox *, QWidget * );
void updateBlocklistCheckBox( );
void updateBlocklistLabel( );
public:
PrefsDialog( Session&, Prefs&, QWidget * parent = 0 );
@ -114,6 +114,7 @@ class PrefsDialog: public QDialog
int myBlocklistHttpTag;
QHttp * myBlocklistHttp;
QMessageBox * myBlocklistDialog;
QLabel * myBlocklistLabel;
};
#endif

View File

@ -75,6 +75,7 @@ Prefs::PrefItem Prefs::myItems[] =
{ ALT_SPEED_LIMIT_TIME_ENABLED, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, QVariant::Bool },
{ ALT_SPEED_LIMIT_TIME_DAY, TR_PREFS_KEY_ALT_SPEED_TIME_DAY, QVariant::Int },
{ BLOCKLIST_ENABLED, TR_PREFS_KEY_BLOCKLIST_ENABLED, QVariant::Bool },
{ BLOCKLIST_URL, TR_PREFS_KEY_BLOCKLIST_URL, QVariant::String },
{ DSPEED, TR_PREFS_KEY_DSPEED_KBps, QVariant::Int },
{ DSPEED_ENABLED, TR_PREFS_KEY_DSPEED_ENABLED, QVariant::Bool },
{ DOWNLOAD_DIR, TR_PREFS_KEY_DOWNLOAD_DIR, QVariant::String },

View File

@ -80,6 +80,7 @@ class Prefs: public QObject
ALT_SPEED_LIMIT_TIME_ENABLED,
ALT_SPEED_LIMIT_TIME_DAY,
BLOCKLIST_ENABLED,
BLOCKLIST_URL,
DSPEED,
DSPEED_ENABLED,
DOWNLOAD_DIR,

View File

@ -141,6 +141,7 @@ Session :: updatePref( int key )
case Prefs :: ALT_SPEED_LIMIT_UP:
case Prefs :: BLOCKLIST_DATE:
case Prefs :: BLOCKLIST_ENABLED:
case Prefs :: BLOCKLIST_URL:
case Prefs :: DHT_ENABLED:
case Prefs :: DOWNLOAD_DIR:
case Prefs :: DSPEED: