/* * This file Copyright (C) 2008 Charles Kerr * * This file is licensed by the GPL version 2. Works owned by the * Transmission project are granted a special exemption to clause 2(b) * so that the bulk of its code can remain under the MIT license. * This exemption does not extend to derived works not owned by * the Transmission project. * * $Id:$ */ #include #include /* strcmp */ #include "transmission.h" #include "bencode.h" #include "rpc.h" #include "json.h" #include "torrent.h" #include "utils.h" #define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( (ary)[0] ) ) /*** **** ***/ static tr_torrent ** getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount ) { tr_torrent ** torrents = NULL; int torrentCount = 0; tr_benc * ids; if( tr_bencDictFindList( args, "ids", &ids ) ) { int i; const int n = tr_bencListSize( ids ); torrents = tr_new0( tr_torrent*, n ); for( i=0; ipeersFrom; const struct tr_tracker_stat * s = &st->tracker_stat; tr_bencDictAddInt( d, "id", tor->uniqueId ); tr_bencDictAddInt( d, "status", st->status ); tr_bencDictAddInt( d, "error", st->error ); tr_bencDictAddStr( d, "errorString", st->errorString ); tr_bencDictAddDouble( d, "recheckProgress", st->recheckProgress ); tr_bencDictAddDouble( d, "percentComplete", st->percentComplete ); tr_bencDictAddDouble( d, "percentDone", st->percentDone ); tr_bencDictAddDouble( d, "rateDownload", st->rateDownload ); tr_bencDictAddDouble( d, "rateUpload", st->rateUpload ); tr_bencDictAddDouble( d, "swarmspeed", st->swarmspeed ); tr_bencDictAddDouble( d, "ratio", st->ratio ); tr_bencDictAddInt( d, "eta", st->eta ); tr_bencDictAddInt( d, "peersKnown", st->peersKnown ); tr_bencDictAddInt( d, "peersConnected", st->peersConnected ); tr_bencDictAddInt( d, "peersSendingToUs", st->peersSendingToUs ); tr_bencDictAddInt( d, "peersGettingFromUs", st->peersGettingFromUs ); tr_bencDictAddInt( d, "seeders", st->seeders ); tr_bencDictAddInt( d, "leechers", st->leechers ); tr_bencDictAddInt( d, "completedFromTracker", st->completedFromTracker ); tr_bencDictAddInt( d, "manualAnnounceTime", st->manualAnnounceTime ); tr_bencDictAddInt( d, "sizeWhenDone", st->sizeWhenDone ); tr_bencDictAddInt( d, "leftUntilDone", st->leftUntilDone ); tr_bencDictAddInt( d, "desiredAvailable", st->desiredAvailable ); tr_bencDictAddInt( d, "corruptEver", st->corruptEver ); tr_bencDictAddInt( d, "uploadedEver", st->uploadedEver ); tr_bencDictAddInt( d, "downloadedEver", st->downloadedEver ); tr_bencDictAddInt( d, "haveValid", st->haveValid ); tr_bencDictAddInt( d, "haveUnchecked", st->haveUnchecked ); tr_bencDictAddInt( d, "startDate", st->startDate ); tr_bencDictAddInt( d, "activityDate", st->activityDate ); t = tr_bencDictAddDict( d, "peersFrom", 4 ); tr_bencDictAddInt( t, "cache", f[TR_PEER_FROM_CACHE] ); tr_bencDictAddInt( t, "incoming", f[TR_PEER_FROM_INCOMING] ); tr_bencDictAddInt( t, "pex", f[TR_PEER_FROM_PEX] ); tr_bencDictAddInt( t, "tracker", f[TR_PEER_FROM_TRACKER] ); t = tr_bencDictAddDict( d, "tracker_stat", 7 ); tr_bencDictAddStr( t, "scrapeResponse", s->scrapeResponse ); tr_bencDictAddStr( t, "announceResponse", s->announceResponse ); tr_bencDictAddInt( t, "lastScrapeTime", s->lastScrapeTime ); tr_bencDictAddInt( t, "nextScrapeTime", s->nextScrapeTime ); tr_bencDictAddInt( t, "lastAnnounceTime", s->lastAnnounceTime ); tr_bencDictAddInt( t, "nextAnnounceTime", s->nextAnnounceTime ); tr_bencDictAddInt( t, "nextManualAnnounceTime", s->nextManualAnnounceTime ); } /* cleanup */ tr_free( torrents ); return NULL; } /** *** **/ static void addFiles( const tr_info * info, tr_benc * files ) { unsigned int i; for( i=0; ifileCount; ++i ) { const tr_file * file = &info->files[i]; tr_benc * d = tr_bencListAddDict( files, 4 ); tr_bencDictAddInt( d, "length", file->length ); tr_bencDictAddStr( d, "name", file->name ); tr_bencDictAddInt( d, "priority", file->priority ); tr_bencDictAddInt( d, "dnd", file->dnd ); } } static void addTrackers( const tr_info * info, tr_benc * trackers ) { int i; for( i=0; itrackerCount; ++i ) { const tr_tracker_info * t = &info->trackers[i]; tr_benc * d = tr_bencListAddDict( trackers, 3 ); tr_bencDictAddInt( d, "tier", t->tier ); tr_bencDictAddStr( d, "announce", t->announce ); tr_bencDictAddStr( d, "scrape", t->scrape ); } } static void addInfo( const tr_torrent * tor, tr_benc * d ) { const tr_info * inf = tr_torrentInfo( tor ); tr_bencInitDict( d, 14 ); tr_bencDictAddStr( d, "comment", inf->comment ? inf->comment : "" ); tr_bencDictAddStr( d, "creator", inf->creator ? inf->creator : "" ); tr_bencDictAddInt( d, "dateCreated", inf->dateCreated ); tr_bencDictAddStr( d, "hashString", inf->hashString ); tr_bencDictAddInt( d, "id", tor->uniqueId ); tr_bencDictAddInt( d, "isMultifile", inf->isMultifile ); tr_bencDictAddInt( d, "isPrivate", inf->isPrivate ); tr_bencDictAddStr( d, "name", inf->name ); tr_bencDictAddInt( d, "pieceCount", inf->pieceCount ); tr_bencDictAddInt( d, "pieceSize", inf->pieceSize ); tr_bencDictAddStr( d, "torrent", inf->torrent ); tr_bencDictAddInt( d, "totalSize", inf->totalSize ); addFiles ( inf, tr_bencDictAddList( d, "files", inf->fileCount ) ); addTrackers( inf, tr_bencDictAddList( d, "trackers", inf->trackerCount ) ); } static const char* torrentInfo( tr_handle * handle, tr_benc * args_in, tr_benc * args_out ) { int i, torrentCount; tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount ); tr_benc * list = tr_bencDictAddList( args_out, "info", torrentCount ); for( i=0; iuniqueId ); tr_bencDictAddInt( d, "peer-limit", tr_torrentGetPeerLimit( tor ) ); tr_bencDictAddInt( d, "speed-limit-down", tr_torrentGetSpeedLimit( tor, TR_DOWN ) ); tr_bencDictAddInt( d, "speed-limit-down-enabled", tr_torrentGetSpeedMode( tor, TR_DOWN ) == TR_SPEEDLIMIT_SINGLE ); tr_bencDictAddInt( d, "speed-limit-up", tr_torrentGetSpeedLimit( tor, TR_UP ) ); tr_bencDictAddInt( d, "speed-limit-up-enabled", tr_torrentGetSpeedMode( tor, TR_UP ) == TR_SPEEDLIMIT_SINGLE ); } tr_free( torrents ); return NULL; } static const char* torrentSet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED ) { int i, torrentCount; tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount ); for( i=0; iinfo.files[i].priority == TR_PRI_HIGH; } static int testFileLow( const tr_torrent * tor, int i ) { return tor->info.files[i].priority == TR_PRI_LOW; } static int testFileNormal( const tr_torrent * tor, int i ) { return tor->info.files[i].priority == TR_PRI_NORMAL; } static int testFileDND( const tr_torrent * tor, int i ) { return tor->info.files[i].dnd != 0; } static int testFileDownload( const tr_torrent * tor, int i ) { return tor->info.files[i].dnd == 0; } static void buildFileList( const tr_torrent * tor, tr_benc * dict, const char * key, fileTestFunc func ) { int i; const int n = tor->info.fileCount; tr_benc * list; int * files = tr_new0( int, n ); int fileCount = 0; for( i=0; iuniqueId ); buildFileList( tor, d, "download", testFileDownload ); buildFileList( tor, d, "no-download", testFileDND ); buildFileList( tor, d, "priority-low", testFileLow ); buildFileList( tor, d, "priority-normal", testFileNormal ); buildFileList( tor, d, "priority-high", testFileHigh ); } tr_free( torrents ); return NULL; } static void setFilePriorities( tr_torrent * tor, int priority, tr_benc * list ) { int i; int64_t tmp; int fileCount = 0; const int n = tr_bencListSize( list ); tr_file_index_t * files = tr_new0( tr_file_index_t, n ); for( i=0; i %s <--\n", request ); /* possibly convert o-rison to rison */ if( request && ( *request != '(' ) ) { const int n = strlen( request ); char * tmp = tr_new( char, n + 3 ); tmp[0] = '('; memcpy( tmp+1, request, n ); tmp[n+1] = ')'; tmp[n+2] = '\0'; tr_free( request ); request = tmp; } fprintf( stderr, "after o-rison conversion: --> %s <--\n", request ); /* convert rison to json */ { char * tmp = tr_rison2json( request, strlen( request ) ); tr_free( request ); request = tmp; } fprintf( stderr, "after json conversion: --> %s <--\n", request ); /* parse the json */ have_content = !tr_jsonParse( request, request+strlen(request), &top, NULL ); if( have_content ) { /* for convenience' sake, our URI rpc notation allows the * `args' object to be declared implicitly... */ tr_benc tmp, *args; int64_t i; const char * str; tr_bencInitDict( &tmp, 3 ); if( tr_bencDictFindInt( &top, "tag", &i ) ) tr_bencDictAddInt( &tmp, "tag", i ); if( tr_bencDictFindStr( &top, "method", &str ) ) tr_bencDictAddStr( &tmp, "method", str ); args = tr_bencDictAdd( &tmp, "args" ); *args = top; tr_bencPrint( &tmp); ret = request_exec( handle, &tmp, response_len ); tr_bencInitInt( args, 0 ); tr_bencFree( &tmp ); tr_bencFree( &top ); } tr_free( request ); return ret; }