source: trunk/libtransmission/rpc.c @ 5868

Last change on this file since 5868 was 5868, checked in by charles, 14 years ago

(#954) rpc: add "torrent-remove" method. rename tr_torrentDelete() as tr_torrentRemove() for consistency with various parts of the code.

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