~ubuntu-branches/ubuntu/maverick/transmission/maverick

« back to all changes in this revision

Viewing changes to gtk/tr-core.c

  • Committer: Bazaar Package Importer
  • Author(s): Krzysztof Klimonda
  • Date: 2009-05-22 21:57:30 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (2.1.18 sid) (1.3.8 upstream)
  • mto: This revision was merged to the branch mainline in revision 36.
  • Revision ID: james.westby@ubuntu.com-20090522215730-ly5kgv5aw9ig2u82
Tags: upstream-1.61
ImportĀ upstreamĀ versionĀ 1.61

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/******************************************************************************
2
 
 * $Id: tr-core.c 7861 2009-02-09 20:11:32Z charles $
 
2
 * $Id: tr-core.c 8279 2009-04-24 01:37:04Z charles $
3
3
 *
4
4
 * Copyright (c) 2007-2008 Transmission authors and contributors
5
5
 *
34
34
#endif
35
35
 
36
36
#include <libtransmission/transmission.h>
 
37
#include <libtransmission/bencode.h>
 
38
#include <libtransmission/rpcimpl.h>
 
39
#include <libtransmission/json.h>
37
40
#include <libtransmission/utils.h> /* tr_free */
38
41
 
39
42
#include "conf.h"
68
71
    tr_session *    session;
69
72
};
70
73
 
71
 
static void
72
 
tr_core_marshal_err( GClosure *     closure,
73
 
                     GValue * ret   UNUSED,
74
 
                     guint          count,
75
 
                     const GValue * vals,
76
 
                     gpointer hint  UNUSED,
77
 
                     gpointer       marshal )
78
 
{
79
 
    typedef void ( *TRMarshalErr )
80
 
                                ( gpointer, enum tr_core_err, const char *,
81
 
                                gpointer );
82
 
    TRMarshalErr     callback;
83
 
    GCClosure *      cclosure = (GCClosure*) closure;
84
 
    enum tr_core_err errcode;
85
 
    const char *     errstr;
86
 
    gpointer         inst, gdata;
87
 
 
88
 
    g_return_if_fail( count == 3 );
89
 
 
90
 
    inst    = g_value_peek_pointer( vals );
91
 
    errcode = g_value_get_int( vals + 1 );
92
 
    errstr  = g_value_get_string( vals + 2 );
93
 
    gdata   = closure->data;
94
 
 
95
 
    callback = (TRMarshalErr)( marshal ? marshal : cclosure->callback );
96
 
    callback( inst, errcode, errstr, gdata );
97
 
}
98
 
 
99
 
static void
100
 
tr_core_marshal_blocklist( GClosure *     closure,
101
 
                           GValue * ret   UNUSED,
102
 
                           guint          count,
103
 
                           const GValue * vals,
104
 
                           gpointer hint  UNUSED,
105
 
                           gpointer       marshal )
106
 
{
107
 
    typedef void ( *TRMarshalErr )
108
 
                                ( gpointer, enum tr_core_err, const char *,
109
 
                                gpointer );
110
 
    TRMarshalErr callback;
111
 
    GCClosure *  cclosure = (GCClosure*) closure;
112
 
    gboolean     flag;
113
 
    const char * str;
114
 
    gpointer     inst, gdata;
115
 
 
116
 
    g_return_if_fail( count == 3 );
117
 
 
118
 
    inst    = g_value_peek_pointer( vals );
119
 
    flag    = g_value_get_boolean( vals + 1 );
120
 
    str     = g_value_get_string( vals + 2 );
121
 
    gdata   = closure->data;
122
 
 
123
 
    callback = (TRMarshalErr)( marshal ? marshal : cclosure->callback );
124
 
    callback( inst, flag, str, gdata );
125
 
}
126
 
 
127
 
static void
128
 
tr_core_marshal_prompt( GClosure *     closure,
129
 
                        GValue * ret   UNUSED,
130
 
                        guint          count,
131
 
                        const GValue * vals,
132
 
                        gpointer hint  UNUSED,
133
 
                        gpointer       marshal )
134
 
