1 /******************************************************************************
2 * $Id: cli.c 10084 2010-02-02 22:45:22Z 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 *****************************************************************************/
31 #include <libtransmission/transmission.h>
32 #include <libtransmission/bencode.h>
33 #include <libtransmission/makemeta.h>
34 #include <libtransmission/tr-getopt.h>
35 #include <libtransmission/utils.h> /* tr_wait_msec */
36 #include <libtransmission/version.h>
37 #include <libtransmission/web.h> /* tr_webRun */
40 #define MY_NAME "transmissioncli"
43 #define TOF_DISPLAY_INTERVAL 5
44 #define TOF_DISPLAY_INTERVAL_STR "5"
45 #define TOF_DIEWHENDONE 0
46 #define TOF_DIEWHENDONE_STR "0"
47 #define TOF_CMDFILE_MAXLEN 65536
50 static tr_bool showInfo
= 0;
51 static tr_bool showScrape
= 0;
52 static tr_bool isPrivate
= 0;
53 static tr_bool verify
= 0;
54 static sig_atomic_t gotsig
= 0;
55 static sig_atomic_t manualUpdate
= 0;
57 static const char * torrentPath
= NULL
;
58 static const char * finishCall
= NULL
;
59 static const char * sourceFile
= NULL
;
60 static const char * comment
= NULL
;
62 #define MAX_ANNOUNCE 128
63 static tr_tracker_info announce
[MAX_ANNOUNCE
];
64 static int announceCount
= 0;
66 /* Torrentflux -START- */
67 //static volatile char tf_shutdown = 0;
68 static int TOF_dieWhenDone
= TOF_DIEWHENDONE
;
69 static int TOF_seedLimit
= 0;
70 static int TOF_displayInterval
= TOF_DISPLAY_INTERVAL
;
71 static int TOF_checkCmd
= 0;
73 static const char * TOF_owner
= NULL
;
74 static char * TOF_statFile
= NULL
;
75 static FILE * TOF_statFp
= NULL
;
76 static char * TOF_cmdFile
= NULL
;
77 static FILE * TOF_cmdFp
= NULL
;
78 static char TOF_message
[512];
81 static const struct tr_option options
[] =
83 { 'a', "announce", "Set the new torrent's announce URL", "a", 1, "<url>" },
84 { 'b', "blocklist", "Enable peer blocklists", "b", 0, NULL
},
85 { 'B', "no-blocklist", "Disable peer blocklists", "B", 0, NULL
},
86 { 'c', "comment", "Set the new torrent's comment", "c", 1, "<comment>" },
87 { 'd', "downlimit", "Set max download speed in KB/s", "d", 1, "<speed>" },
88 { 'D', "no-downlimit", "Don't limit the download speed", "D", 0, NULL
},
89 { 910, "encryption-required", "Encrypt all peer connections", "er", 0, NULL
},
90 { 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", 0, NULL
},
91 { 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", 0, NULL
},
92 { 'f', "finish", "Run a script when the torrent finishes", "f", 1, "<script>" },
93 { 'g', "config-dir", "Where to find configuration files", "g", 1, "<path>" },
94 { 'i', "info", "Show torrent details and exit", "i", 0, NULL
},
95 { 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", 0, NULL
},
96 { 'M', "no-portmap", "Disable portmapping", "M", 0, NULL
},
97 { 'n', "new", "Create a new torrent", "n", 1, "<source>" },
98 { 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR
")", "p", 1, "<port>" },
99 { 'r', "private", "Set the new torrent's 'private' flag", "r", 0, NULL
},
100 { 's', "scrape", "Scrape the torrent and exit", "s", 0, NULL
},
101 { 't', "tos", "Peer socket TOS (0 to 255, default=" TR_DEFAULT_PEER_SOCKET_TOS_STR
")", "t", 1, "<tos>" },
102 { 'u', "uplimit", "Set max upload speed in KB/s", "u", 1, "<speed>" },
103 { 'U', "no-uplimit", "Don't limit the upload speed", "U", 0, NULL
},
104 { 'v', "verify", "Verify the specified torrent", "v", 0, NULL
},
105 { 'w', "download-dir", "Where to save downloaded data", "w", 1, "<path>" },
106 //Torrentflux Commands:
107 { 'E', "display-interval","Time between updates of stat-file (default = "TOF_DISPLAY_INTERVAL_STR
")","E",1,"<int>"},
108 { 'L', "seedlimit","Seed-Limit (Percent) to reach before shutdown","L",1,"<int>"},
109 { 'O', "owner","Name of the owner (default = 'n/a')","O",1,"<string>"},
110 { 'W', "die-when-done", "Auto-Shutdown when done (0 = Off, 1 = On, default = "TOF_DIEWHENDONE_STR
")","W",1,NULL
},
112 { 0, NULL
, NULL
, NULL
, 0, NULL
}
118 return "A fast and easy BitTorrent client\n"
120 "Usage: " MY_NAME
" [options] <file|url|magnet>";
123 static int parseCommandLine( tr_benc
*, int argc
, const char ** argv
);
125 static void sigHandler( int signal
);
127 /* Torrentflux -START- */
128 static int TOF_processCommands(tr_session
*h
);
129 static int TOF_execCommand(tr_session
*h
, char *s
);
130 static void TOF_print ( char *printmsg
);
131 static void TOF_free ( void );
132 static int TOF_initStatus ( void );
133 static void TOF_writeStatus ( const tr_stat
*s
, const tr_info
*info
,
134 const int state
, const char *status
);
135 static int TOF_initCommand ( void );
136 static int TOF_writePID ( void );
137 static void TOF_deletePID ( void );
138 static int TOF_writeAllowed ( void );
143 tr_strlratio( char * buf
,
147 if( (int)ratio
== TR_RATIO_NA
)
148 tr_strlcpy( buf
, _( "None" ), buflen
);
149 else if( (int)ratio
== TR_RATIO_INF
)
150 tr_strlcpy( buf
, "Inf", buflen
);
151 else if( ratio
< 10.0 )
152 tr_snprintf( buf
, buflen
, "%.2f", ratio
);
153 else if( ratio
< 100.0 )
154 tr_snprintf( buf
, buflen
, "%.1f", ratio
);
156 tr_snprintf( buf
, buflen
, "%.0f", ratio
);
161 is_rfc2396_alnum( char ch
)
163 return ( '0' <= ch
&& ch
<= '9' )
164 || ( 'A' <= ch
&& ch
<= 'Z' )
165 || ( 'a' <= ch
&& ch
<= 'z' );
171 int in_len
) /* rfc2396 */
173 const uint8_t *end
= in
+ in_len
;
176 if( is_rfc2396_alnum( *in
) )
177 *out
++ = (char) *in
++;
179 out
+= tr_snprintf( out
, 4, "%%%02X", (unsigned int)*in
++ );
185 torrentCompletenessChanged( tr_torrent
* torrent UNUSED
,
186 tr_completeness completeness UNUSED
,
187 void * user_data UNUSED
)
189 system( finishCall
);
192 static tr_bool waitingOnWeb;
195 onTorrentFileDownloaded( tr_session * session UNUSED,
196 long response_code UNUSED,
197 const void * response,
198 size_t response_byte_count,
201 tr_ctorSetMetainfo( ctor, response, response_byte_count );
202 waitingOnWeb = FALSE;
205 static int leftToScrape
= 0;
208 scrapeDoneFunc( tr_session
* session UNUSED
,
210 const void * response
,
211 size_t response_byte_count
,
216 if( !tr_bencLoad( response
, response_byte_count
, &top
, NULL
)
217 && tr_bencDictFindDict( &top
, "files", &files
)
218 && files
->val
.l
.count
>= 2 )
220 int64_t complete
= -1, incomplete
= -1, downloaded
= -1;
221 tr_benc
* hash
= &files
->val
.l
.vals
[1];
222 tr_bencDictFindInt( hash
, "complete", &complete
);
223 tr_bencDictFindInt( hash
, "incomplete", &incomplete
);
224 tr_bencDictFindInt( hash
, "downloaded", &downloaded
);
225 printf( "%4d seeders, %4d leechers, %5d downloads at %s\n",
226 (int)complete
, (int)incomplete
, (int)downloaded
,
231 fprintf( stderr
, "Unable to parse response (http code %lu) at %s",
241 dumpInfo( FILE * out
,
242 const tr_info
* inf
)
248 fprintf( out
, "hash:\t" );
249 for( i
= 0; i
< SHA_DIGEST_LENGTH
; ++i
)
250 fprintf( out
, "%02x", inf
->hash
[i
] );
251 fprintf( out
, "\n" );
253 fprintf( out
, "name:\t%s\n", inf
->name
);
255 for( i
= 0; i
< inf
->trackerCount
; ++i
)
257 if( prevTier
!= inf
->trackers
[i
].tier
)
259 prevTier
= inf
->trackers
[i
].tier
;
260 fprintf( out
, "\ntracker tier #%d:\n", ( prevTier
+ 1 ) );
262 fprintf( out
, "\tannounce:\t%s\n", inf
->trackers
[i
].announce
);
265 fprintf( out
, "size:\t%" PRIu64
" (%" PRIu64
" * %d + %" PRIu64
")\n",
266 inf
->totalSize
, inf
->totalSize
/ inf
->pieceSize
,
267 inf
->pieceSize
, inf
->totalSize
% inf
->pieceSize
);
269 if( inf
->comment
&& *inf
->comment
)
270 fprintf( out
, "comment:\t%s\n", inf
->comment
);
271 if( inf
->creator
&& *inf
->creator
)
272 fprintf( out
, "creator:\t%s\n", inf
->creator
);
274 fprintf( out
, "private flag set\n" );
276 fprintf( out
, "file(s):\n" );
277 for( ff
= 0; ff
< inf
->fileCount
; ++ff
)
278 fprintf( out
, "\t%s (%" PRIu64
")\n", inf
->files
[ff
].name
,
279 inf
->files
[ff
].length
);
283 getStatusStr( const tr_stat
* st
, const tr_info
*information
)
288 if( st
->activity
& TR_STATUS_CHECK_WAIT
)
290 TOF_writeStatus(st
, information
, 1, "Waiting to verify local files" );
292 else if( st
->activity
& TR_STATUS_CHECK
)
295 tr_snprintf( buf, buflen,
296 "Verifying local files (%.2f%%, %.2f%% valid)",
297 tr_truncd( 100 * st->recheckProgress, 2 ),
298 tr_truncd( 100 * st->percentDone, 2 ) );
300 sprintf(TOF_eta
, "%.2f%% Verifying local files",100 * st
->recheckProgress
);
301 TOF_writeStatus(st
, information
, 1, TOF_eta
);
303 else if( st
->activity
& TR_STATUS_DOWNLOAD
)
318 if( TOF_writeAllowed() )
323 if ( st
->eta
< 604800 ) // 7 days
325 if ( st
->eta
>= 86400 ) // 1 day
326 sprintf(TOF_eta
, "%d:",
329 if ( st
->eta
>= 3600 ) // 1 hour
330 sprintf(TOF_eta
, "%s%02d:",
331 TOF_eta
,((st
->eta
% 86400) / 3600));
333 if ( st
->eta
>= 60 ) // 1 Minute
334 sprintf(TOF_eta
, "%s%02d:",
335 TOF_eta
,((st
->eta
% 3600) / 60));
337 sprintf(TOF_eta
, "%s%02d",
338 TOF_eta
,(st
->eta
% 60));
341 sprintf(TOF_eta
, "-");
344 if ((st
->seeders
< -1) && (st
->peersConnected
== 0))
345 sprintf(TOF_eta
, "Connecting to Peers");
347 TOF_writeStatus(st
, information
, 1, TOF_eta
);
350 else if( st
->activity
& TR_STATUS_SEED
)
358 if (TOF_dieWhenDone
== 1)
360 TOF_print( "Die-when-done set, setting shutdown-flag...\n" );
367 if (TOF_seedLimit
== -1)
369 TOF_print( "Sharekill set to -1, setting shutdown-flag...\n" );
372 else if ( ( TOF_seedLimit
> 0 ) && ( ( st
->ratio
* 100.0 ) > (float)TOF_seedLimit
) )
374 sprintf( TOF_message
, "Seed-limit %d%% reached, setting shutdown-flag...\n", TOF_seedLimit
);
375 TOF_print( TOF_message
);
379 TOF_writeStatus(st
, information
, 1, "Download Succeeded" );
383 sprintf( TOF_message
, "error: %s\n", st
->errorString
);
384 TOF_print( TOF_message
);
389 getConfigDir( int argc
, const char ** argv
)
392 const char * configDir
= NULL
;
394 const int ind
= tr_optind
;
396 while(( c
= tr_getopt( getUsage( ), argc
, argv
, options
, &optarg
))) {
405 if( configDir
== NULL
)
406 configDir
= tr_getDefaultConfigDir( MY_NAME
);
418 tr_torrent
* tor
= NULL
;
420 const tr_info
* information
;
421 const char * configDir
;
424 tr_bool haveAnnounce
;
425 uint8_t * fileContents
;
428 printf( "Transmission %s - http://www.transmissionbt.com/ - modified for Torrentflux-b4rt\n",
429 LONG_VERSION_STRING
);
431 /* user needs to pass in at least one argument */
433 tr_getopt_usage( MY_NAME
, getUsage( ), options
);
437 /* load the defaults from config file + libtransmission defaults */
438 tr_bencInitDict( &settings
, 0 );
439 configDir
= getConfigDir( argc
, (const char**)argv
);
440 //tr_sessionLoadSettings( &settings, configDir, MY_NAME );
442 /* the command line overrides defaults */
443 if( parseCommandLine( &settings
, argc
, (const char**)argv
) )
445 printf("Invalid commandline option given\n");
449 /* Check the options for validity */
451 fprintf( stderr
, "No torrent specified!\n" );
454 tr_bencDictRemove( &settings
, TR_PREFS_KEY_DOWNLOAD_DIR
);
455 getcwd( cwd
, sizeof( cwd
) );
456 tr_bencDictAddStr( &settings
, TR_PREFS_KEY_DOWNLOAD_DIR
, cwd
);
458 /* don't bind the port if we're just running the CLI
459 to get metainfo or to create a torrent */
460 if( showInfo
|| showScrape
|| ( sourceFile
!= NULL
) )
461 tr_bencDictAddInt( &settings
, TR_PREFS_KEY_PEER_PORT
, -1 );
463 h
= tr_sessionInit( "cli", configDir
, FALSE
, &settings
);
465 haveSource
= sourceFile
&& *sourceFile
;
466 haveAnnounce
= announceCount
> 0;
468 if( haveSource
&& !haveAnnounce
)
469 fprintf( stderr
, "Did you mean to create a torrent without a tracker's announce URL?\n" );
471 if( haveSource
) /* creating a torrent */
474 tr_metainfo_builder
* b
;
475 fprintf( stderr
, "creating torrent \"%s\"\n", torrentPath
);
477 b
= tr_metaInfoBuilderCreate( sourceFile
);
478 tr_makeMetaInfo( b
, torrentPath
, announce
, announceCount
, comment
, isPrivate
);
481 tr_wait_msec( 1000 );
486 tr_metaInfoBuilderFree( b
);
490 ctor
= tr_ctorNew( h
);
491 tr_ctorSetMetainfoFromFile( ctor
, torrentPath
);
492 tr_ctorSetPaused( ctor
, TR_FORCE
, showScrape
);
493 tr_ctorSetDownloadDir( ctor
, TR_FORCE
, cwd
);
494 tr_ctorSetDownloadDir( ctor
, TR_FALLBACK
, cwd
);
500 if( !tr_torrentParse( ctor
, &info
) )
503 const time_t start
= time( NULL
);
504 for( i
= 0; i
< info
.trackerCount
; ++i
)
506 if( info
.trackers
[i
].scrape
)
508 const char * scrape
= info
.trackers
[i
].scrape
;
509 char escaped
[SHA_DIGEST_LENGTH
* 3 + 1];
511 escape( escaped
, info
.hash
, SHA_DIGEST_LENGTH
);
512 url
= tr_strdup_printf( "%s%cinfo_hash=%s",
517 tr_urlParse( scrape
, -1, NULL
, &host
, NULL
, NULL
);
520 tr_webRun( h
, url
, NULL
, scrapeDoneFunc
, host
);
525 fprintf( stderr
, "scraping %d trackers:\n", leftToScrape
);
527 while( leftToScrape
> 0 && ( ( time( NULL
) - start
) < 20 ) )
532 //* Torrentflux -START- */
533 if (TOF_owner
== NULL
)
535 sprintf( TOF_message
, "No owner supplied, using 'n/a'.\n" );
536 TOF_print( TOF_message
);
537 TOF_owner
= malloc((4) * sizeof(char));
538 if (TOF_owner
== NULL
)
540 sprintf( TOF_message
, "Error : not enough mem for malloc\n" );
541 TOF_print( TOF_message
);
547 sprintf( TOF_message
, "transmission %s starting up :\n", LONG_VERSION_STRING
);
548 TOF_print( TOF_message
);
549 sprintf( TOF_message
, " - torrent : %s\n", torrentPath
);
550 TOF_print( TOF_message
);
551 sprintf( TOF_message
, " - owner : %s\n", TOF_owner
);
552 TOF_print( TOF_message
);
553 sprintf( TOF_message
, " - dieWhenDone : %d\n", TOF_dieWhenDone
);
554 TOF_print( TOF_message
);
555 sprintf( TOF_message
, " - seedLimit : %d\n", TOF_seedLimit
);
556 TOF_print( TOF_message
);
557 sprintf( TOF_message
, " - bindPort : %d\n", tr_sessionGetPeerPort(h
) );
558 TOF_print( TOF_message
);
559 sprintf( TOF_message
, " - uploadLimit : %d\n", tr_sessionGetSpeedLimit(h
, TR_UP
) );
560 TOF_print( TOF_message
);
561 sprintf( TOF_message
, " - downloadLimit : %d\n", tr_sessionGetSpeedLimit(h
, TR_DOWN
) );
562 TOF_print( TOF_message
);
563 sprintf( TOF_message
, " - natTraversal : %d\n", tr_sessionIsPortForwardingEnabled(h
) );
564 TOF_print( TOF_message
);
565 sprintf( TOF_message
, " - displayInterval : %d\n", TOF_displayInterval
);
566 TOF_print( TOF_message
);
567 sprintf( TOF_message
, " - downloadDir : %s\n", tr_sessionGetDownloadDir(h
) );
568 TOF_print( TOF_message
);
570 if (finishCall
!= NULL
)
572 sprintf( TOF_message
, " - finishCall : %s\n", finishCall
);
573 TOF_print( TOF_message
);
582 if( !tr_torrentParse( ctor
, &info
) )
584 dumpInfo( stdout
, &info
);
585 tr_metainfoFree( &info
);
592 tor
= tr_torrentNew( ctor
, &error
);
593 sprintf( TOF_message
, " - downloadDir from torrent object, usually loaded from resume data : %s\n", tr_torrentGetDownloadDir( tor
) );
594 TOF_print( TOF_message
);
598 //fprintf( stderr, "Failed opening torrent file `%s'\n", torrentPath );
600 sprintf( TOF_message
, "Failed opening torrent file %s'\n", torrentPath
);
601 TOF_print( TOF_message
);
602 tr_sessionClose( h
);
606 signal( SIGINT
, sigHandler
);
608 signal( SIGHUP
, sigHandler
);
610 tr_torrentSetCompletenessCallback( tor
, torrentCompletenessChanged
, NULL
);
611 tr_torrentStart( tor
);
616 tr_torrentVerify( tor
);
619 /* Torrentflux -START */
621 // initialize status-facility
622 if (TOF_initStatus() == 0)
624 sprintf( TOF_message
, "Failed to init status-facility. exit transmission.\n" );
625 TOF_print( TOF_message
);
629 // initialize command-facility
630 if (TOF_initCommand() == 0)
632 sprintf( TOF_message
, "Failed to init command-facility. exit transmission.\n" );
633 TOF_print( TOF_message
);
638 if (TOF_writePID() == 0)
640 sprintf( TOF_message
, "Failed to write pid-file. exit transmission.\n" );
641 TOF_print( TOF_message
);
645 sprintf( TOF_message
, "Transmission up and running.\n" );
647 information
= tr_torrentInfo( tor
);
653 //char line[LINEWIDTH];
655 const char * messageName
[] = { NULL
, "Tracker gave a warning:",
656 "Tracker gave an error:",
659 /* Torrentflux -START */
662 if( TOF_checkCmd
== TOF_displayInterval
)
665 /* If Torrentflux wants us to shutdown */
666 if (TOF_processCommands(h
))
677 //printf( "\nStopping torrent...\n" );
678 tr_torrentStop( tor
);
684 if( !tr_torrentCanManualUpdate( tor
) )
688 "\nReceived SIGHUP, but can't send a manual update now\n" );
693 "\nReceived SIGHUP: manual update scheduled\n" );
694 tr_torrentManualUpdate( tor
);
698 st
= tr_torrentStat( tor
);
699 if( st
->activity
& TR_STATUS_STOPPED
)
704 getStatusStr( st
, information
);
705 //printf( "\r%-*s", LINEWIDTH, line );
707 if( messageName
[st
->error
] )
708 fprintf( stderr
, "\n%s: %s\n", messageName
[st
->error
], st
->errorString
);
714 st
= tr_torrentStat( tor
);
716 TOF_print("Transmission shutting down...\n");
718 /* Try for 5 seconds to delete any port mappings for nat traversal */
719 tr_sessionSetPortForwardingEnabled( h
, 0 );
720 for( i
= 0; i
< 10; i
++ )
722 if( TR_PORT_UNMAPPED
== tr_sessionIsPortForwardingEnabled( h
) )
724 /* Port mappings were deleted */
729 if (st
->percentDone
>= 1)
730 TOF_writeStatus(st
, information
, 0, "Download Succeeded" );
732 TOF_writeStatus(st
, information
, 0, "Torrent Stopped" );
736 TOF_print("Transmission exit.\n");
743 //tr_sessionSaveSettings( h, configDir, &settings );
746 tr_bencFree( &settings
);
747 tr_sessionClose( h
);
752 tr_torrentFree( tor
);
753 tr_sessionClose( h
);
765 parseCommandLine( tr_benc
* d
, int argc
, const char ** argv
)
767 int64_t downloadLimit
, uploadLimit
;
771 while(( c
= tr_getopt( getUsage( ), argc
, argv
, options
, &optarg
)))
775 case 'a': if( announceCount
+ 1 < MAX_ANNOUNCE
) {
776 announce
[announceCount
].tier
= announceCount
;
777 announce
[announceCount
].announce
= (char*) optarg
;
781 case 'b': tr_bencDictAddBool( d
, TR_PREFS_KEY_BLOCKLIST_ENABLED
, TRUE
);
783 case 'B': tr_bencDictAddBool( d
, TR_PREFS_KEY_BLOCKLIST_ENABLED
, FALSE
);
785 case 'c': comment
= optarg
;
788 case 'd': downloadLimit
=atoi( optarg
);
789 switch (downloadLimit
) {
797 if (downloadLimit
>=0)
799 tr_bencDictAddInt( d
, TR_PREFS_KEY_DSPEED
, downloadLimit
);
800 tr_bencDictAddInt( d
, TR_PREFS_KEY_DSPEED_ENABLED
, 1 );
803 tr_bencDictAddInt( d
, TR_PREFS_KEY_DSPEED_ENABLED
, 0 );
805 case 'D': tr_bencDictAddBool( d
, TR_PREFS_KEY_DSPEED_ENABLED
, FALSE
);
807 case 'f': finishCall
= optarg
;
809 case 'g': /* handled above */
811 case 'i': showInfo
= 1;
813 case 'm': tr_bencDictAddBool( d
, TR_PREFS_KEY_PORT_FORWARDING
, TRUE
);
815 case 'M': tr_bencDictAddBool( d
, TR_PREFS_KEY_PORT_FORWARDING
, FALSE
);
817 case 'n': sourceFile
= optarg
; break;
818 case 'p': tr_bencDictAddInt( d
, TR_PREFS_KEY_PEER_PORT
, atoi( optarg
) );
820 case 'r': isPrivate
= 1;
822 case 's': showScrape
= 1;
824 case 't': tr_bencDictAddInt( d
, TR_PREFS_KEY_PEER_SOCKET_TOS
, atoi( optarg
) );
827 uploadLimit
=atoi( optarg
);
828 switch (uploadLimit
) {
838 tr_bencDictAddInt( d
, TR_PREFS_KEY_USPEED
, uploadLimit
);
839 tr_bencDictAddInt( d
, TR_PREFS_KEY_USPEED_ENABLED
, 1 );
842 tr_bencDictAddInt( d
, TR_PREFS_KEY_USPEED_ENABLED
, 0 );
844 case 'U': tr_bencDictAddBool( d
, TR_PREFS_KEY_USPEED_ENABLED
, FALSE
);
846 case 'v': verify
= 1;
848 case 'w': tr_bencDictAddStr( d
, TR_PREFS_KEY_DOWNLOAD_DIR
, optarg
);
851 TOF_displayInterval
= atoi( optarg
);
854 TOF_seedLimit
= atoi( optarg
);
860 TOF_dieWhenDone
= atoi( optarg
);
862 case 910: tr_bencDictAddInt( d
, TR_PREFS_KEY_ENCRYPTION
, TR_ENCRYPTION_REQUIRED
);
864 case 911: tr_bencDictAddInt( d
, TR_PREFS_KEY_ENCRYPTION
, TR_ENCRYPTION_PREFERRED
);
866 case 912: tr_bencDictAddInt( d
, TR_PREFS_KEY_ENCRYPTION
, TR_CLEAR_PREFERRED
);
869 torrentPath
= optarg
;
879 sigHandler( int signal
)
888 manualUpdate
= 1; break;
897 /* Torrentflux -START- */
898 static void TOF_print( char *printmsg
)
901 struct tm
* timeinfo
;
903 timeinfo
= localtime(&rawtime
);
905 fprintf(stderr
, "[%4d/%02d/%02d - %02d:%02d:%02d] %s",
906 timeinfo
->tm_year
+ 1900,
907 timeinfo
->tm_mon
+ 1,
912 ((printmsg
!= NULL
) && (strlen(printmsg
) > 0)) ? printmsg
: ""
916 static int TOF_initStatus( void )
918 int len
= strlen(torrentPath
) + 5;
919 TOF_statFile
= malloc((len
+ 1) * sizeof(char));
920 if (TOF_statFile
== NULL
) {
921 TOF_print( "Error : TOF_initStatus: not enough mem for malloc\n" );
925 sprintf( TOF_statFile
, "%s.stat", torrentPath
);
927 sprintf( TOF_message
, "Initialized status-facility. (%s)\n", TOF_statFile
);
928 TOF_print( TOF_message
);
932 static int TOF_initCommand( void )
934 int len
= strlen(torrentPath
) + 4;
935 TOF_cmdFile
= malloc((len
+ 1) * sizeof(char));
936 if (TOF_cmdFile
== NULL
) {
937 TOF_print( "Error : TOF_initCommand: not enough mem for malloc\n" );
940 sprintf( TOF_cmdFile
, "%s.cmd", torrentPath
);
942 sprintf( TOF_message
, "Initialized command-facility. (%s)\n", TOF_cmdFile
);
943 TOF_print( TOF_message
);
945 // remove command-file if exists
947 TOF_cmdFp
= fopen(TOF_cmdFile
, "r");
948 if (TOF_cmdFp
!= NULL
)
951 sprintf( TOF_message
, "Removing command-file. (%s)\n", TOF_cmdFile
);
952 TOF_print( TOF_message
);
959 static int TOF_writePID( void )
962 char TOF_pidFile
[strlen(torrentPath
) + 4];
964 sprintf(TOF_pidFile
,"%s.pid",torrentPath
);
966 TOF_pidFp
= fopen(TOF_pidFile
, "w+");
967 if (TOF_pidFp
!= NULL
)
969 fprintf(TOF_pidFp
, "%d", getpid());
971 sprintf( TOF_message
, "Wrote pid-file: %s (%d)\n",
972 TOF_pidFile
, getpid() );
973 TOF_print( TOF_message
);
978 sprintf( TOF_message
, "Error opening pid-file for writting: %s (%d)\n",
979 TOF_pidFile
, getpid() );
980 TOF_print( TOF_message
);
985 static void TOF_deletePID( void )
987 char TOF_pidFile
[strlen(torrentPath
) + 4];
989 sprintf(TOF_pidFile
,"%s.pid",torrentPath
);
991 sprintf( TOF_message
, "Removing pid-file: %s (%d)\n", TOF_pidFile
, getpid() );
992 TOF_print( TOF_message
);
997 static void TOF_writeStatus( const tr_stat
*s
, const tr_info
*info
, const int state
, const char *status
)
999 if( !TOF_writeAllowed() && state
!= 0 ) return;
1001 TOF_statFp
= fopen(TOF_statFile
, "w+");
1002 if (TOF_statFp
!= NULL
)
1004 float TOF_pd
,TOF_ratio
;
1005 int TOF_seeders
,TOF_leechers
;
1007 TOF_seeders
= ( s
->seeders
< 0 ) ? 0 : s
->seeders
;
1008 TOF_leechers
= ( s
->leechers
< 0 ) ? 0 : s
->leechers
;
1010 if (state
== 0 && s
->percentDone
< 1)
1011 TOF_pd
= ( -100.0 * s
->percentDone
) - 100;
1013 TOF_pd
= 100.0 * s
->percentDone
;
1015 TOF_ratio
= s
->ratio
< 0 ? 0 : s
->ratio
;
1018 "%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
,
1020 TOF_pd
, /* Progress */
1021 status
, /* Status text */
1022 s
->pieceDownloadSpeed
, /* Download speed */ // versus rawDownloadSpeed
1023 s
->pieceUploadSpeed
, /* Upload speed */ // versus rawUploadSpeed
1024 TOF_owner
, /* Owner */
1025 s
->peersSendingToUs
, TOF_seeders
, /* Seeder */
1026 s
->peersGettingFromUs
, TOF_leechers
, /* Leecher */
1027 100.0 * TOF_ratio
, /* ratio */
1028 TOF_seedLimit
, /* seedlimit */
1029 s
->uploadedEver
, /* uploaded bytes */
1030 s
->downloadedEver
, /* downloaded bytes */
1031 info
->totalSize
/* global size */
1038 sprintf( TOF_message
, "Error opening stat-file for writting: %s\n", TOF_statFile
);
1039 TOF_print( TOF_message
);
1043 static int TOF_processCommands(tr_session
* h
)
1046 * 0 :: do not shutdown transmission
1047 * 1 :: shutdown transmission
1050 /* Now Process the CommandFile */
1052 int commandCount
= 0;
1058 char currentLine
[128];
1060 char *fileCurrentPos
;
1062 /* Try opening the CommandFile */
1064 TOF_cmdFp
= fopen(TOF_cmdFile
, "r");
1066 /* File does not exist */
1067 if( TOF_cmdFp
== NULL
)
1070 sprintf( TOF_message
, "Processing command-file %s...\n", TOF_cmdFile
);
1071 TOF_print( TOF_message
);
1074 fseek(TOF_cmdFp
, 0L, SEEK_END
);
1075 fileLen
= ftell(TOF_cmdFp
);
1078 if ( fileLen
>= TOF_CMDFILE_MAXLEN
|| fileLen
< 1 )
1080 if( fileLen
>= TOF_CMDFILE_MAXLEN
)
1081 sprintf( TOF_message
, "Size of command-file too big, skip. (max-size: %d)\n", TOF_CMDFILE_MAXLEN
);
1083 sprintf( TOF_message
, "No commands found in command-file.\n" );
1085 TOF_print( TOF_message
);
1087 remove(TOF_cmdFile
);
1091 fileBuffer
= calloc(fileLen
+ 1, sizeof(char));
1092 if (fileBuffer
== NULL
)
1094 TOF_print( "Not enough memory to read command-file\n" );
1096 remove(TOF_cmdFile
);
1100 fread(fileBuffer
, fileLen
, 1, TOF_cmdFp
);
1102 remove(TOF_cmdFile
);
1105 fileCurrentPos
= fileBuffer
;
1107 while (*fileCurrentPos
)
1111 startPos
= totalChars
;
1112 while (*fileCurrentPos
)
1116 if ( *fileCurrentPos
== 10 )
1119 else if (*fileCurrentPos
!= 10)
1125 currentLine
[index
++] = *fileCurrentPos
++;
1136 currentLine
[index
- 1] = '\0';
1138 if (TOF_execCommand(h
, currentLine
))
1146 if (commandCount
== 0)
1147 TOF_print( "No commands found in command-file.\n" );
1155 static int TOF_execCommand(tr_session
*h
, char *s
)
1157 int i
, uploadLimit
, downloadLimit
;
1158 int len
= strlen(s
);
1163 for (i
= 0; i
< len
- 1; i
++)
1164 workload
[i
] = s
[i
+ 1];
1165 workload
[len
- 1] = '\0';
1170 TOF_print( "command: stop-request, setting shutdown-flag...\n" );
1174 if (strlen(workload
) < 1)
1176 TOF_print( "invalid upload-rate...\n" );
1180 uploadLimit
= atoi(workload
);
1181 sprintf( TOF_message
, "command: setting upload-rate to %d...\n", uploadLimit
);
1182 TOF_print( TOF_message
);
1184 tr_sessionSetSpeedLimit( h
, TR_UP
, uploadLimit
);
1185 tr_sessionLimitSpeed( h
, TR_UP
, uploadLimit
> 0 );
1190 if (strlen(workload
) < 1)
1192 TOF_print( "invalid download-rate...\n" );
1196 downloadLimit
= atoi(workload
);
1197 sprintf( TOF_message
, "command: setting download-rate to %d...\n", downloadLimit
);
1198 TOF_print( TOF_message
);
1200 tr_sessionSetSpeedLimit( h
, TR_DOWN
, downloadLimit
);
1201 tr_sessionLimitSpeed( h
, TR_DOWN
, downloadLimit
> 0 );
1205 if (strlen(workload
) < 1)
1207 TOF_print( "invalid die-when-done flag...\n" );
1211 switch (workload
[0])
1214 TOF_print( "command: setting die-when-done to 0\n" );
1215 TOF_dieWhenDone
= 0;
1218 TOF_print( "command: setting die-when-done to 1\n" );
1219 TOF_dieWhenDone
= 1;
1222 sprintf( TOF_message
, "invalid die-when-done flag: %c...\n", workload
[0] );
1223 TOF_print( TOF_message
);
1228 if (strlen(workload
) < 1)
1230 TOF_print( "invalid sharekill ratio...\n" );
1234 TOF_seedLimit
= atoi(workload
);
1235 sprintf( TOF_message
, "command: setting sharekill to %d...\n", TOF_seedLimit
);
1236 TOF_print( TOF_message
);
1240 sprintf( TOF_message
, "op-code unknown: %c\n", opcode
);
1241 TOF_print( TOF_message
);
1246 static int TOF_writeAllowed ( void )
1248 /* We want to write status every <TOF_displayInterval> seconds,
1249 but we also want to start in the first round */
1250 if( TOF_checkCmd
== 1 ) return 1;
1254 static void TOF_free ( void )
1258 if(strcmp(TOF_owner
,"n/a") == 0) free(TOF_owner
);