source: trunk/libtransmission/rpc.c @ 6612

Last change on this file since 6612 was 6612, checked in by charles, 13 years ago

bencode cleanup: remove unused functions and unnecessary #includes

  • Property svn:keywords set to Date Rev Author Id
File size: 27.4 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: rpc.c 6612 2008-08-21 14:57:59Z charles $
11 */
12
13#include <assert.h>
14#include <ctype.h> /* isdigit */
15#include <stdlib.h> /* strtol */
16#include <string.h> /* strcmp */
17
18#include "transmission.h"
19#include "bencode.h"
20#include "ratecontrol.h"
21#include "rpc.h"
22#include "json.h"
23#include "session.h"
24#include "torrent.h"
25#include "utils.h"
26
27#define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( *ary ) )
28
29/***
30****
31***/
32
33static tr_rpc_callback_status
34notify( tr_handle * session, int type, tr_torrent * tor )
35{
36    tr_rpc_callback_status status = 0;
37
38    if( session->rpc_func )
39        status = session->rpc_func( session, type, tor, session->rpc_func_user_data );
40
41    return status;
42}
43
44/***
45****
46***/
47
48static tr_torrent **
49getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
50{
51    int torrentCount = 0;
52    int64_t id;
53    tr_torrent ** torrents = NULL;
54    tr_benc * ids;
55
56    if( tr_bencDictFindList( args, "ids", &ids ) )
57    {
58        int i;
59        const int n = tr_bencListSize( ids );
60
61        torrents = tr_new0( tr_torrent*, n );
62
63        for( i=0; i<n; ++i )
64        {
65            tr_torrent * tor = NULL;
66            tr_benc * node = tr_bencListChild( ids, i );
67            int64_t id;
68            const char * str;
69            if( tr_bencGetInt( node, &id ) )
70                tor = tr_torrentFindFromId( handle, id );
71            else if( tr_bencGetStr( node, &str ) )
72                tor = tr_torrentFindFromHashString( handle, str );
73            if( tor )
74                torrents[torrentCount++] = tor;
75        }
76    }
77    else if( tr_bencDictFindInt( args, "ids", &id ) 
78          || tr_bencDictFindInt( args, "id", &id ) )
79    {
80        tr_torrent * tor;
81        torrents = tr_new0( tr_torrent*, 1 );
82        if(( tor = tr_torrentFindFromId( handle, id )))
83            torrents[torrentCount++] = tor;
84    }
85    else /* all of them */
86    {
87        tr_torrent * tor = NULL;
88        const int n = tr_sessionCountTorrents( handle );
89        torrents = tr_new0( tr_torrent*, n );
90        while(( tor = tr_torrentNext( handle, tor )))
91            torrents[torrentCount++] = tor;
92    }
93
94    *setmeCount = torrentCount;
95    return torrents;
96}
97
98static const char*
99torrentStart( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
100{
101    int i, torrentCount;
102    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
103    for( i=0; i<torrentCount; ++i )
104    {
105        tr_torrent * tor = torrents[i];
106        tr_torrentStart( tor );
107        notify( h, TR_RPC_TORRENT_STARTED, tor );
108    }
109    tr_free( torrents );
110    return NULL;
111}
112
113static const char*
114torrentStop( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
115{
116    int i, torrentCount;
117    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
118    for( i=0; i<torrentCount; ++i )
119    {
120        tr_torrent * tor = torrents[i];
121        tr_torrentStop( tor );
122        notify( h, TR_RPC_TORRENT_STOPPED, tor );
123    }
124    tr_free( torrents );
125    return NULL;
126}
127
128static const char*
129torrentRemove( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
130{
131    int i, torrentCount;
132    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
133    for( i=0; i<torrentCount; ++i )
134    {
135        tr_torrent * tor = torrents[i];
136        const tr_rpc_callback_status status = notify( h, TR_RPC_TORRENT_REMOVING, tor );
137        if( ! ( status & TR_RPC_NOREMOVE ) )
138            tr_torrentRemove( tor );
139    }
140    tr_free( torrents );
141    return NULL;
142}
143
144static const char*
145torrentVerify( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
146{
147    int i, torrentCount;
148    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
149    for( i=0; i<torrentCount; ++i )
150    {
151        tr_torrent * tor = torrents[i];
152        tr_torrentVerify( tor );
153        notify( h, TR_RPC_TORRENT_CHANGED, tor );
154    }
155    tr_free( torrents );
156    return NULL;
157}
158
159/***
160****
161***/
162
163static void
164addFiles( const tr_torrent * tor, tr_benc * list )
165{
166    tr_file_index_t i;
167    tr_file_index_t n;
168    const tr_info * info = tr_torrentInfo( tor );
169    tr_file_stat * files = tr_torrentFiles( tor, &n );
170
171    for( i=0; i<info->fileCount; ++i )
172    {
173        const tr_file * file = &info->files[i];
174        tr_benc * d = tr_bencListAddDict( list, 3 );
175        tr_bencDictAddInt( d, "bytesCompleted", files[i].bytesCompleted );
176        tr_bencDictAddInt( d, "length", file->length );
177        tr_bencDictAddStr( d, "name", file->name );
178    }
179
180    tr_torrentFilesFree( files, n );
181}
182
183static void
184addWebseeds( const tr_info * info, tr_benc * webseeds )
185{
186    int i;
187    for( i=0; i<info->webseedCount; ++i )
188        tr_bencListAddStr( webseeds, info->webseeds[i] );
189}
190
191static void
192addTrackers( const tr_info * info, tr_benc * trackers )
193{
194    int i;
195    for( i=0; i<info->trackerCount; ++i )
196    {
197        const tr_tracker_info * t = &info->trackers[i];
198        tr_benc * d = tr_bencListAddDict( trackers, 3 );
199        tr_bencDictAddStr( d, "announce", t->announce );
200        tr_bencDictAddStr( d, "scrape", t->scrape );
201        tr_bencDictAddInt( d, "tier", t->tier );
202    }
203}
204
205static void
206addField( const tr_torrent * tor, tr_benc * d, const char * key )
207{
208    const tr_info * inf = tr_torrentInfo( tor );
209    const tr_stat * st = tr_torrentStat( (tr_torrent*)tor );
210
211    if( !strcmp( key, "activityDate" ) )
212        tr_bencDictAddInt( d, key, st->activityDate );
213    else if( !strcmp( key, "addedDate" ) )
214        tr_bencDictAddInt( d, key, st->addedDate );
215    else if( !strcmp( key, "announceResponse" ) )
216        tr_bencDictAddStr( d, key, st->announceResponse );
217    else if( !strcmp( key, "announceURL" ) )
218        tr_bencDictAddStr( d, key, st->announceURL );
219    else if( !strcmp( key, "comment" ) )
220        tr_bencDictAddStr( d, key, inf->comment ? inf->comment : "" );
221    else if( !strcmp( key, "corruptEver" ) )
222        tr_bencDictAddInt( d, key, st->corruptEver );
223    else if( !strcmp( key, "creator" ) )
224        tr_bencDictAddStr( d, key, inf->creator ? inf->creator : "" );
225    else if( !strcmp( key, "dateCreated" ) )
226        tr_bencDictAddInt( d, key, inf->dateCreated );
227    else if( !strcmp( key, "desiredAvailable" ) )
228        tr_bencDictAddInt( d, key, st->desiredAvailable );
229    else if( !strcmp( key, "doneDate" ) )
230        tr_bencDictAddInt( d, key, st->doneDate );
231    else if( !strcmp( key, "downloadedEver" ) )
232        tr_bencDictAddInt( d, key, st->downloadedEver );
233    else if( !strcmp( key, "downloadLimitMode" ) )
234        tr_bencDictAddInt( d, key, tr_torrentGetSpeedMode( tor, TR_DOWN ) );
235    else if( !strcmp( key, "downloadLimit" ) )
236        tr_bencDictAddInt( d, key, tr_torrentGetSpeedLimit( tor, TR_DOWN ) );
237    else if( !strcmp( key, "error" ) )
238        tr_bencDictAddInt( d, key, st->error );
239    else if( !strcmp( key, "errorString" ) )
240        tr_bencDictAddStr( d, key, st->errorString );
241    else if( !strcmp( key, "eta" ) )
242        tr_bencDictAddInt( d, key, st->eta );
243    else if( !strcmp( key, "files" ) )
244        addFiles( tor, tr_bencDictAddList( d, key, inf->fileCount ) );
245    else if( !strcmp( key, "hashString" ) )
246        tr_bencDictAddStr( d, key, tor->info.hashString );
247    else if( !strcmp( key, "haveUnchecked" ) )
248        tr_bencDictAddInt( d, key, st->haveUnchecked );
249    else if( !strcmp( key, "haveValid" ) )
250        tr_bencDictAddInt( d, key, st->haveValid );
251    else if( !strcmp( key, "id" ) )
252        tr_bencDictAddInt( d, key, st->id );
253    else if( !strcmp( key, "isPrivate" ) )
254        tr_bencDictAddInt( d, key, tr_torrentIsPrivate( tor ) );
255    else if( !strcmp( key, "lastAnnounceTime" ) )
256        tr_bencDictAddInt( d, key, st->lastAnnounceTime );
257    else if( !strcmp( key, "lastScrapeTime" ) )
258        tr_bencDictAddInt( d, key, st->lastScrapeTime );
259    else if( !strcmp( key, "leechers" ) )
260        tr_bencDictAddInt( d, key, st->leechers );
261    else if( !strcmp( key, "leftUntilDone" ) )
262        tr_bencDictAddInt( d, key, st->leftUntilDone );
263    else if( !strcmp( key, "manualAnnounceTime" ) )
264        tr_bencDictAddInt( d, key, st->manualAnnounceTime );
265    else if( !strcmp( key, "maxConnectedPeers" ) )
266        tr_bencDictAddInt( d, key,  tr_torrentGetPeerLimit( tor ) );
267    else if( !strcmp( key, "name" ) )
268        tr_bencDictAddStr( d, key, inf->name );
269    else if( !strcmp( key, "nextAnnounceTime" ) )
270        tr_bencDictAddInt( d, key, st->nextAnnounceTime );
271    else if( !strcmp( key, "nextScrapeTime" ) )
272        tr_bencDictAddInt( d, key, st->nextScrapeTime );
273    else if( !strcmp( key, "peersConnected" ) )
274        tr_bencDictAddInt( d, key, st->peersConnected );
275    else if( !strcmp( key, "peersFrom" ) ) {
276        tr_benc * tmp = tr_bencDictAddDict( d, key, 4 );
277        const int * f = st->peersFrom;
278        tr_bencDictAddInt( tmp, "fromCache",    f[TR_PEER_FROM_CACHE] );
279        tr_bencDictAddInt( tmp, "fromIncoming", f[TR_PEER_FROM_INCOMING] );
280        tr_bencDictAddInt( tmp, "fromPex",      f[TR_PEER_FROM_PEX] );
281        tr_bencDictAddInt( tmp, "fromTracker",  f[TR_PEER_FROM_TRACKER] );
282    }
283    else if( !strcmp( key, "peersGettingFromUs" ) )
284        tr_bencDictAddInt( d, key, st->peersGettingFromUs );
285    else if( !strcmp( key, "peersKnown" ) )
286        tr_bencDictAddInt( d, key, st->peersKnown );
287    else if( !strcmp( key, "peersSendingToUs" ) )
288        tr_bencDictAddInt( d, key, st->peersSendingToUs );
289    else if( !strcmp( key, "pieceCount" ) )
290        tr_bencDictAddInt( d, key, inf->pieceCount );
291    else if( !strcmp( key, "pieceSize" ) )
292        tr_bencDictAddInt( d, key, inf->pieceSize );
293    else if( !strcmp( key, "priorities" ) ) {
294        tr_file_index_t i;
295        tr_benc * p = tr_bencDictAddList( d, key, inf->fileCount );
296        for( i=0; i<inf->fileCount; ++i )
297            tr_bencListAddInt( p, inf->files[i].priority );
298    }
299    else if( !strcmp( key, "rateDownload" ) )
300        tr_bencDictAddInt( d, key, (int)(st->rateDownload*1024) );
301    else if( !strcmp( key, "rateUpload" ) )
302        tr_bencDictAddInt( d, key, (int)(st->rateUpload*1024) );
303    else if( !strcmp( key, "recheckProgress" ) )
304        tr_bencDictAddDouble( d, key, st->recheckProgress );
305    else if( !strcmp( key, "scrapeResponse" ) )
306        tr_bencDictAddStr( d, key, st->scrapeResponse );
307    else if( !strcmp( key, "scrapeURL" ) )
308        tr_bencDictAddStr( d, key, st->scrapeURL );
309    else if( !strcmp( key, "seeders" ) )
310        tr_bencDictAddInt( d, key, st->seeders );
311    else if( !strcmp( key, "sizeWhenDone" ) )
312        tr_bencDictAddInt( d, key, st->sizeWhenDone );
313    else if( !strcmp( key, "startDate" ) )
314        tr_bencDictAddInt( d, key, st->startDate );
315    else if( !strcmp( key, "status" ) )
316        tr_bencDictAddInt( d, key, st->status );
317    else if( !strcmp( key, "swarmSpeed" ) )
318        tr_bencDictAddInt( d, key, (int)(st->swarmSpeed*1024) );
319    else if( !strcmp( key, "timesCompleted" ) )
320        tr_bencDictAddInt( d, key, st->timesCompleted );
321    else if( !strcmp( key, "trackers" ) )
322        addTrackers( inf, tr_bencDictAddList( d, key, inf->trackerCount ) );
323    else if( !strcmp( key, "totalSize" ) )
324        tr_bencDictAddInt( d, key, inf->totalSize );
325    else if( !strcmp( key, "uploadedEver" ) )
326        tr_bencDictAddInt( d, key, st->uploadedEver );
327    else if( !strcmp( key, "uploadLimitMode" ) )
328        tr_bencDictAddInt( d, key,   tr_torrentGetSpeedMode( tor, TR_UP ) );
329    else if( !strcmp( key, "uploadLimit" ) )
330        tr_bencDictAddInt( d, key, tr_torrentGetSpeedLimit( tor, TR_UP ) );
331    else if( !strcmp( key, "uploadRatio" ) )
332        tr_bencDictAddDouble( d, key, tr_getRatio( st->uploadedEver, st->downloadedEver ) );
333    else if( !strcmp( key, "wanted" ) ) {
334        tr_file_index_t i;
335        tr_benc * w = tr_bencDictAddList( d, key, inf->fileCount );
336        for( i=0; i<inf->fileCount; ++i )
337            tr_bencListAddInt( w, inf->files[i].dnd ? 0 : 1 );
338    }
339    else if( !strcmp( key, "webseeds" ) )
340        addWebseeds( inf, tr_bencDictAddList( d, key, inf->trackerCount ) );
341    else if( !strcmp( key, "webseedsSendingToUs" ) )
342        tr_bencDictAddInt( d, key, st->webseedsSendingToUs );
343}
344
345static void
346addInfo( const tr_torrent * tor, tr_benc * d, tr_benc * fields )
347{
348    int i;
349    const int n = tr_bencListSize( fields );
350    const char * str;
351
352    tr_bencInitDict( d, n );
353
354    for( i=0; i<n; ++i )
355        if( tr_bencGetStr( tr_bencListChild( fields, i ), &str ) )
356            addField( tor, d, str );
357}
358
359static const char*
360torrentGet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
361{
362    int i, torrentCount;
363    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
364    tr_benc * list = tr_bencDictAddList( args_out, "torrents", torrentCount );
365    tr_benc * fields;
366    char *msg = NULL;
367
368    if( !tr_bencDictFindList( args_in, "fields", &fields ) )
369        msg = "no fields specified";
370    else for( i=0; i<torrentCount; ++i )
371        addInfo( torrents[i], tr_bencListAdd( list ), fields );
372
373    tr_free( torrents );
374    return msg;
375}
376
377/***
378****
379***/
380
381static void
382setFilePriorities( tr_torrent * tor, int priority, tr_benc * list )
383{
384    int i;
385    int64_t tmp;
386    int fileCount = 0;
387    const int n = tr_bencListSize( list );
388    tr_file_index_t * files = tr_new0( tr_file_index_t, tor->info.fileCount );
389
390    if( n )
391    {
392        for( i=0; i<n; ++i )
393            if( tr_bencGetInt( tr_bencListChild( list, i ), &tmp ) )
394                if( 0<=tmp && tmp<tor->info.fileCount )
395                    files[fileCount++] = tmp;
396    }
397    else // if empty set, apply to all
398    {
399        tr_file_index_t t;
400        for( t=0; t<tor->info.fileCount; ++t )
401            files[fileCount++] = t;
402    }
403
404    if( fileCount )
405        tr_torrentSetFilePriorities( tor, files, fileCount, priority );
406
407    tr_free( files );
408}
409
410static void
411setFileDLs( tr_torrent * tor, int do_download, tr_benc * list )
412{
413    int i;
414    int64_t tmp;
415    int fileCount = 0;
416    const int n = tr_bencListSize( list );
417    tr_file_index_t * files = tr_new0( tr_file_index_t, tor->info.fileCount );
418
419    if( n ) // if argument list, process them
420    {
421        for( i=0; i<n; ++i )
422            if( tr_bencGetInt( tr_bencListChild( list, i ), &tmp ) )
423                if( 0<=tmp && tmp<tor->info.fileCount )
424                    files[fileCount++] = tmp;
425    }
426    else // if empty set, apply to all
427    {
428        tr_file_index_t t;
429        for( t=0; t<tor->info.fileCount; ++t )
430            files[fileCount++] = t;
431    }
432
433    if( fileCount )
434        tr_torrentSetFileDLs( tor, files, fileCount, do_download );
435
436    tr_free( files );
437}
438
439static const char*
440torrentSet( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
441{
442    int i, torrentCount;
443    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
444
445    for( i=0; i<torrentCount; ++i )
446    {
447        int64_t tmp;
448        tr_benc * files;
449        tr_torrent * tor = torrents[i];
450
451        if( tr_bencDictFindList( args_in, "files-unwanted", &files ) )
452            setFileDLs( tor, FALSE, files );
453        if( tr_bencDictFindList( args_in, "files-wanted", &files ) )
454            setFileDLs( tor, TRUE, files );
455        if( tr_bencDictFindInt( args_in, "peer-limit", &tmp ) )
456            tr_torrentSetPeerLimit( tor, tmp );
457        if( tr_bencDictFindList( args_in, "priority-high", &files ) )
458            setFilePriorities( tor, TR_PRI_HIGH, files );
459        if( tr_bencDictFindList( args_in, "priority-low", &files ) )
460            setFilePriorities( tor, TR_PRI_LOW, files );
461        if( tr_bencDictFindList( args_in, "priority-normal", &files ) )
462            setFilePriorities( tor, TR_PRI_NORMAL, files );
463        if( tr_bencDictFindInt( args_in, "speed-limit-down", &tmp ) )
464            tr_torrentSetSpeedLimit( tor, TR_DOWN, tmp );
465        if( tr_bencDictFindInt( args_in, "speed-limit-down-enabled", &tmp ) )
466            tr_torrentSetSpeedMode( tor, TR_DOWN, tmp ? TR_SPEEDLIMIT_SINGLE
467                                                      : TR_SPEEDLIMIT_GLOBAL );
468        if( tr_bencDictFindInt( args_in, "speed-limit-up", &tmp ) )
469            tr_torrentSetSpeedLimit( tor, TR_UP, tmp );
470        if( tr_bencDictFindInt( args_in, "speed-limit-up-enabled", &tmp ) )
471            tr_torrentSetSpeedMode( tor, TR_UP, tmp ? TR_SPEEDLIMIT_SINGLE
472                                                    : TR_SPEEDLIMIT_GLOBAL );
473
474        notify( h, TR_RPC_TORRENT_CHANGED, tor );
475    }
476
477    tr_free( torrents );
478    return NULL;
479}
480
481/***
482****
483***/
484
485static const char*
486torrentAdd( tr_handle * h, tr_benc * args_in, tr_benc * args_out )
487{
488    const char * filename = NULL;
489    const char * metainfo_base64 = NULL;
490    tr_bencDictFindStr( args_in, "filename", &filename );
491    tr_bencDictFindStr( args_in, "metainfo", &metainfo_base64 );
492    if( !filename && !metainfo_base64 )
493        return "no filename or metainfo specified";
494    else
495    {
496        int64_t i;
497        int err = 0;
498        const char * str;
499        tr_ctor * ctor;
500        tr_torrent * tor;
501
502        ctor = tr_ctorNew( h );
503
504        /* set the metainfo */
505        if( filename )
506            tr_ctorSetMetainfoFromFile( ctor, filename );
507        else {
508            int len;
509            char * metainfo = tr_base64_decode( metainfo_base64, -1,  &len );
510            tr_ctorSetMetainfo( ctor, (uint8_t*)metainfo, len );
511            tr_free( metainfo );
512        }
513
514        /* set the optional arguments */
515        if( tr_bencDictFindStr( args_in, "download-dir", &str ) )
516            tr_ctorSetDownloadDir( ctor, TR_FORCE, str );
517        if( tr_bencDictFindInt( args_in, "paused", &i ) )
518            tr_ctorSetPaused( ctor, TR_FORCE, i );
519        if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
520            tr_ctorSetPeerLimit( ctor, TR_FORCE, i );
521
522        tor = tr_torrentNew( h, ctor, &err );
523        tr_ctorFree( ctor );
524
525        if( tor ) {
526            tr_benc fields;
527            tr_bencInitList( &fields, 3 );
528            tr_bencListAddStr( &fields, "id" );
529            tr_bencListAddStr( &fields, "name" );
530            tr_bencListAddStr( &fields, "hashString" );
531            addInfo( tor, tr_bencDictAdd( args_out, "torrent-added" ), &fields );
532            notify( h, TR_RPC_TORRENT_ADDED, tor );
533            tr_bencFree( &fields );
534        } else if( err == TR_EDUPLICATE ) {
535            return "duplicate torrent";
536        } else if( err == TR_EINVALID ) {
537            return "invalid or corrupt torrent file";
538        }
539    }
540
541    return NULL;
542}
543
544/***
545****
546***/
547
548static const char*
549sessionSet( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
550{
551    int64_t i;
552    const char * str;
553
554    if( tr_bencDictFindStr( args_in, "download-dir", &str ) )
555        tr_sessionSetDownloadDir( h, str );
556    if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
557        tr_sessionSetPeerLimit( h, i );
558    if( tr_bencDictFindInt( args_in, "pex-allowed", &i ) )
559        tr_sessionSetPexEnabled( h, i );
560    if( tr_bencDictFindInt( args_in, "port", &i ) )
561        tr_sessionSetPeerPort( h, i );
562    if( tr_bencDictFindInt( args_in, "port-forwarding-enabled", &i ) )
563        tr_sessionSetPortForwardingEnabled( h, i );
564    if( tr_bencDictFindInt( args_in, "speed-limit-down", &i ) )
565        tr_sessionSetSpeedLimit( h, TR_DOWN, i );
566    if( tr_bencDictFindInt( args_in, "speed-limit-down-enabled", &i ) )
567        tr_sessionSetSpeedLimitEnabled( h, TR_DOWN, i );
568    if( tr_bencDictFindInt( args_in, "speed-limit-up", &i ) )
569        tr_sessionSetSpeedLimit( h, TR_UP, i );
570    if( tr_bencDictFindInt( args_in, "speed-limit-up-enabled", &i ) )
571        tr_sessionSetSpeedLimitEnabled( h, TR_UP, i );
572    if( tr_bencDictFindStr( args_in, "encryption", &str ) ) {
573        if( !strcmp( str, "required" ) )
574            tr_sessionSetEncryption( h, TR_ENCRYPTION_REQUIRED );
575        else if( !strcmp( str, "tolerated" ) )
576            tr_sessionSetEncryption( h, TR_CLEAR_PREFERRED );
577        else
578            tr_sessionSetEncryption( h, TR_ENCRYPTION_PREFERRED );
579    }
580
581    notify( h, TR_RPC_SESSION_CHANGED, NULL );
582
583    return NULL;
584}
585
586static const char*
587sessionStats( tr_handle * h, tr_benc * args_in UNUSED, tr_benc * args_out )
588{
589    tr_benc * d = tr_bencDictAddDict( args_out, "session-stats", 10 );
590    tr_torrent * tor = NULL;
591    float up, down;
592    int running = 0;
593    int total = 0;
594
595    tr_sessionGetSpeed( h, &down, &up );
596    while(( tor = tr_torrentNext( h, tor ))) {
597        ++total;
598        if( tor->isRunning )
599            ++running;
600    }
601       
602    tr_bencDictAddInt( d, "activeTorrentCount", running );
603    tr_bencDictAddInt( d, "downloadSpeed", (int)(down*1024) );
604    tr_bencDictAddInt( d, "pausedTorrentCount", total-running );
605    tr_bencDictAddInt( d, "torrentCount", total );
606    tr_bencDictAddInt( d, "uploadSpeed", (int)(up*1024) );
607    return NULL;
608}
609
610static const char*
611sessionGet( tr_handle * h, tr_benc * args_in UNUSED, tr_benc * args_out )
612{
613    const char * str;
614    tr_benc * d = args_out;
615
616    tr_bencDictAddStr( d, "download-dir",
617                          tr_sessionGetDownloadDir( h ) );
618    tr_bencDictAddInt( d, "peer-limit",
619                          tr_sessionGetPeerLimit( h ) );
620    tr_bencDictAddInt( d, "pex-allowed",
621                          tr_sessionIsPexEnabled( h ) );
622    tr_bencDictAddInt( d, "port",
623                          tr_sessionGetPeerPort( h ) );
624    tr_bencDictAddInt( d, "port-forwarding-enabled",
625                          tr_sessionIsPortForwardingEnabled( h ) );
626    tr_bencDictAddInt( d, "speed-limit-up",
627                          tr_sessionGetSpeedLimit( h, TR_UP ) * 1024 );
628    tr_bencDictAddInt( d, "speed-limit-up-enabled",
629                          tr_sessionIsSpeedLimitEnabled( h, TR_UP ) );
630    tr_bencDictAddInt( d, "speed-limit-down",
631                          tr_sessionGetSpeedLimit( h, TR_DOWN ) * 1024 );
632    tr_bencDictAddInt( d, "speed-limit-down-enabled",
633                          tr_sessionIsSpeedLimitEnabled( h, TR_DOWN ) );
634    switch( tr_sessionGetEncryption( h ) ) {
635        case TR_CLEAR_PREFERRED: str = "tolerated"; break;
636        case TR_ENCRYPTION_REQUIRED: str = "required"; break;
637        default: str = "preferred"; break;
638    }
639    tr_bencDictAddStr( d, "encryption", str );
640
641    return NULL;
642}
643
644/***
645****
646***/
647
648typedef const char* (handler)( tr_handle*, tr_benc*, tr_benc* );
649
650static struct method {
651    const char * name;
652    handler * func;
653} methods[] = { 
654    { "session-get", sessionGet },
655    { "session-set", sessionSet },
656    { "session-stats", sessionStats },
657    { "torrent-add", torrentAdd },
658    { "torrent-get", torrentGet },
659    { "torrent-remove", torrentRemove },
660    { "torrent-set", torrentSet },
661    { "torrent-start", torrentStart },
662    { "torrent-stop", torrentStop },
663    { "torrent-verify", torrentVerify }
664};
665
666static char*
667request_exec( struct tr_handle * handle,
668              tr_benc          * request,
669              int              * response_len )
670{
671    int64_t i;
672    const char * str;
673    char * out;
674    tr_benc response;
675    tr_benc * args_in = tr_bencDictFind( request, "arguments" );
676    tr_benc * args_out = NULL;
677    const char * result = NULL;
678
679    /* build the response skeleton */
680    tr_bencInitDict( &response, 3 );
681    args_out = tr_bencDictAddDict( &response, "arguments", 0 );
682
683    /* parse the request */
684    if( !tr_bencDictFindStr( request, "method", &str ) )
685        result = "no method name";
686    else {
687        const int n = TR_N_ELEMENTS( methods );
688        for( i=0; i<n; ++i )
689            if( !strcmp( str, methods[i].name ) )
690                break;
691        result = i==n
692            ? "method name not recognized"
693            : (*methods[i].func)( handle, args_in, args_out );
694    }
695
696    /* serialize & return the response */
697    if( !result )
698         result = "success";
699    tr_bencDictAddStr( &response, "result", result );
700    if( tr_bencDictFindInt( request, "tag", &i ) )
701        tr_bencDictAddInt( &response, "tag", i );
702    out = tr_bencSaveAsJSON( &response, response_len );
703    tr_bencFree( &response );
704    return out;
705}
706
707char*
708tr_rpc_request_exec_json( struct tr_handle  * handle,
709                          const void        * request_json,
710                          int                 request_len,
711                          int               * response_len )
712{
713    tr_benc top;
714    int have_content;
715    char * ret;
716
717    if( request_len < 0 )
718        request_len = strlen( request_json );
719
720    have_content = !tr_jsonParse( request_json, request_len, &top, NULL );
721    ret = request_exec( handle, have_content ? &top : NULL, response_len );
722
723    if( have_content )
724        tr_bencFree( &top );
725    return ret;
726}
727
728static void
729addToken( tr_benc * list, const char * token, size_t len )
730{
731    char * p;
732    const char * end = token + len;
733    const long a = strtol( token, &p, 10 );
734    if( p == end )
735        tr_bencListAddInt( list, a );
736    else if( *p == '-' && isdigit(p[1]) ) {
737        const long b = strtol( p+1, &p, 10 );
738        if( ( p == end ) && ( b > a ) ) {
739            long i;
740            for( i=a; i<=b; ++i )
741                tr_bencListAddInt( list, i );
742        }
743    }
744}
745
746/**
747 * Munge the URI into a usable form.
748 *
749 * We have very loose typing on this to make the URIs as simple as possible:
750 * - anything not a 'tag' or 'method' is automatically in 'arguments'
751 * - values that are all-digits are numbers
752 * - values that are all-digits or commas are number lists
753 * - all other values are strings
754 */
755void
756tr_rpc_parse_list_str( tr_benc     * setme,
757                       const char  * str_in,
758                       size_t        len )
759
760{
761    char * str = tr_strndup( str_in, len );
762    int isNum;
763    int isNumList;
764    int commaCount;
765    const char * walk;
766
767    isNum = 1;
768    isNumList = 1;
769    commaCount = 0;
770    walk = str;
771    for( ; *walk && (isNumList || isNum); ++walk ) {
772        if( isNumList ) isNumList = *walk=='-' || isdigit(*walk) || *walk==',';
773        if( isNum     ) isNum     = *walk=='-' || isdigit(*walk);
774        if( *walk == ',' ) ++commaCount;
775    }
776
777    if( isNum )
778        tr_bencInitInt( setme, strtol( str, NULL, 10 ) );
779    else if( !isNumList )
780        tr_bencInitStr( setme, str, len );
781    else {
782        tr_bencInitList( setme, commaCount + 1 );
783        walk = str;
784        while( *walk ) {
785            const char * p = strchr( walk, ',' );
786            if( !p )
787                p = walk + strlen( walk );
788            addToken( setme, walk, p-walk );
789            if( *p!=',' )
790                break;
791            walk = p + 1;
792        }
793    }
794
795    tr_free( str );
796}
797
798
799char*
800tr_rpc_request_exec_uri( struct tr_handle  * handle,
801                         const void        * request_uri,
802                         int                 request_len,
803                         int               * response_len )
804{
805    char * ret = NULL;
806    tr_benc top, * args;
807    char * request = tr_strndup( request_uri, request_len );
808    const char * pch;
809
810    tr_bencInitDict( &top, 3 );
811    args = tr_bencDictAddDict( &top, "arguments", 0 );
812
813    pch = strchr( request, '?' );
814    if( !pch ) pch = request;
815    while( pch )
816    {
817        const char * delim = strchr( pch, '=' );
818        const char * next = strchr( pch, '&' );
819        if( delim )
820        {
821            char * key = tr_strndup( pch, delim-pch );
822            int isArg = strcmp( key, "method" ) && strcmp( key, "tag" );
823            tr_benc * parent = isArg ? args : &top;
824            tr_rpc_parse_list_str( tr_bencDictAdd( parent, key ),
825                                   delim+1,
826                                   next ? (size_t)(next-(delim+1)) : strlen(delim+1) );
827            tr_free( key );
828        }
829        pch = next ? next+1 : NULL;
830    }
831
832    ret = request_exec( handle, &top, response_len );
833
834    /* cleanup */
835    tr_bencFree( &top );
836    tr_free( request );
837    return ret;
838}
Note: See TracBrowser for help on using the repository browser.