source: trunk/libtransmission/rpc.c @ 5911

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

more cleanup work:
(1) kill the pointless "tr_tracker_stat" struct.
(2) kill the unused "tr_torrentRemoveSaved()" function.
(3) kill the redundant "nextManualAnnounceTime" variable.
(4) make the TR_ERROR_IS_* macros private.

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