source: trunk/cli/transmissioncli.c @ 2149

Last change on this file since 2149 was 2149, checked in by livings124, 14 years ago

Merge file selection and torrent creation into the main branch.

The new code for these features is under a new license.

  • Property svn:keywords set to Date Rev Author Id
File size: 12.2 KB
Line 
1/******************************************************************************
2 * $Id: transmissioncli.c 2149 2007-06-18 03:40:41Z livings124 $
3 *
4 * Copyright (c) 2005-2006 Transmission authors and contributors
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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 *****************************************************************************/
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include <getopt.h>
30#include <signal.h>
31#include <transmission.h>
32#include <makemeta.h>
33#ifdef SYS_BEOS
34#include <kernel/OS.h>
35#define usleep snooze
36#endif
37
38/* macro to shut up "unused parameter" warnings */
39#ifdef __GNUC__
40#define UNUSED                  __attribute__((unused))
41#else
42#define UNUSED
43#endif
44
45const char * USAGE =
46"Usage: %s [options] file.torrent [options]\n\n"
47"Options:\n"
48"  -c, --create-from <file>  Create torrent from the specified source file.\n"
49"  -a, --announce <url> Used in conjunction with -c.\n"
50"  -r, --private        Used in conjunction with -c.\n"
51"  -m, --comment <text> Adds an optional comment when creating a torrent.\n"
52"  -d, --download <int> Maximum download rate (-1 = no limit, default = -1)\n"
53"  -f, --finish <shell script> Command you wish to run on completion\n" 
54"  -h, --help           Print this help and exit\n" 
55"  -i, --info           Print metainfo and exit\n"
56"  -n  --nat-traversal  Attempt NAT traversal using NAT-PMP or UPnP IGD\n"
57"  -p, --port <int>     Port we should listen on (default = %d)\n"
58"  -s, --scrape         Print counts of seeders/leechers and exit\n"
59"  -u, --upload <int>   Maximum upload rate (-1 = no limit, default = 20)\n"
60"  -v, --verbose <int>  Verbose level (0 to 2, default = 0)\n";
61
62static int           showHelp      = 0;
63static int           showInfo      = 0;
64static int           showScrape    = 0;
65static int           isPrivate     = 0;
66static int           verboseLevel  = 0;
67static int           bindPort      = TR_DEFAULT_PORT;
68static int           uploadLimit   = 20;
69static int           downloadLimit = -1;
70static char          * torrentPath = NULL;
71static int           natTraversal  = 0;
72static sig_atomic_t  gotsig        = 0;
73static tr_torrent_t  * tor;
74
75static char          * finishCall   = NULL;
76static char          * announce     = NULL;
77static char          * sourceFile   = NULL;
78static char          * comment      = NULL;
79
80static int  parseCommandLine ( int argc, char ** argv );
81static void sigHandler       ( int signal );
82
83char * getStringRatio( float ratio )
84{
85    static char string[20];
86
87    if( ratio == TR_RATIO_NA )
88        return "n/a";
89    snprintf( string, sizeof string, "%.3f", ratio );
90    return string;
91}
92
93#define LINEWIDTH 80
94
95int main( int argc, char ** argv )
96{
97    int i, error;
98    tr_handle_t  * h;
99    tr_stat_t    * s;
100    tr_handle_status_t * hstat;
101
102    printf( "Transmission %s (%d) - http://transmission.m0k.org/\n\n",
103            VERSION_STRING, VERSION_REVISION );
104
105    /* Get options */
106    if( parseCommandLine( argc, argv ) )
107    {
108        printf( USAGE, argv[0], TR_DEFAULT_PORT );
109        return EXIT_FAILURE;
110    }
111
112    if( showHelp )
113    {
114        printf( USAGE, argv[0], TR_DEFAULT_PORT );
115        return EXIT_SUCCESS;
116    }
117
118    if( verboseLevel < 0 )
119    {
120        verboseLevel = 0;
121    }
122    else if( verboseLevel > 9 )
123    {
124        verboseLevel = 9;
125    }
126    if( verboseLevel )
127    {
128        static char env[11];
129        snprintf( env, sizeof env, "TR_DEBUG=%d", verboseLevel );
130        putenv( env );
131    }
132
133    if( bindPort < 1 || bindPort > 65535 )
134    {
135        printf( "Invalid port '%d'\n", bindPort );
136        return EXIT_FAILURE;
137    }
138
139    /* Initialize libtransmission */
140    h = tr_init( "cli" );
141
142    if( sourceFile && *sourceFile ) /* creating a torrent */
143    {
144        int ret;
145        tr_metainfo_builder_t* builder = tr_metaInfoBuilderCreate( h, sourceFile );
146        tr_makeMetaInfo( builder, NULL, announce, comment, isPrivate );
147        while( !builder->isDone ) {
148            usleep( 1 );
149            printf( "." );
150        }
151        ret = !builder->failed;
152        tr_metaInfoBuilderFree( builder );
153        return ret;
154    }
155
156    /* Open and parse torrent file */
157    if( !( tor = tr_torrentInit( h, torrentPath, NULL, 0, &error ) ) )
158    {
159        printf( "Failed opening torrent file `%s'\n", torrentPath );
160        tr_close( h );
161        return EXIT_FAILURE;
162    }
163
164    if( showInfo )
165    {
166        tr_info_t * info = tr_torrentInfo( tor );
167
168        s = tr_torrentStat( tor );
169
170        /* Print torrent info (quite à la btshowmetainfo) */
171        printf( "hash:     " );
172        for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
173        {
174            printf( "%02x", info->hash[i] );
175        }
176        printf( "\n" );
177        printf( "tracker:  %s:%d\n",
178                s->tracker->address, s->tracker->port );
179        printf( "announce: %s\n", s->tracker->announce );
180        printf( "size:     %"PRIu64" (%"PRIu64" * %d + %"PRIu64")\n",
181                info->totalSize, info->totalSize / info->pieceSize,
182                info->pieceSize, info->totalSize % info->pieceSize );
183        if( info->comment[0] )
184        {
185            printf( "comment:  %s\n", info->comment );
186        }
187        if( info->creator[0] )
188        {
189            printf( "creator:  %s\n", info->creator );
190        }
191        if( TR_FLAG_PRIVATE & info->flags )
192        {
193            printf( "private flag set\n" );
194        }
195        printf( "file(s):\n" );
196        for( i = 0; i < info->fileCount; i++ )
197        {
198            printf( " %s (%"PRIu64")\n", info->files[i].name,
199                    info->files[i].length );
200        }
201
202        goto cleanup;
203    }
204
205    if( showScrape )
206    {
207        int seeders, leechers, downloaded;
208
209        if( tr_torrentScrape( tor, &seeders, &leechers, &downloaded ) )
210        {
211            printf( "Scrape failed.\n" );
212        }
213        else
214        {
215            printf( "%d seeder(s), %d leecher(s), %d download(s).\n",
216                    seeders, leechers, downloaded );
217        }
218
219        goto cleanup;
220    }
221
222    signal( SIGINT, sigHandler );
223
224    tr_setBindPort( h, bindPort );
225    tr_setGlobalUploadLimit( h, uploadLimit );
226    tr_setGlobalDownloadLimit( h, downloadLimit );
227
228    tr_natTraversalEnable( h, natTraversal );
229   
230    tr_torrentSetFolder( tor, "." );
231    tr_torrentStart( tor );
232
233    for( ;; )
234    {
235        char string[LINEWIDTH];
236        int  chars = 0;
237        int result;
238
239        sleep( 1 );
240
241        if( gotsig )
242        {
243            gotsig = 0;
244            tr_torrentStop( tor );
245        }
246
247        s = tr_torrentStat( tor );
248
249        if( s->status & TR_STATUS_PAUSE )
250        {
251            break;
252        }
253        else if( s->status & TR_STATUS_CHECK_WAIT )
254        {
255            chars = snprintf( string, sizeof string,
256                "Waiting to check files... %.2f %%", 100.0 * s->percentDone );
257        }
258        else if( s->status & TR_STATUS_CHECK )
259        {
260            chars = snprintf( string, sizeof string,
261                "Checking files... %.2f %%", 100.0 * s->percentDone );
262        }
263        else if( s->status & TR_STATUS_DOWNLOAD )
264        {
265            chars = snprintf( string, sizeof string,
266                "Progress: %.2f %%, %d peer%s, dl from %d (%.2f KB/s), "
267                "ul to %d (%.2f KB/s) [%s]", 100.0 * s->percentDone,
268                s->peersTotal, ( s->peersTotal == 1 ) ? "" : "s",
269                s->peersUploading, s->rateDownload,
270                s->peersDownloading, s->rateUpload,
271                getStringRatio(s->ratio) );
272        }
273        else if( s->status & TR_STATUS_SEED )
274        {
275            chars = snprintf( string, sizeof string,
276                "Seeding, uploading to %d of %d peer(s), %.2f KB/s [%s]",
277                s->peersDownloading, s->peersTotal,
278                s->rateUpload, getStringRatio(s->ratio) );
279        }
280        else if( s->status & TR_STATUS_STOPPING )
281        {
282            chars = snprintf( string, sizeof string, "Stopping..." );
283        }
284        if( ( signed )sizeof string > chars )
285        {
286            memset( &string[chars], ' ', sizeof string - 1 - chars );
287        }
288        string[sizeof string - 1] = '\0';
289        fprintf( stderr, "\r%s", string );
290
291        if( s->error )
292        {
293            fprintf( stderr, "\n%s\n", s->errorString );
294        }
295        else if( verboseLevel > 0 )
296        {
297            fprintf( stderr, "\n" );
298        }
299       
300        if( tr_getDone(tor) || tr_getComplete(tor) )
301        {
302            result = system(finishCall);
303        }
304    }
305    fprintf( stderr, "\n" );
306
307    /* Try for 5 seconds to delete any port mappings for nat traversal */
308    tr_natTraversalEnable( h, 0 );
309    for( i = 0; i < 10; i++ )
310    {
311        hstat = tr_handleStatus( h );
312        if( TR_NAT_TRAVERSAL_DISABLED == hstat->natTraversalStatus )
313        {
314            /* Port mappings were deleted */
315            break;
316        }
317        usleep( 500000 );
318    }
319   
320cleanup:
321    tr_torrentClose( tor );
322    tr_close( h );
323
324    return EXIT_SUCCESS;
325}
326
327static int parseCommandLine( int argc, char ** argv )
328{
329    for( ;; )
330    {
331        static struct option long_options[] =
332          { { "help",     no_argument,       NULL, 'h' },
333            { "info",     no_argument,       NULL, 'i' },
334            { "scrape",   no_argument,       NULL, 's' },
335            { "private",  no_argument,       NULL, 'r' },
336            { "verbose",  required_argument, NULL, 'v' },
337            { "port",     required_argument, NULL, 'p' },
338            { "upload",   required_argument, NULL, 'u' },
339            { "download", required_argument, NULL, 'd' },
340            { "finish",   required_argument, NULL, 'f' },
341            { "create",   required_argument, NULL, 'c' },
342            { "comment",  required_argument, NULL, 'm' },
343            { "announce", required_argument, NULL, 'a' },
344            { "nat-traversal", no_argument,  NULL, 'n' },
345            { 0, 0, 0, 0} };
346
347        int c, optind = 0;
348        c = getopt_long( argc, argv, "hisrv:p:u:d:f:c:m:a:n:",
349                         long_options, &optind );
350        if( c < 0 )
351        {
352            break;
353        }
354        switch( c )
355        {
356            case 'h':
357                showHelp = 1;
358                break;
359            case 'i':
360                showInfo = 1;
361                break;
362            case 's':
363                showScrape = 1;
364                break;
365            case 'r':
366                isPrivate = 1;
367                break;
368            case 'v':
369                verboseLevel = atoi( optarg );
370                break;
371            case 'p':
372                bindPort = atoi( optarg );
373                break;
374            case 'u':
375                uploadLimit = atoi( optarg );
376                break;
377            case 'd':
378                downloadLimit = atoi( optarg );
379                break;
380            case 'f':
381                finishCall = optarg;
382                break;
383            case 'c':
384                sourceFile = optarg;
385                break;
386            case 'm':
387                comment = optarg;
388                break;
389            case 'a':
390                announce = optarg;
391                break;
392            case 'n':
393                natTraversal = 1;
394                break;
395            default:
396                return 1;
397        }
398    }
399
400    if( optind > argc - 1  )
401    {
402        return !showHelp;
403    }
404
405    torrentPath = argv[optind];
406
407    return 0;
408}
409
410static void sigHandler( int signal )
411{
412    switch( signal )
413    {
414        case SIGINT:
415            gotsig = 1;
416            break;
417
418        default:
419            break;
420    }
421}
Note: See TracBrowser for help on using the repository browser.