diff --git a/daemon/remote.c b/daemon/remote.c index d50038168..3ae05f939 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1276,6 +1276,7 @@ printTrackersImpl( tr_benc * trackerStats ) tr_bool hasAnnounced; tr_bool hasScraped; const char * host; + int64_t id; tr_bool isBackup; int64_t lastAnnouncePeerCount; const char * lastAnnounceResult; @@ -1300,6 +1301,7 @@ printTrackersImpl( tr_benc * trackerStats ) tr_bencDictFindBool( t, "hasAnnounced", &hasAnnounced ) && tr_bencDictFindBool( t, "hasScraped", &hasScraped ) && tr_bencDictFindStr ( t, "host", &host ) && + tr_bencDictFindInt ( t, "id", &id ) && tr_bencDictFindBool( t, "isBackup", &isBackup ) && tr_bencDictFindInt ( t, "announceState", &announceState ) && tr_bencDictFindInt ( t, "scrapeState", &scrapeState ) && @@ -1323,7 +1325,7 @@ printTrackersImpl( tr_benc * trackerStats ) const time_t now = time( NULL ); printf( "\n" ); - printf( " Tracker #%d: %s\n", (int)(i+1), host ); + printf( " Tracker %d: %s\n", (int)(id), host ); if( isBackup ) printf( " Backup on tier #%d\n", (int)tier ); else @@ -2035,8 +2037,8 @@ processArgs( const char * host, int port, int argc, const char ** argv ) { case 712: { - tr_benc * trackers = tr_bencDictAddDict( args, "trackerRemove", 1 ); - tr_bencDictAddInt( trackers, "id", atoi(optarg) ); + tr_benc * trackers = tr_bencDictAddList( args, "trackerRemove", 1 ); + tr_bencListAddInt( trackers, atoi(optarg) ); break; } case 950: tr_bencDictAddReal( args, "seedRatioLimit", atof(optarg) ); diff --git a/extras/rpc-spec.txt b/extras/rpc-spec.txt index ceb08a434..b558ae5c4 100644 --- a/extras/rpc-spec.txt +++ b/extras/rpc-spec.txt @@ -105,8 +105,8 @@ "seedRatioLimit" | double torrent-level seeding ratio "seedRatioMode" | number which ratio to use. See tr_ratiolimit "trackerAdd" | array strings of announce URLs to add - "trackerRemove" | array strings of announce URLs to remove - "trackerReplace" | array pairs of old/new announce announce URLs + "trackerRemove" | array ids of trackers to remove + "trackerReplace" | array pairs of "uploadLimit" | number maximum upload speed (KBps) "uploadLimited" | boolean true if "uploadLimit" is honored @@ -616,8 +616,8 @@ ------+---------+-----------+----------------+------------------------------- 10 | 2.10 | yes | session-get | new arg "cache-size" | | yes | torrent-set | new arg "trackerAdd" - | | yes | torrent-set | new arg "trackerEdit" | | yes | torrent-set | new arg "trackerRemove" + | | yes | torrent-set | new arg "trackerReplace" | | yes | session-set | new arg "idle-seeding-limit" | | yes | session-set | new arg "idle-seeding-limit-enabled" | | yes | session-get | new arg "idle-seeding-limit" diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index c2937d2ff..995351eb0 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -847,7 +847,7 @@ addTrackerUrls( tr_torrent * tor, tr_benc * urls ) } static const char* -replaceTrackerUrls( tr_torrent * tor, tr_benc * urls ) +replaceTrackers( tr_torrent * tor, tr_benc * urls ) { int i; tr_benc * pair[2]; @@ -866,17 +866,16 @@ replaceTrackerUrls( tr_torrent * tor, tr_benc * urls ) while(((pair[0] = tr_bencListChild(urls,i))) && ((pair[1] = tr_bencListChild(urls,i+1)))) { - const char * oldval; + int64_t pos; const char * newval; - if( tr_bencGetStr( pair[0], &oldval ) + if( tr_bencGetInt( pair[0], &pos ) && tr_bencGetStr( pair[1], &newval ) - && strcmp( oldval, newval ) && tr_urlIsValid( newval, -1 ) - && findAnnounceUrl( trackers, n, oldval, &i ) ) + && pos < n ) { - tr_free( trackers[i].announce ); - trackers[i].announce = tr_strdup( newval ); + tr_free( trackers[pos].announce ); + trackers[pos].announce = tr_strdup( newval ); changed = TRUE; } @@ -893,10 +892,12 @@ replaceTrackerUrls( tr_torrent * tor, tr_benc * urls ) } static const char* -removeTrackerUrls( tr_torrent * tor, tr_benc * urls ) +removeTrackers( tr_torrent * tor, tr_benc * ids ) { int i; int n; + int * tids; + int t = 0; tr_benc * val; tr_tracker_info * trackers; tr_bool changed = FALSE; @@ -905,20 +906,27 @@ removeTrackerUrls( tr_torrent * tor, tr_benc * urls ) /* make a working copy of the existing announce list */ n = inf->trackerCount; + tids = tr_new0( int, n ); trackers = tr_new0( tr_tracker_info, n ); copyTrackers( trackers, inf->trackers, n ); /* remove the ones specified in the urls list */ i = 0; - while(( val = tr_bencListChild( urls, i++ ))) + while(( val = tr_bencListChild( ids, i++ ))) { - int pos; - const char * url; - if( tr_bencGetStr( val, &url ) && findAnnounceUrl( trackers, n, url, &pos ) ) - { - tr_removeElementFromArray( trackers, pos, sizeof( tr_tracker_info ), n-- ); - changed = TRUE; - } + int64_t pos; + if( tr_bencGetInt( val, &pos ) && pos < n ) + tids[t++] = pos; + } + + /* sort trackerIds because tr_removeElementFromArray changes indices as it removes */ + qsort( tids, t, sizeof(int), compareInt ); + + /* remove from largest trackerId to smallest */ + while( t-- ) + { + tr_removeElementFromArray( trackers, tids[t], sizeof( tr_tracker_info ), n-- ); + changed = TRUE; } if( !changed ) @@ -927,6 +935,7 @@ removeTrackerUrls( tr_torrent * tor, tr_benc * urls ) errmsg = "error setting announce list"; freeTrackers( trackers, n ); + tr_free( tids ); return errmsg; } @@ -947,7 +956,7 @@ torrentSet( tr_session * session, int64_t tmp; double d; tr_benc * files; - tr_benc * urls; + tr_benc * trackers; tr_bool boolVal; tr_torrent * tor = torrents[i]; @@ -984,12 +993,12 @@ torrentSet( tr_session * session, tr_torrentSetRatioLimit( tor, d ); if( tr_bencDictFindInt( args_in, "seedRatioMode", &tmp ) ) tr_torrentSetRatioMode( tor, tmp ); - if( !errmsg && tr_bencDictFindList( args_in, "trackerAdd", &urls ) ) - errmsg = addTrackerUrls( tor, urls ); - if( !errmsg && tr_bencDictFindList( args_in, "trackerRemove", &urls ) ) - errmsg = removeTrackerUrls( tor, urls ); - if( !errmsg && tr_bencDictFindList( args_in, "trackerReplace", &urls ) ) - errmsg = replaceTrackerUrls( tor, urls ); + if( !errmsg && tr_bencDictFindList( args_in, "trackerAdd", &trackers ) ) + errmsg = addTrackerUrls( tor, trackers ); + if( !errmsg && tr_bencDictFindList( args_in, "trackerRemove", &trackers ) ) + errmsg = removeTrackers( tor, trackers ); + if( !errmsg && tr_bencDictFindList( args_in, "trackerReplace", &trackers ) ) + errmsg = replaceTrackers( tor, trackers ); notify( session, TR_RPC_TORRENT_CHANGED, tor ); } diff --git a/libtransmission/utils.c b/libtransmission/utils.c index 337241843..ec3b7fb43 100644 --- a/libtransmission/utils.c +++ b/libtransmission/utils.c @@ -1296,7 +1296,7 @@ parseNumberSection( const char * str, int len, struct number_range * setme ) return success; } -static int +int compareInt( const void * va, const void * vb ) { const int a = *(const int *)va; diff --git a/libtransmission/utils.h b/libtransmission/utils.h index d6f3eba12..78e6afef0 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -438,6 +438,8 @@ void tr_set_compare( const void * a, size_t aCount, tr_set_func in_both_cb, void * userData ); +int compareInt( const void * va, const void * vb ); + void tr_sha1_to_hex( char * out, const uint8_t * sha1 ) TR_GNUC_NONNULL(1,2); void tr_hex_to_sha1( uint8_t * out, const char * hex ) TR_GNUC_NONNULL(1,2); diff --git a/qt/details.cc b/qt/details.cc index dc762d340..922cc794e 100644 --- a/qt/details.cc +++ b/qt/details.cc @@ -1035,11 +1035,9 @@ Details :: onEditTrackerClicked( ) QSet ids; ids << trackerInfo.torrentId; - QStringList urls; - urls << trackerInfo.st.announce; - urls << newval; + const QPair idUrl = qMakePair( trackerInfo.st.id, newval ); - mySession.torrentSet( ids, "trackerReplace", urls ); + mySession.torrentSet( ids, "trackerReplace", idUrl ); getNewData( ); } } @@ -1050,21 +1048,23 @@ Details :: onRemoveTrackerClicked( ) // make a map of torrentIds to announce URLs to remove QItemSelectionModel * selectionModel = myTrackerView->selectionModel( ); QModelIndexList selectedRows = selectionModel->selectedRows( ); - QMap torrentId_to_urls; + QMap torrentId_to_trackerIds; foreach( QModelIndex i, selectedRows ) { const TrackerInfo inf = myTrackerView->model()->data( i, TrackerModel::TrackerRole ).value(); - torrentId_to_urls[ inf.torrentId ].append( inf.st.announce ); + torrentId_to_trackerIds.insertMulti( inf.torrentId, inf.st.id ); } // batch all of a tracker's torrents into one command - foreach( int id, torrentId_to_urls.keys( ) ) + foreach( int id, torrentId_to_trackerIds.uniqueKeys( ) ) { QSet ids; ids << id; - mySession.torrentSet( ids, "trackerRemove", torrentId_to_urls.value( id ) ); - getNewData( ); + mySession.torrentSet( ids, "trackerRemove", torrentId_to_trackerIds.values( id ) ); } + + selectionModel->clearSelection( ); + getNewData( ); } QWidget * diff --git a/qt/session.cc b/qt/session.cc index f1f450d13..dc14d24f7 100644 --- a/qt/session.cc +++ b/qt/session.cc @@ -451,6 +451,21 @@ Session :: torrentSet( const QSet& ids, const QString& key, const QList& ids, const QString& key, const QPair& value ) +{ + tr_benc top; + tr_bencInitDict( &top, 2 ); + tr_bencDictAddStr( &top, "method", "torrent-set" ); + tr_benc * args( tr_bencDictAddDict( &top, "arguments", 2 ) ); + addOptionalIds( args, ids ); + tr_benc * list( tr_bencDictAddList( args, key.toUtf8().constData(), 2 ) ); + tr_bencListAddInt( list, value.first ); + tr_bencListAddStr( list, value.second.toUtf8().constData() ); + exec( &top ); + tr_bencFree( &top ); +} + void Session :: torrentSetLocation( const QSet& ids, const QString& location, bool doMove ) { diff --git a/qt/session.h b/qt/session.h index 1c4446f0b..eaa9a412a 100644 --- a/qt/session.h +++ b/qt/session.h @@ -97,6 +97,7 @@ class Session: public QObject void torrentSet( const QSet& ids, const QString& key, double val ); void torrentSet( const QSet& ids, const QString& key, const QList& val ); void torrentSet( const QSet& ids, const QString& key, const QStringList& val ); + void torrentSet( const QSet& ids, const QString& key, const QPair& val); void torrentSetLocation( const QSet& ids, const QString& path, bool doMove );