From da2ef53eeb184ff65e1688fb6c95d2f0788b2cd6 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sat, 8 May 2010 22:42:28 +0000 Subject: [PATCH] (trunk) #1796 "run script after torrent completion" -- implemented for libT, RPC, and the GTK+ and Qt clients --- configure.ac | 2 +- doc/rpc-spec.txt | 2 + gtk/main.c | 16 ++-- gtk/tr-prefs.c | 43 ++++++---- libtransmission/rpcimpl.c | 6 ++ libtransmission/session.c | 55 +++++++++++++ libtransmission/session.h | 3 + libtransmission/torrent.c | 31 +++++++ libtransmission/transmission.h | 145 ++++++++++++++++++--------------- qt/prefs-dialog.cc | 33 +++++++- qt/prefs-dialog.h | 4 + qt/prefs.cc | 2 + qt/prefs.h | 2 + qt/session.cc | 26 +++--- 14 files changed, 271 insertions(+), 99 deletions(-) diff --git a/configure.ac b/configure.ac index 8af18ef53..de6e7e945 100644 --- a/configure.ac +++ b/configure.ac @@ -108,7 +108,7 @@ fi AC_HEADER_STDC AC_HEADER_TIME -AC_CHECK_FUNCS([pread pwrite lrintf strlcpy daemon dirname basename strcasecmp localtime_r fallocate64 posix_fallocate memmem strtold syslog valloc getpagesize posix_memalign]) +AC_CHECK_FUNCS([pread pwrite lrintf strlcpy daemon dirname basename strcasecmp localtime_r fallocate64 posix_fallocate memmem strtold syslog valloc getpagesize posix_memalign clearenv]) AC_PROG_INSTALL AC_PROG_MAKE_SET ACX_PTHREAD diff --git a/doc/rpc-spec.txt b/doc/rpc-spec.txt index 110c6ea36..7d136ea1e 100644 --- a/doc/rpc-spec.txt +++ b/doc/rpc-spec.txt @@ -415,6 +415,8 @@ "rename-partial-files" | boolean true means append ".part" to incomplete files "rpc-version" | number the current RPC API version "rpc-version-minimum" | number the minimum RPC API version supported + "script-torrent-done-filename"| string filename of the script to run + "script-torrent-done-enabled" | boolean whether or not to call the "done" script "seedRatioLimit" | double the default seed ratio for torrents to use "seedRatioLimited" | boolean true if seedRatioLimit is honored by default "speed-limit-down" | number max global download speed (in K/s) diff --git a/gtk/main.c b/gtk/main.c index 1204d7510..2e841ed84 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1144,12 +1144,10 @@ onAddTorrent( TrCore * core, } static void -prefschanged( TrCore * core UNUSED, - const char * key, - gpointer data ) +prefschanged( TrCore * core UNUSED, const char * key, gpointer data ) { - struct cbdata * cbdata = data; - tr_session * tr = tr_core_session( cbdata->core ); + struct cbdata * cbdata = data; + tr_session * tr = tr_core_session( cbdata->core ); if( !strcmp( key, TR_PREFS_KEY_ENCRYPTION ) ) { @@ -1323,6 +1321,14 @@ prefschanged( TrCore * core UNUSED, { tr_sessionSetIncompleteDirEnabled( tr, pref_flag_get( key ) ); } + else if( !strcmp( key, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED ) ) + { + tr_sessionSetTorrentDoneScriptEnabled( tr, pref_flag_get( key ) ); + } + else if( !strcmp( key, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME ) ) + { + tr_sessionSetTorrentDoneScript( tr, pref_string_get( key ) ); + } else if( !strcmp( key, TR_PREFS_KEY_START) ) { tr_sessionSetPaused( tr, !pref_flag_get( key ) ); diff --git a/gtk/tr-prefs.c b/gtk/tr-prefs.c index 6742c5efe..7dc1d7a16 100644 --- a/gtk/tr-prefs.c +++ b/gtk/tr-prefs.c @@ -223,29 +223,35 @@ new_entry( const char * key, } static void -chosen_cb( GtkFileChooser * w, - gpointer core ) +chosen_cb( GtkFileChooser * w, gpointer core ) { const char * key = g_object_get_data( G_OBJECT( w ), PREF_KEY ); - char * value = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( w ) ); - + char * value = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( w ) ); tr_core_set_pref( TR_CORE( core ), key, value ); g_free( value ); } static GtkWidget* -new_path_chooser_button( const char * key, - gpointer core ) +new_path_chooser_button( const char * key, gpointer core ) { - GtkWidget * w = gtk_file_chooser_button_new( - NULL, - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ); + GtkWidget * w = gtk_file_chooser_button_new( NULL, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ); const char * path = pref_string_get( key ); - - g_object_set_data_full( G_OBJECT( w ), PREF_KEY, g_strdup( - key ), g_free ); + g_object_set_data_full( G_OBJECT( w ), PREF_KEY, g_strdup( key ), g_free ); + g_signal_connect( w, "selection-changed", G_CALLBACK( chosen_cb ), core ); + if( path != NULL ) + gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), path ); + return w; +} + +static GtkWidget* +new_file_chooser_button( const char * key, gpointer core ) +{ + GtkWidget * w = gtk_file_chooser_button_new( NULL, GTK_FILE_CHOOSER_ACTION_OPEN ); + const char * path = pref_string_get( key ); + g_object_set_data_full( G_OBJECT( w ), PREF_KEY, g_strdup( key ), g_free ); + if( path != NULL ) + gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), path ); g_signal_connect( w, "selection-changed", G_CALLBACK( chosen_cb ), core ); - gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( w ), path ); return w; } @@ -301,6 +307,9 @@ torrentPage( GObject * core ) w = new_check_button( s, TR_PREFS_KEY_RENAME_PARTIAL_FILES, core ); hig_workarea_add_wide_control( t, &row, w ); + w = new_path_chooser_button( TR_PREFS_KEY_DOWNLOAD_DIR, core ); + hig_workarea_add_row( t, &row, _( "Save to _Location:" ), w, NULL ); + s = _( "Keep _incomplete torrents in:" ); l = new_check_button( s, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, core ); w = new_path_chooser_button( TR_PREFS_KEY_INCOMPLETE_DIR, core ); @@ -308,8 +317,12 @@ torrentPage( GObject * core ) g_signal_connect( l, "toggled", G_CALLBACK( target_cb ), w ); hig_workarea_add_row_w( t, &row, l, w, NULL ); - w = new_path_chooser_button( TR_PREFS_KEY_DOWNLOAD_DIR, core ); - hig_workarea_add_row( t, &row, _( "Save to _Location:" ), w, NULL ); + s = _( "Call scrip_t when torrent is completed:" ); + l = new_check_button( s, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, core ); + w = new_file_chooser_button( TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, core ); + gtk_widget_set_sensitive( GTK_WIDGET( w ), pref_flag_get( TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED ) ); + g_signal_connect( l, "toggled", G_CALLBACK( target_cb ), w ); + hig_workarea_add_row_w( t, &row, l, w, NULL ); hig_workarea_add_section_divider( t, &row ); hig_workarea_add_section_title( t, &row, _( "Limits" ) ); diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index 900bb7b22..f4464c680 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -1230,6 +1230,10 @@ sessionSet( tr_session * session, tr_sessionSetRatioLimited( session, boolVal ); if( tr_bencDictFindBool( args_in, TR_PREFS_KEY_START, &boolVal ) ) tr_sessionSetPaused( session, !boolVal ); + if( tr_bencDictFindStr( args_in, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, &str ) ) + tr_sessionSetTorrentDoneScript( session, str ); + if( tr_bencDictFindBool( args_in, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, &boolVal ) ) + tr_sessionSetTorrentDoneScriptEnabled( session, boolVal ); if( tr_bencDictFindBool( args_in, TR_PREFS_KEY_TRASH_ORIGINAL, &boolVal ) ) tr_sessionSetDeleteSource( session, boolVal ); if( tr_bencDictFindInt( args_in, TR_PREFS_KEY_DSPEED, &i ) ) @@ -1343,6 +1347,8 @@ sessionGet( tr_session * s, tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, tr_sessionIsSpeedLimited( s, TR_UP ) ); tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED, tr_sessionGetSpeedLimit( s, TR_DOWN ) ); tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED, tr_sessionIsSpeedLimited( s, TR_DOWN ) ); + tr_bencDictAddStr ( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, tr_sessionGetTorrentDoneScript( s ) ); + tr_bencDictAddBool( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, tr_sessionIsTorrentDoneScriptEnabled( s ) ); tr_bencDictAddStr ( d, "version", LONG_VERSION_STRING ); switch( tr_sessionGetEncryption( s ) ) { case TR_CLEAR_PREFERRED: str = "tolerated"; break; diff --git a/libtransmission/session.c b/libtransmission/session.c index 32d01bb5e..b24ac7a2d 100644 --- a/libtransmission/session.c +++ b/libtransmission/session.c @@ -283,6 +283,8 @@ tr_sessionGetDefaultSettings( const char * configDir UNUSED, tr_benc * d ) tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST, TR_DEFAULT_RPC_WHITELIST ); tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, TRUE ); tr_bencDictAddInt ( d, TR_PREFS_KEY_RPC_PORT, atoi( TR_DEFAULT_RPC_PORT_STR ) ); + tr_bencDictAddStr ( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, "" ); + tr_bencDictAddBool( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, FALSE ); tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_ENABLED, FALSE ); tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_UP, 50 ); /* half the regular */ tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_DOWN, 50 ); /* half the regular */ @@ -348,6 +350,8 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d ) tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_USERNAME, tr_sessionGetRPCUsername( s ) ); tr_bencDictAddStr ( d, TR_PREFS_KEY_RPC_WHITELIST, tr_sessionGetRPCWhitelist( s ) ); tr_bencDictAddBool( d, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, tr_sessionGetRPCWhitelistEnabled( s ) ); + tr_bencDictAddBool( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, tr_sessionIsTorrentDoneScriptEnabled( s ) ); + tr_bencDictAddStr ( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, tr_sessionGetTorrentDoneScript( s ) ); tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_ENABLED, tr_sessionUsesAltSpeed( s ) ); tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_UP, tr_sessionGetAltSpeed( s, TR_UP ) ); tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_DOWN, tr_sessionGetAltSpeed( s, TR_DOWN ) ); @@ -802,6 +806,15 @@ sessionSetImpl( void * vdata ) turtle->isEnabled = boolVal; turtleBootstrap( session, turtle ); + /** + *** Scripts + **/ + + if( tr_bencDictFindBool( settings, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, &boolVal ) ) + tr_sessionSetTorrentDoneScriptEnabled( session, boolVal ); + if( tr_bencDictFindStr( settings, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, &str ) ) + tr_sessionSetTorrentDoneScript( session, str ); + data->done = TRUE; } @@ -1669,6 +1682,7 @@ tr_sessionClose( tr_session * session ) tr_bencFree( session->metainfoLookup ); tr_free( session->metainfoLookup ); } + tr_free( session->torrentDoneScript ); tr_free( session->buffer ); tr_free( session->tag ); tr_free( session->configDir ); @@ -2431,3 +2445,44 @@ tr_sessionSetProxyPassword( tr_session * session, session->proxyPassword = tr_strdup( password ); } } + +/**** +***** +****/ + +tr_bool +tr_sessionIsTorrentDoneScriptEnabled( const tr_session * session ) +{ + assert( tr_isSession( session ) ); + + return session->isTorrentDoneScriptEnabled; +} + +void +tr_sessionSetTorrentDoneScriptEnabled( tr_session * session, tr_bool isEnabled ) +{ + assert( tr_isSession( session ) ); + assert( tr_isBool( isEnabled ) ); + + session->isTorrentDoneScriptEnabled = isEnabled; +} + +const char * +tr_sessionGetTorrentDoneScript( const tr_session * session ) +{ + assert( tr_isSession( session ) ); + + return session->torrentDoneScript; +} + +void +tr_sessionSetTorrentDoneScript( tr_session * session, const char * scriptFilename ) +{ + assert( tr_isSession( session ) ); + + if( session->torrentDoneScript != scriptFilename ) + { + tr_free( session->torrentDoneScript ); + session->torrentDoneScript = tr_strdup( scriptFilename ); + } +} diff --git a/libtransmission/session.h b/libtransmission/session.h index a01b2e7dd..d7cdf3e5b 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -88,6 +88,7 @@ struct tr_session tr_bool isBlocklistEnabled; tr_bool isProxyEnabled; tr_bool isProxyAuthEnabled; + tr_bool isTorrentDoneScriptEnabled; tr_bool isClosed; tr_bool useLazyBitfield; tr_bool isIncompleteFileNamingEnabled; @@ -130,6 +131,8 @@ struct tr_session int torrentCount; tr_torrent * torrentList; + char * torrentDoneScript; + char * tag; char * configDir; char * downloadDir; diff --git a/libtransmission/torrent.c b/libtransmission/torrent.c index 62034c581..fc9725a24 100644 --- a/libtransmission/torrent.c +++ b/libtransmission/torrent.c @@ -1689,6 +1689,34 @@ tr_torrentClearRatioLimitHitCallback( tr_torrent * torrent ) tr_torrentSetRatioLimitHitCallback( torrent, NULL, NULL ); } + +static void +torrentCallScript( tr_torrent * tor, const char * script ) +{ + assert( tr_isTorrent( tor ) ); + + if( script && *script ) + { + char buf[128]; + const time_t now = tr_time( ); + +#ifdef HAVE_CLEARENV + clearenv( ); +#endif + + tr_snprintf( buf, sizeof( buf ), "%d", tr_torrentId( tor ) ); + setenv( "TR_TORRENT_ID", buf, 1 ); + setenv( "TR_TORRENT_NAME", tr_torrentName( tor ), 1 ); + setenv( "TR_TORRENT_DIR", tor->currentDir, 1 ); + setenv( "TR_TORRENT_HASH", tor->info.hashString, 1 ); + ctime_r( &now, buf ); + *strchr( buf,'\n' ) = '\0'; + setenv( "TR_TIME_LOCALTIME", buf, 1 ); + tr_torinf( tor, "Calling script \"%s\"", script ); + system( script ); + } +} + void tr_torrentRecheckCompleteness( tr_torrent * tor ) { @@ -1720,6 +1748,9 @@ tr_torrentRecheckCompleteness( tr_torrent * tor ) if( tor->currentDir == tor->incompleteDir ) tr_torrentSetLocation( tor, tor->downloadDir, TRUE, NULL, NULL ); + + if( tr_sessionIsTorrentDoneScriptEnabled( tor->session ) ) + torrentCallScript( tor, tr_sessionGetTorrentDoneScript( tor->session ) ); } fireCompletenessChange( tor, completeness ); diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index eb3f45a09..091b19175 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -143,72 +143,74 @@ const char* tr_getDefaultConfigDir( const char * appname ); const char* tr_getDefaultDownloadDir( void ); -#define TR_DEFAULT_BIND_ADDRESS_IPV4 "0.0.0.0" -#define TR_DEFAULT_BIND_ADDRESS_IPV6 "::" -#define TR_DEFAULT_OPEN_FILE_LIMIT_STR "32" -#define TR_DEFAULT_RPC_WHITELIST "127.0.0.1" -#define TR_DEFAULT_RPC_PORT_STR "9091" -#define TR_DEFAULT_PEER_PORT_STR "51413" -#define TR_DEFAULT_PEER_SOCKET_TOS_STR "0" -#define TR_DEFAULT_PEER_LIMIT_GLOBAL_STR "240" -#define TR_DEFAULT_PEER_LIMIT_TORRENT_STR "60" +#define TR_DEFAULT_BIND_ADDRESS_IPV4 "0.0.0.0" +#define TR_DEFAULT_BIND_ADDRESS_IPV6 "::" +#define TR_DEFAULT_OPEN_FILE_LIMIT_STR "32" +#define TR_DEFAULT_RPC_WHITELIST "127.0.0.1" +#define TR_DEFAULT_RPC_PORT_STR "9091" +#define TR_DEFAULT_PEER_PORT_STR "51413" +#define TR_DEFAULT_PEER_SOCKET_TOS_STR "0" +#define TR_DEFAULT_PEER_LIMIT_GLOBAL_STR "240" +#define TR_DEFAULT_PEER_LIMIT_TORRENT_STR "60" -#define TR_PREFS_KEY_ALT_SPEED_ENABLED "alt-speed-enabled" -#define TR_PREFS_KEY_ALT_SPEED_UP "alt-speed-up" -#define TR_PREFS_KEY_ALT_SPEED_DOWN "alt-speed-down" -#define TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN "alt-speed-time-begin" -#define TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED "alt-speed-time-enabled" -#define TR_PREFS_KEY_ALT_SPEED_TIME_END "alt-speed-time-end" -#define TR_PREFS_KEY_ALT_SPEED_TIME_DAY "alt-speed-time-day" -#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_DHT_ENABLED "dht-enabled" -#define TR_PREFS_KEY_LPD_ENABLED "lpd-enabled" -#define TR_PREFS_KEY_DOWNLOAD_DIR "download-dir" -#define TR_PREFS_KEY_ENCRYPTION "encryption" -#define TR_PREFS_KEY_INCOMPLETE_DIR "incomplete-dir" -#define TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED "incomplete-dir-enabled" -#define TR_PREFS_KEY_LAZY_BITFIELD "lazy-bitfield-enabled" -#define TR_PREFS_KEY_MSGLEVEL "message-level" -#define TR_PREFS_KEY_OPEN_FILE_LIMIT "open-file-limit" -#define TR_PREFS_KEY_PEER_LIMIT_GLOBAL "peer-limit-global" -#define TR_PREFS_KEY_PEER_LIMIT_TORRENT "peer-limit-per-torrent" -#define TR_PREFS_KEY_PEER_PORT "peer-port" -#define TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START "peer-port-random-on-start" -#define TR_PREFS_KEY_PEER_PORT_RANDOM_LOW "peer-port-random-low" -#define TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH "peer-port-random-high" -#define TR_PREFS_KEY_PEER_SOCKET_TOS "peer-socket-tos" -#define TR_PREFS_KEY_PEER_CONGESTION_ALGORITHM "peer-congestion-algorithm" -#define TR_PREFS_KEY_PEX_ENABLED "pex-enabled" -#define TR_PREFS_KEY_PORT_FORWARDING "port-forwarding-enabled" -#define TR_PREFS_KEY_PROXY_AUTH_ENABLED "proxy-auth-enabled" -#define TR_PREFS_KEY_PREALLOCATION "preallocation" -#define TR_PREFS_KEY_PROXY_ENABLED "proxy-enabled" -#define TR_PREFS_KEY_PROXY_PASSWORD "proxy-auth-password" -#define TR_PREFS_KEY_PROXY_PORT "proxy-port" -#define TR_PREFS_KEY_PROXY "proxy" -#define TR_PREFS_KEY_PROXY_TYPE "proxy-type" -#define TR_PREFS_KEY_PROXY_USERNAME "proxy-auth-username" -#define TR_PREFS_KEY_RATIO "ratio-limit" -#define TR_PREFS_KEY_RATIO_ENABLED "ratio-limit-enabled" -#define TR_PREFS_KEY_RENAME_PARTIAL_FILES "rename-partial-files" -#define TR_PREFS_KEY_RPC_AUTH_REQUIRED "rpc-authentication-required" -#define TR_PREFS_KEY_RPC_BIND_ADDRESS "rpc-bind-address" -#define TR_PREFS_KEY_RPC_ENABLED "rpc-enabled" -#define TR_PREFS_KEY_RPC_PASSWORD "rpc-password" -#define TR_PREFS_KEY_RPC_PORT "rpc-port" -#define TR_PREFS_KEY_RPC_USERNAME "rpc-username" -#define TR_PREFS_KEY_RPC_WHITELIST_ENABLED "rpc-whitelist-enabled" -#define TR_PREFS_KEY_RPC_WHITELIST "rpc-whitelist" -#define TR_PREFS_KEY_DSPEED "speed-limit-down" -#define TR_PREFS_KEY_DSPEED_ENABLED "speed-limit-down-enabled" -#define TR_PREFS_KEY_USPEED_ENABLED "speed-limit-up-enabled" -#define TR_PREFS_KEY_USPEED "speed-limit-up" -#define TR_PREFS_KEY_UMASK "umask" -#define TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT "upload-slots-per-torrent" -#define TR_PREFS_KEY_START "start-added-torrents" -#define TR_PREFS_KEY_TRASH_ORIGINAL "trash-original-torrent-files" +#define TR_PREFS_KEY_ALT_SPEED_ENABLED "alt-speed-enabled" +#define TR_PREFS_KEY_ALT_SPEED_UP "alt-speed-up" +#define TR_PREFS_KEY_ALT_SPEED_DOWN "alt-speed-down" +#define TR_PREFS_KEY_ALT_SPEED_TIME_BEGIN "alt-speed-time-begin" +#define TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED "alt-speed-time-enabled" +#define TR_PREFS_KEY_ALT_SPEED_TIME_END "alt-speed-time-end" +#define TR_PREFS_KEY_ALT_SPEED_TIME_DAY "alt-speed-time-day" +#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_DHT_ENABLED "dht-enabled" +#define TR_PREFS_KEY_LPD_ENABLED "lpd-enabled" +#define TR_PREFS_KEY_DOWNLOAD_DIR "download-dir" +#define TR_PREFS_KEY_ENCRYPTION "encryption" +#define TR_PREFS_KEY_INCOMPLETE_DIR "incomplete-dir" +#define TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED "incomplete-dir-enabled" +#define TR_PREFS_KEY_LAZY_BITFIELD "lazy-bitfield-enabled" +#define TR_PREFS_KEY_MSGLEVEL "message-level" +#define TR_PREFS_KEY_OPEN_FILE_LIMIT "open-file-limit" +#define TR_PREFS_KEY_PEER_LIMIT_GLOBAL "peer-limit-global" +#define TR_PREFS_KEY_PEER_LIMIT_TORRENT "peer-limit-per-torrent" +#define TR_PREFS_KEY_PEER_PORT "peer-port" +#define TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START "peer-port-random-on-start" +#define TR_PREFS_KEY_PEER_PORT_RANDOM_LOW "peer-port-random-low" +#define TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH "peer-port-random-high" +#define TR_PREFS_KEY_PEER_SOCKET_TOS "peer-socket-tos" +#define TR_PREFS_KEY_PEER_CONGESTION_ALGORITHM "peer-congestion-algorithm" +#define TR_PREFS_KEY_PEX_ENABLED "pex-enabled" +#define TR_PREFS_KEY_PORT_FORWARDING "port-forwarding-enabled" +#define TR_PREFS_KEY_PROXY_AUTH_ENABLED "proxy-auth-enabled" +#define TR_PREFS_KEY_PREALLOCATION "preallocation" +#define TR_PREFS_KEY_PROXY_ENABLED "proxy-enabled" +#define TR_PREFS_KEY_PROXY_PASSWORD "proxy-auth-password" +#define TR_PREFS_KEY_PROXY_PORT "proxy-port" +#define TR_PREFS_KEY_PROXY "proxy" +#define TR_PREFS_KEY_PROXY_TYPE "proxy-type" +#define TR_PREFS_KEY_PROXY_USERNAME "proxy-auth-username" +#define TR_PREFS_KEY_RATIO "ratio-limit" +#define TR_PREFS_KEY_RATIO_ENABLED "ratio-limit-enabled" +#define TR_PREFS_KEY_RENAME_PARTIAL_FILES "rename-partial-files" +#define TR_PREFS_KEY_RPC_AUTH_REQUIRED "rpc-authentication-required" +#define TR_PREFS_KEY_RPC_BIND_ADDRESS "rpc-bind-address" +#define TR_PREFS_KEY_RPC_ENABLED "rpc-enabled" +#define TR_PREFS_KEY_RPC_PASSWORD "rpc-password" +#define TR_PREFS_KEY_RPC_PORT "rpc-port" +#define TR_PREFS_KEY_RPC_USERNAME "rpc-username" +#define TR_PREFS_KEY_RPC_WHITELIST_ENABLED "rpc-whitelist-enabled" +#define TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME "script-torrent-done-filename" +#define TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED "script-torrent-done-enabled" +#define TR_PREFS_KEY_RPC_WHITELIST "rpc-whitelist" +#define TR_PREFS_KEY_DSPEED "speed-limit-down" +#define TR_PREFS_KEY_DSPEED_ENABLED "speed-limit-down-enabled" +#define TR_PREFS_KEY_USPEED_ENABLED "speed-limit-up-enabled" +#define TR_PREFS_KEY_USPEED "speed-limit-up" +#define TR_PREFS_KEY_UMASK "umask" +#define TR_PREFS_KEY_UPLOAD_SLOTS_PER_TORRENT "upload-slots-per-torrent" +#define TR_PREFS_KEY_START "start-added-torrents" +#define TR_PREFS_KEY_TRASH_ORIGINAL "trash-original-torrent-files" /** @@ -747,6 +749,19 @@ tr_torrent ** tr_sessionLoadTorrents( tr_session * session, tr_ctor * ctor, int * setmeCount ); +/** +*** +**/ + +tr_bool tr_sessionIsTorrentDoneScriptEnabled( const tr_session * ); + +void tr_sessionSetTorrentDoneScriptEnabled( tr_session *, tr_bool isEnabled ); + +const char * tr_sessionGetTorrentDoneScript( const tr_session * ); + +void tr_sessionSetTorrentDoneScript( tr_session *, const char * scriptFilename ); + + /** @} */ /** diff --git a/qt/prefs-dialog.cc b/qt/prefs-dialog.cc index 9822be5d6..4bea6913d 100644 --- a/qt/prefs-dialog.cc +++ b/qt/prefs-dialog.cc @@ -489,6 +489,26 @@ PrefsDialog :: createPrivacyTab( ) **** ***/ +void +PrefsDialog :: onScriptClicked( void ) +{ + const QString title = tr( "Select \"Torrent Done\" Script" ); + const QString path = myPrefs.getString( Prefs::SCRIPT_TORRENT_DONE_FILENAME ); + QFileDialog * d = new QFileDialog( this, title, path ); + d->setFileMode( QFileDialog::ExistingFiles ); + connect( d, SIGNAL(filesSelected(const QStringList&)), + this, SLOT(onScriptSelected(const QStringList&)) ); + d->show( ); +} + +void +PrefsDialog :: onScriptSelected( const QStringList& list ) +{ + if( list.size() == 1 ) + myPrefs.set( Prefs::Prefs::SCRIPT_TORRENT_DONE_FILENAME, list.first( ) ); +} + + void PrefsDialog :: onIncompleteClicked( void ) { @@ -554,6 +574,8 @@ PrefsDialog :: createTorrentsTab( ) const QFileIconProvider iconProvider; const QIcon folderIcon = iconProvider.icon( QFileIconProvider::Folder ); const QPixmap folderPixmap = folderIcon.pixmap( iconSize ); + const QIcon fileIcon = iconProvider.icon( QFileIconProvider::File ); + const QPixmap filePixmap = fileIcon.pixmap( iconSize ); QWidget *l, *r; HIG * hig = new HIG( this ); @@ -572,12 +594,21 @@ PrefsDialog :: createTorrentsTab( ) hig->addWideControl( checkBoxNew( tr( "Mo&ve .torrent file to the trash" ), Prefs::TRASH_ORIGINAL ) ); hig->addWideControl( checkBoxNew( tr( "Append \".&part\" to incomplete files' names" ), Prefs::RENAME_PARTIAL_FILES ) ); - myIncompleteCheckbox = checkBoxNew( tr( "Keep &incomplete files in:" ), Prefs::INCOMPLETE_DIR_ENABLED ); + l = myIncompleteCheckbox = checkBoxNew( tr( "Keep &incomplete files in:" ), Prefs::INCOMPLETE_DIR_ENABLED ); b = myIncompleteButton = new QPushButton; b->setIcon( folderPixmap ); b->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" ); connect( b, SIGNAL(clicked(bool)), this, SLOT(onIncompleteClicked(void)) ); hig->addRow( myIncompleteCheckbox, b ); + enableBuddyWhenChecked( qobject_cast(l), b ); + + l = myTorrentDoneScriptCheckbox = checkBoxNew( tr( "Call scrip&t when torrent is completed" ), Prefs::SCRIPT_TORRENT_DONE_ENABLED ); + b = myTorrentDoneScriptFilename = new QPushButton; + b->setIcon( filePixmap ); + b->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" ); + connect( b, SIGNAL(clicked(bool)), this, SLOT(onScriptClicked(void)) ); + hig->addRow( myTorrentDoneScriptCheckbox, b ); + enableBuddyWhenChecked( qobject_cast(l), b ); b = myDestinationButton = new QPushButton; b->setIcon( folderPixmap ); diff --git a/qt/prefs-dialog.h b/qt/prefs-dialog.h index 80c2c97a6..9ab575207 100644 --- a/qt/prefs-dialog.h +++ b/qt/prefs-dialog.h @@ -52,6 +52,8 @@ class PrefsDialog: public QDialog void sessionUpdated( ); void onWatchClicked( ); void onWatchSelected( const QStringList& ); + void onScriptClicked( ); + void onScriptSelected( const QStringList& ); void onIncompleteClicked( ); void onIncompleteSelected( const QStringList& ); void onDestinationClicked( ); @@ -96,6 +98,8 @@ class PrefsDialog: public QDialog QLabel * myPortLabel; QPushButton * myPortButton; QPushButton * myWatchButton; + QPushButton * myTorrentDoneScriptFilename; + QCheckBox * myTorrentDoneScriptCheckbox; QCheckBox * myIncompleteCheckbox; QPushButton * myIncompleteButton; QPushButton * myDestinationButton; diff --git a/qt/prefs.cc b/qt/prefs.cc index 0ee94d457..73b94ea6f 100644 --- a/qt/prefs.cc +++ b/qt/prefs.cc @@ -88,6 +88,8 @@ Prefs::PrefItem Prefs::myItems[] = { PEER_PORT_RANDOM_ON_START, TR_PREFS_KEY_PEER_PORT_RANDOM_ON_START, QVariant::Bool }, { PEER_PORT_RANDOM_LOW, TR_PREFS_KEY_PEER_PORT_RANDOM_LOW, QVariant::Int }, { PEER_PORT_RANDOM_HIGH, TR_PREFS_KEY_PEER_PORT_RANDOM_HIGH, QVariant::Int }, + { SCRIPT_TORRENT_DONE_ENABLED, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, QVariant::Bool }, + { SCRIPT_TORRENT_DONE_FILENAME, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, QVariant::String }, { SOCKET_TOS, TR_PREFS_KEY_PEER_SOCKET_TOS, QVariant::Int }, { START, TR_PREFS_KEY_START, QVariant::Bool }, { TRASH_ORIGINAL, TR_PREFS_KEY_TRASH_ORIGINAL, QVariant::Bool }, diff --git a/qt/prefs.h b/qt/prefs.h index 8f3d415de..01aeb5d0a 100644 --- a/qt/prefs.h +++ b/qt/prefs.h @@ -92,6 +92,8 @@ class Prefs: public QObject PEER_PORT_RANDOM_ON_START, PEER_PORT_RANDOM_LOW, PEER_PORT_RANDOM_HIGH, + SCRIPT_TORRENT_DONE_ENABLED, + SCRIPT_TORRENT_DONE_FILENAME, SOCKET_TOS, START, TRASH_ORIGINAL, diff --git a/qt/session.cc b/qt/session.cc index 25c5e6f5b..2b10432f1 100644 --- a/qt/session.cc +++ b/qt/session.cc @@ -128,32 +128,34 @@ Session :: updatePref( int key ) { if( myPrefs.isCore( key ) ) switch( key ) { - case Prefs :: ALT_SPEED_LIMIT_UP: case Prefs :: ALT_SPEED_LIMIT_DOWN: case Prefs :: ALT_SPEED_LIMIT_ENABLED: case Prefs :: ALT_SPEED_LIMIT_TIME_BEGIN: - case Prefs :: ALT_SPEED_LIMIT_TIME_END: - case Prefs :: ALT_SPEED_LIMIT_TIME_ENABLED: case Prefs :: ALT_SPEED_LIMIT_TIME_DAY: - case Prefs :: BLOCKLIST_ENABLED: + case Prefs :: ALT_SPEED_LIMIT_TIME_ENABLED: + case Prefs :: ALT_SPEED_LIMIT_TIME_END: + case Prefs :: ALT_SPEED_LIMIT_UP: case Prefs :: BLOCKLIST_DATE: + case Prefs :: BLOCKLIST_ENABLED: case Prefs :: DHT_ENABLED: case Prefs :: DOWNLOAD_DIR: + case Prefs :: DSPEED: + case Prefs :: DSPEED_ENABLED: case Prefs :: INCOMPLETE_DIR: case Prefs :: INCOMPLETE_DIR_ENABLED: case Prefs :: LPD_ENABLED: case Prefs :: PEER_LIMIT_GLOBAL: case Prefs :: PEER_LIMIT_TORRENT: - case Prefs :: USPEED_ENABLED: - case Prefs :: USPEED: - case Prefs :: DSPEED_ENABLED: - case Prefs :: DSPEED: - case Prefs :: START: - case Prefs :: TRASH_ORIGINAL: - case Prefs :: PEX_ENABLED: - case Prefs :: PORT_FORWARDING: case Prefs :: PEER_PORT: case Prefs :: PEER_PORT_RANDOM_ON_START: + case Prefs :: PEX_ENABLED: + case Prefs :: PORT_FORWARDING: + case Prefs :: SCRIPT_TORRENT_DONE_ENABLED: + case Prefs :: SCRIPT_TORRENT_DONE_FILENAME: + case Prefs :: START: + case Prefs :: TRASH_ORIGINAL: + case Prefs :: USPEED: + case Prefs :: USPEED_ENABLED: sessionSet( myPrefs.keyStr(key), myPrefs.variant(key) ); break;