Changeset 5989


Ignore:
Timestamp:
Jun 1, 2008, 5:36:23 AM (14 years ago)
Author:
charles
Message:

#224 (creating multi-tracker torrents): add multitracker support in libT's makemeta API, and in the gtk+ interface. This probably breaks the mac build...

Location:
trunk
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/cli/transmissioncli.c

    r5971 r5989  
    177177        int err;
    178178        tr_metainfo_builder * builder = tr_metaInfoBuilderCreate( h, sourceFile );
    179         tr_makeMetaInfo( builder, torrentPath, announce, comment, isPrivate );
     179        tr_tracker_info ti;
     180        ti.tier = 0;
     181        ti.announce = announce;
     182        tr_makeMetaInfo( builder, torrentPath, &ti, 1, comment, isPrivate );
    180183        while( !builder->isDone ) {
    181184            tr_wait( 1000 );
  • trunk/gtk/Makefile.am

    r5868 r5989  
    3232    sexy-icon-entry.h \
    3333    torrent-cell-renderer.h \
     34    tracker-list.h \
    3435    tr-core.h \
    3536    tr-core-dbus.h \
     
    5960    stats.c \
    6061    torrent-cell-renderer.c \
     62    tracker-list.c \
    6163    tr-core.c \
    6264    tr-icon.c \
  • trunk/gtk/details.c

    r5987 r5989  
    2525#include "file-list.h"
    2626#include "tr-torrent.h"
     27#include "tracker-list.h"
    2728#include "hig.h"
    2829#include "util.h"
     
    11001101};
    11011102
    1102 enum
    1103 {
    1104     TR_COL_TIER,
    1105     TR_COL_ANNOUNCE,
    1106     TR_N_COLS
    1107 };
    1108 
    1109 static void
    1110 setTrackerChangeState( struct tracker_page * page, gboolean changed )
    1111 {
    1112     gtk_widget_set_sensitive( page->save_button, changed );
    1113     gtk_widget_set_sensitive( page->revert_button, changed );
    1114 }
    1115 
    1116 static GtkTreeModel*
    1117 tracker_model_new( tr_torrent * tor )
    1118 {
    1119     int i;
    1120     const tr_info * inf = tr_torrentInfo( tor );
    1121     GtkListStore * store = gtk_list_store_new( TR_N_COLS, G_TYPE_INT, G_TYPE_STRING );
    1122 
    1123     for( i=0; i<inf->trackerCount; ++i )
    1124     {
    1125         GtkTreeIter iter;
    1126         const tr_tracker_info * tinf = inf->trackers + i;
    1127         gtk_list_store_append( store, &iter );
    1128         gtk_list_store_set( store, &iter, TR_COL_TIER, tinf->tier + 1,
    1129                                           TR_COL_ANNOUNCE, tinf->announce,
    1130                                           -1 );
    1131     }
    1132 
    1133     gtk_tree_sortable_set_sort_column_id( GTK_TREE_SORTABLE( store ),
    1134                                           TR_COL_TIER,
    1135                                           GTK_SORT_ASCENDING );
    1136 
    1137     return GTK_TREE_MODEL( store );
    1138 }
    1139 
    1140 static void
    1141 onTrackerSelectionChanged( GtkTreeSelection  * sel,
    1142                            gpointer            gpage )
    1143 {
    1144     struct tracker_page * page = gpage;
    1145     gboolean has_selection = gtk_tree_selection_get_selected( sel, NULL, NULL );
    1146     gtk_widget_set_sensitive( page->remove_button, has_selection );
    1147 }
    1148 
    1149 static void
    1150 onTrackerRemoveClicked( GtkButton * w UNUSED, gpointer gpage )
    1151 {
    1152     struct tracker_page * page = gpage;
    1153     GtkTreeIter iter;
    1154     if( gtk_tree_selection_get_selected( page->sel, NULL, &iter ) ) {
    1155         gtk_list_store_remove( page->store, &iter );
    1156         setTrackerChangeState( page, TRUE );
    1157     }
    1158 }
    1159 
    1160 static void
    1161 onTrackerAddClicked( GtkButton * w UNUSED, gpointer gpage )
    1162 {
    1163     GtkTreeIter iter;
    1164     struct tracker_page * page = gpage;
    1165     GtkTreePath * path;
    1166     gtk_list_store_append( page->store, &iter );
    1167     setTrackerChangeState( page, TRUE );
    1168     gtk_list_store_set( page->store, &iter, TR_COL_TIER, 1,
    1169                                       TR_COL_ANNOUNCE, _( "Announce URL" ),
    1170                                       -1 );
    1171     path = gtk_tree_model_get_path( GTK_TREE_MODEL( page->store ), &iter );
    1172     gtk_tree_view_set_cursor( page->view,
    1173                               path,
    1174                               gtk_tree_view_get_column( page->view, TR_COL_ANNOUNCE ),
    1175                               TRUE );
    1176     gtk_tree_path_free( path );
    1177 }
    1178 
    1179 static void
    1180 onTrackerSaveClicked( GtkButton * w UNUSED, gpointer gpage )
    1181 {
    1182     struct tracker_page * page = gpage;
    1183     GtkTreeModel * model = GTK_TREE_MODEL( page->store );
    1184     const int n = gtk_tree_model_iter_n_children( model, NULL );
    1185 
    1186     if( n > 0 ) /* must have at least one tracker */
    1187     {
    1188         int i = 0;
    1189         GtkTreeIter iter;
    1190         tr_tracker_info * trackers;
    1191 
    1192         /* build the tracker list */
    1193         trackers = g_new0( tr_tracker_info, n );
    1194         if( gtk_tree_model_get_iter_first( model, &iter ) ) do {
    1195             gtk_tree_model_get( model, &iter, TR_COL_TIER, &trackers[i].tier,
    1196                                               TR_COL_ANNOUNCE, &trackers[i].announce,
    1197                                               -1 );
    1198             ++i;
    1199         } while( gtk_tree_model_iter_next( model, &iter ) );
    1200         g_assert( i == n );
    1201 
    1202         /* set the tracker list */
    1203         tr_torrentSetAnnounceList( tr_torrent_handle( page->gtor ),
    1204                                    trackers, n );
    1205 
    1206 
    1207         setTrackerChangeState( page, FALSE );
    1208 
    1209         /* cleanup */
    1210         for( i=0; i<n; ++i )
    1211             g_free( trackers[i].announce );
    1212         g_free( trackers );
    1213     }
    1214 }
    1215 
    1216 static void
    1217 onTrackerRevertClicked( GtkButton * w UNUSED, gpointer gpage )
    1218 {
    1219     struct tracker_page * page = gpage;
    1220     GtkTreeModel * model = tracker_model_new( tr_torrent_handle( page->gtor ) );
    1221     gtk_tree_view_set_model( page->view, model );
    1222     page->store = GTK_LIST_STORE( model );
    1223     g_object_unref( G_OBJECT( model ) );
    1224     setTrackerChangeState( page, FALSE );
    1225 }
    1226 
    1227 static void
    1228 onAnnounceEdited( GtkCellRendererText * renderer UNUSED,
    1229                   gchar               * path_string,
    1230                   gchar               * new_text,
    1231                   gpointer              gpage )
    1232 {
    1233     struct tracker_page * page = gpage;
    1234     GtkTreeModel * model = GTK_TREE_MODEL( page->store );
    1235     GtkTreeIter iter;
    1236     GtkTreePath * path = gtk_tree_path_new_from_string( path_string ) ;
    1237     if( gtk_tree_model_get_iter( model, &iter, path ) )
    1238     {
    1239         char * old_text;
    1240         gtk_tree_model_get( model, &iter, TR_COL_ANNOUNCE, &old_text, -1 );
    1241         if( tr_httpIsValidURL( new_text ) )
    1242         {
    1243             if( strcmp( old_text, new_text ) )
    1244             {
    1245                 gtk_list_store_set( page->store, &iter, TR_COL_ANNOUNCE, new_text, -1 );
    1246                 setTrackerChangeState( page, TRUE );
    1247             }
    1248         }
    1249         else if( !tr_httpIsValidURL( old_text ) )
    1250         {
    1251             /* both old and new are invalid...
    1252                they must've typed in an invalid URL
    1253                after hitting the "Add" button */
    1254             onTrackerRemoveClicked( NULL, page );
    1255             setTrackerChangeState( page, TRUE );
    1256         }
    1257         g_free( old_text );
    1258     }
    1259     gtk_tree_path_free( path );
    1260 }
    1261 
    1262 static void
    1263 onTierEdited( GtkCellRendererText  * renderer UNUSED,
    1264               gchar                * path_string,
    1265               gchar                * new_text,
    1266               gpointer               gpage )
    1267 {
    1268     struct tracker_page * page = gpage;
    1269     GtkTreeModel * model = GTK_TREE_MODEL( page->store );
    1270     GtkTreeIter iter;
    1271     GtkTreePath * path;
    1272     char * end;
    1273     int new_tier;
    1274 
    1275     errno = 0;
    1276     new_tier = strtol( new_text, &end, 10 );
    1277     if( new_tier<1 || *end || errno )
    1278         return;
    1279  
    1280     path = gtk_tree_path_new_from_string( path_string ) ;
    1281     if( gtk_tree_model_get_iter( model, &iter, path ) )
    1282     {
    1283         int old_tier;
    1284         gtk_tree_model_get( model, &iter, TR_COL_TIER, &old_tier, -1 );
    1285         if( old_tier != new_tier )
    1286         {
    1287             gtk_list_store_set( page->store, &iter, TR_COL_TIER, new_tier, -1 );
    1288             setTrackerChangeState( page, TRUE );
    1289         }
    1290     }
    1291     gtk_tree_path_free( path );
    1292 }
    1293 
    12941103GtkWidget*
    12951104tracker_page_new( TrTorrent * gtor )
     
    12981107    GtkWidget * l;
    12991108    GtkWidget * w;
    1300     GtkWidget * h;
    1301     GtkWidget * v;
    1302     GtkWidget * fr;
    13031109    int row = 0;
    13041110    const char * s;
    1305     GtkTreeModel * m;
    1306     GtkCellRenderer * r;
    1307     GtkTreeViewColumn * c;
    1308     GtkTreeSelection * sel;
    13091111    struct tracker_page * page = g_new0( struct tracker_page, 1 );
    13101112    const tr_info * info = tr_torrent_info (gtor);
     
    13151117    hig_workarea_add_section_title( t, &row, _( "Trackers" ) );
    13161118
    1317         h = gtk_hbox_new( FALSE, GUI_PAD );
    1318         m = tracker_model_new( tr_torrent_handle( gtor ) );
    1319         page->store = GTK_LIST_STORE( m );
    1320         w = gtk_tree_view_new_with_model( m );
    1321         page->view = GTK_TREE_VIEW( w );
    1322         gtk_tree_view_set_enable_search( page->view, FALSE );
    1323         r = gtk_cell_renderer_text_new( );
    1324         g_object_set( G_OBJECT( r ),
    1325                 "editable", TRUE,
    1326                 NULL );
    1327         g_signal_connect( r, "edited",
    1328                           G_CALLBACK( onTierEdited ), page );
    1329         c = gtk_tree_view_column_new_with_attributes( _( "Tier" ), r,
    1330                 "text", TR_COL_TIER,
    1331                 NULL );
    1332         gtk_tree_view_column_set_sort_column_id( c, TR_COL_TIER );
    1333         gtk_tree_view_append_column( page->view, c );
    1334         r = gtk_cell_renderer_text_new( );
    1335         g_object_set( G_OBJECT( r ),
    1336                 "editable", TRUE,
    1337                 "ellipsize", PANGO_ELLIPSIZE_END,
    1338                 NULL );
    1339         g_signal_connect( r, "edited",
    1340                           G_CALLBACK( onAnnounceEdited ), page );
    1341         c = gtk_tree_view_column_new_with_attributes( _( "Announce URL" ), r,
    1342                 "text", TR_COL_ANNOUNCE,
    1343                 NULL );
    1344         gtk_tree_view_column_set_sort_column_id( c, TR_COL_ANNOUNCE );
    1345         gtk_tree_view_append_column( page->view, c );
    1346         w = gtk_scrolled_window_new( NULL, NULL );
    1347         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( w ),
    1348                                         GTK_POLICY_NEVER,
    1349                                         GTK_POLICY_AUTOMATIC );
    1350         sel = gtk_tree_view_get_selection( page->view );
    1351         page->sel = sel;
    1352         g_signal_connect( sel, "changed",
    1353                           G_CALLBACK( onTrackerSelectionChanged ), page );
    1354         gtk_container_add( GTK_CONTAINER( w ), GTK_WIDGET( page->view ) );
    1355         gtk_widget_set_size_request( w, -1, 133 );
    1356         fr = gtk_frame_new( NULL );
    1357         gtk_frame_set_shadow_type( GTK_FRAME( fr ), GTK_SHADOW_IN );
    1358         gtk_container_add( GTK_CONTAINER( fr ), w );
    1359         gtk_box_pack_start_defaults( GTK_BOX( h ), fr );
    1360         g_object_unref( G_OBJECT( m ) );
    1361 
    1362         v = gtk_vbox_new( TRUE, GUI_PAD_SMALL );
    1363         w = gtk_button_new_from_stock( GTK_STOCK_ADD );
    1364         g_signal_connect( w, "clicked", G_CALLBACK( onTrackerAddClicked ), page );
    1365         gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );
    1366         page->add_button = w;
    1367         w = gtk_button_new_from_stock( GTK_STOCK_REMOVE );
    1368         g_signal_connect( w, "clicked", G_CALLBACK( onTrackerRemoveClicked ), page );
    1369         gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );
    1370         page->remove_button = w;
    1371         w = gtk_button_new_from_stock( GTK_STOCK_SAVE );
    1372         g_signal_connect( w, "clicked", G_CALLBACK( onTrackerSaveClicked ), page );
    1373         gtk_widget_set_sensitive( w, FALSE );
    1374         gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );
    1375         page->save_button = w;
    1376         w = gtk_button_new_from_stock( GTK_STOCK_REVERT_TO_SAVED );
    1377         g_signal_connect( w, "clicked", G_CALLBACK( onTrackerRevertClicked ), page );
    1378         gtk_widget_set_sensitive( w, FALSE );
    1379         gtk_box_pack_start( GTK_BOX( v ), w, FALSE, FALSE, 0 );
    1380         page->revert_button = w;
    1381         gtk_box_pack_start( GTK_BOX( h ), v, FALSE, FALSE, 0 );
    1382 
    1383         hig_workarea_add_wide_control( t, &row, h );
    1384         onTrackerSelectionChanged( sel, page );
     1119        w = tracker_list_new( gtor, GTK_POS_RIGHT );
     1120        hig_workarea_add_wide_control( t, &row, w );
    13851121
    13861122    hig_workarea_add_section_divider( t, &row );
  • trunk/gtk/makemeta-ui.c

    r5765 r5989  
    2121#include "hig.h"
    2222#include "makemeta-ui.h"
     23#include "tracker-list.h"
    2324#include "util.h"
    2425
     
    3233    GtkWidget * size_lb;
    3334    GtkWidget * pieces_lb;
    34     GtkWidget * announce_entry;
     35    GtkWidget * announce_list;
    3536    GtkWidget * comment_entry;
    3637    GtkWidget * progressbar;
     
    146147    char buf[1024];
    147148    guint tag;
     149    tr_tracker_info * trackers = NULL;
     150    int i;
     151    int trackerCount = 0;
    148152
    149153    if( response != GTK_RESPONSE_ACCEPT )
     
    178182    g_free( tmp );
    179183
     184    trackers = tracker_list_get_trackers( ui->announce_list, &trackerCount );
     185
    180186    tr_makeMetaInfo( ui->builder,
    181187                     NULL,
    182                      gtk_entry_get_text( GTK_ENTRY( ui->announce_entry ) ),
     188                     trackers, trackerCount,
    183189                     gtk_entry_get_text( GTK_ENTRY( ui->comment_entry ) ),
    184190                     gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( ui->private_check ) ) );
     
    186192    tag = g_timeout_add (UPDATE_INTERVAL_MSEC, refresh_cb, ui);
    187193    g_object_set_data_full (G_OBJECT(d), "tag", GUINT_TO_POINTER(tag), remove_tag);
     194
     195    /* cleanup */
     196    for( i=0; i<trackerCount; ++i )
     197        g_free( trackers[i].announce );
     198    g_free( trackers );
    188199}
    189200
     
    321332
    322333    hig_workarea_add_section_divider( t, &row );
    323     hig_workarea_add_section_title (t, &row, _("Details"));
     334    hig_workarea_add_section_title (t, &row, _("Tracker"));
    324335
    325336        w = ui->private_check = hig_workarea_add_wide_checkbutton( t, &row, _( "_Private to this tracker" ), FALSE );
    326337
    327         w = ui->announce_entry = gtk_entry_new( );
    328         gtk_entry_set_text(GTK_ENTRY(w), "http://");
    329         hig_workarea_add_row (t, &row, _( "Announce _URL:" ), w, NULL );
     338        w = tracker_list_new( NULL, GTK_POS_LEFT );
     339        ui->announce_list = w;
     340        hig_workarea_add_wide_control (t, &row, w );
     341
     342    hig_workarea_add_section_divider( t, &row );
     343    hig_workarea_add_section_title (t, &row, _("Optional Information"));
    330344
    331345        w = ui->comment_entry = gtk_entry_new( );
  • trunk/gtk/tr-torrent.c

    r5947 r5989  
    6161
    6262static int
    63 isDisposed( const TrTorrent * self )
    64 {
    65     return !self || !self->priv;
     63isDisposed( const TrTorrent * tor )
     64{
     65    return !tor || !TR_IS_TORRENT( tor ) || !tor->priv;
    6666}
    6767
     
    124124tr_torrent_handle(TrTorrent *tor)
    125125{
    126     g_assert( TR_IS_TORRENT(tor) );
    127 
    128126    return isDisposed( tor ) ? NULL : tor->priv->handle;
    129127}
  • trunk/libtransmission/makemeta.c

    r5953 r5989  
    169169    if( builder )
    170170    {
    171         uint32_t i;
    172         for( i=0; i<builder->fileCount; ++i )
    173             tr_free( builder->files[i].filename );
     171        tr_file_index_t t;
     172        int i;
     173        for( t=0; t<builder->fileCount; ++t )
     174            tr_free( builder->files[t].filename );
    174175        tr_free( builder->files );
    175176        tr_free( builder->top );
    176177        tr_free( builder->comment );
    177         tr_free( builder->announce );
     178        for( i=0; i<builder->trackerCount; ++i )
     179            tr_free( builder->trackers[i].announce );
     180        tr_free( builder->trackers );
    178181        tr_free( builder->outputFile );
    179182        tr_free( builder );
     
    342345tr_realMakeMetaInfo ( tr_metainfo_builder * builder )
    343346{
    344     int n = 5;
     347    int i;
    345348    tr_benc top;
    346     const char * ann = builder->announce;
    347 
    348     if ( builder->comment && *builder->comment ) ++n;
    349     tr_bencInitDict( &top, n );
    350 
    351     tr_bencDictAddStr( &top, "announce", ann );
    352 
    353     /* if a URL was entered but it's invalid, don't allow it. #814, #971 */
    354     if( ann && *ann && !tr_httpIsValidURL( ann ) )
    355         builder->result = TR_MAKEMETA_URL;
     349
     350    /* allow an empty set, but if URLs *are* listed, verify them. #814, #971 */
     351    for( i=0; i<builder->trackerCount && !builder->result; ++i )
     352        if( !tr_httpIsValidURL( builder->trackers[i].announce ) )
     353            builder->result = TR_MAKEMETA_URL;
     354
     355    tr_bencInitDict( &top, 6 );
     356
     357    if( !builder->result && builder->trackerCount )
     358    {
     359        int prevTier = -1;
     360        tr_benc * tier = NULL;
     361        tr_benc * announceList;
     362
     363        announceList = tr_bencDictAddList( &top, "announce-list", 0 );
     364        for( i=0; i<builder->trackerCount; ++i ) {
     365            if( prevTier != builder->trackers[i].tier ) {
     366                prevTier = builder->trackers[i].tier;
     367                tier = tr_bencListAddList( announceList, 0 );
     368            }
     369            tr_bencListAddStr( tier, builder->trackers[i].announce );
     370        }
     371
     372        tr_bencDictAddStr( &top, "announce", builder->trackers[0].announce );
     373    }
    356374   
    357375    if( !builder->result && !builder->abortFlag )
     
    375393
    376394    /* cleanup */
    377     tr_bencFree( & top );
     395    tr_bencFree( &top );
    378396    if( builder->abortFlag )
    379397        builder->result = TR_MAKEMETA_CANCELLED;
     
    431449
    432450void
    433 tr_makeMetaInfo( tr_metainfo_builder  * builder,
    434                  const char           * outputFile,
    435                  const char           * announce,
    436                  const char           * comment,
    437                  int                    isPrivate )
    438 {
     451tr_makeMetaInfo( tr_metainfo_builder    * builder,
     452                 const char             * outputFile,
     453                 const tr_tracker_info  * trackers,
     454                 int                      trackerCount,
     455                 const char             * comment,
     456                 int                      isPrivate )
     457{
     458    int i;
    439459    tr_lock * lock;
    440460
    441461    /* free any variables from a previous run */
    442     tr_free( builder->announce );
     462    for( i=0; i<builder->trackerCount; ++i )
     463        tr_free( builder->trackers[i].announce );
     464    tr_free( builder->trackers );
    443465    tr_free( builder->comment );
    444466    tr_free( builder->outputFile );
     
    447469    builder->abortFlag = 0;
    448470    builder->isDone = 0;
    449     builder->announce = tr_strdup( announce );
     471    builder->trackerCount = trackerCount;
     472    builder->trackers = tr_new0( tr_tracker_info, builder->trackerCount );
     473    for( i=0; i<builder->trackerCount; ++i ) {
     474        builder->trackers[i].tier = trackers[i].tier;
     475        builder->trackers[i].announce = tr_strdup( trackers[i].announce );
     476    }
    450477    builder->comment = tr_strdup( comment );
    451478    builder->isPrivate = isPrivate;
  • trunk/libtransmission/makemeta.h

    r5358 r5989  
    5555    **/
    5656
    57     char * announce;
     57    tr_tracker_info  * trackers;
     58    int trackerCount;
    5859    char * comment;
    5960    char * outputFile;
     
    9697
    9798/**
    98  * 'outputFile' if NULL, builder->top + ".torrent" will be used.
     99 * @brief create a new .torrent file
    99100 *
    100101 * This is actually done in a worker thread, not the main thread!
     
    104105 * from time to time!  When the worker thread sets that flag,
    105106 * the caller must pass the builder to tr_metaInfoBuilderFree().
     107 *
     108 * @param outputFile if NULL, builder->top + ".torrent" will be used.
     109
     110 * @param trackers An array of trackers, sorted by tier from first to last.
     111 *                 NOTE: only the `tier' and `announce' fields are used.
     112 *
     113 * @param trackerCount size of the `trackers' array
    106114 */
    107115void
    108 tr_makeMetaInfo( tr_metainfo_builder  * builder,
    109                  const char           * outputFile,
    110                  const char           * announce,
    111                  const char           * comment,
    112                  int                    isPrivate );
     116tr_makeMetaInfo( tr_metainfo_builder     * builder,
     117                 const char              * outputFile,
     118                 const tr_tracker_info   * trackers,
     119                 int                       trackerCount,
     120                 const char              * comment,
     121                 int                       isPrivate );
    113122
    114123
Note: See TracChangeset for help on using the changeset viewer.