27
27
#include <gtk/gtk.h>
28
28
#include <glib/gi18n.h>
33
#include <dbus/dbus-glib.h>
33
36
#include <libtransmission/transmission.h>
37
#include <libtransmission/bencode.h>
38
#include <libtransmission/rpcimpl.h>
39
#include <libtransmission/json.h>
34
40
#include <libtransmission/utils.h> /* tr_free */
37
43
#include "tr-core.h"
45
#include "tr-core-dbus.h"
38
47
#include "tr-prefs.h"
39
48
#include "tr-torrent.h"
52
static void maybeInhibitHibernation( TrCore * core );
54
static gboolean our_instance_adds_remote_torrents = FALSE;
42
56
struct TrCorePrivate
45
GFileMonitor * monitor;
48
GSList * monitor_files;
49
guint monitor_idle_tag;
59
GFileMonitor * monitor;
62
GSList * monitor_files;
63
guint monitor_idle_tag;
65
gboolean adding_from_watch_dir;
66
gboolean inhibit_allowed;
67
gboolean have_inhibit_cookie;
57
tr_core_marshal_err( GClosure * closure, GValue * ret UNUSED,
58
guint count, const GValue * vals,
59
gpointer hint UNUSED, gpointer marshal )
61
typedef void (*TRMarshalErr)
62
( gpointer, enum tr_core_err, const char *, gpointer );
63
TRMarshalErr callback;
64
GCClosure * cclosure = (GCClosure*) closure;
65
enum tr_core_err errcode;
69
g_return_if_fail( count == 3 );
71
inst = g_value_peek_pointer( vals );
72
errcode = g_value_get_int( vals + 1 );
73
errstr = g_value_get_string( vals + 2 );
74
gdata = closure->data;
76
callback = (TRMarshalErr)( marshal ? marshal : cclosure->callback );
77
callback( inst, errcode, errstr, gdata );
81
tr_core_marshal_prompt( GClosure * closure, GValue * ret UNUSED,
82
guint count, const GValue * vals,
83
gpointer hint UNUSED, gpointer marshal )
85
typedef void (*TRMarshalPrompt)( gpointer, tr_ctor *, gpointer );
86
TRMarshalPrompt callback;
87
GCClosure * cclosure = (GCClosure*) closure;
91
g_return_if_fail( count == 2 );
93
inst = g_value_peek_pointer( vals );
94
ctor = g_value_peek_pointer( vals + 1 );
95
gdata = closure->data;
97
callback = (TRMarshalPrompt)( marshal ? marshal : cclosure->callback );
98
callback( inst, ctor, gdata );
102
75
isDisposed( const TrCore * core )
125
tr_core_class_init( gpointer g_class, gpointer g_class_data UNUSED )
97
tr_core_class_init( gpointer g_class,
98
gpointer g_class_data UNUSED )
127
100
GObjectClass * gobject_class;
128
TrCoreClass * core_class;
130
g_type_class_add_private( g_class, sizeof(struct TrCorePrivate) );
103
g_type_class_add_private( g_class, sizeof( struct TrCorePrivate ) );
132
105
gobject_class = G_OBJECT_CLASS( g_class );
133
106
gobject_class->dispose = tr_core_dispose;
136
core_class = TR_CORE_CLASS( g_class );
137
core_class->errsig = g_signal_new( "error", G_TYPE_FROM_CLASS( g_class ),
138
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
139
tr_core_marshal_err, G_TYPE_NONE,
140
2, G_TYPE_INT, G_TYPE_STRING );
141
core_class->promptsig = g_signal_new( "add-torrent-prompt",
142
G_TYPE_FROM_CLASS( g_class ),
143
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
144
tr_core_marshal_prompt, G_TYPE_NONE,
146
core_class->quitsig = g_signal_new( "quit", G_TYPE_FROM_CLASS( g_class ),
147
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
148
g_cclosure_marshal_VOID__VOID,
150
core_class->prefsig = g_signal_new( "prefs-changed",
151
G_TYPE_FROM_CLASS( g_class ),
152
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
153
g_cclosure_marshal_VOID__STRING,
154
G_TYPE_NONE, 1, G_TYPE_STRING );
108
cc = TR_CORE_CLASS( g_class );
110
cc->blocklistSignal = g_signal_new( "blocklist-updated", /* name */
111
G_TYPE_FROM_CLASS( g_class ), /* applies to TrCore */
112
G_SIGNAL_RUN_FIRST, /* when to invoke */
113
0, NULL, NULL, /* accumulator */
114
g_cclosure_marshal_VOID__INT, /* marshaler */
115
G_TYPE_NONE, /* return type */
116
1, G_TYPE_INT ); /* signal arguments */
118
cc->portSignal = g_signal_new( "port-tested",
119
G_TYPE_FROM_CLASS( g_class ),
122
g_cclosure_marshal_VOID__BOOLEAN,
126
cc->errsig = g_signal_new( "error",
127
G_TYPE_FROM_CLASS( g_class ),
130
g_cclosure_marshal_VOID__UINT_POINTER,
132
2, G_TYPE_UINT, G_TYPE_POINTER );
134
cc->promptsig = g_signal_new( "add-torrent-prompt",
135
G_TYPE_FROM_CLASS( g_class ),
138
g_cclosure_marshal_VOID__POINTER,
142
cc->quitsig = g_signal_new( "quit",
143
G_TYPE_FROM_CLASS( g_class ),
146
g_cclosure_marshal_VOID__VOID,
150
cc->prefsig = g_signal_new( "prefs-changed",
151
G_TYPE_FROM_CLASS( g_class ),
154
g_cclosure_marshal_VOID__STRING,
158
#ifdef HAVE_DBUS_GLIB
160
DBusGConnection * bus = dbus_g_bus_get( DBUS_BUS_SESSION, NULL );
161
DBusGProxy * bus_proxy = NULL;
164
dbus_g_proxy_new_for_name( bus, "org.freedesktop.DBus",
165
"/org/freedesktop/DBus",
166
"org.freedesktop.DBus" );
170
dbus_g_proxy_call( bus_proxy, "RequestName", NULL,
172
"com.transmissionbt.Transmission",
175
G_TYPE_UINT, &result,
177
if( ( our_instance_adds_remote_torrents = result == 1 ) )
178
dbus_g_object_type_install_info(
181
dbus_glib_tr_core_object_info );
194
return ( t != TR_ETA_NOT_AVAIL ) && ( t != TR_ETA_UNKNOWN );
198
compareETA( int a, int b )
200
const gboolean a_valid = isValidETA( a );
201
const gboolean b_valid = isValidETA( b );
203
if( !a_valid && !b_valid ) return 0;
204
if( !a_valid ) return -1;
205
if( !b_valid ) return 1;
206
return a < b ? 1 : -1;
162
210
compareDouble( double a, double b )
239
compareByProgress( GtkTreeModel * model,
296
compareByAge( GtkTreeModel * model,
299
gpointer user_data UNUSED )
303
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
304
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
305
return compareTime( tr_torrentStatCached( ta )->addedDate,
306
tr_torrentStatCached( tb )->addedDate );
310
compareBySize( GtkTreeModel * model,
313
gpointer user_data UNUSED )
316
const tr_info *ia, *ib;
318
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &t, -1 );
319
ia = tr_torrentInfo( t );
320
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &t, -1 );
321
ib = tr_torrentInfo( t );
323
if( ia->totalSize < ib->totalSize ) return 1;
324
if( ia->totalSize > ib->totalSize ) return -1;
329
compareByProgress( GtkTreeModel * model,
242
332
gpointer user_data UNUSED )
246
336
const tr_stat *sa, *sb;
247
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
248
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
249
sa = tr_torrentStatCached( ta );
250
sb = tr_torrentStatCached( tb );
338
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &t, -1 );
339
sa = tr_torrentStatCached( t );
340
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &t, -1 );
341
sb = tr_torrentStatCached( t );
251
342
ret = compareDouble( sa->percentDone, sb->percentDone );
253
344
ret = compareRatio( sa->ratio, sb->ratio );
258
compareByState( GtkTreeModel * model,
349
compareByETA( GtkTreeModel * model,
352
gpointer user_data UNUSED )
356
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
357
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
359
return compareETA( tr_torrentStatCached( ta )->eta,
360
tr_torrentStatCached( tb )->eta );
364
compareByState( GtkTreeModel * model,
265
371
/* first by state */
266
gtk_tree_model_get( model, a, MC_STATUS, &sa, -1 );
267
gtk_tree_model_get( model, b, MC_STATUS, &sb, -1 );
372
gtk_tree_model_get( model, a, MC_ACTIVITY, &sa, -1 );
373
gtk_tree_model_get( model, b, MC_ACTIVITY, &sb, -1 );
270
376
/* second by progress */
278
compareByTracker( GtkTreeModel * model,
281
gpointer user_data UNUSED )
384
compareByTracker( GtkTreeModel * model,
387
gpointer user_data UNUSED )
283
389
const tr_torrent *ta, *tb;
284
391
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
285
392
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
286
return strcmp( tr_torrentInfo(ta)->trackers[0].announce,
287
tr_torrentInfo(tb)->trackers[0].announce );
393
return strcmp( tr_torrentInfo( ta )->trackers[0].announce,
394
tr_torrentInfo( tb )->trackers[0].announce );
291
setSort( TrCore * core, const char * mode, gboolean isReversed )
398
setSort( TrCore * core,
400
gboolean isReversed )
293
const int col = MC_TORRENT_RAW;
402
const int col = MC_TORRENT_RAW;
294
403
GtkTreeIterCompareFunc sort_func;
295
GtkSortType type = isReversed ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING;
296
GtkTreeSortable * sortable = GTK_TREE_SORTABLE( tr_core_model( core ) );
405
isReversed ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING;
406
GtkTreeSortable * sortable =
407
GTK_TREE_SORTABLE( tr_core_model( core ) );
298
409
if( !strcmp( mode, "sort-by-activity" ) )
299
410
sort_func = compareByActivity;
411
else if( !strcmp( mode, "sort-by-age" ) )
412
sort_func = compareByAge;
300
413
else if( !strcmp( mode, "sort-by-progress" ) )
301
414
sort_func = compareByProgress;
415
else if( !strcmp( mode, "sort-by-eta" ) )
416
sort_func = compareByETA;
302
417
else if( !strcmp( mode, "sort-by-ratio" ) )
303
418
sort_func = compareByRatio;
304
419
else if( !strcmp( mode, "sort-by-state" ) )
305
420
sort_func = compareByState;
306
421
else if( !strcmp( mode, "sort-by-tracker" ) )
307
422
sort_func = compareByTracker;
423
else if( !strcmp( mode, "sort-by-size" ) )
424
sort_func = compareBySize;
309
426
sort_func = compareByName;
310
427
type = isReversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING;
313
430
gtk_tree_sortable_set_sort_func( sortable, col, sort_func, NULL, NULL );
314
431
gtk_tree_sortable_set_sort_column_id( sortable, col, type );
320
437
if( tr_ctorGetPaused( ctor, TR_FORCE, NULL ) )
321
438
tr_ctorSetPaused( ctor, TR_FORCE, !pref_flag_get( PREF_KEY_START ) );
323
if( tr_ctorGetDeleteSource( ctor, NULL ) )
324
tr_ctorSetDeleteSource( ctor, pref_flag_get( PREF_KEY_TRASH_ORIGINAL ) );
326
if( tr_ctorGetMaxConnectedPeers( ctor, TR_FORCE, NULL ) )
327
tr_ctorSetMaxConnectedPeers( ctor, TR_FORCE,
328
pref_int_get( PREF_KEY_MAX_PEERS_PER_TORRENT ) );
330
if( tr_ctorGetDestination( ctor, TR_FORCE, NULL ) ) {
331
char * path = pref_string_get( PREF_KEY_DIR_DEFAULT );
332
tr_ctorSetDestination( ctor, TR_FORCE, path );
440
if( tr_ctorGetDeleteSource( ctor, NULL ) )
441
tr_ctorSetDeleteSource( ctor,
442
pref_flag_get( PREF_KEY_TRASH_ORIGINAL ) );
444
if( tr_ctorGetPeerLimit( ctor, TR_FORCE, NULL ) )
445
tr_ctorSetPeerLimit( ctor, TR_FORCE,
446
pref_int_get( TR_PREFS_KEY_PEER_LIMIT_TORRENT ) );
448
if( tr_ctorGetDownloadDir( ctor, TR_FORCE, NULL ) )
450
const char * path = pref_string_get( TR_PREFS_KEY_DOWNLOAD_DIR );
451
tr_ctorSetDownloadDir( ctor, TR_FORCE, path );
456
tr_strcmp( const void * a,
459
if( a && b ) return strcmp( a, b );
339
467
watchFolderIdle( gpointer gcore )
341
469
TrCore * core = TR_CORE( gcore );
471
core->priv->adding_from_watch_dir = TRUE;
342
472
tr_core_add_list_defaults( core, core->priv->monitor_files );
473
core->priv->adding_from_watch_dir = FALSE;
345
476
core->priv->monitor_files = NULL;
417
553
if( isEnabled && !p->monitor )
419
GFile * file = g_file_new_for_path( filename );
555
GFile * file = g_file_new_for_path( filename );
420
556
GFileMonitor * m = g_file_monitor_directory( file, 0, NULL, NULL );
421
557
scanWatchDir( core );
423
559
p->monitor_path = g_strdup( filename );
424
560
p->monitor_tag = g_signal_connect( m, "changed",
425
G_CALLBACK( watchFolderChanged ), core );
562
watchFolderChanged ), core );
433
prefsChanged( TrCore * core, const char * key, gpointer data UNUSED )
569
prefsChanged( TrCore * core,
571
gpointer data UNUSED )
435
if( !strcmp( key, PREF_KEY_SORT_MODE ) ||
436
!strcmp( key, PREF_KEY_SORT_REVERSED ) )
573
if( !strcmp( key, PREF_KEY_SORT_MODE )
574
|| !strcmp( key, PREF_KEY_SORT_REVERSED ) )
438
char * mode = pref_string_get( PREF_KEY_SORT_MODE );
439
gboolean isReversed = pref_flag_get( PREF_KEY_SORT_REVERSED );
576
const char * mode = pref_string_get( PREF_KEY_SORT_MODE );
577
gboolean isReversed = pref_flag_get( PREF_KEY_SORT_REVERSED );
440
578
setSort( core, mode, isReversed );
443
else if( !strcmp( key, PREF_KEY_MAX_PEERS_GLOBAL ) )
445
const uint16_t val = pref_int_get( key );
446
tr_setGlobalPeerLimit( tr_core_handle( core ), val );
580
else if( !strcmp( key, TR_PREFS_KEY_PEER_LIMIT_GLOBAL ) )
582
const uint16_t val = pref_int_get( key );
583
tr_sessionSetPeerLimit( tr_core_session( core ), val );
585
else if( !strcmp( key, TR_PREFS_KEY_PEER_LIMIT_TORRENT ) )
587
const uint16_t val = pref_int_get( key );
588
tr_sessionSetPeerLimitPerTorrent( tr_core_session( core ), val );
590
else if( !strcmp( key, PREF_KEY_INHIBIT_HIBERNATION ) )
592
maybeInhibitHibernation( core );
449
else if( !strcmp( key, PREF_KEY_DIR_WATCH ) ||
450
!strcmp( key, PREF_KEY_DIR_WATCH_ENABLED ) )
595
else if( !strcmp( key, PREF_KEY_DIR_WATCH )
596
|| !strcmp( key, PREF_KEY_DIR_WATCH_ENABLED ) )
452
598
updateWatchDir( core );
560
720
GtkTreeIter * iter,
561
721
gpointer gstats )
564
724
struct core_stats * stats = gstats;
567
727
gtk_tree_model_get( model, iter, MC_TORRENT_RAW, &tor, -1 );
568
status = tr_torrentGetStatus( tor );
728
activity = tr_torrentGetActivity( tor );
570
if( status == TR_STATUS_DOWNLOAD )
730
if( activity == TR_STATUS_DOWNLOAD )
571
731
++stats->downloadCount;
572
else if( status == TR_STATUS_SEED )
732
else if( activity == TR_STATUS_SEED )
573
733
++stats->seedingCount;
579
tr_core_get_stats( const TrCore * core,
580
struct core_stats * setme )
739
tr_core_get_stats( const TrCore * core,
740
struct core_stats * setme )
582
742
memset( setme, 0, sizeof( struct core_stats ) );
584
744
if( !isDisposed( core ) )
586
tr_torrentRates( core->priv->handle,
587
&setme->clientDownloadSpeed,
588
&setme->clientUploadSpeed );
590
gtk_tree_model_foreach( core->priv->model,
746
tr_session * session = core->priv->session;
748
setme->clientDownloadSpeed = tr_sessionGetPieceSpeed( session, TR_DOWN );
750
setme->clientUploadSpeed = tr_sessionGetPieceSpeed( session, TR_UP );
752
gtk_tree_model_foreach( core->priv->model, statsForeach, setme );
622
tr_core_add_torrent( TrCore * self, TrTorrent * tor )
784
tr_core_add_torrent( TrCore * self,
624
const tr_info * inf = tr_torrent_info( tor );
625
const tr_stat * torStat = tr_torrent_stat( tor );
626
char * collated = doCollate( inf->name );
627
GtkListStore * store = GTK_LIST_STORE( tr_core_model( self ) );
787
const tr_info * inf = tr_torrent_info( gtor );
788
const tr_stat * torStat = tr_torrent_stat( gtor );
789
tr_torrent * tor = tr_torrent_handle( gtor );
790
char * collated = doCollate( inf->name );
791
GtkListStore * store = GTK_LIST_STORE( tr_core_model( self ) );
630
gtk_list_store_insert_with_values( store, &unused, 0,
794
gtk_list_store_insert_with_values( store, &unused, 0,
631
795
MC_NAME, inf->name,
632
796
MC_NAME_COLLATED, collated,
633
MC_HASH, inf->hashString,
635
MC_TORRENT_RAW, tr_torrent_handle( tor ),
636
MC_STATUS, torStat->status,
637
MC_ID, self->priv->nextid,
639
++self->priv->nextid;
799
MC_ACTIVITY, torStat->activity,
642
g_object_unref( G_OBJECT( tor ) );
803
g_object_unref( G_OBJECT( gtor ) );
643
804
g_free( collated );
647
tr_core_load( TrCore * self, gboolean forcePaused )
808
tr_core_load( TrCore * self,
809
gboolean forcePaused )
651
813
tr_torrent ** torrents;
655
path = getdownloaddir( );
657
ctor = tr_ctorNew( tr_core_handle( self ) );
816
ctor = tr_ctorNew( tr_core_session( self ) );
658
817
if( forcePaused )
659
818
tr_ctorSetPaused( ctor, TR_FORCE, TRUE );
660
tr_ctorSetDestination( ctor, TR_FALLBACK, path );
661
tr_ctorSetMaxConnectedPeers( ctor, TR_FALLBACK,
662
pref_int_get( PREF_KEY_MAX_PEERS_PER_TORRENT ) );
819
tr_ctorSetPeerLimit( ctor, TR_FALLBACK,
820
pref_int_get( TR_PREFS_KEY_PEER_LIMIT_TORRENT ) );
664
torrents = tr_loadTorrents ( tr_core_handle( self ), ctor, &count );
665
for( i=0; i<count; ++i )
822
torrents = tr_sessionLoadTorrents ( tr_core_session( self ), ctor, &count );
823
for( i = 0; i < count; ++i )
666
824
tr_core_add_torrent( self, tr_torrent_new_preexisting( torrents[i] ) );
668
826
tr_free( torrents );
669
827
tr_ctorFree( ctor );
676
tr_core_errsig( TrCore * core, enum tr_core_err type, const char * msg )
678
g_signal_emit( core, TR_CORE_GET_CLASS(core)->errsig, 0, type, msg );
682
tr_core_add_ctor( TrCore * self, tr_ctor * ctor )
685
char * errstr = NULL;
687
tr_core_apply_defaults( ctor );
689
if(( tor = tr_torrent_new_ctor( tr_core_handle( self ), ctor, &errstr )))
690
tr_core_add_torrent( self, tor );
692
tr_core_errsig( self, TR_CORE_ERR_ADD_TORRENT, errstr );
833
emitBlocklistUpdated( TrCore * core, int ruleCount )
835
g_signal_emit( core, TR_CORE_GET_CLASS( core )->blocklistSignal, 0, ruleCount );
839
emitPortTested( TrCore * core, gboolean isOpen )
841
g_signal_emit( core, TR_CORE_GET_CLASS( core )->portSignal, 0, isOpen );
845
tr_core_errsig( TrCore * core,
846
enum tr_core_err type,
849
g_signal_emit( core, TR_CORE_GET_CLASS( core )->errsig, 0, type, msg );
853
add_filename( TrCore * core,
854
const char * filename,
858
tr_session * session = tr_core_session( core );
860
if( filename && session )
864
ctor = tr_ctorNew( session );
865
tr_core_apply_defaults( ctor );
866
tr_ctorSetPaused( ctor, TR_FORCE, !doStart );
868
if( tr_ctorSetMetainfoFromFile( ctor, filename ) )
870
tr_core_errsig( core, TR_EINVALID, filename );
876
int err = tr_torrentParse( ctor, &inf );
881
tr_core_errsig( core, err, filename );
885
/* don't complain about .torrent files in the watch directory
886
* that have already been added... that gets annoying and we
887
* don't want to be naggign users to clean up their watch dirs */
888
if( !core->priv->adding_from_watch_dir )
889
tr_core_errsig( core, err, inf.name );
890
tr_metainfoFree( &inf );
895
g_signal_emit( core, TR_CORE_GET_CLASS( core )->promptsig, 0, ctor );
897
TrTorrent * gtor = tr_torrent_new_ctor( session, ctor, &err );
899
tr_core_errsig( core, err, filename );
901
tr_core_add_torrent( core, gtor );
903
tr_metainfoFree( &inf );
911
tr_core_add_file( TrCore * core,
912
const char * filename,
914
GError ** err UNUSED )
916
add_filename( core, filename,
917
pref_flag_get( PREF_KEY_START ),
918
pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) );
924
tr_core_present_window( TrCore * core UNUSED,
926
GError ** err UNUSED )
928
action_activate( "present-main-window" );
701
tr_core_add_list( TrCore * core,
702
GSList * torrentFiles,
934
tr_core_add_list( TrCore * core,
935
GSList * torrentFiles,
706
939
const gboolean doStart = pref_flag_eval( start, PREF_KEY_START );
707
940
const gboolean doPrompt = pref_flag_eval( prompt, PREF_KEY_OPTIONS_PROMPT );
709
if( torrentFiles && !isDisposed( core ) )
712
tr_handle * handle = core->priv->handle;
714
for( l=torrentFiles; l!=NULL; l=l->next )
716
tr_ctor * ctor = tr_ctorNew( handle );
717
tr_core_apply_defaults( ctor );
718
tr_ctorSetPaused( ctor, TR_FORCE, !doStart );
719
if( tr_ctorSetMetainfoFromFile( ctor, l->data ) )
721
else if( tr_torrentParse( handle, ctor, NULL ) )
724
g_signal_emit( core, TR_CORE_GET_CLASS(core)->promptsig, 0, ctor );
726
tr_core_add_ctor( core, ctor );
943
for( l = torrentFiles; l != NULL; l = l->next )
944
add_filename( core, l->data, doStart, doPrompt );
946
tr_core_torrents_added( core );
730
947
freestrlist( torrentFiles );
737
954
tr_core_errsig( self, TR_CORE_ERR_NO_MORE_TORRENTS, NULL );
741
tr_core_delete_torrent( TrCore * self, GtkTreeIter * iter )
744
GtkTreeModel * model = tr_core_model( self );
746
gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );
747
gtk_list_store_remove( GTK_LIST_STORE( model ), iter );
748
tr_torrentRemoveSaved( tr_torrent_handle( tor ) );
750
g_object_unref( G_OBJECT( tor ) );
754
findTorrentInModel( TrCore * core, const TrTorrent * gtor, GtkTreeIter * setme )
958
findTorrentInModel( TrCore * core,
960
GtkTreeIter * setme )
758
964
GtkTreeModel * model = tr_core_model( core );
760
966
if( gtk_tree_model_iter_children( model, &iter, NULL ) ) do
763
gtk_tree_model_get( model, &iter, MC_TORRENT, &tmp, -1 );
765
g_object_unref( G_OBJECT( tmp ) );
767
while( !match && gtk_tree_model_iter_next( model, &iter ) );
969
gtk_tree_model_get( model, &iter, MC_TORRENT_RAW, &tor, -1 );
970
match = tr_torrentId( tor ) == id;
972
while( !match && gtk_tree_model_iter_next( model, &iter ) );
776
tr_core_remove_torrent( TrCore * self, TrTorrent * gtor, int deleteFiles )
981
tr_core_torrent_destroyed( TrCore * core,
778
984
GtkTreeIter iter;
779
GtkTreeModel * model = tr_core_model( self );
781
/* remove from the gui */
782
if( findTorrentInModel( self, gtor, &iter ) )
986
if( findTorrentInModel( core, id, &iter ) )
989
GtkTreeModel * model = tr_core_model( core );
990
gtk_tree_model_get( model, &iter, MC_TORRENT, >or, -1 );
991
tr_torrent_clear( gtor );
783
992
gtk_list_store_remove( GTK_LIST_STORE( model ), &iter );
785
/* maybe delete the downloaded files */
787
tr_torrent_delete_files( gtor );
789
/* delete the torrent */
790
tr_torrent_set_delete_flag( gtor, TRUE );
791
g_object_unref( G_OBJECT( gtor ) );
993
g_object_unref( G_OBJECT( gtor ) );
998
tr_core_remove_torrent( TrCore * core,
1002
const tr_torrent * tor = tr_torrent_handle( gtor );
1006
int id = tr_torrentId( tor );
1008
if( findTorrentInModel( core, id, &iter ) )
1010
GtkTreeModel * model = tr_core_model( core );
1012
/* remove from the gui */
1013
gtk_list_store_remove( GTK_LIST_STORE( model ), &iter );
1015
/* maybe delete the downloaded files */
1017
tr_torrent_delete_files( gtor );
1019
/* remove the torrent */
1020
tr_torrent_set_remove_flag( gtor, TRUE );
1021
g_object_unref( G_OBJECT( gtor ) );
800
update_foreach( GtkTreeModel * model,
1031
update_foreach( GtkTreeModel * model,
801
1032
GtkTreePath * path UNUSED,
803
1034
gpointer data UNUSED )
807
1038
TrTorrent * gtor;
809
1040
/* maybe update the status column in the model */
810
1041
gtk_tree_model_get( model, iter,
811
1042
MC_TORRENT, >or,
812
MC_STATUS, &oldStatus,
1043
MC_ACTIVITY, &oldActivity,
814
newStatus = tr_torrentGetStatus( tr_torrent_handle( gtor ) );
815
if( newStatus != oldStatus )
1045
newActivity = tr_torrentGetActivity( tr_torrent_handle( gtor ) );
1046
if( newActivity != oldActivity )
816
1047
gtk_list_store_set( GTK_LIST_STORE( model ), iter,
817
MC_STATUS, newStatus,
1048
MC_ACTIVITY, newActivity,
820
/* check the seeding cap */
821
tr_torrent_check_seeding_cap ( gtor );
824
1052
g_object_unref( gtor );
829
1057
tr_core_update( TrCore * self )
833
1061
GtkTreeSortable * sortable;
834
GtkTreeModel * model = tr_core_model( self );
1062
GtkTreeModel * model = tr_core_model( self );
836
1064
/* pause sorting */
837
1065
sortable = GTK_TREE_SORTABLE( model );
838
1066
gtk_tree_sortable_get_sort_column_id( sortable, &column, &order );
839
gtk_tree_sortable_set_sort_column_id( sortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, order );
1067
gtk_tree_sortable_set_sort_column_id(
1068
sortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, order );
841
1070
/* refresh the model */
842
1071
gtk_tree_model_foreach( model, update_foreach, NULL );
844
1073
/* resume sorting */
845
1074
gtk_tree_sortable_set_sort_column_id( sortable, column, order );
1076
/* maybe inhibit hibernation */
1077
maybeInhibitHibernation( self );
849
1081
tr_core_quit( TrCore * core )
851
g_signal_emit( core, TR_CORE_GET_CLASS(core)->quitsig, 0 );
1083
g_signal_emit( core, TR_CORE_GET_CLASS( core )->quitsig, 0 );
1090
#ifdef HAVE_DBUS_GLIB
1093
get_hibernation_inhibit_proxy( void )
1095
GError * error = NULL;
1096
DBusGConnection * conn;
1098
conn = dbus_g_bus_get( DBUS_BUS_SESSION, &error );
1101
g_warning ( "DBUS cannot connect : %s", error->message );
1102
g_error_free ( error );
1106
return dbus_g_proxy_new_for_name (
1108
"org.freedesktop.PowerManagement",
1109
"/org/freedesktop/PowerManagement/Inhibit",
1110
"org.freedesktop.PowerManagement.Inhibit" );
1114
gtr_inhibit_hibernation( guint * cookie )
1116
gboolean success = FALSE;
1117
DBusGProxy * proxy = get_hibernation_inhibit_proxy( );
1121
GError * error = NULL;
1122
const char * application = _( "Transmission Bittorrent Client" );
1123
const char * reason = _( "BitTorrent Activity" );
1124
success = dbus_g_proxy_call( proxy, "Inhibit", &error,
1125
G_TYPE_STRING, application,
1126
G_TYPE_STRING, reason,
1128
G_TYPE_UINT, cookie,
1131
tr_inf( _( "Disallowing desktop hibernation" ) );
1135
"Couldn't disable desktop hibernation: %s" ),
1137
g_error_free( error );
1140
g_object_unref( G_OBJECT( proxy ) );
1143
return success != 0;
1147
gtr_uninhibit_hibernation( guint inhibit_cookie )
1149
DBusGProxy * proxy = get_hibernation_inhibit_proxy( );
1153
GError * error = NULL;
1154
gboolean success = dbus_g_proxy_call( proxy, "UnInhibit", &error,
1155
G_TYPE_UINT, inhibit_cookie,
1159
tr_inf( _( "Allowing desktop hibernation" ) );
1162
g_warning( "Couldn't uninhibit the system from suspending: %s.",
1164
g_error_free( error );
1167
g_object_unref( G_OBJECT( proxy ) );
1174
tr_core_set_hibernation_allowed( TrCore * core,
1177
#ifdef HAVE_DBUS_GLIB
1178
g_return_if_fail( core );
1179
g_return_if_fail( core->priv );
1181
core->priv->inhibit_allowed = allowed != 0;
1183
if( allowed && core->priv->have_inhibit_cookie )
1185
gtr_uninhibit_hibernation( core->priv->inhibit_cookie );
1186
core->priv->have_inhibit_cookie = FALSE;
1190
&& !core->priv->have_inhibit_cookie
1191
&& !core->priv->dbus_error )
1193
if( gtr_inhibit_hibernation( &core->priv->inhibit_cookie ) )
1194
core->priv->have_inhibit_cookie = TRUE;
1196
core->priv->dbus_error = TRUE;
1202
maybeInhibitHibernation( TrCore * core )
1204
gboolean inhibit = pref_flag_get( PREF_KEY_INHIBIT_HIBERNATION );
1206
/* always allow hibernation when all the torrents are paused */
1208
tr_session * session = tr_core_session( core );
1210
if( tr_sessionGetActiveTorrentCount( session ) == 0 )
1214
tr_core_set_hibernation_allowed( core, !inhibit );
859
commitPrefsChange( TrCore * core, const char * key )
1222
commitPrefsChange( TrCore * core,
862
g_signal_emit( core, TR_CORE_GET_CLASS(core)->prefsig, 0, key );
1225
g_signal_emit( core, TR_CORE_GET_CLASS( core )->prefsig, 0, key );
1226
pref_save( tr_core_session( core ) );
866
tr_core_set_pref( TrCore * self, const char * key, const char * newval )
1230
tr_core_set_pref( TrCore * self,
1232
const char * newval )
868
char * oldval = pref_string_get( key );
1234
const char * oldval = pref_string_get( key );
869
1236
if( tr_strcmp( oldval, newval ) )
871
1238
pref_string_set( key, newval );
872
1239
commitPrefsChange( self, key );
878
tr_core_set_pref_bool( TrCore * self, const char * key, gboolean newval )
1244
tr_core_set_pref_bool( TrCore * self,
880
1248
const gboolean oldval = pref_flag_get( key );
881
1250
if( oldval != newval )
883
1252
pref_flag_set( key, newval );
889
tr_core_set_pref_int( TrCore * self, const char * key, int newval )
1258
tr_core_set_pref_int( TrCore * self,
891
1262
const int oldval = pref_int_get( key );
892
1264
if( oldval != newval )
894
1266
pref_int_set( key, newval );
895
1267
commitPrefsChange( self, key );
1272
tr_core_set_pref_double( TrCore * self,
1276
const double oldval = pref_double_get( key );
1278
if( oldval != newval )
1280
pref_double_set( key, newval );
1281
commitPrefsChange( self, key );
1291
/* #define DEBUG_RPC */
1293
static int nextTag = 1;
1295
typedef void ( server_response_func )( TrCore * core, tr_benc * response, gpointer user_data );
1297
struct pending_request_data
1301
server_response_func * responseFunc;
1302
gpointer responseFuncUserData;
1305
static GHashTable * pendingRequests = NULL;
1308
readResponseIdle( void * vresponse )
1310
GByteArray * response;
1314
struct pending_request_data * data;
1316
response = vresponse;
1317
tr_jsonParse( response->data, response->len, &top, NULL );
1318
tr_bencDictFindInt( &top, "tag", &intVal );
1321
data = g_hash_table_lookup( pendingRequests, &tag );
1323
(*data->responseFunc)(data->core, &top, data->responseFuncUserData );
1325
tr_bencFree( &top );
1326
g_hash_table_remove( pendingRequests, &tag );
1327
g_byte_array_free( response, TRUE );
1332
readResponse( tr_session * session UNUSED,
1333
const char * response,
1334
size_t response_len,
1335
void * unused UNUSED )
1337
GByteArray * bytes = g_byte_array_new( );
1339
g_message( "response: [%*.*s]", (int)response_len, (int)response_len, response );
1341
g_byte_array_append( bytes, (const uint8_t*)response, response_len );
1342
g_idle_add( readResponseIdle, bytes );
1346
sendRequest( TrCore * core, const char * json, int tag,
1347
server_response_func * responseFunc, void * responseFuncUserData )
1349
tr_session * session = tr_core_session( core );
1351
if( pendingRequests == NULL )
1353
pendingRequests = g_hash_table_new_full( g_int_hash, g_int_equal, NULL, g_free );
1356
if( session == NULL )
1358
g_error( "GTK+ client doesn't support connections to remote servers yet." );
1362
/* remember this request */
1363
struct pending_request_data * data;
1364
data = g_new0( struct pending_request_data, 1 );
1367
data->responseFunc = responseFunc;
1368
data->responseFuncUserData = responseFuncUserData;
1369
g_hash_table_insert( pendingRequests, &data->tag, data );
1371
/* make the request */
1373
g_message( "request: [%s]", json );
1375
tr_rpc_request_exec_json( session, json, strlen( json ), readResponse, GINT_TO_POINTER(tag) );
1380
**** Sending a test-port request via RPC
1384
portTestResponseFunc( TrCore * core, tr_benc * response, gpointer userData UNUSED )
1387
tr_bool isOpen = FALSE;
1389
if( tr_bencDictFindDict( response, "arguments", &args ) )
1390
tr_bencDictFindBool( args, "port-is-open", &isOpen );
1392
emitPortTested( core, isOpen );
1396
tr_core_port_test( TrCore * core )
1399
const int tag = nextTag++;
1400
g_snprintf( buf, sizeof( buf ), "{ \"method\": \"port-test\", \"tag\": %d }", tag );
1401
sendRequest( core, buf, tag, portTestResponseFunc, NULL );
1405
**** Updating a blocklist via RPC
1409
blocklistResponseFunc( TrCore * core, tr_benc * response, gpointer userData UNUSED )
1412
int64_t ruleCount = 0;
1414
if( tr_bencDictFindDict( response, "arguments", &args ) )
1415
tr_bencDictFindInt( args, "blocklist-size", &ruleCount );
1418
pref_int_set( "blocklist-date", time( NULL ) );
1420
emitBlocklistUpdated( core, ruleCount );
1424
tr_core_blocklist_update( TrCore * core )
1427
const int tag = nextTag++;
1428
g_snprintf( buf, sizeof( buf ), "{ \"method\": \"blocklist-update\", \"tag\": %d }", tag );
1429
sendRequest( core, buf, tag, blocklistResponseFunc, NULL );
1437
tr_core_exec_json( TrCore * core, const char * json )
1439
g_message( "executing %s", json );
1440
sendRequest( core, json, 0, NULL, NULL );
1444
tr_core_exec( TrCore * core, const tr_benc * top )
1446
char * json = tr_bencToJSON( top );
1447
tr_core_exec_json( core, json );