updated on Thu Jan 26 16:09:46 UTC 2012
[aur-mirror.git] / transmission-ng / cli.c
blob787086202c034ed465c135009ba9e09fb1967746
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"
71 static tr_bool showVersion = FALSE;
72 static tr_bool verify = 0;
73 static sig_atomic_t gotsig = 0;
74 static sig_atomic_t manualUpdate = 0;
76 static const char * torrentPath = NULL;
78 //Torrentflux
79 #define TOF_DISPLAY_INTERVAL 5
80 #define TOF_DISPLAY_INTERVAL_STR "5"
81 #define TOF_DIEWHENDONE 0
82 #define TOF_DIEWHENDONE_STR "0"
83 #define TOF_CMDFILE_MAXLEN 65536
85 //static volatile char tf_shutdown = 0;
86 static int TOF_dieWhenDone = TOF_DIEWHENDONE;
87 static int TOF_seedLimit = 0;
88 static int TOF_displayInterval = TOF_DISPLAY_INTERVAL;
89 static int TOF_checkCmd = 0;
91 static const char * finishCall = NULL;
93 static const char * TOF_owner = NULL;
94 static char * TOF_statFile = NULL;
95 static FILE * TOF_statFp = NULL;
96 static char * TOF_cmdFile = NULL;
97 static FILE * TOF_cmdFp = NULL;
98 static char TOF_message[512];
99 //END Torrentflux
101 static const struct tr_option options[] =
103 { 'b', "blocklist", "Enable peer blocklists", "b", 0, NULL },
104 { 'B', "no-blocklist", "Disable peer blocklists", "B", 0, NULL },
105 { 'd', "downlimit", "Set max download speed in "SPEED_K_STR, "d", 1, "<speed>" },
106 { 'D', "no-downlimit", "Don't limit the download speed", "D", 0, NULL },
107 { 910, "encryption-required", "Encrypt all peer connections", "er", 0, NULL },
108 { 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", 0, NULL },
109 { 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", 0, NULL },
110 { 'f', "finish", "Run a script when the torrent finishes", "f", 1, "<script>" },
111 { 'g', "config-dir", "Where to find configuration files", "g", 1, "<path>" },
112 { 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", 0, NULL },
113 { 'M', "no-portmap", "Disable portmapping", "M", 0, NULL },
114 { 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", 1, "<port>" },
115 { 't', "tos", "Peer socket TOS (0 to 255, default=" TR_DEFAULT_PEER_SOCKET_TOS_STR ")", "t", 1, "<tos>" },
116 { 'u', "uplimit", "Set max upload speed in "SPEED_K_STR, "u", 1, "<speed>" },
117 { 'U', "no-uplimit", "Don't limit the upload speed", "U", 0, NULL },
118 { 'v', "verify", "Verify the specified torrent", "v", 0, NULL },
119 { 'V', "version", "Show version number and exit", "V", 0, NULL },
120 { 'w', "download-dir", "Where to save downloaded data", "w", 1, "<path>" },
121 //Torrentflux Commands:
122 { 'E', "display-interval","Time between updates of stat-file (default = "TOF_DISPLAY_INTERVAL_STR")","E",1,"<int>"},
123 { 'L', "seedlimit","Seed-Limit (Percent) to reach before shutdown","L",1,"<int>"},
124 { 'O', "owner","Name of the owner (default = 'n/a')","O",1,"<string>"},
125 { 'W', "die-when-done", "Auto-Shutdown when done (0 = Off, 1 = On, default = "TOF_DIEWHENDONE_STR")","W",1,NULL},
126 //END
127 { 0, NULL, NULL, NULL, 0, NULL }
130 static const char *
131 getUsage( void )
133 return "A fast and easy BitTorrent client\n"
134 "\n"
135 "Usage: " MY_READABLE_NAME " [options] <file|url|magnet>";
138 static int parseCommandLine( tr_benc*, int argc, const char ** argv );
140 static void sigHandler( int signal );
142 /* Torrentflux -START- */
143 static int TOF_processCommands(tr_session *h);
144 static int TOF_execCommand(tr_session *h, char *s);
145 static void TOF_print ( char *printmsg );
146 static void TOF_free ( void );
147 static int TOF_initStatus ( void );
148 static void TOF_writeStatus ( const tr_stat *s, const tr_info *info,
149 const int state, const char *status );
150 static int TOF_initCommand ( void );
151 static int TOF_writePID ( void );
152 static void TOF_deletePID ( void );
153 static int TOF_writeAllowed ( void );
154 /* -END- */
156 static char*
157 tr_strlratio( char * buf,
158 double ratio,
159 size_t buflen )
161 if( (int)ratio == TR_RATIO_NA )
162 tr_strlcpy( buf, _( "None" ), buflen );
163 else if( (int)ratio == TR_RATIO_INF )
164 tr_strlcpy( buf, "Inf", buflen );
165 else if( ratio < 10.0 )
166 tr_snprintf( buf, buflen, "%.2f", ratio );
167 else if( ratio < 100.0 )
168 tr_snprintf( buf, buflen, "%.1f", ratio );
169 else
170 tr_snprintf( buf, buflen, "%.0f", ratio );
171 return buf;
174 static tr_bool waitingOnWeb;
176 static void
177 onTorrentFileDownloaded( tr_session * session UNUSED,
178 long response_code UNUSED,
179 const void * response,
180 size_t response_byte_count,
181 void * ctor )
183 tr_ctorSetMetainfo( ctor, response, response_byte_count );
184 waitingOnWeb = FALSE;
187 static void
188 getStatusStr( const tr_stat * st,
189 char * buf,
190 size_t buflen )
192 static void
193 getStatusStr( const tr_stat * st, const tr_info *information )
195 char TOF_eta[80];
196 char buf[512];
197 size_t buflen=512;
199 if( st->activity & TR_STATUS_CHECK_WAIT )
201 tr_snprintf( buf, buflen, "Waiting to verify local files" );
202 TOF_writeStatus(st, information, 1, buf );
204 else if( st->activity & TR_STATUS_CHECK )
206 tr_snprintf( buf, buflen,
207 // "Verifying local files (%.2f%%, %.2f%% valid)",
208 "%.2f%% Verifying local files (%.2f%% valid)",
209 tr_truncd( 100 * st->recheckProgress, 2 ),
210 tr_truncd( 100 * st->percentDone, 2 ) );
211 TOF_writeStatus(st, information, 1, buf );
213 else if( st->activity & TR_STATUS_DOWNLOAD )
215 char upStr[80];
216 char dnStr[80];
217 char ratioStr[80];
219 tr_formatter_speed_KBps( upStr, st->pieceUploadSpeed_KBps, sizeof( upStr ) );
220 tr_formatter_speed_KBps( dnStr, st->pieceDownloadSpeed_KBps, sizeof( dnStr ) );
221 tr_strlratio( ratioStr, st->ratio, sizeof( ratioStr ) );
223 tr_snprintf( buf, buflen,
224 "Progress: %.1f%%, "
225 "dl from %d of %d peers (%s), "
226 "ul to %d (%s) "
227 "[%s]",
228 tr_truncd( 100 * st->percentDone, 1 ),
229 st->peersSendingToUs, st->peersConnected, upStr,
230 st->peersGettingFromUs, dnStr,
231 ratioStr );
233 if( TOF_writeAllowed() )
235 strcpy(TOF_eta,"");
236 if ( st->eta > 0 )
238 if ( st->eta < 604800 ) // 7 days
240 if ( st->eta >= 86400 ) // 1 day
241 sprintf(TOF_eta, "%d:",
242 st->eta / 86400);
244 if ( st->eta >= 3600 ) // 1 hour
245 sprintf(TOF_eta, "%s%02d:",
246 TOF_eta,((st->eta % 86400) / 3600));
248 if ( st->eta >= 60 ) // 1 Minute
249 sprintf(TOF_eta, "%s%02d:",
250 TOF_eta,((st->eta % 3600) / 60));
252 sprintf(TOF_eta, "%s%02d",
253 TOF_eta,(st->eta % 60));
255 else
256 sprintf(TOF_eta, "-");
259 if ((st->seeders < -1) && (st->peersConnected == 0))
260 sprintf(TOF_eta, "Connecting to Peers");
262 TOF_writeStatus(st, information, 1, TOF_eta );
265 else if( st->activity & TR_STATUS_SEED )
267 char upStr[80];
268 char ratioStr[80];
270 tr_formatter_speed_KBps( upStr, st->pieceUploadSpeed_KBps, sizeof( upStr ) );
271 tr_strlratio( ratioStr, st->ratio, sizeof( ratioStr ) );
273 tr_snprintf( buf, buflen,
274 "Seeding, uploading to %d of %d peer(s), %s [%s]",
275 st->peersGettingFromUs, st->peersConnected, upStr, ratioStr );
277 if (TOF_dieWhenDone == 1)
279 TOF_print( (char *) "Die-when-done set, setting shutdown-flag...\n" );
280 gotsig = 1;
282 else
284 if (TOF_seedLimit == -1)
286 TOF_print( (char *) "Sharekill set to -1, setting shutdown-flag...\n" );
287 gotsig = 1;
289 else if ( ( TOF_seedLimit > 0 ) && ( ( st->ratio * 100.0 ) > (float)TOF_seedLimit ) )
291 sprintf( TOF_message, "Seed-limit %d%% reached, setting shutdown-flag...\n", TOF_seedLimit );
292 TOF_print( TOF_message );
293 gotsig = 1;
296 TOF_writeStatus(st, information, 1, "Download Succeeded" );
298 else *buf = '\0';
300 if( st->error )
302 sprintf( TOF_message, "error: %s\n", st->errorString );
303 TOF_print( TOF_message );
307 static const char*
308 getConfigDir( int argc, const char ** argv )
310 int c;
311 const char * configDir = NULL;
312 const char * optarg;
313 const int ind = tr_optind;
315 while(( c = tr_getopt( getUsage( ), argc, argv, options, &optarg ))) {
316 if( c == 'g' ) {
317 configDir = optarg;
318 break;
322 tr_optind = ind;
324 if( configDir == NULL )
325 configDir = tr_getDefaultConfigDir( MY_CONFIG_NAME );
327 return configDir;
331 main( int argc, char ** argv )
333 int error;
334 tr_session * h;
335 tr_ctor * ctor;
336 tr_torrent * tor = NULL;
337 tr_benc settings;
338 const char * configDir;
339 uint8_t * fileContents;
340 size_t fileLength;
342 int i;
343 const tr_info * information;
344 char cwd[1024];
346 tr_formatter_mem_init( MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR );
347 tr_formatter_size_init( DISK_K,DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR );
348 tr_formatter_speed_init( SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR );
350 printf( "%s %s - patched for TorrentFlux-NG\n", MY_READABLE_NAME, LONG_VERSION_STRING );
352 /* user needs to pass in at least one argument */
353 if( argc < 2 ) {
354 tr_getopt_usage( MY_READABLE_NAME, getUsage( ), options );
355 return EXIT_FAILURE;
358 /* load the defaults from config file + libtransmission defaults */
359 tr_bencInitDict( &settings, 0 );
360 configDir = getConfigDir( argc, (const char**)argv );
361 //tr_sessionLoadSettings( &settings, configDir, MY_CONFIG_NAME );
363 /* the command line overrides defaults */
364 if( parseCommandLine( &settings, argc, (const char**)argv ) )
366 printf("Invalid commandline option given\n");
367 return EXIT_FAILURE;
370 tr_bencDictRemove( &settings, TR_PREFS_KEY_DOWNLOAD_DIR );
371 getcwd( cwd, sizeof( cwd ) );
372 tr_bencDictAddStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, cwd );
374 if( showVersion )
375 return 0;
377 /* Check the options for validity */
378 if( !torrentPath ) {
379 fprintf( stderr, "No torrent specified!\n" );
380 return EXIT_FAILURE;
383 h = tr_sessionInit( "cli", configDir, FALSE, &settings );
385 ctor = tr_ctorNew( h );
386 tr_ctorSetMetainfoFromFile( ctor, torrentPath );
388 //fileContents = tr_loadFile( torrentPath, &fileLength );
389 tr_ctorSetPaused( ctor, TR_FORCE, FALSE );
390 tr_ctorSetDownloadDir( ctor, TR_FORCE, cwd );
391 tr_ctorSetDownloadDir( ctor, TR_FALLBACK, cwd );
393 if( fileContents != NULL ) {
394 tr_ctorSetMetainfo( ctor, fileContents, fileLength );
395 } else if( !memcmp( torrentPath, "magnet:?", 8 ) ) {
396 tr_ctorSetMetainfoFromMagnetLink( ctor, torrentPath );
397 } else if( !memcmp( torrentPath, "http", 4 ) ) {
398 tr_webRun( h, torrentPath, NULL, onTorrentFileDownloaded, ctor );
399 waitingOnWeb = TRUE;
400 while( waitingOnWeb ) tr_wait_msec( 1000 );
401 } else {
402 fprintf( stderr, "ERROR: Unrecognized torrent \"%s\".\n", torrentPath );
403 fprintf( stderr, " * If you're trying to create a torrent, use transmission-create.\n" );
404 fprintf( stderr, " * If you're trying to see a torrent's info, use transmission-show.\n" );
405 tr_sessionClose( h );
406 return EXIT_FAILURE;
408 tr_free( fileContents );
410 // Torrentflux -START-
411 if (TOF_owner == NULL)
413 sprintf( TOF_message, "No owner supplied, using 'n/a'.\n" );
414 TOF_print( TOF_message );
415 TOF_owner = malloc((4) * sizeof(char));
416 if (TOF_owner == NULL)
418 sprintf( TOF_message, "Error : not enough mem for malloc\n" );
419 TOF_print( TOF_message );
420 goto failed;
424 // Output for log
425 sprintf( TOF_message, "transmission %s starting up :\n", LONG_VERSION_STRING );
426 TOF_print( TOF_message );
427 sprintf( TOF_message, " - torrent : %s\n", torrentPath );
428 TOF_print( TOF_message );
429 sprintf( TOF_message, " - owner : %s\n", TOF_owner );
430 TOF_print( TOF_message );
431 sprintf( TOF_message, " - dieWhenDone : %d\n", TOF_dieWhenDone );
432 TOF_print( TOF_message );
433 sprintf( TOF_message, " - seedLimit : %d\n", TOF_seedLimit );
434 TOF_print( TOF_message );
435 sprintf( TOF_message, " - bindPort : %d\n", tr_sessionGetPeerPort(h) );
436 TOF_print( TOF_message );
437 sprintf( TOF_message, " - uploadLimit : %d\n", tr_sessionGetSpeedLimit_KBps(h, TR_UP ) );
438 TOF_print( TOF_message );
439 sprintf( TOF_message, " - downloadLimit : %d\n", tr_sessionGetSpeedLimit_KBps(h, TR_DOWN ) );
440 TOF_print( TOF_message );
441 sprintf( TOF_message, " - natTraversal : %d\n", tr_sessionIsPortForwardingEnabled(h) );
442 TOF_print( TOF_message );
443 sprintf( TOF_message, " - displayInterval : %d\n", TOF_displayInterval );
444 TOF_print( TOF_message );
445 sprintf( TOF_message, " - downloadDir : %s\n", tr_sessionGetDownloadDir(h) );
446 TOF_print( TOF_message );
448 if (finishCall != NULL)
450 sprintf( TOF_message, " - finishCall : %s\n", finishCall );
451 TOF_print( TOF_message );
453 // -END-
455 tor = tr_torrentNew( ctor, &error );
457 sprintf( TOF_message, " - downloadDir from torrent object, usually loaded from resume data : %s\n", tr_torrentGetDownloadDir( tor ) );
458 TOF_print( TOF_message );
460 tr_ctorFree( ctor );
461 if( !tor )
463 //fprintf( stderr, "Failed opening torrent file `%s'\n", torrentPath );
464 sprintf( TOF_message, "Failed opening torrent file %s'\n", torrentPath );
465 TOF_print( TOF_message );
466 tr_sessionClose( h );
467 return EXIT_FAILURE;
470 signal( SIGINT, sigHandler );
471 #ifndef WIN32
472 signal( SIGHUP, sigHandler );
473 #endif
474 tr_torrentStart( tor );
476 if( verify )
478 verify = 0;
479 tr_torrentVerify( tor );
482 // Torrentflux -START-
484 // initialize status-facility
485 if (TOF_initStatus() == 0)
487 sprintf( TOF_message, "Failed to init status-facility. exit transmission.\n" );
488 TOF_print( TOF_message );
489 goto failed;
492 // initialize command-facility
493 if (TOF_initCommand() == 0)
495 sprintf( TOF_message, "Failed to init command-facility. exit transmission.\n" );
496 TOF_print( TOF_message );
497 goto failed;
500 // write pid
501 if (TOF_writePID() == 0)
503 sprintf( TOF_message, "Failed to write pid-file. exit transmission.\n" );
504 TOF_print( TOF_message );
505 goto failed;
508 sprintf( TOF_message, "Transmission up and running.\n" );
510 information = tr_torrentInfo( tor );
511 // -END-
513 for( ; ; )
515 char line[LINEWIDTH];
516 const tr_stat * st;
517 const char * messageName[] = { NULL, "Tracker gave a warning:",
518 "Tracker gave an error:",
519 "Error:" };
521 // Torrentflux -START-
522 TOF_checkCmd++;
524 if( TOF_checkCmd == TOF_displayInterval)
526 TOF_checkCmd = 1;
527 /* If Torrentflux wants us to shutdown */
528 if (TOF_processCommands(h))
529 gotsig = 1;
531 // -END-
533 tr_wait_msec( 200 );
535 if( gotsig )
537 gotsig = 0;
538 //printf( "\nStopping torrent...\n" );
539 tr_torrentStop( tor );
542 if( manualUpdate )
544 manualUpdate = 0;
545 if( !tr_torrentCanManualUpdate( tor ) )
546 fprintf(
547 stderr,
548 "\nReceived SIGHUP, but can't send a manual update now\n" );
549 else
551 fprintf( stderr,
552 "\nReceived SIGHUP: manual update scheduled\n" );
553 tr_torrentManualUpdate( tor );
557 st = tr_torrentStat( tor );
558 if( st->activity & TR_STATUS_STOPPED )
559 break;
561 //getStatusStr( st, line, sizeof( line ) );
562 getStatusStr( st, information);
563 //printf( "\r%-*s", LINEWIDTH, line );
565 if( messageName[st->error] )
566 fprintf( stderr, "\n%s: %s\n", messageName[st->error], st->errorString );
569 const tr_stat * st;
570 st = tr_torrentStat( tor );
572 TOF_print( (char*) "Transmission shutting down...\n");
574 /* Try for 5 seconds to delete any port mappings for nat traversal */
575 tr_sessionSetPortForwardingEnabled( h, 0 );
576 for( i = 0; i < 10; i++ )
578 if( TR_PORT_UNMAPPED == tr_sessionIsPortForwardingEnabled( h ) )
580 /* Port mappings were deleted */
581 break;
583 tr_wait_msec( 500 );
585 if (st->percentDone >= 1)
586 TOF_writeStatus(st, information, 0, "Download Succeeded" );
587 else
588 TOF_writeStatus(st, information, 0, "Torrent Stopped" );
590 TOF_deletePID();
591 TOF_print( (char*) "Transmission exit.\n");
592 TOF_free();
594 //tr_sessionSaveSettings( h, configDir, &settings );
596 printf( "\n" );
597 tr_bencFree( &settings );
598 tr_sessionClose( h );
599 return EXIT_SUCCESS;
601 failed:
602 TOF_free();
603 tr_torrentFree( tor );
604 tr_sessionClose( h );
605 return EXIT_FAILURE;
608 /***
609 ****
610 ****
611 ****
612 ***/
614 static int
615 parseCommandLine( tr_benc * d, int argc, const char ** argv )
617 int c;
618 const char * optarg;
619 int64_t downloadLimit, uploadLimit;
621 while(( c = tr_getopt( getUsage( ), argc, argv, options, &optarg )))
623 switch( c )
625 case 'b': tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, TRUE );
626 break;
627 case 'B': tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, FALSE );
628 break;
629 case 'd': tr_bencDictAddInt ( d, TR_PREFS_KEY_DSPEED_KBps, atoi( optarg ) );
630 tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED, TRUE );
631 break;
632 case 'D': tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED, FALSE );
633 break;
634 case 'f': tr_bencDictAddStr( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_FILENAME, optarg );
635 tr_bencDictAddBool( d, TR_PREFS_KEY_SCRIPT_TORRENT_DONE_ENABLED, TRUE );
636 finishCall = optarg;
637 break;
638 case 'g': /* handled above */
639 break;
640 case 'm': tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING, TRUE );
641 break;
642 case 'M': tr_bencDictAddBool( d, TR_PREFS_KEY_PORT_FORWARDING, FALSE );
643 break;
644 case 'p': tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_PORT, atoi( optarg ) );
645 break;
646 case 't': tr_bencDictAddInt( d, TR_PREFS_KEY_PEER_SOCKET_TOS, atoi( optarg ) );
647 break;
648 case 'u': tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED_KBps, atoi( optarg ) );
649 tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, TRUE );
650 break;
651 case 'U': tr_bencDictAddBool( d, TR_PREFS_KEY_USPEED_ENABLED, FALSE );
652 break;
653 case 'v': verify = TRUE;
654 break;
655 case 'V': showVersion = TRUE;
656 break;
657 case 'w': tr_bencDictAddStr( d, TR_PREFS_KEY_DOWNLOAD_DIR, optarg );
658 break;
659 case 910: tr_bencDictAddInt( d, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_REQUIRED );
660 break;
661 case 911: tr_bencDictAddInt( d, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_PREFERRED );
662 break;
663 case 912: tr_bencDictAddInt( d, TR_PREFS_KEY_ENCRYPTION, TR_CLEAR_PREFERRED );
664 break;
665 case TR_OPT_UNK:
666 if( torrentPath == NULL )
667 torrentPath = optarg;
668 break;
669 /* seems now implemented
670 case 'd': downloadLimit=atoi( optarg );
671 switch (downloadLimit) {
672 case 0: downloadLimit = -1;
673 break;
674 case -2: downloadLimit = 0;
675 break;
677 if (downloadLimit>=0)
679 tr_bencDictAddInt( d, TR_PREFS_KEY_DSPEED, downloadLimit );
680 tr_bencDictAddInt( d, TR_PREFS_KEY_DSPEED_ENABLED, 1 );
682 else
683 tr_bencDictAddInt( d, TR_PREFS_KEY_DSPEED_ENABLED, 0 );
684 break;
685 case 'u':
686 uploadLimit=atoi( optarg );
687 switch (uploadLimit) {
688 case 0: uploadLimit = -1;
689 break;
690 case -2: uploadLimit = 0;
691 break;
693 if (uploadLimit>=0)
695 tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED, uploadLimit );
696 tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED_ENABLED, 1 );
698 else
699 tr_bencDictAddInt( d, TR_PREFS_KEY_USPEED_ENABLED, 0 );
700 break;
702 case 'E':
703 TOF_displayInterval = atoi( optarg );
704 break;
705 case 'L':
706 TOF_seedLimit = atoi( optarg );
707 break;
708 case 'O':
709 TOF_owner = optarg;
710 break;
711 case 'W':
712 TOF_dieWhenDone = atoi( optarg );
713 break;
714 default: return 1;
718 return 0;
721 static void
722 sigHandler( int signal )
724 switch( signal )
726 case SIGINT:
727 gotsig = 1; break;
729 #ifndef WIN32
730 case SIGHUP:
731 manualUpdate = 1; break;
733 #endif
734 default:
735 break;
740 /* Torrentflux -START- */
741 static void TOF_print( char *printmsg )
743 time_t rawtime;
744 struct tm * timeinfo;
745 time(&rawtime);
746 timeinfo = localtime(&rawtime);
748 fprintf(stderr, "[%4d/%02d/%02d - %02d:%02d:%02d] %s",
749 timeinfo->tm_year + 1900,
750 timeinfo->tm_mon + 1,
751 timeinfo->tm_mday,
752 timeinfo->tm_hour,
753 timeinfo->tm_min,
754 timeinfo->tm_sec,
755 ((printmsg != NULL) && (strlen(printmsg) > 0)) ? printmsg : ""
759 static int TOF_initStatus( void )
761 int len = strlen(torrentPath) + 5;
762 TOF_statFile = malloc((len + 1) * sizeof(char));
763 if (TOF_statFile == NULL) {
764 TOF_print( "Error : TOF_initStatus: not enough mem for malloc\n" );
765 return 0;
768 sprintf( TOF_statFile, "%s.stat", torrentPath );
770 sprintf( TOF_message, "Initialized status-facility. (%s)\n", TOF_statFile );
771 TOF_print( TOF_message );
772 return 1;
775 static int TOF_initCommand( void )
777 int len = strlen(torrentPath) + 4;
778 TOF_cmdFile = malloc((len + 1) * sizeof(char));
779 if (TOF_cmdFile == NULL) {
780 TOF_print( "Error : TOF_initCommand: not enough mem for malloc\n" );
781 return 0;
783 sprintf( TOF_cmdFile, "%s.cmd", torrentPath );
785 sprintf( TOF_message, "Initialized command-facility. (%s)\n", TOF_cmdFile );
786 TOF_print( TOF_message );
788 // remove command-file if exists
789 TOF_cmdFp = NULL;
790 TOF_cmdFp = fopen(TOF_cmdFile, "r");
791 if (TOF_cmdFp != NULL)
793 fclose(TOF_cmdFp);
794 sprintf( TOF_message, "Removing command-file. (%s)\n", TOF_cmdFile );
795 TOF_print( TOF_message );
796 remove(TOF_cmdFile);
797 TOF_cmdFp = NULL;
799 return 1;
802 static int TOF_writePID( void )
804 FILE * TOF_pidFp;
805 char TOF_pidFile[strlen(torrentPath) + 4];
807 sprintf(TOF_pidFile,"%s.pid",torrentPath);
809 TOF_pidFp = fopen(TOF_pidFile, "w+");
810 if (TOF_pidFp != NULL)
812 fprintf(TOF_pidFp, "%d", getpid());
813 fclose(TOF_pidFp);
814 sprintf( TOF_message, "Wrote pid-file: %s (%d)\n",
815 TOF_pidFile , getpid() );
816 TOF_print( TOF_message );
817 return 1;
819 else
821 sprintf( TOF_message, "Error opening pid-file for writting: %s (%d)\n",
822 TOF_pidFile , getpid() );
823 TOF_print( TOF_message );
824 return 0;
828 static void TOF_deletePID( void )
830 char TOF_pidFile[strlen(torrentPath) + 4];
832 sprintf(TOF_pidFile,"%s.pid",torrentPath);
834 sprintf( TOF_message, "Removing pid-file: %s (%d)\n", TOF_pidFile , getpid() );
835 TOF_print( TOF_message );
837 remove(TOF_pidFile);
840 static void TOF_writeStatus( const tr_stat *s, const tr_info *info, const int state, const char *status )
842 if( !TOF_writeAllowed() && state != 0 ) return;
844 TOF_statFp = fopen(TOF_statFile, "w+");
845 if (TOF_statFp != NULL)
847 float TOF_pd,TOF_ratio;
848 int TOF_seeders,TOF_leechers;
850 TOF_seeders = ( s->seeders < 0 ) ? 0 : s->seeders;
851 TOF_leechers = ( s->leechers < 0 ) ? 0 : s->leechers;
853 if (state == 0 && s->percentDone < 1)
854 TOF_pd = ( -100.0 * s->percentDone ) - 100;
855 else
856 TOF_pd = 100.0 * s->percentDone;
858 TOF_ratio = s->ratio < 0 ? 0 : s->ratio;
860 fprintf(TOF_statFp,
861 "%d\n%.1f\n%s\n%.1f kB/s\n%.1f kB/s\n%s\n%d (%d)\n%d (%d)\n%.1f\n%d\n%" PRIu64 "\n%" PRIu64 "\n%" PRIu64,
862 state, /* State */
863 TOF_pd, /* Progress */
864 status, /* Status text */
865 s->pieceDownloadSpeed_KBps, /* Download speed */ // versus rawDownloadSpeed
866 s->pieceUploadSpeed_KBps, /* Upload speed */ // versus rawUploadSpeed
867 TOF_owner, /* Owner */
868 s->peersSendingToUs, TOF_seeders, /* Seeder */
869 s->peersGettingFromUs, TOF_leechers, /* Leecher */
870 100.0 * TOF_ratio, /* ratio */
871 TOF_seedLimit, /* seedlimit */
872 s->uploadedEver, /* uploaded bytes */
873 s->downloadedEver, /* downloaded bytes */
874 info->totalSize /* global size */
876 fclose(TOF_statFp);
879 else
881 sprintf( TOF_message, "Error opening stat-file for writting: %s\n", TOF_statFile );
882 TOF_print( TOF_message );
886 static int TOF_processCommands(tr_session * h)
888 /* return values:
889 * 0 :: do not shutdown transmission
890 * 1 :: shutdown transmission
893 /* Now Process the CommandFile */
895 int commandCount = 0;
896 int isNewline;
897 long fileLen;
898 long index;
899 long startPos;
900 long totalChars;
901 char currentLine[128];
902 char *fileBuffer;
903 char *fileCurrentPos;
905 /* Try opening the CommandFile */
906 TOF_cmdFp = NULL;
907 TOF_cmdFp = fopen(TOF_cmdFile, "r");
909 /* File does not exist */
910 if( TOF_cmdFp == NULL )
911 return 0;
913 sprintf( TOF_message, "Processing command-file %s...\n", TOF_cmdFile );
914 TOF_print( TOF_message );
916 // get length
917 fseek(TOF_cmdFp, 0L, SEEK_END);
918 fileLen = ftell(TOF_cmdFp);
919 rewind(TOF_cmdFp);
921 if ( fileLen >= TOF_CMDFILE_MAXLEN || fileLen < 1 )
923 if( fileLen >= TOF_CMDFILE_MAXLEN )
924 sprintf( TOF_message, "Size of command-file too big, skip. (max-size: %d)\n", TOF_CMDFILE_MAXLEN );
925 else
926 sprintf( TOF_message, "No commands found in command-file.\n" );
928 TOF_print( TOF_message );
929 /* remove file */
930 remove(TOF_cmdFile);
931 goto finished;
934 fileBuffer = calloc(fileLen + 1, sizeof(char));
935 if (fileBuffer == NULL)
937 TOF_print( (char*) "Not enough memory to read command-file\n" );
938 /* remove file */
939 remove(TOF_cmdFile);
940 goto finished;
943 fread(fileBuffer, fileLen, 1, TOF_cmdFp);
944 fclose(TOF_cmdFp);
945 remove(TOF_cmdFile);
946 TOF_cmdFp = NULL;
947 totalChars = 0L;
948 fileCurrentPos = fileBuffer;
950 while (*fileCurrentPos)
952 index = 0L;
953 isNewline = 0;
954 startPos = totalChars;
955 while (*fileCurrentPos)
957 if (!isNewline)
959 if ( *fileCurrentPos == 10 )
960 isNewline = 1;
962 else if (*fileCurrentPos != 10)
964 break;
966 ++totalChars;
967 if ( index < 127 )
968 currentLine[index++] = *fileCurrentPos++;
969 else
971 fileCurrentPos++;
972 break;
976 if ( index > 1 )
978 commandCount++;
979 currentLine[index - 1] = '\0';
981 if (TOF_execCommand(h, currentLine))
983 free(fileBuffer);
984 return 1;
989 if (commandCount == 0)
990 TOF_print( (char*) "No commands found in command-file.\n" );
992 free(fileBuffer);
994 finished:
995 return 0;
998 static int TOF_execCommand(tr_session *h, char *s)
1000 int i, uploadLimit, downloadLimit;
1001 int len = strlen(s);
1002 char opcode;
1003 char workload[len];
1005 opcode = s[0];
1006 for (i = 0; i < len - 1; i++)
1007 workload[i] = s[i + 1];
1008 workload[len - 1] = '\0';
1010 switch (opcode)
1012 case 'q':
1013 TOF_print( (char*) "command: stop-request, setting shutdown-flag...\n" );
1014 return 1;
1016 case 'u':
1017 if (strlen(workload) < 1)
1019 TOF_print( (char*) "invalid upload-rate...\n" );
1020 return 0;
1023 uploadLimit = atoi(workload);
1024 sprintf( TOF_message, "command: setting upload-rate to %d...\n", uploadLimit );
1025 TOF_print( TOF_message );
1027 tr_sessionSetSpeedLimit_KBps( h, TR_UP, uploadLimit );
1028 tr_sessionLimitSpeed( h, TR_UP, uploadLimit > 0 );
1030 return 0;
1032 case 'd':
1033 if (strlen(workload) < 1)
1035 TOF_print( (char*) "invalid download-rate...\n" );
1036 return 0;
1039 downloadLimit = atoi(workload);
1040 sprintf( TOF_message, "command: setting download-rate to %d...\n", downloadLimit );
1041 TOF_print( TOF_message );
1043 tr_sessionSetSpeedLimit_KBps( h, TR_DOWN, downloadLimit );
1044 tr_sessionLimitSpeed( h, TR_DOWN, downloadLimit > 0 );
1045 return 0;
1047 case 'w':
1048 if (strlen(workload) < 1)
1050 TOF_print( (char*) "invalid die-when-done flag...\n" );
1051 return 0;
1054 switch (workload[0])
1056 case '0':
1057 TOF_print( (char*) "command: setting die-when-done to 0\n" );
1058 TOF_dieWhenDone = 0;
1059 break;
1060 case '1':
1061 TOF_print( (char*) "command: setting die-when-done to 1\n" );
1062 TOF_dieWhenDone = 1;
1063 break;
1064 default:
1065 sprintf( TOF_message, "invalid die-when-done flag: %c...\n", workload[0] );
1066 TOF_print( TOF_message );
1068 return 0;
1070 case 'l':
1071 if (strlen(workload) < 1)
1073 TOF_print( (char*) "invalid sharekill ratio...\n" );
1074 return 0;
1077 TOF_seedLimit = atoi(workload);
1078 sprintf( TOF_message, "command: setting sharekill to %d...\n", TOF_seedLimit );
1079 TOF_print( TOF_message );
1080 return 0;
1082 default:
1083 sprintf( TOF_message, "op-code unknown: %c\n", opcode );
1084 TOF_print( TOF_message );
1086 return 0;
1089 static int TOF_writeAllowed ( void )
1091 /* We want to write status every <TOF_displayInterval> seconds,
1092 but we also want to start in the first round */
1093 if( TOF_checkCmd == 1 ) return 1;
1094 return 0;
1097 static void TOF_free ( void )
1099 free(TOF_cmdFile);
1100 free(TOF_statFile);
1101 if(strcmp(TOF_owner,"n/a") == 0)
1102 free((void *)TOF_owner);
1105 /* -END- */