{
135
 
    typedef void ( *TRMarshalPrompt )( gpointer, tr_ctor *, gpointer );
136
 
    TRMarshalPrompt callback;
137
 
    GCClosure *     cclosure = (GCClosure*) closure;
138
 
    gpointer        ctor;
139
 
    gpointer        inst, gdata;
140
 
 
141
 
    g_return_if_fail( count == 2 );
142
 
 
143
 
    inst      = g_value_peek_pointer( vals );
144
 
    ctor      = g_value_peek_pointer( vals + 1 );
145
 
    gdata     = closure->data;
146
 
 
147
 
    callback = (TRMarshalPrompt)( marshal ? marshal : cclosure->callback );
148
 
    callback( inst, ctor, gdata );
149
 
}
150
 
 
151
74
static int
152
75
isDisposed( const TrCore * core )
153
76
{
175
98
                    gpointer g_class_data UNUSED )
176
99
{
177
100
    GObjectClass * gobject_class;
178
 
    TrCoreClass *  core_class;
 
101
    TrCoreClass *  cc;
179
102
 
180
103
    g_type_class_add_private( g_class, sizeof( struct TrCorePrivate ) );
181
104
 
182
105
    gobject_class = G_OBJECT_CLASS( g_class );
183
106
    gobject_class->dispose = tr_core_dispose;
184
107
 
185
 
 
186
 
    core_class = TR_CORE_CLASS( g_class );
187
 
    core_class->blocksig = g_signal_new( "blocklist-status",
188
 
                                         G_TYPE_FROM_CLASS(
189
 
                                             g_class ),
190
 
                                         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
191
 
                                         tr_core_marshal_blocklist,
192
 
                                         G_TYPE_NONE,
193
 
                                         2, G_TYPE_BOOLEAN, G_TYPE_STRING );
194
 
    core_class->errsig = g_signal_new( "error", G_TYPE_FROM_CLASS( g_class ),
195
 
                                       G_SIGNAL_RUN_LAST, 0, NULL, NULL,
196
 
                                       tr_core_marshal_err, G_TYPE_NONE,
197
 
                                       2, G_TYPE_INT, G_TYPE_STRING );
198
 
    core_class->promptsig = g_signal_new( "add-torrent-prompt",
199
 
                                          G_TYPE_FROM_CLASS(
200
 
                                              g_class ),
201
 
                                          G_SIGNAL_RUN_LAST, 0, NULL, NULL,
202
 
                                          tr_core_marshal_prompt,
203
 
                                          G_TYPE_NONE,
204
 
                                          1, G_TYPE_POINTER );
205
 
    core_class->quitsig = g_signal_new( "quit", G_TYPE_FROM_CLASS( g_class ),
206
 
                                        G_SIGNAL_RUN_LAST, 0, NULL, NULL,
207
 
                                        g_cclosure_marshal_VOID__VOID,
208
 
                                        G_TYPE_NONE, 0 );
209
 
    core_class->prefsig = g_signal_new( "prefs-changed",
210
 
                                        G_TYPE_FROM_CLASS( g_class ),
211
 
                                        G_SIGNAL_RUN_LAST, 0, NULL, NULL,
212
 
                                        g_cclosure_marshal_VOID__STRING,
213
 
                                        G_TYPE_NONE, 1, G_TYPE_STRING );
 
108
    cc = TR_CORE_CLASS( g_class );
 
109
 
 
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 */
 
117
 
 
118
    cc->portSignal = g_signal_new( "port-tested",
 
119
                                   G_TYPE_FROM_CLASS( g_class ),
 
120
                                   G_SIGNAL_RUN_LAST,
 
121
                                   0, NULL, NULL,
 
122
                                   g_cclosure_marshal_VOID__BOOLEAN,
 
123
                                   G_TYPE_NONE,
 
124
                                   1, G_TYPE_BOOLEAN );
 
125
 
 
126
    cc->errsig = g_signal_new( "error",
 
127
                               G_TYPE_FROM_CLASS( g_class ),
 
128
                               G_SIGNAL_RUN_LAST,
 
129
                               0, NULL, NULL,
 
130
                               g_cclosure_marshal_VOID__UINT_POINTER,
 
131
                               G_TYPE_NONE,
 
132
                               2, G_TYPE_UINT, G_TYPE_POINTER );
 
133
 
 
134
    cc->promptsig = g_signal_new( "add-torrent-prompt",
 
135
                                  G_TYPE_FROM_CLASS( g_class ),
 
136
                                  G_SIGNAL_RUN_LAST,
 
137
                                  0, NULL, NULL,
 
138
                                  g_cclosure_marshal_VOID__POINTER,
 
139
                                  G_TYPE_NONE,
 
140
                                  1, G_TYPE_POINTER );
 
141
 
 
142
    cc->quitsig = g_signal_new( "quit",
 
143
                                G_TYPE_FROM_CLASS( g_class ),
 
144
                                G_SIGNAL_RUN_LAST,
 
145
                                0, NULL, NULL,
 
146
                                g_cclosure_marshal_VOID__VOID,
 
147
                                G_TYPE_NONE,
 
148
                                0 );
 
149
 
 
150
    cc->prefsig = g_signal_new( "prefs-changed",
 
151
                                G_TYPE_FROM_CLASS( g_class ),
 
152
                                G_SIGNAL_RUN_LAST,
 
153
                                0, NULL, NULL,
 
154
                                g_cclosure_marshal_VOID__STRING,
 
155
                                G_TYPE_NONE,
 
156
                                1, G_TYPE_STRING );
214
157
 
215
158
#ifdef HAVE_DBUS_GLIB
216
159
    {
245
188
****  SORTING
246
189
***/
247
190
 
248
 
static int
249
 
compareDouble( double a,
250
 
               double b )
 
191
static gboolean
 
192
isValidETA( int t )
 
193
{
 
194
    return ( t != TR_ETA_NOT_AVAIL ) && ( t != TR_ETA_UNKNOWN );
 
195
}
 
196
 
 
197
static int
 
198
compareETA( int a, int b )
 
199
{
 
200
    const gboolean a_valid = isValidETA( a );
 
201
    const gboolean b_valid = isValidETA( b );
 
202
 
 
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;
 
207
}
 
208
 
 
209
static int
 
210
compareDouble( double a, double b )
251
211
{
252
212
    if( a < b ) return -1;
253
213
    if( a > b ) return 1;
255
215
}
256
216
 
257
217
static int
258
 
compareRatio( double a,
259
 
              double b )
 
218
compareRatio( double a, double b )
260
219
{
261
220
    if( (int)a == TR_RATIO_INF && (int)b == TR_RATIO_INF ) return 0;
262
221
    if( (int)a == TR_RATIO_INF ) return 1;
265
224
}
266
225
 
267
226
static int
268
 
compareTime( time_t a,
269
 
             time_t b )
 
227
compareTime( time_t a, time_t b )
270
228
{
271
229
    if( a < b ) return -1;
272
230
    if( a > b ) return 1;
274
232
}
275
233
 
276
234
static int
277
 
compareByRatio( GtkTreeModel *           model,
278
 
                GtkTreeIter *            a,
279
 
                GtkTreeIter *            b,
280
 
                gpointer       user_data UNUSED )
 
235
compareByRatio( GtkTreeModel  * model,
 
236
                GtkTreeIter   * a,
 
237
                GtkTreeIter   * b,
 
238
                gpointer        user_data UNUSED )
281
239
{
282
 
    tr_torrent *   ta, *tb;
 
240
    tr_torrent *ta, *tb;
283
241
    const tr_stat *sa, *sb;
284
242
 
285
243
    gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
335
293
}
336
294
 
337
295
static int
338
 
compareByAge( GtkTreeModel *             model,
339
 
              GtkTreeIter *              a,
340
 
              GtkTreeIter *              b,
341
 
              gpointer         user_data UNUSED )
 
296
compareByAge( GtkTreeModel * model,
 
297
              GtkTreeIter  * a,
 
298
              GtkTreeIter  * b,
 
299
              gpointer       user_data UNUSED )
342
300
{
343
301
    tr_torrent *ta, *tb;
344
302
 
349
307
}
350
308
 
351
309
static int
 
310
compareBySize( GtkTreeModel * model,
 
311
               GtkTreeIter  * a,
 
312
               GtkTreeIter  * b,
 
313
               gpointer       user_data UNUSED )
 
314
{
 
315
    tr_torrent *t;
 
316
    const tr_info *ia, *ib;
 
317
 
 
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 );
 
322
 
 
323
    if( ia->totalSize < ib->totalSize ) return 1;
 
324
    if( ia->totalSize > ib->totalSize ) return -1;
 
325
    return 0;
 
326
}
 
327
 
 
328
static int
352
329
compareByProgress( GtkTreeModel *             model,
353
330
                   GtkTreeIter *              a,
354
331
                   GtkTreeIter *              b,
355
332
                   gpointer         user_data UNUSED )
356
333
{
357
 
    int            ret;
358
 
    tr_torrent *   ta, *tb;
 
334
    int ret;
 
335
    tr_torrent * t;
359
336
    const tr_stat *sa, *sb;
360
337
 
361
 
    gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
362
 
    gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
363
 
    sa = tr_torrentStatCached( ta );
364
 
    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 );
365
342
    ret = compareDouble( sa->percentDone, sb->percentDone );
366
343
    if( !ret )
367
344
        ret = compareRatio( sa->ratio, sb->ratio );
369
346
}
370
347
 
