static void saveIdleLimits( tr_benc * dict, const tr_torrent * tor ) { tr_benc * d = tr_bencDictAddDict( dict, KEY_IDLELIMIT, 2 ); tr_bencDictAddInt( d, KEY_IDLELIMIT_MINS, tr_torrentGetIdleLimit( tor ) ); tr_bencDictAddInt( d, KEY_IDLELIMIT_MODE, tr_torrentGetIdleMode( tor ) ); }
static void saveRatioLimits( tr_benc * dict, const tr_torrent * tor ) { tr_benc * d = tr_bencDictAddDict( dict, KEY_RATIOLIMIT, 2 ); tr_bencDictAddReal( d, KEY_RATIOLIMIT_RATIO, tr_torrentGetRatioLimit( tor ) ); tr_bencDictAddInt( d, KEY_RATIOLIMIT_MODE, tr_torrentGetRatioMode( tor ) ); }
void tr_magnetCreateMetainfo( const tr_magnet_info * info, tr_benc * top ) { int i; tr_benc * d; tr_bencInitDict( top, 4 ); /* announce list */ if( info->trackerCount == 1 ) tr_bencDictAddStr( top, "announce", info->trackers[0] ); else { tr_benc * trackers = tr_bencDictAddList( top, "announce-list", info->trackerCount ); for( i=0; i<info->trackerCount; ++i ) tr_bencListAddStr( tr_bencListAddList( trackers, 1 ), info->trackers[i] ); } /* webseeds */ if( info->webseedCount > 0 ) { tr_benc * urls = tr_bencDictAddList( top, "url-list", info->webseedCount ); for( i=0; i<info->webseedCount; ++i ) tr_bencListAddStr( urls, info->webseeds[i] ); } /* nonstandard keys */ d = tr_bencDictAddDict( top, "magnet-info", 2 ); tr_bencDictAddRaw( d, "info_hash", info->hash, 20 ); if( info->displayName != NULL ) tr_bencDictAddStr( d, "display-name", info->displayName ); }
static void saveSpeedLimits( tr_benc * dict, const tr_torrent * tor ) { tr_benc * d = tr_bencDictAddDict( dict, KEY_SPEEDLIMIT, 4 ); tr_bencDictAddInt( d, KEY_SPEEDLIMIT_DOWN_SPEED, tr_torrentGetSpeedLimit( tor, TR_DOWN ) ); tr_bencDictAddInt( d, KEY_SPEEDLIMIT_DOWN_MODE, tr_torrentGetSpeedMode( tor, TR_DOWN ) ); tr_bencDictAddInt( d, KEY_SPEEDLIMIT_UP_SPEED, tr_torrentGetSpeedLimit( tor, TR_UP ) ); tr_bencDictAddInt( d, KEY_SPEEDLIMIT_UP_MODE, tr_torrentGetSpeedMode( tor, TR_UP ) ); }
static void saveProgress( tr_benc * dict, tr_torrent * tor ) { tr_benc * l; tr_benc * prog; tr_file_index_t fi; const tr_info * inf = tr_torrentInfo( tor ); const time_t now = tr_time( ); prog = tr_bencDictAddDict( dict, KEY_PROGRESS, 3 ); /* add the file/piece check timestamps... */ l = tr_bencDictAddList( prog, KEY_PROGRESS_CHECKTIME, inf->fileCount ); for( fi=0; fi<inf->fileCount; ++fi ) { const tr_piece * p; const tr_piece * pend; time_t oldest_nonzero = now; time_t newest = 0; tr_bool has_zero = FALSE; const time_t mtime = tr_torrentGetFileMTime( tor, fi ); const tr_file * f = &inf->files[fi]; /* get the oldest and newest nonzero timestamps for pieces in this file */ for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]; p!=pend; ++p ) { if( !p->timeChecked ) has_zero = TRUE; else if( oldest_nonzero > p->timeChecked ) oldest_nonzero = p->timeChecked; if( newest < p->timeChecked ) newest = p->timeChecked; } /* If some of a file's pieces have been checked more recently than the file's mtime, and some lest recently, then that file will have a list containing timestamps for each piece. However, the most common use case is that the file doesn't change after it's downloaded. To reduce overhead in the .resume file, only a single timestamp is saved for the file if *all* or *none* of the pieces were tested more recently than the file's mtime. */ if( !has_zero && ( mtime <= oldest_nonzero ) ) /* all checked */ tr_bencListAddInt( l, oldest_nonzero ); else if( newest < mtime ) /* none checked */ tr_bencListAddInt( l, newest ); else { /* some are checked, some aren't... so list piece by piece */ const int offset = oldest_nonzero - 1; tr_benc * ll = tr_bencListAddList( l, 2 + f->lastPiece - f->firstPiece ); tr_bencListAddInt( ll, offset ); for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]+1; p!=pend; ++p ) tr_bencListAddInt( ll, p->timeChecked ? p->timeChecked - offset : 0 ); } } /* add the progress */ if( tor->completeness == TR_SEED ) tr_bencDictAddStr( prog, KEY_PROGRESS_HAVE, "all" ); /* add the blocks bitfield */ tr_bitsetToBenc( tr_cpBlockBitset( &tor->completion ), tr_bencDictAdd( prog, KEY_PROGRESS_BLOCKS ) ); }
static void saveSpeedLimits( tr_benc * dict, const tr_torrent * tor ) { saveSingleSpeedLimit( tr_bencDictAddDict( dict, KEY_SPEEDLIMIT_DOWN, 0 ), tor, TR_DOWN ); saveSingleSpeedLimit( tr_bencDictAddDict( dict, KEY_SPEEDLIMIT_UP, 0 ), tor, TR_UP ); }
static void handle_upload( struct evhttp_request * req, struct tr_rpc_server * server ) { if( req->type != EVHTTP_REQ_POST ) { send_simple_response( req, 405, NULL ); } else { const char * content_type = evhttp_find_header( req->input_headers, "Content-Type" ); const char * query = strchr( req->uri, '?' ); const int paused = query && strstr( query + 1, "paused=true" ); const char * in = (const char *) EVBUFFER_DATA( req->input_buffer ); size_t inlen = EVBUFFER_LENGTH( req->input_buffer ); const char * boundary_key = "boundary="; const char * boundary_key_begin = strstr( content_type, boundary_key ); const char * boundary_val = boundary_key_begin ? boundary_key_begin + strlen( boundary_key ) : "arglebargle"; char * boundary = tr_strdup_printf( "--%s", boundary_val ); const size_t boundary_len = strlen( boundary ); const char * delim = tr_memmem( in, inlen, boundary, boundary_len ); while( delim ) { size_t part_len; const char * part = delim + boundary_len; inlen -= ( part - in ); in = part; delim = tr_memmem( in, inlen, boundary, boundary_len ); part_len = delim ? (size_t)( delim - part ) : inlen; if( part_len ) { char * text = tr_strndup( part, part_len ); if( strstr( text, "filename=\"" ) ) { const char * body = strstr( text, "\r\n\r\n" ); if( body ) { char * b64; size_t body_len; tr_benc top, *args; struct evbuffer * json = tr_getBuffer( ); body += 4; /* walk past the \r\n\r\n */ body_len = part_len - ( body - text ); if( body_len >= 2 && !memcmp( &body[body_len - 2], "\r\n", 2 ) ) body_len -= 2; tr_bencInitDict( &top, 2 ); args = tr_bencDictAddDict( &top, "arguments", 2 ); tr_bencDictAddStr( &top, "method", "torrent-add" ); b64 = tr_base64_encode( body, body_len, NULL ); tr_bencDictAddStr( args, "metainfo", b64 ); tr_bencDictAddInt( args, "paused", paused ); tr_bencSaveAsJSON( &top, json ); tr_rpc_request_exec_json( server->session, EVBUFFER_DATA( json ), EVBUFFER_LENGTH( json ), NULL, NULL ); tr_releaseBuffer( json ); tr_free( b64 ); tr_bencFree( &top ); } } tr_free( text ); } } tr_free( boundary ); /* use xml here because json responses to file uploads is trouble. * see http://www.malsup.com/jquery/form/#sample7 for details */ evhttp_add_header( req->output_headers, "Content-Type", "text/xml; charset=UTF-8" ); send_simple_response( req, HTTP_OK, NULL ); } }