/* * 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 /* isdigit */ #include /* strtol */ #include /* strcmp */ #include "transmission.h" #include "bencode.h" #include "rpc.h" #include "json.h" #include "session.h" #include "torrent.h" #include "utils.h" #define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( *ary ) ) /*** **** ***/ static void notify( tr_handle * session, int type, tr_torrent * tor ) { if( session->rpc_func != NULL ) session->rpc_func( session, type, tor, session->rpc_func_user_data ); } /*** **** ***/ static tr_torrent ** getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount ) { int64_t id; 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; tr_benc * d = tr_bencListAddDict( list, 41 ); tr_benc * t; tr_bencDictAddInt( d, "activityDate", st->activityDate ); tr_bencDictAddStr( d, "announceResponse", st->announceResponse ); tr_bencDictAddStr( d, "announceURL", st->announceURL ); tr_bencDictAddInt( d, "completedFromTracker", st->completedFromTracker ); tr_bencDictAddInt( d, "corruptEver", st->corruptEver ); tr_bencDictAddInt( d, "desiredAvailable", st->desiredAvailable ); tr_bencDictAddInt( d, "downloadedEver", st->downloadedEver ); tr_bencDictAddInt( d, "error", st->error ); tr_bencDictAddStr( d, "errorString", st->errorString ); tr_bencDictAddInt( d, "eta", st->eta ); tr_bencDictAddStr( d, "hashString", tor->info.hashString ); tr_bencDictAddInt( d, "haveUnchecked", st->haveUnchecked ); tr_bencDictAddInt( d, "haveValid", st->haveValid ); tr_bencDictAddInt( d, "id", st->id ); tr_bencDictAddInt( d, "lastAnnounceTime", st->lastAnnounceTime ); tr_bencDictAddInt( d, "lastScrapeTime", st->lastScrapeTime ); tr_bencDictAddInt( d, "leechers", st->leechers ); tr_bencDictAddInt( d, "leftUntilDone", st->leftUntilDone ); tr_bencDictAddInt( d, "manualAnnounceTime", st->manualAnnounceTime ); tr_bencDictAddInt( d, "nextAnnounceTime", st->nextAnnounceTime ); tr_bencDictAddInt( d, "nextScrapeTime", st->nextScrapeTime ); tr_bencDictAddInt( d, "peersConnected", st->peersConnected ); 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] ); tr_bencDictAddInt( d, "peersGettingFromUs", st->peersGettingFromUs ); tr_bencDictAddInt( d, "peersKnown", st->peersKnown ); tr_bencDictAddInt( d, "peersSendingToUs", st->peersSendingToUs ); 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, "ratio", st->ratio ); tr_bencDictAddDouble( d, "recheckProgress", st->recheckProgress ); tr_bencDictAddStr( d, "scrapeResponse", st->scrapeResponse ); tr_bencDictAddStr( d, "scrapeURL", st->scrapeURL ); tr_bencDictAddInt( d, "seeders", st->seeders ); tr_bencDictAddInt( d, "sizeWhenDone", st->sizeWhenDone ); tr_bencDictAddInt( d, "startDate", st->startDate ); tr_bencDictAddInt( d, "status", st->status ); tr_bencDictAddDouble( d, "swarmSpeed", st->swarmSpeed ); tr_bencDictAddInt( d, "uploadedEver", st->uploadedEver ); } tr_free( torrents ); return NULL; } /** *** **/ static void addFiles( const tr_info * info, tr_benc * files ) { tr_file_index_t i; for( i=0; ifileCount; ++i ) { const tr_file * file = &info->files[i]; tr_benc * d = tr_bencListAddDict( files, 2 ); tr_bencDictAddInt( d, "length", file->length ); tr_bencDictAddStr( d, "name", file->name ); } } 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_bencDictAddStr( d, "announce", t->announce ); tr_bencDictAddStr( d, "scrape", t->scrape ); tr_bencDictAddInt( d, "tier", t->tier ); } } 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 ); addFiles( inf, tr_bencDictAddList( d, "files", inf->fileCount ) ); tr_bencDictAddStr( d, "hashString", inf->hashString ); tr_bencDictAddInt( d, "id", tr_torrentId( tor ) ); 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 ); 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, "torrent-info", torrentCount ); for( i=0; iinfo.hashString ); tr_bencDictAddInt( d, "id", tr_torrentId( tor ) ); tr_bencDictAddStr( d, "name", tor->info.name ); tr_bencDictAddDouble( d, "rateDownload", st->rateDownload ); tr_bencDictAddDouble( d, "rateUpload", st->rateUpload ); tr_bencDictAddDouble( d, "ratio", st->ratio ); tr_bencDictAddInt( d, "status", st->status ); } tr_free( torrents ); return NULL; } /** *** **/ static const char* torrentGet( 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, "torrents", 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; i