371
348
static int
 
349
compareByETA( GtkTreeModel * model,
 
350
              GtkTreeIter  * a,
 
351
              GtkTreeIter  * b,
 
352
              gpointer       user_data UNUSED )
 
353
{
 
354
    tr_torrent *ta, *tb;
 
355
 
 
356
    gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
 
357
    gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
 
358
 
 
359
    return compareETA( tr_torrentStatCached( ta )->eta,
 
360
                       tr_torrentStatCached( tb )->eta );
 
361
}
 
362
 
 
363
static int
372
364
compareByState( GtkTreeModel * model,
373
365
                GtkTreeIter *  a,
374
366
                GtkTreeIter *  b,
389
381
}
390
382
 
391
383
static int
392
 
compareByTracker( GtkTreeModel *             model,
393
 
                  GtkTreeIter *              a,
394
 
                  GtkTreeIter *              b,
395
 
                  gpointer         user_data UNUSED )
 
384
compareByTracker( GtkTreeModel * model,
 
385
                  GtkTreeIter  * a,
 
386
                  GtkTreeIter  * b,
 
387
                  gpointer       user_data UNUSED )
396
388
{
397
389
    const tr_torrent *ta, *tb;
398
390
 
420
412
        sort_func = compareByAge;
421
413
    else if( !strcmp( mode, "sort-by-progress" ) )
422
414
        sort_func = compareByProgress;
 
415
    else if( !strcmp( mode, "sort-by-eta" ) )
 
416
        sort_func = compareByETA;
423
417
    else if( !strcmp( mode, "sort-by-ratio" ) )
424
418
        sort_func = compareByRatio;
425
419
    else if( !strcmp( mode, "sort-by-state" ) )
426
420
        sort_func = compareByState;
427
421
    else if( !strcmp( mode, "sort-by-tracker" ) )
428
422
        sort_func = compareByTracker;
429
 
    else
430
 
    {
 
423
    else if( !strcmp( mode, "sort-by-size" ) )
 
424
        sort_func = compareBySize;
 
425
    else {
431
426
        sort_func = compareByName;
432
427
        type = isReversed ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING;
433
428
    }
834
829
    return count;
835
830
}
836
831
 
837
 
void
838
 
tr_core_blocksig( TrCore *     core,
839
 
                  gboolean     isDone,
840
 
                  const char * status )
841
 
{
842
 
    g_signal_emit( core, TR_CORE_GET_CLASS(
843
 
                       core )->blocksig, 0, isDone, status );
 
832
static void
 
833
emitBlocklistUpdated( TrCore * core, int ruleCount )
 
834
{
 
835
    g_signal_emit( core, TR_CORE_GET_CLASS( core )->blocklistSignal, 0, ruleCount );
 
836
}
 
837
 
 
838
static void
 
839
emitPortTested( TrCore * core, gboolean isOpen )
 
840
{
 
841
    g_signal_emit( core, TR_CORE_GET_CLASS( core )->portSignal, 0, isOpen );
844
842
}
845
843
 
846
844
static void
875
873
        else
876
874
        {
877
875
            tr_info inf;
878
 
            int err = tr_torrentParse( session, ctor, &inf );
 
876
            int err = tr_torrentParse( ctor, &inf );
879
877
 
880
878
            switch( err )
881
879
            {
987
985
 
988
986
    if( findTorrentInModel( core, id, &iter ) )
989
987
    {
990
 
        TrTorrent *    gtor;
 
988
        TrTorrent * gtor;
991
989
        GtkTreeModel * model = tr_core_model( core );
992
990
        gtk_tree_model_get( model, &iter, MC_TORRENT, &gtor, -1 );
993
991
        tr_torrent_clear( gtor );
1270
1268
    }
1271
1269
}
1272
1270
 
 
1271
void
 
1272
tr_core_set_pref_double( TrCore *     self,
 
1273
                         const char * key,
 
1274
                         double       newval )
 
1275
{
 
1276
    const double oldval = pref_double_get( key );
 
1277
 
 
1278
    if( oldval != newval )
 
1279
    {
 
1280
        pref_double_set( key, newval );
 
1281
        commitPrefsChange( self, key );
 
1282
    }
 
1283
}
 
1284
 
 
1285
/***
 
1286
****
 
1287
****  RPC Interface
 
1288
****
 
1289
***/
 
1290
 
 
1291
/* #define DEBUG_RPC */
 
1292
 
 
1293
static int nextTag = 1;
 
1294
 
 
1295
typedef void ( server_response_func )( TrCore * core, tr_benc * response, gpointer user_data );
 
1296
 
 
1297
struct pending_request_data
 
1298
{
 
1299
    int tag;
 
1300
    TrCore * core;
 
1301
    server_response_func * responseFunc;
 
1302
    gpointer responseFuncUserData;
 
1303
};
 
1304
 
 
1305
static GHashTable * pendingRequests = NULL;
 
1306
 
 
1307
static gboolean
 
1308
readResponseIdle( void * vresponse )
 
1309
{
 
1310
    GByteArray * response;
 
1311
    tr_benc top;
 
1312
    int64_t intVal;
 
1313
    int tag;
 
1314
    struct pending_request_data * data;
 
1315
 
 
1316
    response = vresponse;
 
1317
    tr_jsonParse( response->data, response->len, &top, NULL );
 
1318
    tr_bencDictFindInt( &top, "tag", &intVal );
 
1319
    tag = (int)intVal;
 
1320
 
 
1321
    data = g_hash_table_lookup( pendingRequests, &tag );
 
1322
    if( data )
 
1323
        (*data->responseFunc)(data->core, &top, data->responseFuncUserData );
 
1324
 
 
1325
    tr_bencFree( &top );
 
1326
    g_hash_table_remove( pendingRequests, &tag );
 
1327
    g_byte_array_free( response, TRUE );
 
1328
    return FALSE;
 
1329
}
 
1330
 
 
1331
static void
 
1332
readResponse( tr_session  * session UNUSED,
 
1333
              const char  * response,
 
1334
              size_t        response_len,
 
1335
              void        * unused UNUSED )
 
1336
{
 
1337
    GByteArray * bytes = g_byte_array_new( );
 
1338
#ifdef DEBUG_RPC
 
1339
    g_message( "response: [%*.*s]", (int)response_len, (int)response_len, response );
 
1340
#endif
 
1341
    g_byte_array_append( bytes, (const uint8_t*)response, response_len );
 
1342
    g_idle_add( readResponseIdle, bytes );
 
1343
}
 
1344
 
 
1345
static void
 
1346
sendRequest( TrCore * core, const char * json, int tag,
 
1347
             server_response_func * responseFunc, void * responseFuncUserData )
 
1348
{
 
1349
    tr_session * session = tr_core_session( core );
 
1350
 
 
1351
    if( pendingRequests == NULL )
 
1352
    {
 
1353
        pendingRequests = g_hash_table_new_full( g_int_hash, g_int_equal, NULL, g_free );
 
1354
    }
 
1355
 
 
1356
    if( session == NULL )
 
1357
    {
 
1358
        g_error( "GTK+ client doesn't support connections to remote servers yet." );
 
1359
    }
 
1360
    else
 
1361
    {
 
1362
        /* remember this request */
 
1363
        struct pending_request_data * data;
 
1364
        data = g_new0( struct pending_request_data, 1 );
 
1365
        data->core = core;
 
1366
        data->tag = tag;
 
1367
        data->responseFunc = responseFunc;
 
1368
        data->responseFuncUserData = responseFuncUserData;
 
1369
        g_hash_table_insert( pendingRequests, &data->tag, data );
 
1370
 
 
1371
        /* make the request */
 
1372
#ifdef DEBUG_RPC
 
1373
        g_message( "request: [%s]", json );
 
1374
#endif
 
1375
        tr_rpc_request_exec_json( session, json, strlen( json ), readResponse, GINT_TO_POINTER(tag) );
 
1376
    }
 
1377
}
 
1378
 
 
1379
/***
 
1380
****  Sending a test-port request via RPC
 
1381
***/
 
1382
 
 
1383
static void
 
1384
portTestResponseFunc( TrCore * core, tr_benc * response, gpointer userData UNUSED )
 
1385
{
 
1386
    tr_benc * args;
 
1387
    tr_bool isOpen = FALSE;
 
1388
 
 
1389
    if( tr_bencDictFindDict( response, "arguments", &args ) )
 
1390
        tr_bencDictFindBool( args, "port-is-open", &isOpen );
 
1391
 
 
1392
    emitPortTested( core, isOpen );
 
1393
}
 
1394
 
 
1395
void
 
1396
tr_core_port_test( TrCore * core )
 
1397
{
 
1398
    char buf[128];
 
1399
    const int tag = nextTag++;
 
1400
    g_snprintf( buf, sizeof( buf ), "{ \"method\": \"port-test\", \"tag\": %d }", tag );
 
1401
    sendRequest( core, buf, tag, portTestResponseFunc, NULL );
 
1402
}
 
1403
 
 
1404
/***
 
1405
****  Updating a blocklist via RPC
 
1406
***/
 
1407
 
 
1408
static void
 
1409
blocklistResponseFunc( TrCore * core, tr_benc * response, gpointer userData UNUSED )
 
1410
{
 
1411
    tr_benc * args;
 
1412
    int64_t ruleCount = 0;
 
1413
 
 
1414
    if( tr_bencDictFindDict( response, "arguments", &args ) )
 
1415
        tr_bencDictFindInt( args, "blocklist-size", &ruleCount );
 
1416
 
 
1417
    if( ruleCount > 0 )
 
1418
        pref_int_set( "blocklist-date", time( NULL ) );
 
1419
 
 
1420
    emitBlocklistUpdated( core, ruleCount );
 
1421
}
 
1422
 
 
1423
void
 
1424
tr_core_blocklist_update( TrCore * core )
 
1425
{
 
1426
    char buf[128];
 
1427
    const int tag = nextTag++;
 
1428
    g_snprintf( buf, sizeof( buf ), "{ \"method\": \"blocklist-update\", \"tag\": %d }", tag );
 
1429
    sendRequest( core, buf, tag, blocklistResponseFunc, NULL );
 
1430
}
 
1431
 
 
1432
/***
 
1433
****
 
1434
***/
 
1435
 
 
1436
void
 
1437
tr_core_exec_json( TrCore * core, const char * json )
 
1438
{
 
1439
    g_message( "executing %s", json );
 
1440
    sendRequest( core, json, 0, NULL, NULL );
 
1441
}
 
1442
 
 
1443
void
 
1444
tr_core_exec( TrCore * core, const tr_benc * top )
 
1445
{
 
1446
    char * json = tr_bencToJSON( top );
 
1447
    tr_core_exec_json( core, json );
 
1448
    tr_free( json );
 
1449
}