Revert "transmission: update from 2.13 to 2.22"
[tomato.git] / release / src / router / transmission / cli / cli.c
blob181ea562fb6a2b69a912bd39df643913966c899f
1 /******************************************************************************
2 * $Id: cli.c 11335 2010-10-18 03:11:51Z charles $
4 * Copyright (c) 2005-2006 Transmission authors and contributors
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <signal.h>
31 #include <libtransmission/transmission.h>
32 #include <libtransmission/bencode.h>
33 #include <libtransmission/tr-getopt.h>
34 #include <libtransmission/utils.h> /* tr_wait_msec */
35 #include <libtransmission/version.h>
36 #include <libtransmission/web.h> /* tr_webRun */
38 /***
39 ****
40 ***/
42 #define MEM_K 1024
43 #define MEM_K_STR "KiB"
44 #define MEM_M_STR "MiB"
45 #define MEM_G_STR "GiB"
46 #define MEM_T_STR "TiB"
48 #define DISK_K 1024
49 #define DISK_B_STR "B"
50 #define DISK_K_STR "KiB"
51 #define DISK_M_STR "MiB"
52 #define DISK_G_STR "GiB"
53 #define DISK_T_STR "TiB"
55 #define SPEED_K 1024
56 #define SPEED_B_STR "B/s"
57 #define SPEED_K_STR "KiB/s"
58 #define SPEED_M_STR "MiB/s"
59 #define SPEED_G_STR "GiB/s"
60 #define SPEED_T_STR "TiB/s"
62 /***
63 ****
64 ***/
66 #define LINEWIDTH 80
67 #define MY_CONFIG_NAME "transmission"
68 #define MY_READABLE_NAME "transmission-cli"
70 static tr_bool showVersion = FALSE;
71 static tr_bool verify = 0;
72 static sig_atomic_t gotsig = 0;
73 static sig_atomic_t manualUpdate = 0;
75 static const char * torrentPath = NULL;
77 static const struct tr_option options[] =
79 { 'b', "blocklist", "Enable peer blocklists", "b", 0, NULL },
80 { 'B', "no-blocklist", "Disable peer blocklists", "B", 0, NULL },
81 { 'd', "downlimit", "Set max download speed in "SPEED_K_STR, "d", 1, "<speed>" },
82 { 'D', "no-downlimit", "Don't limit the download speed", "D", 0, NULL },
83 { 910, "encryption-required", "Encrypt all peer connections", "er", 0, NULL },
84 { 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", 0, NULL },
85 { 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", 0, NULL },
86 { 'f', "finish", "Run a script when the torrent finishes", "f", 1, "<script>" },
87 { 'g', "config-dir", "Where to find configuration files", "g", 1, "<path>" },
88 { 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", 0, NULL },
89 { 'M', "no-portmap", "Disable portmapping", "M", 0, NULL },
90 { 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", 1, "<port>" },
91 { 't', "tos", "Peer socket TOS (0 to 255, default=" TR_DEFAULT_PEER_SOCKET_TOS_STR ")", "t", 1, "<tos>" },
92 { 'u', "uplimit", "Set max upload speed in "SPEED_K_STR, "u", 1, "<speed>" },
93 { 'U', "no-uplimit", "Don't limit the upload speed", "U", 0, NULL },
94 { 'v', "verify", "Verify the specified torrent", "v", 0, NULL },
95 { 'V', "version", "Show version number and exit", "V", 0, NULL },
96 { 'w', "download-dir", "Where to save downloaded data", "w", 1, "<path>" },
97 { 0, NULL, NULL, NULL, 0, NULL }
100 static const char *
101 getUsage( void )
103 return "A fast and easy BitTorrent client\n"
104 "\n"
105 "Usage: " MY_READABLE_NAME " [options] <file|url|magnet>";
108 static int parseCommandLine( tr_benc*, int argc, const char ** argv );
110 static void sigHandler( int signal );
112 static char*
113 tr_strlratio( char * buf,
114 double ratio,
115 size_t buflen )
117 if( (int)ratio == TR_RATIO_NA )
118 tr_strlcpy( buf, _( "None" ), buflen );
119 else if( (int)ratio == TR_RATIO_INF )
120 tr_strlcpy( buf, "Inf", buflen );
121 else if( ratio < 10.0 )
122 tr_snprintf( buf, buflen, "%.2f", ratio );
123 else if( ratio < 100.0 )
124 tr_snprintf( buf, buflen, "%.1f", ratio );
125 else
126 tr_snprintf( buf, buflen, "%.0f", ratio );
127 return buf;
130 static tr_bool waitingOnWeb;
132 static void
133 onTorrentFileDownloaded( tr_session * session UNUSED,
134 long response_code UNUSED,
135 const void * response,
136 size_t response_byte_count,
137 void * ctor )
139 tr_ctorSetMetainfo( ctor, response, response_byte_count );
140 waitingOnWeb = FALSE;
143 static void
144 getStatusStr( const tr_stat * st,
145 char * buf,
146 size_t buflen )
148 if( st->activity & TR_STATUS_CHECK_WAIT )
150 tr_snprintf( buf, buflen, "Waiting to verify local files" );
152 else if( st->activity & TR_STATUS_CHECK )
154 tr_snprintf( buf, buflen,
155 "Verifying local files (%.2f%%, %.2f%% valid)",
156 tr_truncd( 100 * st->recheckProgress, 2 ),
157 tr_truncd( 100 * st->percentDone, 2 ) );
159 else if( st->activity & TR_STATUS_DOWNLOAD )
161 char upStr[80];
162 char dnStr[80];
163 char ratioStr[80];
165 tr_formatter_speed_KBps( upStr, st->pieceUploadSpeed_KBps, sizeof( upStr ) );
166 tr_formatter_speed_KBps( dnStr, st->pieceDownloadSpeed_KBps, sizeof( dnStr ) );
167 tr_strlratio( ratioStr, st->ratio, sizeof( ratioStr ) );
169 tr_snprintf( buf, buflen,
170 "Progress: %.1f%%, "
171 "dl from %d of %d peers (%s), "
172 "ul to %d (%s) "
173 "[%s]",
174 tr_truncd( 100 * st->percentDone, 1 ),
175 st->peersSendingToUs, st->peersConnected, upStr,
176 st->peersGettingFromUs, dnStr,
177 ratioStr );
179 else if( st->activity & TR_STATUS_SEED )
181 char upStr[80];
182 char ratioStr[80];
184 tr_formatter_speed_KBps( upStr, st->pieceUploadSpeed_KBps, sizeof( upStr ) );
185 tr_strlratio( ratioStr, st->ratio, sizeof( ratioStr ) );
187 tr_snprintf( buf, buflen,
188 "Seeding, uploading to %d of %d peer(s), %s [%s]",
189 st->peersGettingFromUs, st->peersConnected, upStr, ratioStr );
191 else *buf = '\0';
194 static const char*
195 getConfigDir( int argc, const char ** argv )
197 int c;
198 const char * configDir = NULL;
199 const char * optarg;
200 const int ind = tr_optind;
202 while(( c = tr_getopt( getUsage( ), argc, argv, options, &optarg ))) {
203 if( c == 'g' ) {
204 configDir = optarg;
205 break;
209 tr_optind = ind;
211 if( configDir == NULL )
212 configDir = tr_getDefaultConfigDir( MY_CONFIG_NAME );
214 return configDir;
218 main( int argc, char ** argv )
220 int error;
221 tr_session * h;
222 tr_ctor * ctor;
223 tr_torrent * tor = NULL;
224 tr_benc settings;
225 const char * configDir;
226 uint8_t * fileContents;
227 size_t fileLength;
229 tr_formatter_mem_init( MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR );
230 tr_formatter_size_init( DISK_K,DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR );
231 tr_formatter_speed_init( SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR );
233 printf( "%s %s\n", MY_READABLE_NAME, LONG_VERSION_STRING );
235 /* user needs to pass in at least one argument */
236 if( argc < 2 ) {
237 tr_getopt_usage( MY_READABLE_NAME, getUsage( ), options );
238 return EXIT_FAILURE;
241 /* load the defaults from config file + libtransmission defaults */
242 tr_bencInitDict( &settings, 0 );
243 configDir = getConfigDir( argc, (const char**)argv );
244 tr_sessionLoadSettings( &settings, configDir, MY_CONFIG_NAME );
246 /* the command line overrides defaults */
247 if( parseCommandLine( &settings, argc, (const char**)argv ) )
248 return EXIT_FAILURE;
250 if( showVersion )
251 return 0;
253 /* Check the options for validity */
254 if( !torrentPath ) {
255 fprintf( stderr, "No torrent specified!\n" );
256 return EXIT_FAILURE;
259 h = tr_sessionInit( "cli", configDir, FALSE, &settings );
261 ctor = tr_ctorNew( h );
263 fileContents = tr_loadFile( torrentPath, &fileLength );
264 tr_ctorSetPaused( ctor, TR_FORCE, FALSE );
265 if( fileContents != NULL ) {
266 tr_ctorSetMetainfo( ctor, fileContents, fileLength );
267 } else if( !memcmp( torrentPath, "magnet:?", 8 ) ) {
268 tr_ctorSetMetainfoFromMagnetLink( ctor, torrentPath );
269 } else if( !memcmp( torrentPath, "http", 4 ) ) {
270 tr_webRun( h, torrentPath, NULL, onTorrentFileDownloaded, ctor );
271 waitingOnWeb = TRUE;
272 while( waitingOnWeb ) tr_wait_msec( 1000 );
273 } else {
274 fprintf( stderr, "ERROR: Unrecognized torrent \"%s\".\n", torrentPath );
275 fprintf( stderr, " * If you're trying to create a torrent, use transmission-create.\n" );
276 fprintf( stderr, " * If you're trying to see a torrent's info, use transmission-show.\n" );
277 tr_sessionClose( h );
278 return EXIT_FAILURE;
280 tr_free( fileContents );
282 tor = tr_torrentNew( ctor, &error );
283 tr_ctorFree( ctor );
284 if( !tor )
286 fprintf( stderr, "Failed opening torrent file `%s'\n", torrentPath );
287 tr_sessionClose( h );
288 return EXIT_FAILURE;
291 signal( SIGINT, sigHandler );
292 #ifndef WIN32
293 signal( SIGHUP, sigHandler );
294 #endif
295 tr_torrentStart( tor );
297 if( verify )
299 verify = 0;
300 tr_torrentVerify( tor );
303 for( ; ; )
305 char line[LINEWIDTH];
306 const tr_stat * st;
307 const char * messageName[] = { NULL, "Tracker gave a warning:",
308 "Tracker gave an error:",
309 "Error:" };
311 tr_wait_msec( 200 );
313 if( gotsig )
315 gotsig = 0;
316 printf( "\nStopping torrent...\n" );
317 tr_torrentStop( tor );
320 if( manualUpdate )
322 manualUpdate = 0;
323 if( !tr_torrentCanManualUpdate( tor ) )
324 fprintf(
325 stderr,
326 "\nReceived SIGHUP, but can't send a manual update now\n" );
327 else
329 fprintf( stderr,
330 "\nReceived SIGHUP: manual update scheduled\n" );
331 tr_torrentManualUpdate( tor );
335 st = tr_torrentStat( tor );
336 if( st->activity & TR_STATUS_STOPPED )
337 break;
339 getStatusStr( st, line, sizeof( line ) );
340 printf( "\r%-*s", LINEWIDTH, line );
342 if( messageName[st->error] )
343 fprintf( stderr, "\n%s: %s\n", messageName[st->error], st->errorString );
346 tr_sessionSaveSettings( h, configDir, &settings );
348 printf( "\n" );
349 tr_bencFree( &settings );
350 tr_sessionClose( h );
351 return EXIT_SUCCESS;
354 /***
355 ****
356 ****
357 ****
358 ***/
360 static int
361 parseCommandLine( tr_benc * d, int argc, const char ** argv )
363 int c;
364 const char * optarg;
366 while(( c = tr_getopt( getUsage( ), argc, argv, options, &optarg )))
368 switch( c )
370 case 'b': tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, TRUE );
371 break;
372 case 'B': tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, FALSE );
373 break;
374 case 'd': tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED_KBps, atoi( optarg ) );
375 tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED, TRUE );
376 break;
377 case 'D': tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED, FALSE );
378 break;
379 case 'f': tr_bencDictAddStr( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, optarg );
380 tr_bencDictAddBool( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, TRUE );
381 break;
382 case 'g': /* handled above */
383 break;
384 case 'm': tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING, TRUE );
385 break;
386 case 'M': tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING, FALSE );
387 break;
388 case 'p': tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT, atoi( optarg ) );
389 break;
390 case 't': tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_SOCKET_TOS, atoi( optarg ) );
391 break;
392 case 'u': tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED_KBps, atoi( optarg ) );
393 tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, TRUE );
394 break;
395 case 'U': tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, FALSE );
396 break;
397 case 'v': verify = TRUE;
398 break;
399 case 'V': showVersion = TRUE;
400 break;
401 case 'w': tr_bencDictAddStr( d, TR_PREFS_KEY_DOWNLOAD_DIR, optarg );
402 break;
403 case 910: tr_bencDictAddInt( d, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_REQUIRED );
404 break;
405 case 911: tr_bencDictAddInt( d, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_PREFERRED );
406 break;
407 case 912: tr_bencDictAddInt( d, TR_PREFS_KEY_ENCRYPTION, TR_CLEAR_PREFERRED );
408 break;
409 case TR_OPT_UNK:
410 if( torrentPath == NULL )
411 torrentPath = optarg;
412 break;
413 default: return 1;
417 return 0;
420 static void
421 sigHandler( int signal )
423 switch( signal )
425 case SIGINT:
426 gotsig = 1; break;
428 #ifndef WIN32
429 case SIGHUP:
430 manualUpdate = 1; break;
432 #endif
433 default:
434 break;