source: trunk/utils/edit.c @ 11709

Last change on this file since 11709 was 11709, checked in by jordan, 11 years ago

Update the copyright year in the source code comments.

The Berne Convention says that the copyright year is moot, so instead of adding another year to each file as in previous years, I've removed the year altogether from the source code comments in libtransmission, gtk, qt, utils, daemon, and cli.

Juliusz's copyright notice in tr-dht and Johannes' copyright notice in tr-lpd have been left alone; it didn't seem appropriate to modify them.

  • Property svn:keywords set to Date Rev Author Id
File size: 9.0 KB
Line 
1/*
2 * This file Copyright (C) Mnemosyne LLC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
7 *
8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9 *
10 * $Id: edit.c 11709 2011-01-19 13:48:47Z jordan $
11 */
12
13#include <stdio.h>
14
15#include <event2/buffer.h>
16
17#include <libtransmission/transmission.h>
18#include <libtransmission/bencode.h>
19#include <libtransmission/tr-getopt.h>
20#include <libtransmission/utils.h>
21#include <libtransmission/version.h>
22
23#define MY_NAME "transmission-edit"
24
25static int fileCount = 0;
26static tr_bool showVersion = FALSE;
27static const char ** files = NULL;
28static const char * add = NULL;
29static const char * deleteme = NULL;
30static const char * replace[2] = { NULL, NULL };
31
32static tr_option options[] =
33{
34  { 'a', "add", "Add a tracker's announce URL", "a", 1, "<url>" },
35  { 'd', "delete", "Delete a tracker's announce URL", "d", 1, "<url>" },
36  { 'r', "replace", "Search and replace a substring in the announce URLs", "r", 1, "<old> <new>" },
37  { 'V', "version", "Show version number and exit", "V", 0, NULL },
38  { 0, NULL, NULL, NULL, 0, NULL }
39};
40
41static const char *
42getUsage( void )
43{
44    return "Usage: " MY_NAME " [options] torrent-file(s)";
45}
46
47static int
48parseCommandLine( int argc, const char ** argv )
49{
50    int c;
51    const char * optarg;
52
53    while(( c = tr_getopt( getUsage( ), argc, argv, options, &optarg )))
54    {
55        switch( c )
56        {
57            case 'a': add = optarg;
58                      break;
59            case 'd': deleteme = optarg;
60                      break;
61            case 'r': replace[0] = optarg;
62                      c = tr_getopt( getUsage( ), argc, argv, options, &optarg );
63                      if( c != TR_OPT_UNK ) return 1;
64                      replace[1] = optarg;
65                      break;
66            case 'V': showVersion = TRUE;
67                      break;
68            case TR_OPT_UNK: files[fileCount++] = optarg; break;
69            default: return 1;
70        }
71    }
72
73    return 0;
74}
75
76static tr_bool
77removeURL( tr_benc * metainfo, const char * url )
78{
79    const char * str;
80    tr_benc * announce_list;
81    tr_bool changed = FALSE;
82
83    if( tr_bencDictFindStr( metainfo, "announce", &str ) && !strcmp( str, url ) )
84    {
85        printf( "\tRemoved \"%s\" from \"announce\"\n", str );
86        tr_bencDictRemove( metainfo, "announce" );
87        changed = TRUE;
88    }
89
90    if( tr_bencDictFindList( metainfo, "announce-list", &announce_list ) )
91    {
92        tr_benc * tier;
93        int tierIndex = 0;
94        while(( tier = tr_bencListChild( announce_list, tierIndex )))
95        {
96            tr_benc * node;
97            int nodeIndex = 0;
98            while(( node = tr_bencListChild( tier, nodeIndex )))
99            {
100                if( tr_bencGetStr( node, &str ) && !strcmp( str, url ) )
101                {
102                    printf( "\tRemoved \"%s\" from \"announce-list\" tier #%d\n", str, (tierIndex+1) );
103                    tr_bencListRemove( tier, nodeIndex );
104                    changed = TRUE;
105                }
106                else ++nodeIndex;
107            }
108
109            if( tr_bencListSize( tier ) == 0 )
110            {
111                printf( "\tNo URLs left in tier #%d... removing tier\n", (tierIndex+1) );
112                tr_bencListRemove( announce_list, tierIndex );
113            }
114            else ++tierIndex;
115        }
116
117        if( tr_bencListSize( announce_list ) == 0 )
118        {
119            printf( "\tNo tiers left... removing announce-list\n" );
120            tr_bencDictRemove( metainfo, "announce-list" );
121        }
122    }
123
124    /* if we removed the "announce" field and there's still another track left,
125     * use it as the "announce" field */
126    if( changed && !tr_bencDictFindStr( metainfo, "announce", &str ) )
127    {
128        tr_benc * tier;
129        tr_benc * node;
130
131        if(( tier = tr_bencListChild( announce_list, 0 ))) {
132            if(( node = tr_bencListChild( tier, 0 ))) {
133                if( tr_bencGetStr( node, &str ) ) {
134                    tr_bencDictAddStr( metainfo, "announce", str );
135                    printf( "\tAdded \"%s\" to announce\n", str );
136                }
137            }
138        }
139    }
140
141    return changed;
142}
143
144static char*
145replaceSubstr( const char * str, const char * in, const char * out )
146{
147    char * walk;
148    struct evbuffer * buf = evbuffer_new( );
149    const size_t inlen = strlen( in );
150    const size_t outlen = strlen( out );
151
152    while(( walk = strstr( str, in )))
153    {
154        evbuffer_add( buf, str, walk-str );
155        evbuffer_add( buf, out, outlen );
156        str = walk + inlen;
157    }
158
159    return evbuffer_free_to_str( buf );
160}
161
162static tr_bool
163replaceURL( tr_benc * metainfo, const char * in, const char * out )
164{
165    const char * str;
166    tr_benc * announce_list;
167    tr_bool changed = FALSE;
168
169    if( tr_bencDictFindStr( metainfo, "announce", &str ) && strstr( str, in ) )
170    {
171        char * newstr = replaceSubstr( str, in, out );
172        printf( "\tReplaced in \"announce\": \"%s\" --> \"%s\"\n", str, newstr );
173        tr_bencDictAddStr( metainfo, "announce", newstr );
174        tr_free( newstr );
175        changed = TRUE;
176    }
177
178    if( tr_bencDictFindList( metainfo, "announce-list", &announce_list ) )
179    {
180        tr_benc * tier;
181        int tierCount = 0;
182        while(( tier = tr_bencListChild( announce_list, tierCount++ )))
183        {
184            tr_benc * node;
185            int nodeCount = 0;
186            while(( node = tr_bencListChild( tier, nodeCount++ )))
187            {
188                if( tr_bencGetStr( node, &str ) && strstr( str, in ) )
189                {
190                    char * newstr = replaceSubstr( str, in, out );
191                    printf( "\tReplaced in \"announce-list\" tier %d: \"%s\" --> \"%s\"\n", tierCount, str, newstr );
192                    tr_bencFree( node );
193                    tr_bencInitStr( node, newstr, -1 );
194                    tr_free( newstr );
195                    changed = TRUE;
196                }
197            }
198        }
199    }
200
201    return changed;
202}
203
204static tr_bool
205addURL( tr_benc * metainfo, const char * url )
206{
207    const char * str;
208    tr_benc * announce_list;
209    tr_bool changed = FALSE;
210    tr_bool match = FALSE;
211
212    /* maybe add it to "announce" */
213    if( !tr_bencDictFindStr( metainfo, "announce", &str ) )
214    {
215        printf( "\tAdded \"%s\" in \"announce\"\n", url );
216        tr_bencDictAddStr( metainfo, "announce", url );
217        changed = TRUE;
218    }
219
220    /* see if it's already in announce-list */
221    if( tr_bencDictFindList( metainfo, "announce-list", &announce_list ) ) {
222        tr_benc * tier;
223        int tierCount = 0;
224        while(( tier = tr_bencListChild( announce_list, tierCount++ ))) {
225            tr_benc * node;
226            int nodeCount = 0;
227            while(( node = tr_bencListChild( tier, nodeCount++ )))
228                if( tr_bencGetStr( node, &str ) && !strcmp( str, url ) )
229                    match = TRUE;
230        }
231    }
232
233    /* if it's not in announce-list, add it now */
234    if( !match )
235    {
236        tr_benc * tier;
237
238        if( !tr_bencDictFindList( metainfo, "announce-list", &announce_list ) )
239            announce_list = tr_bencDictAddList( metainfo, "announce-list", 1 );
240
241        tier = tr_bencListAddList( announce_list, 1 );
242        tr_bencListAddStr( tier, url );
243        printf( "\tAdded \"%s\" to \"announce-list\" tier %zu\n", url, tr_bencListSize( announce_list ) );
244        changed = TRUE;
245    }
246
247    return changed;
248}
249
250int
251main( int argc, char * argv[] )
252{
253    int i;
254    int changedCount = 0;
255
256    files = tr_new0( const char*, argc );
257
258    tr_setMessageLevel( TR_MSG_ERR );
259
260    if( parseCommandLine( argc, (const char**)argv ) )
261        return EXIT_FAILURE;
262
263    if( showVersion )
264    {
265        fprintf( stderr, MY_NAME" "LONG_VERSION_STRING"\n" );
266        return 0;
267    }
268
269    if( fileCount < 1 )
270    {
271        fprintf( stderr, "ERROR: No torrent files specified.\n" );
272        tr_getopt_usage( MY_NAME, getUsage( ), options );
273        fprintf( stderr, "\n" );
274        return EXIT_FAILURE;
275    }
276
277    if( !add && !deleteme && !replace[0] )
278    {
279        fprintf( stderr, "ERROR: Must specify -a, -d or -r\n" );
280        tr_getopt_usage( MY_NAME, getUsage( ), options );
281        fprintf( stderr, "\n" );
282        return EXIT_FAILURE;
283    }
284
285    for( i=0; i<fileCount; ++i )
286    {
287        tr_benc top;
288        tr_bool changed = FALSE;
289        const char * filename = files[i];
290
291        printf( "%s\n", filename );
292
293        if( tr_bencLoadFile( &top, TR_FMT_BENC, filename ) )
294        {
295            printf( "\tError reading file\n" );
296            continue;
297        }
298
299        if( deleteme != NULL )
300            changed |= removeURL( &top, deleteme );
301
302        if( add != NULL )
303            changed = addURL( &top, add );
304
305        if( replace[0] && replace[1] )
306            changed |= replaceURL( &top, replace[0], replace[1] );
307
308        if( changed )
309        {
310            ++changedCount;
311            tr_bencToFile( &top, TR_FMT_BENC, filename );
312        }
313
314        tr_bencFree( &top );
315    }
316
317    printf( "Changed %d files\n", changedCount );
318
319    tr_free( files );
320    return 0;
321}
Note: See TracBrowser for help on using the repository browser.