source: trunk/libtransmission/rpc.c @ 5913

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

sine we now have two public ports (peer and rpc), rename "publicPort" as "peerPort"

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