Changeset 5843


Ignore:
Timestamp:
May 18, 2008, 4:44:30 PM (14 years ago)
Author:
charles
Message:

RPC/IPC redesign

Location:
trunk
Files:
4 added
20 deleted
56 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/beos/TRWindow.cpp

    r4182 r5843  
    2121 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    2222 *
    23  * $Id:$
     23 * $Id$
    2424 */
    2525
     
    110110       
    111111        // Bring up the Transmission Engine
    112         engine = tr_init( "beos" );
     112        engine = tr_sessionInit( "beos" );
    113113        LoadSettings();
    114114       
     
    133133        }
    134134        /* XXX there's no way to make sure the torrent threads are running so this might crash */
    135         tr_close(engine);
     135        tr_sessionClose(engine);
    136136        stop_watching(this);
    137137        delete quitter;
  • trunk/cli/Makefile.am

    r5735 r5843  
    1313  $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
    1414  $(top_builddir)/third-party/miniupnp/libminiupnp.a \
     15  $(top_builddir)/third-party/shttpd/libshttpd.a \
    1516  $(INTLLIBS) \
    1617  $(OPENSSL_LIBS) \
  • trunk/cli/transmissioncli.c

    r5819 r5843  
    6969static int           isPrivate     = 0;
    7070static int           verboseLevel  = 0;
    71 static int           bindPort      = TR_DEFAULT_PORT;
     71static int           peerPort      = TR_DEFAULT_PORT;
    7272static int           uploadLimit   = 20;
    7373static int           downloadLimit = -1;
    7474static char        * torrentPath   = NULL;
    75 static char        * savePath      = ".";
    7675static int           natTraversal  = 0;
    7776static int           recheckData   = 0;
    7877static sig_atomic_t  gotsig        = 0;
    7978static sig_atomic_t  manualUpdate  = 0;
     79static char          downloadDir[MAX_PATH_LENGTH] = { '\0' };
    8080
    8181static char          * finishCall   = NULL;
     
    136136    }
    137137
    138     if( bindPort < 1 || bindPort > 65535 )
    139     {
    140         printf( "Invalid port '%d'\n", bindPort );
     138    if( peerPort < 1 || peerPort > 65535 )
     139    {
     140        printf( "Invalid port '%d'\n", peerPort );
    141141        return EXIT_FAILURE;
    142142    }
     
    145145     * to get metainfo or to create a torrent */
    146146    if( showInfo || showScrape || ( sourceFile != NULL ) )
    147         bindPort = -1;
     147        peerPort = -1;
    148148
    149149    if( configdir == NULL )
     
    151151
    152152    /* Initialize libtransmission */
    153     h = tr_initFull( configdir,
    154                      "cli",                         /* tag */
    155                      1,                             /* pex enabled */
    156                      natTraversal,                  /* nat enabled */
    157                      bindPort,                      /* public port */
    158                      TR_ENCRYPTION_PREFERRED,       /* encryption mode */
    159                      uploadLimit >= 0,              /* use upload speed limit? */
    160                      uploadLimit,                   /* upload speed limit */
    161                      downloadLimit >= 0,            /* use download speed limit? */
    162                      downloadLimit,                 /* download speed limit */
    163                      TR_DEFAULT_GLOBAL_PEER_LIMIT,
    164                      verboseLevel + 1,              /* messageLevel */
    165                      0,                             /* is message queueing enabled? */
    166                      0,                             /* use the blocklist? */
    167                      TR_DEFAULT_PEER_SOCKET_TOS );
     153    h = tr_sessionInitFull(
     154            configdir,
     155            "cli",                         /* tag */
     156            downloadDir,                   /* where to download torrents */
     157            TR_DEFAULT_PEX_ENABLED,
     158            natTraversal,                  /* nat enabled */
     159            peerPort,
     160            TR_ENCRYPTION_PREFERRED,
     161            uploadLimit >= 0,
     162            uploadLimit,
     163            downloadLimit >= 0,
     164            downloadLimit,
     165            TR_DEFAULT_GLOBAL_PEER_LIMIT,
     166            verboseLevel + 1,              /* messageLevel */
     167            0,                             /* is message queueing enabled? */
     168            TR_DEFAULT_BLOCKLIST_ENABLED,
     169            TR_DEFAULT_PEER_SOCKET_TOS,
     170            TR_DEFAULT_RPC_ENABLED,
     171            TR_DEFAULT_RPC_PORT,
     172            TR_DEFAULT_RPC_ACL );
    168173
    169174    if( sourceFile && *sourceFile ) /* creating a torrent */
     
    184189    tr_ctorSetMetainfoFromFile( ctor, torrentPath );
    185190    tr_ctorSetPaused( ctor, TR_FORCE, 0 );
    186     tr_ctorSetDestination( ctor, TR_FORCE, savePath );
     191    tr_ctorSetDownloadDir( ctor, TR_FORCE, downloadDir );
    187192
    188193    if( showInfo )
     
    238243    {
    239244        printf( "Failed opening torrent file `%s'\n", torrentPath );
    240         tr_close( h );
     245        tr_sessionClose( h );
    241246        return EXIT_FAILURE;
    242247    }
     
    370375cleanup:
    371376    tr_torrentClose( tor );
    372     tr_close( h );
     377    tr_sessionClose( h );
    373378
    374379    return EXIT_SUCCESS;
     
    418423            case 'm': comment = optarg; break;
    419424            case 'n': natTraversal = 1; break;
    420             case 'o': savePath = optarg;
    421             case 'p': bindPort = atoi( optarg ); break;
     425            case 'o': tr_strlcpy( downloadDir, optarg, sizeof( downloadDir ) ); break;
     426            case 'p': peerPort = atoi( optarg ); break;
    422427            case 'r': isPrivate = 1; break;
    423428            case 's': showScrape = 1; break;
     
    430435    }
    431436
     437    if( !*downloadDir )
     438        getcwd( downloadDir, sizeof( downloadDir ) );
     439
    432440    if( showHelp || showVersion )
    433441        return 0;
  • trunk/configure.ac

    r5822 r5843  
    3535AC_HEADER_STDC
    3636AC_HEADER_TIME
    37 AC_CHECK_FUNCS([lrintf strlcpy daemon dirname basename])
     37AC_CHECK_FUNCS([lrintf strlcpy daemon dirname basename daemon])
    3838AC_CHECK_SIZEOF([void*])
    3939AC_PROG_INSTALL
  • trunk/daemon/Makefile.am

    r5735 r5843  
    1 AM_CPPFLAGS = -I@top_srcdir@ $(LIBEVENT_CPPFLAGS)
     1AM_CPPFLAGS = -I@top_srcdir@ $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/third-party/ -DEMBEDDED
    22AM_CFLAGS = $(OPENSSL_CFLAGS) $(LIBCURL_CFLAGS) $(PTHREAD_CFLAGS)
    3 
    4 noinst_LIBRARIES = libdaemon.a
    53
    64dist_man_MANS = \
    75    transmission-daemon.1 \
    8     transmission-proxy.1 \
    96    transmission-remote.1
    10 
    11 libdaemon_a_SOURCES = \
    12     errors.c \
    13     misc.c
    14 
    15 noinst_HEADERS = \
    16     bsdtree.h \
    17     bsdqueue.h \
    18     client.h \
    19     errors.h \
    20     misc.h \
    21     server.h \
    22     torrents.h
    237
    248bin_PROGRAMS = \
    259    transmission-daemon \
    26     transmission-remote \
    27     transmission-proxy
     10    transmission-remote
    2811
    2912COMMON_LDADD = \
    30     ./libdaemon.a \
    3113    $(top_builddir)/libtransmission/libtransmission.a \
    3214    $(top_builddir)/third-party/miniupnp/libminiupnp.a \
     
    3820    $(PTHREAD_LIBS) -lm
    3921
    40 transmission_daemon_SOURCES = daemon.c server.c torrents.c
    41 transmission_daemon_LDADD = $(COMMON_LDADD)
    42 transmission_remote_SOURCES = client.c remote.c
     22transmission_daemon_SOURCES = daemon.c
     23transmission_daemon_LDADD = $(COMMON_LDADD) $(top_builddir)/third-party/shttpd/libshttpd.a
     24transmission_remote_SOURCES = remote.c
    4325transmission_remote_LDADD = $(COMMON_LDADD)
    44 transmission_proxy_SOURCES = proxy.c
    45 transmission_proxy_LDADD = $(COMMON_LDADD)
  • trunk/daemon/daemon.c

    r5758 r5843  
    1 /******************************************************************************
    2  * $Id$
     1/*
     2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
    33 *
    4  * Copyright (c) 2007 Joshua Elsasser
     4 * This file is licensed by the GPL version 2.  Works owned by the
     5 * Transmission project are granted a special exemption to clause 2(b)
     6 * so that the bulk of its code can remain under the MIT license.
     7 * This exemption does not extend to derived works not owned by
     8 * the Transmission project.
    59 *
    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 <sys/types.h>
    26 #include <sys/param.h>
    27 #include <sys/stat.h>
    28 #include <sys/socket.h>
    29 #include <sys/time.h>
    30 #include <sys/uio.h>
    31 #include <sys/un.h>
     10 * $Id:$
     11 */
     12
    3213#include <assert.h>
    3314#include <errno.h>
    34 #include <event.h>
     15#include <stdio.h> /* printf */
     16#include <stdlib.h> /* exit, atoi */
     17#include <string.h> /* strcmp */
     18
     19#include <fcntl.h> /* open */
    3520#include <getopt.h>
    3621#include <signal.h>
    37 #include <stdarg.h>
    38 #include <stdlib.h>
    39 #include <stdio.h>
    40 #include <string.h>
    41 #include <unistd.h>
    42 
    43 #include <libtransmission/trcompat.h>
    44 #include <libtransmission/platform.h>
    45 #include <libtransmission/utils.h>
     22#include <unistd.h> /* daemon, getcwd */
     23
     24#include <libtransmission/transmission.h>
     25#include <libtransmission/bencode.h>
     26#include <libtransmission/rpc.h>
     27#include <libtransmission/utils.h> /* tr_strdup */
    4628#include <libtransmission/version.h>
    4729
    48 #include "errors.h"
    49 #include "misc.h"
    50 #include "server.h"
    51 #include "torrents.h"
    52 
    53 static void usage       ( const char *, ... );
    54 static void readargs    ( int, char **, int *, int *, char **, char **, char ** );
    55 static int  trylocksock ( const char * configdir, const char * sockpath );
    56 static int  getsock     ( const char * );
    57 static void exitcleanup ( void );
    58 static void setupsigs   ( struct event_base * );
    59 static void gotsig      ( int, short, void * );
    60 static int  savepid     ( const char * );
    61 
    62 static char gl_lockpath[MAXPATHLEN] = "";
    63 static int  gl_sockfd               = -1;
    64 static char gl_sockpath[MAXPATHLEN] = "";
    65 static char gl_pidfile[MAXPATHLEN]  = "";
     30#define MY_NAME "transmission-daemon"
     31
     32static int closing = FALSE;
     33static tr_handle * gl_session;
     34static char gl_configfile[MAX_PATH_LENGTH];
     35
     36static void
     37saveState( tr_handle * h )
     38{
     39    tr_benc d;
     40    const char * str;
     41
     42    tr_bencInitDict( &d, 12 );
     43    tr_bencDictAddStr( &d, "download-dir", tr_sessionGetDownloadDir( h ) );
     44    tr_bencDictAddInt( &d, "peer-limit", tr_sessionGetPeerLimit( h ) );
     45    tr_bencDictAddInt( &d, "pex-allowed", tr_sessionIsPexEnabled( h ) );
     46    tr_bencDictAddInt( &d, "port", tr_sessionGetPublicPort( h ) );
     47    tr_bencDictAddInt( &d, "port-forwarding-enabled",
     48                           tr_sessionIsPortForwardingEnabled( h ) );
     49    tr_bencDictAddStr( &d, "rpc-acl", tr_sessionGetRPCACL( h ) );
     50    tr_bencDictAddInt( &d, "rpc-port", tr_sessionGetRPCPort( h ) );
     51    tr_bencDictAddInt( &d, "speed-limit-up",
     52                           tr_sessionGetSpeedLimit( h, TR_UP ) );
     53    tr_bencDictAddInt( &d, "speed-limit-up-enabled",
     54                           tr_sessionIsSpeedLimitEnabled( h, TR_UP ) );
     55    tr_bencDictAddInt( &d, "speed-limit-down",
     56                           tr_sessionGetSpeedLimit( h, TR_DOWN ) );
     57    tr_bencDictAddInt( &d, "speed-limit-down-enabled",
     58                           tr_sessionIsSpeedLimitEnabled( h, TR_DOWN ) );
     59    switch( tr_sessionGetEncryption( h ) ) {
     60        case TR_PLAINTEXT_PREFERRED: str = "tolerated"; break;
     61        case TR_ENCRYPTION_REQUIRED: str = "required"; break;
     62        default: str = "preferred"; break;
     63    }
     64    tr_bencDictAddStr( &d, "encryption", str );
     65
     66    tr_ninf( MY_NAME, "saving \"%s\"\n", gl_configfile );
     67    tr_bencSaveFile( gl_configfile, &d );
     68
     69    tr_bencFree( &d );
     70
     71}
     72
     73static void
     74session_init( const char * configDir, int rpc_port, const char * rpc_acl )
     75{
     76    tr_benc state;
     77    int have_state;
     78    int64_t peer_port = TR_DEFAULT_PORT;
     79    int64_t peers = TR_DEFAULT_GLOBAL_PEER_LIMIT;
     80    int64_t pex_enabled = TR_DEFAULT_PEX_ENABLED;
     81    int64_t fwd_enabled = TR_DEFAULT_PORT_FORWARDING_ENABLED;
     82    int64_t up_limit = 100;
     83    int64_t up_limited = FALSE;
     84    int64_t down_limit = 100;
     85    int64_t down_limited = FALSE;
     86    int encryption = TR_ENCRYPTION_PREFERRED;
     87    char downloadDir[MAX_PATH_LENGTH] = { '\0' };
     88    const char * rpc_acl_fallback = TR_DEFAULT_RPC_ACL;
     89    int64_t rpc_port_fallback = TR_DEFAULT_RPC_PORT;
     90    tr_ctor * ctor;
     91    tr_torrent ** torrents;
     92
     93    assert( !gl_session );
     94
     95    if(( have_state = !tr_bencLoadFile( gl_configfile, &state )))
     96    {
     97        const char * str;
     98        tr_ninf( MY_NAME, "loading settings from \"%s\"", gl_configfile );
     99
     100        if( tr_bencDictFindStr( &state, "download-dir", &str ) )
     101            tr_strlcpy( downloadDir, str, sizeof( downloadDir ) );
     102        tr_bencDictFindInt( &state, "port", &peer_port );
     103        tr_bencDictFindInt( &state, "port-forwarding-enabled", &fwd_enabled );
     104        tr_bencDictFindInt( &state, "peer-limit", &peers );
     105        tr_bencDictFindInt( &state, "pex-allowed", &pex_enabled );
     106        tr_bencDictFindStr( &state, "rpc-acl", &rpc_acl_fallback );
     107        tr_bencDictFindInt( &state, "rpc-port", &rpc_port_fallback );
     108        tr_bencDictFindInt( &state, "speed-limit-down", &down_limit );
     109        tr_bencDictFindInt( &state, "speed-limit-down-enabled", &down_limited );
     110        tr_bencDictFindInt( &state, "speed-limit-up", &up_limit );
     111        tr_bencDictFindInt( &state, "speed-limit-up-enabled", &up_limited );
     112        if( tr_bencDictFindStr( &state, "encryption", &str ) ) {
     113            if( !strcmp( str, "required" ) )
     114                encryption = TR_ENCRYPTION_REQUIRED;
     115            else if( !strcmp( str, "tolerated" ) )
     116                encryption = TR_PLAINTEXT_PREFERRED;
     117        }
     118    }
     119
     120    /* fallbacks */
     121    if( !*downloadDir )
     122        getcwd( downloadDir, sizeof( downloadDir ) );
     123    if( rpc_port < 1 )
     124        rpc_port = rpc_port_fallback;
     125    if( !rpc_acl || !*rpc_acl )
     126        rpc_acl = rpc_acl_fallback;
     127
     128    /* start the session */
     129    gl_session = tr_sessionInitFull( configDir, "daemon", downloadDir,
     130                                     pex_enabled, fwd_enabled, peer_port,
     131                                     encryption,
     132                                     up_limit, up_limited,
     133                                     down_limit, down_limited,
     134                                     peers,
     135                                     TR_MSG_INF, 0,
     136                                     FALSE, /* is the blocklist enabled? */
     137                                     TR_DEFAULT_PEER_SOCKET_TOS,
     138                                     TRUE, rpc_port, rpc_acl );
     139
     140    /* load the torrents */
     141    ctor = tr_ctorNew( gl_session );
     142    torrents = tr_sessionLoadTorrents( gl_session, ctor, NULL );
     143    tr_free( torrents );
     144    tr_ctorFree( ctor );
     145
     146    if( have_state )
     147        tr_bencFree( &state );
     148}
     149
     150static void
     151daemonUsage( void )
     152{
     153    puts( "usage: " MY_NAME " [-dfh] [-p file] [-s file]\n"
     154          "\n"
     155          "Transmission " LONG_VERSION_STRING " http://www.transmissionbt.com/\n"
     156          "A fast and easy BitTorrent client\n"
     157          "\n"
     158          "  -a --acl <list>         Access Control List.  (Default: "TR_DEFAULT_RPC_ACL")\n"
     159          "  -f --foreground         Run in the foreground and log to stderr\n"
     160          "  -g --config-dir <dir>   Where to look for torrents and daemon-config.benc\n"
     161          "  -h --help               Display this message and exit\n"
     162          "  -p --port n             Port to listen to for requests (Default: "TR_DEFAULT_RPC_PORT_STR")\n"
     163          "\n"
     164          MY_NAME" is a headless Transmission session\n"
     165          "that can be controlled via transmission-remote or Clutch.\n" );
     166    exit( 0 );
     167}
     168
     169static void
     170readargs( int argc, char ** argv,
     171          int * nofork, int * port, char ** acl,
     172          char ** configDir )
     173{
     174    int opt;
     175    char optstr[] = "a:fg:hp:";
     176    struct option longopts[] = {
     177        { "acl",         required_argument,  NULL, 'a'  },
     178        { "foreground",  no_argument,        NULL, 'f'  },
     179        { "config-dir",  required_argument,  NULL, 'g'  },
     180        { "help",        no_argument,        NULL, 'h'  },
     181        { "port",        required_argument,  NULL, 'p'  },
     182        { NULL,          0,                  NULL, '\0' }
     183    };
     184    while((( opt = getopt_long( argc, argv, optstr, longopts, NULL ))) != -1 ) {
     185        switch( opt ) {
     186            case 'a': *acl = tr_strdup( optarg ); break;
     187            case 'f': *nofork = 1; break;
     188            case 'g': *configDir = tr_strdup( optarg ); break;
     189            case 'p': *port = atoi( optarg ); break;
     190            default: daemonUsage( ); break;
     191        }
     192    }
     193}
     194
     195static void
     196gotsig( int sig UNUSED )
     197{
     198    closing = TRUE;
     199}
     200
     201#if !defined(HAVE_DAEMON)
     202static int
     203daemon( int nochdir, int noclose )
     204{
     205    switch( fork( ) ) {
     206        case 0:
     207            break;
     208        case -1:
     209            tr_nerr( MY_NAME, "Error daemonizing (fork)! %d - %s\n", errno, strerror(errno) );
     210            return -1;
     211        default:
     212            _exit(0);
     213    }
     214
     215    if( setsid() < 0 ) {
     216        tr_nerr( MY_NAME, "Error daemonizing (setsid)! %d - %s\n", errno, strerror(errno) );
     217        return -1;
     218    }
     219
     220    switch( fork( ) ) {
     221        case 0:
     222            break;
     223        case -1:
     224            tr_nerr( MY_NAME, "Error daemonizing (fork2)! %d - %s\n", errno, strerror(errno) );
     225            return -1;
     226        default:
     227            _exit(0);
     228    }
     229
     230    if( !nochdir && 0 > chdir( "/" ) ) {
     231        tr_nerr( MY_NAME, "Error daemonizing (chdir)! %d - %s\n", errno, strerror(errno) );
     232        return -1;
     233    }
     234
     235    if( !noclose ) {
     236        int fd;
     237        if((( fd = open("/dev/null", O_RDONLY))) != 0 ) {
     238            dup2( fd,  0 );
     239            close( fd );
     240        }
     241        if((( fd = open("/dev/null", O_WRONLY))) != 1 ) {
     242            dup2( fd, 1 );
     243            close( fd );
     244        }
     245        if((( fd = open("/dev/null", O_WRONLY))) != 2 ) {
     246            dup2( fd, 2 );
     247            close( fd );
     248        }
     249    }
     250
     251    return 0;
     252}
     253#endif
    66254
    67255int
    68256main( int argc, char ** argv )
    69257{
    70     struct event_base * evbase;
    71     int                 nofork, debug, sockfd;
    72     char              * configdir, * sockpath, * pidfile;
    73 
    74     setmyname( argv[0] );
    75     readargs( argc, argv, &nofork, &debug, &configdir, &sockpath, &pidfile );
     258    int nofork = 0;
     259    int port = TR_DEFAULT_RPC_PORT;
     260    char * configDir = NULL;
     261    char * acl = NULL;
     262
     263    signal( SIGINT, gotsig );
     264    signal( SIGQUIT, gotsig );
     265    signal( SIGTERM, gotsig );
     266    signal( SIGPIPE, SIG_IGN );
     267    signal( SIGHUP, SIG_IGN );
     268
     269    readargs( argc, argv, &nofork, &port, &acl, &configDir );
     270    if( configDir == NULL )
     271        configDir = tr_strdup_printf( "%s-daemon", tr_getDefaultConfigDir() );
     272    tr_buildPath( gl_configfile, sizeof( gl_configfile ),
     273                  configDir, "daemon-config.benc", NULL );
    76274
    77275    if( !nofork ) {
    78276        if( 0 > daemon( 1, 0 ) ) {
    79             errnomsg( "failed to daemonize" );
     277            fprintf( stderr, "failed to daemonize: %s\n", strerror( errno ) );
    80278            exit( 1 );
    81279        }
    82         errsyslog( 1 );
    83     }
    84 
    85     if( configdir == NULL )
    86         configdir = (char*) tr_getDefaultConfigDir( );
    87 
    88     atexit( exitcleanup );
    89     sockfd = trylocksock( configdir, sockpath );
    90     if( 0 > sockfd )
    91     {
    92         exit( 1 );
    93     }
    94     if( NULL != pidfile && 0 > savepid( pidfile ) )
    95     {
    96         exit( 1 );
    97     }
    98 
    99     evbase = event_init();
    100     setupsigs( evbase );
    101     torrent_init( configdir, evbase );
    102     server_init( evbase );
    103     server_debug( debug );
    104     server_listen( sockfd );
    105 
    106     event_base_dispatch( evbase );
    107 
    108     return 1;
    109 }
    110 
    111 void
    112 usage( const char * msg, ... )
    113 {
    114     va_list ap;
    115 
    116     if( NULL != msg )
    117     {
    118         printf( "%s: ", getmyname() );
    119         va_start( ap, msg );
    120         vprintf( msg, ap );
    121         va_end( ap );
    122         printf( "\n" );
    123     }
    124 
    125     printf(
    126   "usage: %s [-dfh] [-p file] [-s file]\n"
    127   "\n"
    128   "Transmission %s http://www.transmissionbt.com/\n"
    129   "A fast and easy BitTorrent client\n"
    130   "\n"
    131   "  -d --debug                Print data send and received, implies -f\n"
    132   "  -f --foreground           Run in the foreground and log to stderr\n"
    133   "  -g --config-dir <path>    Where to look for configuration files\n"
    134   "  -h --help                 Display this message and exit\n"
    135   "  -p --pidfile <path>       Save the process id in a file at <path>\n"
    136   "  -s --socket <path>        Place the socket file at <path>\n"
    137   "\n"
    138   "To add torrents or set options, use the transmission-remote program.\n",
    139             getmyname(), LONG_VERSION_STRING );
    140     exit( 0 );
    141 }
    142 
    143 void
    144 readargs( int argc, char ** argv, int * nofork, int * debug,
    145           char ** configdir, char ** sock, char ** pidfile )
    146 {
    147     char optstr[] = "dfg:hp:s:";
    148     struct option longopts[] =
    149     {
    150         { "debug",              no_argument,       NULL, 'd' },
    151         { "foreground",         no_argument,       NULL, 'f' },
    152         { "config-dir",         required_argument, NULL, 'g' },
    153         { "help",               no_argument,       NULL, 'h' },
    154         { "pidfile",            required_argument, NULL, 'p' },
    155         { "socket",             required_argument, NULL, 's' },
    156         { NULL, 0, NULL, 0 }
    157     };
    158     int opt;
    159 
    160     *nofork    = 0;
    161     *debug     = 0;
    162     *sock      = NULL;
    163     *pidfile   = NULL;
    164     *configdir = NULL;
    165 
    166     while( 0 <= ( opt = getopt_long( argc, argv, optstr, longopts, NULL ) ) ) {
    167         switch( opt ) {
    168             case 'd': *debug = 1; /* FALLTHROUGH */
    169             case 'f': *nofork = 1; break;
    170             case 'g': *configdir = strdup( optarg ); break;
    171             case 'p': *pidfile = optarg; break;
    172             case 's': *sock   = optarg; break;
    173             default: usage( NULL ); break;
    174         }
    175     }
    176 }
    177 
    178 static int
    179 getlock( const char * filename )
    180 {
    181     const int state = tr_lockfile( filename );
    182     const int success = state == TR_LOCKFILE_SUCCESS;
    183 
    184     if( !success ) switch( state ) {
    185         case TR_LOCKFILE_EOPEN:
    186             errnomsg( "failed to open file: %s", filename );
    187             break;
    188         case TR_LOCKFILE_ELOCK:
    189             errmsg( "another copy of %s is already running", getmyname() );
    190             break;
    191         default:
    192             errmsg( "unhandled tr_lockfile error: %d", state );
    193             break;
    194     }
    195 
    196     return success;
    197 }
    198 
    199 
    200 int
    201 trylocksock( const char * configdir, const char * sockpath )
    202 {
    203     int  fd;
    204     char path[MAXPATHLEN];
    205 
    206     confpath( path, sizeof path, configdir, NULL, CONF_PATH_TYPE_DAEMON );
    207     if( tr_mkdirp( path, 0777 ) && EEXIST != errno )
    208     {
    209         errnomsg( "failed to create directory: %s", path );
    210         return -1;
    211     }
    212 
    213     confpath( path, sizeof path, configdir, CONF_FILE_LOCK, 0 );
    214     if( !getlock( path ) )
    215         return -1;
    216     strlcpy( gl_lockpath, path, sizeof gl_lockpath );
    217 
    218     if( !sockpath )
    219     {
    220         confpath( path, sizeof path, configdir, CONF_FILE_SOCKET, 0 );
    221         sockpath = path;
    222     }
    223     fd = getsock( sockpath );
    224     if( 0 > fd )
    225     {
    226         return -1;
    227     }
    228     gl_sockfd = fd;
    229     strlcpy( gl_sockpath, sockpath, sizeof gl_sockpath );
    230 
    231     return fd;
    232 }
    233 
    234 int
    235 getsock( const char * path )
    236 {
    237     struct sockaddr_un sa;
    238     int                fd;
    239 
    240     fd = socket( PF_LOCAL, SOCK_STREAM, 0 );
    241     if( 0 > fd )
    242     {
    243         errnomsg( "failed to create socket file: %s", path );
    244         return -1;
    245     }
    246 
    247     memset( &sa, 0, sizeof sa );
    248     sa.sun_family = AF_LOCAL;
    249     strlcpy( sa.sun_path, path, sizeof sa.sun_path );
    250     unlink( path );
    251     if( 0 > bind( fd, ( struct sockaddr * )&sa, SUN_LEN( &sa ) ) )
    252     {
    253         /* bind can sometimes fail on the first call */
    254         unlink( path );
    255         if( 0 > bind( fd, ( struct sockaddr * )&sa, SUN_LEN( &sa ) ) )
    256         {
    257             errnomsg( "failed to bind socket file: %s", path );
    258             close( fd );
    259             return -1;
    260         }
    261     }
    262 
    263     return fd;
    264 }
    265 
    266 void
    267 exitcleanup( void )
    268 {
    269     if( 0 <= gl_sockfd )
    270     {
    271         unlink( gl_sockpath );
    272         close( gl_sockfd );
    273     }
    274     if( 0 != gl_pidfile[0] )
    275     {
    276         unlink( gl_pidfile );
    277     }
    278 
    279     if( *gl_lockpath )
    280         unlink( gl_lockpath );
    281 }
    282 
    283 void
    284 setupsigs( struct event_base * base )
    285 {
    286     static struct event ev_int;
    287     static struct event ev_quit;
    288     static struct event ev_term;
    289 
    290     signal_set( &ev_int, SIGINT, gotsig, NULL );
    291     event_base_set( base, &ev_int );
    292     signal_add( &ev_int, NULL );
    293 
    294     signal_set( &ev_quit, SIGQUIT, gotsig, NULL );
    295     event_base_set( base, &ev_quit );
    296     signal_add( &ev_quit, NULL );
    297 
    298     signal_set( &ev_term, SIGTERM, gotsig, NULL );
    299     event_base_set( base, &ev_term );
    300     signal_add( &ev_term, NULL );
    301 
    302     signal( SIGPIPE, SIG_IGN );
    303     signal( SIGHUP, SIG_IGN );
    304 }
    305 
    306 void
    307 gotsig( int sig, short what UNUSED, void * arg UNUSED )
    308 {
    309     static int exiting = 0;
    310 
    311     if( !exiting )
    312     {
    313         exiting = 1;
    314         errmsg( "received fatal signal %i, attempting to exit cleanly", sig );
    315         server_quit();
    316     }
    317     else
    318     {
    319         errmsg( "received fatal signal %i while exiting, exiting immediately",
    320                 sig );
    321         signal( sig, SIG_DFL );
    322         raise( sig );
    323     }
    324 }
    325 
    326 int
    327 savepid( const char * file )
    328 {
    329     FILE * pid;
    330 
    331     pid = fopen( file, "wb" );
    332     if( NULL == pid )
    333     {
    334         errnomsg( "failed to open pid file: %s", file );
    335         return -1;
    336     }
    337 
    338     if( 0 > fprintf( pid, "%d\n", (int) getpid() ) )
    339     {
    340         errnomsg( "failed to write pid to file: %s", file );
    341         fclose( pid );
    342         unlink( file );
    343         return -1;
    344     }
    345 
    346     fclose( pid );
    347     strlcpy( gl_pidfile, file, sizeof gl_pidfile );
    348 
     280    }
     281
     282    session_init( configDir, port, acl );
     283
     284    while( !closing )
     285        sleep( 1 );
     286
     287    saveState( gl_session );
     288    printf( "Closing transmission session..." );
     289    tr_sessionClose( gl_session );
     290    printf( " done.\n" );
     291
     292    tr_free( configDir );
    349293    return 0;
    350294}
  • trunk/daemon/remote.c

    r5646 r5843  
    1 /******************************************************************************
    2  * $Id$
     1/*
     2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
    33 *
    4  * Copyright (c) 2007 Joshua Elsasser
     4 * This file is licensed by the GPL version 2.  Works owned by the
     5 * Transmission project are granted a special exemption to clause 2(b)
     6 * so that the bulk of its code can remain under the MIT license.
     7 * This exemption does not extend to derived works not owned by
     8 * the Transmission project.
    59 *
    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 <sys/types.h>
    26 #include <sys/param.h>
    27 #include <sys/time.h>
    28 #include <assert.h>
    29 #include <ctype.h>
    30 #include <event.h>
     10 * $Id:$
     11 */
     12
     13#include <stdio.h>
     14#include <stdlib.h>
     15#include <string.h> /* strcmp */
     16
    3117#include <getopt.h>
    32 #include <signal.h>
    33 #include <stdarg.h>
    34 #include <stdlib.h>
    35 #include <stdio.h>
    36 #include <string.h>
    37 #include <unistd.h>
    38 
    39 #include <libtransmission/ipcparse.h>
     18#include <unistd.h> /* getcwd */
     19
     20#include <third-party/libevent/event.h>
     21#include <curl/curl.h>
     22
    4023#include <libtransmission/transmission.h>
    41 #include <libtransmission/trcompat.h>
    42 
    43 #include "bsdtree.h"
    44 #include "bsdqueue.h"
    45 #include "client.h"
    46 #include "errors.h"
    47 #include "misc.h"
    48 
    49 #define BESTDECIMAL(d)          (10.0 > (d) ? 2 : (100.0 > (d) ? 1 : 0))
    50 
    51 struct opts
    52 {
    53     int               proxy;
    54     char           ** proxycmd;
    55     enum confpathtype type;
    56     const char      * sock;
    57     struct strlist    files;
    58     int               sendquit;
    59     int               port;
    60     int               map;
    61     int               uplimit;
    62     int               up;
    63     int               downlimit;
    64     int               down;
    65     int               listquick;
    66     int               listfull;
    67     struct strlist    verify;
    68     int               startall;
    69     struct strlist    start;
    70     int               stopall;
    71     struct strlist    stop;
    72     int               removeall;
    73     struct strlist    remove;
    74     char              dir[MAXPATHLEN];
    75     int               pex;
    76     const char *      crypto;
    77     const char *      configdir;
    78 };
    79 
    80 struct torinfo
    81 {
    82     int     id;
    83     int     infogood;
    84     int     statgood;
    85     char  * name;
    86     int64_t size;
    87     char  * state;
    88     int64_t eta;
    89     int64_t done;
    90     int64_t ratedown;
    91     int64_t rateup;
    92     int64_t totaldown;
    93     int64_t totalup;
    94     char  * errorcode;
    95     char  * errormsg;
    96     RB_ENTRY( torinfo ) idlinks;
    97     RB_ENTRY( torinfo ) namelinks;
    98 };
    99 
    100 RB_HEAD( torlist, torinfo );
    101 RB_HEAD( tornames, torinfo );
    102 
    103 struct torhash
    104 {
    105     char                hash[SHA_DIGEST_LENGTH*2+1];
    106     int                 id;
    107     RB_ENTRY( torhash ) link;
    108 };
    109 
    110 RB_HEAD( torhashes, torhash );
    111 
    112 static void   usage        ( const char *, ... );
    113 static int    readargs     ( int, char **, struct opts * );
    114 static int    numarg       ( const char * );
    115 static int    hasharg      ( const char *, struct strlist *, int * );
    116 static int    fileargs     ( struct strlist *, int, char * const * );
    117 static void   listmsg      ( const struct cl_info * );
    118 static void   infomsg      ( const struct cl_info * );
    119 static void   statmsg      ( const struct cl_stat * );
    120 static void   hashmsg      ( const struct cl_info * );
    121 static float  fmtsize      ( int64_t, const char ** );
    122 static char * strdup_noctrl( const char * );
    123 static void   print_eta    ( int64_t );
    124 static void   printlisting ( void );
    125 static int    sendidreqs   ( void );
    126 static int    toridcmp     ( struct torinfo *, struct torinfo * );
    127 static int    tornamecmp   ( struct torinfo *, struct torinfo * );
    128 static int    torhashcmp   ( struct torhash *, struct torhash * );
    129 
    130 static struct torlist   gl_torinfo      = RB_INITIALIZER( &gl_torinfo );
    131 static struct strlist * gl_starthashes  = NULL;
    132 static struct strlist * gl_stophashes   = NULL;
    133 static struct strlist * gl_removehashes = NULL;
    134 static struct strlist * gl_verifyhashes = NULL;
    135 static struct torhashes gl_hashids      = RB_INITIALIZER( &gl_hashids );
    136 static int              gl_gotlistinfo  = 0;
    137 static int              gl_gotliststat  = 0;
    138 
    139 RB_GENERATE_STATIC( torlist,   torinfo, idlinks,   toridcmp )
    140 RB_GENERATE_STATIC( tornames,  torinfo, namelinks, tornamecmp )
    141 RB_GENERATE_STATIC( torhashes, torhash, link,      torhashcmp )
    142 
    143 int
    144 main( int argc, char ** argv )
    145 {
    146     struct event_base * evbase;
    147     struct opts         o;
    148 
    149     setmyname( argv[0] );
    150 
    151     if( 0 > readargs( argc, argv, &o ) )
    152         exit( 1 );
    153 
    154     if( o.configdir == NULL )
    155         o.configdir = strdup( tr_getDefaultConfigDir( ) );
    156 
    157     signal( SIGPIPE, SIG_IGN );
    158 
    159     evbase = event_init();
    160     client_init( evbase );
    161 
    162     if( o.proxy )
    163     {
    164         client_new_cmd( o.proxycmd );
    165     }
    166     else
    167     {
    168         if( o.sock )
    169             client_new_sock( o.sock );
    170         else {
    171             char sockpath[MAXPATHLEN];
    172             confpath( sockpath, sizeof sockpath, o.configdir, CONF_FILE_SOCKET, o.type );
    173             client_new_sock( sockpath );
    174         }
    175     }
    176 
    177     if( ( o.sendquit                &&   0 > client_quit     (           ) ) ||
    178         ( '\0' != o.dir[0]          &&   0 > client_dir      ( o.dir     ) ) ||
    179         ( !SLIST_EMPTY( &o.files )  &&   0 > client_addfiles ( &o.files  ) ) ||
    180         ( o.crypto                  &&   0 > client_crypto   ( o.crypto  ) ) ||
    181         ( o.startall                &&   0 > client_start    ( 0, NULL   ) ) ||
    182         ( o.stopall                 &&   0 > client_stop     ( 0, NULL   ) ) ||
    183         ( o.removeall               &&   0 > client_remove   ( 0, NULL   ) ) ||
    184         ( o.port                    &&   0 > client_port     ( o.port    ) ) ||
    185         ( 0 <= o.map                &&   0 > client_automap  ( o.map     ) ) ||
    186         ( 0 <= o.pex                &&   0 > client_pex      ( o.pex     ) ) ||
    187         ( o.uplimit                 &&   0 > client_uplimit  ( o.up      ) ) ||
    188         ( o.downlimit               &&   0 > client_downlimit( o.down    ) ) ||
    189         ( o.listquick               &&   0 > client_list     ( listmsg   ) ) ||
    190         ( o.listfull                && ( 0 > client_info     ( infomsg     ) ||
    191                                          0 > client_status   ( statmsg ) ) ) )
    192     {
    193         exit( 1 );
    194     }
    195 
    196     if( ( !o.startall   && !SLIST_EMPTY( &o.start  ) ) ||
    197         ( !o.stopall    && !SLIST_EMPTY( &o.stop   ) ) ||
    198         (                  !SLIST_EMPTY( &o.verify ) ) ||
    199         ( !o.removeall  && !SLIST_EMPTY( &o.remove ) ) )
    200     {
    201         if( 0 > client_hashids( hashmsg ) )
    202         {
    203             exit( 1 );
    204         }
    205         gl_starthashes  = ( o.startall  ? NULL : &o.start  );
    206         gl_stophashes   = ( o.stopall   ? NULL : &o.stop   );
    207         gl_removehashes = ( o.removeall ? NULL : &o.remove );
    208         gl_verifyhashes = ( &o.verify );
    209     }
    210 
    211     event_dispatch();
    212     /* event_base_dispatch( evbase ); */
    213 
    214     return 1;
    215 }
    216 
    217 void
    218 usage( const char * msg, ... )
    219 {
    220     va_list ap;
    221 
    222     if( NULL != msg )
    223     {
    224         printf( "%s: ", getmyname() );
    225         va_start( ap, msg );
    226         vprintf( msg, ap );
    227         va_end( ap );
    228         printf( "\n" );
    229     }
    230 
    231     printf(
    232   "usage: %s [options] [files...]\n"
    233   "       %s -x [options] proxy-command [args...]\n"
    234   "\n"
    235   "Transmission %s http://www.transmissionbt.com/\n"
    236   "A fast and easy BitTorrent client\n"
    237   "\n"
    238   "  -a --add <torrent>        Add a torrent\n"
    239   "  -c --encryption required  Require encryption for all peers\n"
    240   "  -c --encryption preferred Prefer peers to use encryption\n"
    241   "  -c --encryption tolerated Prefer peers to use plaintext\n"
    242   "  -d --download-limit <int> Max download rate in KiB/s\n"
    243   "  -D --download-unlimited   No download rate limit\n"
    244   "  -e --enable-pex           Enable peer exchange\n"
    245   "  -E --disable-pex          Disable peer exchange\n"
    246   "  -f --folder <path>        Folder to set for new torrents\n"
    247   "  -g --config-dir <path>    Where to look for configuration files\n"
    248   "  -h --help                 Display this message and exit\n"
    249   "  -i --info                 List all torrents with info hashes\n"
    250   "  -l --list                 List all torrents with status\n"
    251   "  -m --port-mapping         Automatic port mapping via NAT-PMP or UPnP\n"
    252   "  -M --no-port-mapping      Disable automatic port mapping\n"
    253   "  -p --port <int>           Port to listen for incoming connections on\n"
    254   "  -q --quit                 Quit the daemon\n"
    255   "  -r --remove <hash>        Remove the torrent with the given hash\n"
    256   "  -r --remove all           Remove all torrents\n"
    257   "  -s --start <hash>         Start the torrent with the given hash\n"
    258   "  -s --start all            Start all stopped torrents\n"
    259   "  -S --stop <hash>          Stop the torrent with the given hash\n"
    260   "  -S --stop all             Stop all running torrents\n"
    261   "  -t --type daemon          Use the daemon frontend, transmission-daemon\n"
    262   "  -t --type gtk             Use the GTK+ frontend, transmission\n"
    263   "  -t --type mac             Use the MacOS X frontend\n"
    264   "  -u --upload-limit <int>   Max upload rate in KiB/s\n"
    265   "  -U --upload-unlimited     No upload rate limit\n"
    266   "  -v --verify <hash>        Verify the torrent's local data\n"
    267   "  -x --proxy                Use proxy command to connect to frontend\n",
    268             getmyname(), getmyname(), LONG_VERSION_STRING );
     24#include <libtransmission/bencode.h>
     25#include <libtransmission/rpc.h>
     26#include <libtransmission/json.h>
     27#include <libtransmission/utils.h>
     28#include <libtransmission/version.h>
     29
     30#define MY_NAME "transmission-remote"
     31#define DEFAULT_HOST "localhost"
     32#define DEFAULT_PORT TR_DEFAULT_RPC_PORT
     33
     34enum { TAG_LIST };
     35
     36static void
     37showUsage( void )
     38{
     39    puts( "Transmission "LONG_VERSION_STRING"  http://www.transmissionbt.com/\n"
     40            "A fast and easy BitTorrent client\n"
     41            "\n"
     42            "Usage: "MY_NAME" [host] [options]\n"
     43            "       "MY_NAME" [port] [options]\n"
     44            "       "MY_NAME" [host:port] [options]\n"
     45            "\n"
     46            "Options:\n"
     47            "  -a --add <torrent>        Add a torrent\n"
     48            "  -c --encryption required  Require encryption for all peers\n"
     49            "  -c --encryption preferred Prefer peers to use encryption\n"
     50            "  -c --encryption tolerated Prefer peers to use plaintext\n"
     51            "  -d --download-limit <int> Max download rate in KiB/s\n"
     52            "  -D --download-unlimited   No download rate limit\n"
     53            "  -e --enable-pex           Enable peer exchange\n"
     54            "  -E --disable-pex          Disable peer exchange\n"
     55            "  -f --folder <path>        Folder to set for new torrents\n"
     56            "  -g --debug                Print debugging information\n"
     57            "  -h --help                 Display this message and exit\n"
     58            "  -l --list                 Long list of all torrent and status\n"
     59            "  -m --port-mapping         Automatic port mapping via NAT-PMP or UPnP\n"
     60            "  -M --no-port-mapping      Disable automatic port mapping\n"
     61            "  -p --port <int>           Port to listen for incoming peers\n"
     62            "  -r --remove <int>         Remove the torrent with the given ID\n"
     63            "  -r --remove all           Remove all torrents\n"
     64            "  -s --start <int>          Start the torrent with the given ID\n"
     65            "  -s --start all            Start all stopped torrents\n"
     66            "  -S --stop <int>           Stop the torrent with the given ID\n"
     67            "  -S --stop all             Stop all running torrents\n"
     68            "  -u --upload-limit <int>   Max upload rate in KiB/s\n"
     69            "  -U --upload-unlimited     No upload rate limit\n"
     70            "  -v --verify <id>          Verify the torrent's local data\n" );
    26971    exit( 0 );
    27072}
    27173
    272 int
    273 readargs( int argc, char ** argv, struct opts * opts )
    274 {
    275     char optstr[] = "a:c:d:DeEf:g:hilmMp:qr:s:S:t:u:Uxv:";
    276     struct option longopts[] =
     74static int
     75numarg( const char * arg )
     76{
     77    char * end = NULL;
     78    const long num = strtol( arg, &end, 10 );
     79    if( *end ) {
     80        fprintf( stderr, "Not a number: \"%s\"\n", arg );
     81        showUsage( );
     82    }
     83    return num;
     84}
     85
     86static char * reqs[256]; /* arbitrary max */
     87static int reqCount = 0;
     88static int debug = 0;
     89
     90static char*
     91absolutify( char * buf, size_t len, const char * path )
     92{
     93    if( *path == '/' )
     94        tr_strlcpy( buf, path, len );
     95    else {
     96        char cwd[MAX_PATH_LENGTH];
     97        getcwd( cwd, sizeof( cwd ) );
     98        tr_buildPath( buf, len, cwd, path, NULL );
     99    }
     100    return buf;
     101}
     102
     103static void
     104readargs( int argc, char ** argv )
     105{
     106    int opt;
     107    char optstr[] = "a:c:d:DeEf:ghlmMp:r:s:S:u:Uv:";
     108   
     109    const struct option longopts[] =
    277110    {
    278111        { "add",                required_argument, NULL, 'a' },
     
    283116        { "disable-pex",        no_argument,       NULL, 'E' },
    284117        { "folder",             required_argument, NULL, 'f' },
    285         { "config-dir",         required_argument, NULL, 'g' },
     118        { "debug",              no_argument,      NULL, 'g' },
    286119        { "help",               no_argument,       NULL, 'h' },
    287         { "info",               no_argument,       NULL, 'i' },
    288120        { "list",               no_argument,       NULL, 'l' },
    289121        { "port-mapping",       no_argument,       NULL, 'm' },
    290122        { "no-port-mapping",    no_argument,       NULL, 'M' },
    291123        { "port",               required_argument, NULL, 'p' },
    292         { "quit",               no_argument,       NULL, 'q' },
    293124        { "remove",             required_argument, NULL, 'r' },
    294125        { "start",              required_argument, NULL, 's' },
    295126        { "stop",               required_argument, NULL, 'S' },
    296         { "type",               required_argument, NULL, 't' },
    297127        { "upload-limit",       required_argument, NULL, 'u' },
    298128        { "upload-unlimited",   no_argument,       NULL, 'U' },
    299129        { "verify",             required_argument, NULL, 'v' },
    300         { "proxy",              no_argument,       NULL, 'x' },
    301130        { NULL, 0, NULL, 0 }
    302131    };
    303     int opt, gotmsg;
    304 
    305     gotmsg = 0;
    306     memset( opts, 0, sizeof *opts );
    307     opts->type = CONF_PATH_TYPE_DAEMON;
    308     SLIST_INIT( &opts->files );
    309     opts->map = -1;
    310     opts->pex = -1;
    311     opts->configdir = NULL;
    312     SLIST_INIT( &opts->start );
    313     SLIST_INIT( &opts->stop );
    314     SLIST_INIT( &opts->remove );
    315 
    316     while( 0 <= ( opt = getopt_long( argc, argv, optstr, longopts, NULL ) ) )
    317     {
     132
     133    while((( opt = getopt_long( argc, argv, optstr, longopts, NULL ))) != -1 )
     134    {
     135        char * req = NULL;
     136        char buf[MAX_PATH_LENGTH];
     137
    318138        switch( opt )
    319139        {
    320             case 'a':
    321                 if( 0 > fileargs( &opts->files, 1, &optarg ) )
     140            case 'g': debug = 1; break;
     141            case 'h': showUsage( ); break;
     142            case 'a': req = tr_strdup_printf( "method=torrent-add&filename=%s", optarg ); break;
     143            case 'c': req = tr_strdup_printf( "method=session-set&encryption=%s", optarg ); break;
     144            case 'd': req = tr_strdup_printf( "method=session-set&speed-limit-down=%d&speed-limit-down-enabled=1", numarg(optarg) ); break;
     145            case 'D': req = tr_strdup( "method=session-set&speed-limit-down-enabled=0" ); break;
     146            case 'u': req = tr_strdup_printf( "method=session-set&speed-limit-up=%d&speed-limit-up-enabled:1", numarg(optarg) ); break;
     147            case 'U': req = tr_strdup( "method=session-set&speed-limit-up-enabled=0" ); break;
     148            case 'e': req = tr_strdup( "method=session-set&pex-allowed=1" ); break;
     149            case 'E': req = tr_strdup( "method=session-set&pex-allowed=0" ); break;
     150            case 'f': req = tr_strdup_printf( "method=session-set&download-dir=%s", absolutify(buf,sizeof(buf),optarg)); break;
     151            case 'l': req = tr_strdup_printf( "method=torrent-list&tag=%d", TAG_LIST ); break;
     152            case 'm': req = tr_strdup( "method=session-set&port-forwarding-enabled=1" ); break;
     153            case 'M': req = tr_strdup( "method=session-set&port-forwarding-enabled=0" ); break;
     154            case 'p': req = tr_strdup_printf( "method=session-set&port=%d", numarg( optarg ) ); break;
     155            case 'r': req = strcmp( optarg, "all" )
     156                      ? tr_strdup_printf( "method=torrent-remove&ids=%s", optarg )
     157                      : tr_strdup       ( "method=torrent-remove" ); break;
     158            case 's': req = strcmp( optarg, "all" )
     159                      ? tr_strdup_printf( "method=torrent-start&ids=%s", optarg )
     160                      : tr_strdup       ( "method=torrent-start" ); break;
     161            case 'S': req = strcmp( optarg, "all" )
     162                      ? tr_strdup_printf( "method=torrent-stop&ids=%s", optarg )
     163                      : tr_strdup       ( "method=torrent-stop" ); break;
     164            case 'v': req = strcmp( optarg, "all" )
     165                      ? tr_strdup_printf( "method=torrent-verify&ids=%s", optarg )
     166                      : tr_strdup       ( "method=torrent-verify" ); break;
     167        }
     168
     169        if( req )
     170            reqs[reqCount++] = req;
     171    }
     172}
     173
     174/* [host:port] or [host] or [port] */
     175static void
     176getHostAndPort( int * argc, char ** argv, char ** host, int * port )
     177{
     178    if( *argv[1] != '-' )
     179    {
     180        int i;
     181        const char * s = argv[1];
     182        const char * delim = strchr( s, ':' );
     183        if( delim ) { /* user passed in both host and port */
     184            *host = tr_strndup( s, delim-s );
     185            *port = atoi( delim+1 );
     186        } else {
     187            char * end;
     188            const int i = strtol( s, &end, 10 );
     189            if( !*end ) /* user passed in a port */
     190                *port = i;
     191            else /* user passed in a host */
     192                *host = tr_strdup( s );
     193        }
     194
     195        *argc -= 1;
     196        for( i=1; i<*argc; ++i )
     197            argv[i] = argv[i+1];
     198    }
     199}
     200
     201static size_t
     202writeFunc( void * ptr, size_t size, size_t nmemb, void * buf )
     203{
     204    const size_t byteCount = size * nmemb;
     205    evbuffer_add( buf, ptr, byteCount );
     206    return byteCount;
     207}
     208
     209static const char*
     210torrentStatusToString( int i )
     211{
     212    switch( i )
     213    {
     214        case TR_STATUS_CHECK_WAIT: return "Will Verify";
     215        case TR_STATUS_CHECK:      return "Verifying";
     216        case TR_STATUS_DOWNLOAD:   return "Downloading";
     217        case TR_STATUS_SEED:       return "Seeding";
     218        case TR_STATUS_STOPPED:    return "Stopped";
     219        default:                   return "Error";
     220    }
     221}
     222
     223static void
     224processResponse( const void * response, size_t len )
     225{
     226    tr_benc top;
     227
     228    if( tr_jsonParse( response, len, &top, NULL ) )
     229       tr_nerr( MY_NAME, "Unable to parse response\n" );
     230    else
     231    {
     232        tr_benc *args, *list;
     233        int64_t tag = -1;
     234        const char * str;
     235        tr_bencDictFindInt( &top, "tag", &tag );
     236
     237        if( tr_bencDictFindStr( &top, "result", &str ) )
     238            printf( "Server responded: \"%s\"\n", str );
     239
     240        if( ( tag == TAG_LIST ) &&
     241            ( tr_bencDictFindDict( &top, "arguments", &args ) ) &&
     242            ( tr_bencDictFindList( args, "list", &list ) ) )
     243        {
     244            int i, n;
     245            for( i=0, n=tr_bencListSize( list ); i<n; ++i )
     246            {
     247                int64_t id, status;
     248                const char *name, *ratiostr, *upstr, *dnstr;
     249                tr_benc * d = tr_bencListChild( list, i );
     250                if(    tr_bencDictFindInt( d, "id", &id )
     251                    && tr_bencDictFindInt( d, "status", &status )
     252                    && tr_bencDictFindStr( d, "name", &name )
     253                    && tr_bencDictFindStr( d, "ratio", &ratiostr )
     254                    && tr_bencDictFindStr( d, "rateUpload", &upstr )
     255                    && tr_bencDictFindStr( d, "rateDownload", &dnstr ) )
    322256                {
    323                     return -1;
     257                    printf( "%4d.  Up: %5.1f  Down: %5.1f  Ratio: %4.1f  %-15s  %s\n",
     258                            (int)id,
     259                            strtod( upstr, NULL ),
     260                            strtod( dnstr, NULL ),
     261                            strtod( ratiostr, NULL ),
     262                            torrentStatusToString( status ),
     263                            name );
    324264                }
    325                 break;
    326             case 'c':
    327                 if(!strcasecmp(optarg, "required"))
    328                     opts->crypto = "required";
    329                 else if(!strcasecmp(optarg, "preferred"))
    330                     opts->crypto = "preferred";
    331                 else if(!strcasecmp(optarg, "tolerated"))
    332                     opts->crypto = "tolerated";
    333                 else
    334                     usage("invalid encryption mode: %s", optarg);
    335                 break;
    336             case 'd':
    337                 opts->downlimit = 1;
    338                 opts->down      = numarg( optarg );
    339                 break;
    340             case 'D':
    341                 opts->downlimit = 1;
    342                 opts->down      = -1;
    343                 break;
    344             case 'e':
    345                 opts->pex       = 1;
    346                 break;
    347             case 'E':
    348                 opts->pex       = 0;
    349                 break;
    350             case 'f':
    351                 absolutify( opts->dir, sizeof opts->dir, optarg );
    352                 break;
    353             case 'g':
    354                 opts->configdir = strdup( optarg );
    355                 break;
    356             case 'i':
    357                 opts->listquick = 1;
    358                 break;
    359             case 'l':
    360                 opts->listfull  = 1;
    361                 break;
    362             case 'm':
    363                 opts->map       = 1;
    364                 break;
    365             case 'M':
    366                 opts->map       = 0;
    367                 break;
    368             case 'p':
    369                 opts->port      = numarg( optarg );
    370                 if( 0 >= opts->port || 0xffff <= opts->port )
    371                 {
    372                     usage( "invalid port: %i", opts->port );
    373                 }
    374                 break;
    375             case 'q':
    376                 opts->sendquit  = 1;
    377                 break;
    378             case 'r':
    379                 if( 0 > hasharg( optarg, &opts->remove, &opts->removeall ) )
    380                 {
    381                     return -1;
    382                 }
    383                 break;
    384             case 's':
    385                 if( 0 > hasharg( optarg, &opts->start, &opts->startall ) )
    386                 {
    387                     return -1;
    388                 }
    389                 break;
    390             case 'S':
    391                 if( 0 > hasharg( optarg, &opts->stop, &opts->stopall ) )
    392                 {
    393                     return -1;
    394                 }
    395                 break;
    396             case 't':
    397                 if( 0 == strcasecmp( "daemon", optarg ) )
    398                 {
    399                     opts->type  = CONF_PATH_TYPE_DAEMON;
    400                     opts->sock  = NULL;
    401                 }
    402                 else if( 0 == strcasecmp( "gtk", optarg ) )
    403                 {
    404                     opts->type  = CONF_PATH_TYPE_GTK;
    405                     opts->sock  = NULL;
    406                 }
    407                 else if( 0 == strcasecmp( "mac", optarg ) ||
    408                          0 == strcasecmp( "osx", optarg ) ||
    409                          0 == strcasecmp( "macos", optarg ) ||
    410                          0 == strcasecmp( "macosx", optarg ) )
    411                 {
    412                     opts->type  = CONF_PATH_TYPE_OSX;
    413                     opts->sock  = NULL;
    414                 }
    415                 else
    416                 {
    417                     opts->sock  = optarg;
    418                 }
    419                 break;
    420             case 'u':
    421                 opts->uplimit   = 1;
    422                 opts->up        = numarg( optarg );
    423                 break;
    424             case 'U':
    425                 opts->uplimit   = 1;
    426                 opts->up        = -1;
    427                 break;
    428             case 'v':
    429                 if( 0 > hasharg( optarg, &opts->verify, NULL ) )
    430                 {
    431                     return -1;
    432                 }
    433                 break;
    434             case 'x':
    435                 opts->proxy     = 1;
    436                 continue; /* don't set gotmsg, -x isn't a message */
    437             default:
    438                 usage( NULL );
    439                 break;
    440         }
    441         gotmsg = 1;
    442     }
    443 
    444     if( !gotmsg && argc == optind )
    445     {
    446         usage( NULL );
    447     }
    448 
    449     if( opts->proxy )
    450     {
    451         if( argc == optind )
    452             usage( "can't use -x without any arguments" );
    453         opts->proxycmd = argv + optind;
    454     }
    455     else if( 0 > fileargs( &opts->files, argc - optind, argv + optind ) )
    456     {
    457         return -1;
    458     }
    459 
    460     return 0;
    461 }
    462 
    463 int
    464 numarg( const char * arg )
    465 {
    466     char * end;
    467     long   num;
    468 
    469     end = NULL;
    470     num = strtol( arg, &end, 10 );
    471     if( NULL != end && '\0' != *end )
    472     {
    473         usage( "not a number: %s", arg );
    474         return -1;
    475     }
    476 
    477     return num;
    478 }
    479 
    480 int
    481 hasharg( const char * arg, struct strlist * list, int * all )
    482 {
    483     struct stritem * listitem;
    484     struct torhash * treeitem, key, * foo;
    485     size_t           len, ii;
    486 
    487     /* check for special "all" value */
    488     if( 0 == strcasecmp( "all", arg ) )
    489     {
    490         if( all )
    491             *all = 1;
    492         return 0;
    493     }
    494 
    495     /* check hash length */
    496     len = strlen( arg );
    497     if( SHA_DIGEST_LENGTH * 2 != len )
    498     {
    499         usage( "torrent info hash length is not %i: %s",
    500                SHA_DIGEST_LENGTH * 2, arg );
    501         return -1;
    502     }
    503 
    504     /* allocate list item */
    505     listitem = calloc( 1, sizeof *listitem );
    506     if( NULL == listitem )
    507     {
    508         mallocmsg( sizeof *listitem );
    509         return -1;
    510     }
    511     listitem->str = calloc( len + 1, 1 );
    512     if( NULL == listitem->str )
    513     {
    514         mallocmsg( len + 1 );
    515         free( listitem );
    516         return -1;
    517     }
    518 
    519     /* check that the hash is all hex and copy it in lowercase */
    520     for( ii = 0; len > ii; ii++ )
    521     {
    522         if( !isxdigit( arg[ii] ) )
    523         {
    524             usage( "torrent info hash is not hex: %s", arg );
    525             free( listitem->str );
    526             free( listitem );
    527             return -1;
    528         }
    529         listitem->str[ii] = tolower( arg[ii] );
    530     }
    531 
    532     /* try to look up the hash in the hash tree */
    533     memset( &key, 0, sizeof key );
    534     strlcpy( key.hash, listitem->str, sizeof key.hash );
    535     treeitem = RB_FIND( torhashes, &gl_hashids, &key );
    536     if( NULL == treeitem )
    537     {
    538         /* the hash isn't in the tree, allocate a tree item and insert it */
    539         treeitem = calloc( 1, sizeof *treeitem );
    540         if( NULL == treeitem )
    541         {
    542             mallocmsg( sizeof *treeitem );
    543             free( listitem->str );
    544             free( listitem );
    545             return -1;
    546         }
    547         treeitem->id = -1;
    548         strlcpy( treeitem->hash, listitem->str, sizeof treeitem->hash );
    549         foo = RB_INSERT( torhashes, &gl_hashids, treeitem );
    550         assert( NULL == foo );
    551     }
    552 
    553     /* finally, add the list item to the list */
    554     SLIST_INSERT_HEAD( list, listitem, next );
    555 
    556     return 0;
    557 }
    558 
    559 int
    560 fileargs( struct strlist * list, int argc, char * const * argv )
    561 {
    562     struct stritem * item;
    563     int              ii;
    564     char             path[MAXPATHLEN];
    565 
    566     for( ii = 0; argc > ii; ii++ )
    567     {
    568         item = calloc( 1, sizeof *item );
    569         if( NULL == item )
    570         {
    571             mallocmsg( sizeof *item );
    572             return -1;
    573         }
    574         if( '/' == argv[ii][0] )
    575         {
    576             item->str = strdup( argv[ii] );
    577             if( NULL == item->str )
    578             {
    579                 mallocmsg( strlen( argv[ii] ) + 1 );
    580                 free( item );
    581                 return -1;
    582265            }
    583266        }
     267
     268        tr_bencFree( &top );
     269    }
     270}
     271
     272static void
     273processRequests( const char * host, int port,
     274                 const char ** reqs, int reqCount )
     275{
     276    int i;
     277    CURL * curl;
     278    struct evbuffer * buf = evbuffer_new( );
     279
     280    curl = curl_easy_init( );
     281    curl_easy_setopt( curl, CURLOPT_VERBOSE, debug );
     282    curl_easy_setopt( curl, CURLOPT_USERAGENT, MY_NAME"/"LONG_VERSION_STRING );
     283    curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, writeFunc, 0 );
     284    curl_easy_setopt( curl, CURLOPT_WRITEDATA, buf, 0 );
     285
     286    for( i=0; i<reqCount; ++i )
     287    {
     288        CURLcode res;
     289        char * url = tr_strdup_printf( "http://%s:%d/transmission?%s",
     290                                       host, port, reqs[i] );
     291        curl_easy_setopt( curl, CURLOPT_URL, url );
     292        if(( res = curl_easy_perform( curl )))
     293            tr_nerr( MY_NAME, "%s\n", curl_easy_strerror( res ) );
    584294        else
    585         {
    586             absolutify( path, sizeof path, argv[ii] );
    587             item->str = strdup( path );
    588             if( NULL == item->str )
    589             {
    590                 mallocmsg( strlen( path ) + 1 );
    591                 free( item );
    592                 return -1;
    593             }
    594         }
    595         SLIST_INSERT_HEAD( list, item, next );
    596     }
     295            processResponse( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
     296
     297        evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) );
     298        tr_free( url );
     299    }
     300
     301    /* cleanup */
     302    evbuffer_free( buf );
     303    curl_easy_cleanup( curl );
     304}
     305
     306int
     307main( int argc, char ** argv )
     308{
     309    int i;
     310    int port = DEFAULT_PORT;
     311    char * host = NULL;
     312
     313    if( argc < 2 )
     314        showUsage( );
     315
     316    getHostAndPort( &argc, argv, &host, &port );
     317    if( host == NULL )
     318        host = tr_strdup( DEFAULT_HOST );
     319
     320    readargs( argc, argv );
     321    if( reqCount )
     322        processRequests( host, port, (const char**)reqs, reqCount );
     323    else
     324        showUsage( );
     325
     326    for( i=0; i<reqCount; ++i )
     327        tr_free( reqs[i] );
    597328
    598329    return 0;
    599330}
    600 
    601 void
    602 listmsg( const struct cl_info * inf )
    603 {
    604     char * newname;
    605     size_t ii;
    606 
    607     if( NULL == inf )
    608     {
    609         return;
    610     }
    611 
    612     if( NULL == inf->name )
    613     {
    614         errmsg( "missing torrent name from server" );
    615         return;
    616     }
    617     else if( NULL == inf->hash )
    618     {
    619         errmsg( "missing torrent hash from server" );
    620         return;
    621     }
    622 
    623     newname = strdup_noctrl( inf->name );
    624     if( NULL == newname )
    625     {
    626         return;
    627     }
    628 
    629     for( ii = 0; '\0' != inf->hash[ii]; ii++ )
    630     {
    631         if( isxdigit( inf->hash[ii] ) )
    632         {
    633             putchar( tolower( inf->hash[ii] ) );
    634         }
    635     }
    636     putchar( ' ' );
    637     printf( "%s\n", newname );
    638     free( newname );
    639 }
    640 
    641 void
    642 infomsg( const struct cl_info * cinfo )
    643 {
    644     struct torinfo * tinfo, key;
    645 
    646     gl_gotlistinfo = 1;
    647 
    648     if( NULL == cinfo )
    649     {
    650         if( gl_gotliststat )
    651         {
    652             printlisting();
    653         }
    654         return;
    655     }
    656 
    657     if( NULL == cinfo->name || 0 >= cinfo->size )
    658     {
    659         errmsg( "missing torrent info from server" );
    660         return;
    661     }
    662 
    663     memset( &key, 0, sizeof key );
    664     key.id = cinfo->id;
    665     tinfo = RB_FIND( torlist, &gl_torinfo, &key );
    666     if( NULL == tinfo )
    667     {
    668         tinfo = calloc( 1, sizeof *tinfo );
    669         if( NULL == tinfo )
    670         {
    671             mallocmsg( sizeof *tinfo );
    672             return;
    673         }
    674         tinfo->id = cinfo->id;
    675         RB_INSERT( torlist, &gl_torinfo, tinfo );
    676     }
    677 
    678     tinfo->infogood = 1;
    679     free( tinfo->name );
    680     tinfo->name = strdup_noctrl( cinfo->name );
    681     tinfo->size = cinfo->size;
    682 }
    683 
    684 void
    685 statmsg( const struct cl_stat * st )
    686 {
    687     struct torinfo * info, key;
    688 
    689     gl_gotliststat = 1;
    690 
    691     if( NULL == st )
    692     {
    693         if( gl_gotlistinfo )
    694         {
    695             printlisting();
    696         }
    697         return;
    698     }
    699 
    700     if( NULL == st->state || 0 > st->done ||
    701         0 > st->ratedown  || 0 > st->rateup ||
    702         0 > st->totaldown || 0 > st->totalup )
    703     {
    704         errmsg( "missing torrent status from server" );
    705         return;
    706     }
    707 
    708     memset( &key, 0, sizeof key );
    709     key.id = st->id;
    710     info = RB_FIND( torlist, &gl_torinfo, &key );
    711     if( NULL == info )
    712     {
    713         info = calloc( 1, sizeof *info );
    714         if( NULL == info )
    715         {
    716             mallocmsg( sizeof *info );
    717             return;
    718         }
    719         info->id = st->id;
    720         RB_INSERT( torlist, &gl_torinfo, info );
    721     }
    722 
    723     info->statgood = 1;
    724     free( info->state );
    725     info->state     = strdup_noctrl( st->state );
    726     info->eta       = st->eta;
    727     info->done      = st->done;
    728     info->ratedown  = st->ratedown;
    729     info->rateup    = st->rateup;
    730     info->totaldown = st->totaldown;
    731     info->totalup   = st->totalup;
    732     if( NULL != st->error && '\0' != st->error[0] )
    733     {
    734         info->errorcode = strdup_noctrl( st->error );
    735     }
    736     if( NULL != st->errmsg && '\0' != st->errmsg[0] )
    737     {
    738         info->errormsg = strdup_noctrl( st->errmsg );
    739     }
    740 }
    741 
    742 void
    743 hashmsg( const struct cl_info * inf )
    744 {
    745     struct torhash key, * found;
    746 
    747     if( NULL == inf )
    748     {
    749         sendidreqs();
    750         return;
    751     }
    752 
    753     if( NULL == inf->hash )
    754     {
    755         errmsg( "missing torrent hash from server" );
    756         return;
    757     }
    758 
    759     memset( &key, 0, sizeof key );
    760     strlcpy( key.hash, inf->hash, sizeof key.hash );
    761     found = RB_FIND( torhashes, &gl_hashids, &key );
    762     if( NULL != found )
    763     {
    764         found->id = inf->id;
    765     }
    766 }
    767 
    768 float
    769 fmtsize( int64_t num, const char ** units )
    770 {
    771     static const char * sizes[] =
    772     {
    773         "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
    774     };
    775     float  ret;
    776     size_t ii;
    777 
    778     ret = num;
    779     for( ii = 0; ARRAYLEN( sizes ) > ii && 1000.0 < ret; ii++ )
    780     {
    781         ret /= 1024.0;
    782     }
    783 
    784     if( NULL != units )
    785     {
    786         *units = sizes[ii];
    787     }
    788 
    789     return ret;
    790 }
    791 
    792 char *
    793 strdup_noctrl( const char * str )
    794 {
    795     char * ret;
    796     size_t ii;
    797 
    798     ii = strlen( str );
    799     ret = malloc( ii + 1 );
    800     if( NULL == ret )
    801     {
    802         mallocmsg( ii + 1 );
    803         return NULL;
    804     }
    805 
    806     for( ii = 0; '\0' != str[ii]; ii++ )
    807     {
    808         ret[ii] = ( iscntrl( str[ii] ) ? ' ' : str[ii] );
    809     }
    810     ret[ii] = '\0';
    811 
    812     return ret;
    813 }
    814 
    815 void
    816 print_eta( int64_t secs )
    817 {
    818     static const struct
    819     {
    820         const char * label;
    821         int64_t      div;
    822     }
    823     units[] =
    824     {
    825         { "second", 60 },
    826         { "minute", 60 },
    827         { "hour",   24 },
    828         { "day",    7  },
    829         { "week",   1 }
    830     };
    831     int    readable[ ARRAYLEN( units ) ];
    832     int    printed;
    833     size_t ii;
    834 
    835     if( 0 > secs )
    836     {
    837         printf( "stalled" );
    838         return;
    839     }
    840 
    841     for( ii = 0; ARRAYLEN( units ) > ii; ii++ )
    842     {
    843         readable[ii] = secs % units[ii].div;
    844         secs /= units[ii].div;
    845     }
    846     readable[ii-1] = MIN( INT_MAX, secs );
    847 
    848     printf( "done in" );
    849     for( printed = 0; 0 < ii && 2 > printed; ii-- )
    850     {
    851         if( 0 != readable[ii-1] ||
    852             ( 0 == printed && 1 == ii ) )
    853         {
    854             printf( " %i %s%s", readable[ii-1], units[ii-1].label,
    855                     ( 1 == readable[ii-1] ? "" : "s" ) );
    856             printed++;
    857         }
    858     }
    859 }
    860 
    861 int
    862 sendidreqs( void )
    863 {
    864     struct
    865     {
    866         struct strlist * list;
    867         int ( * func )( size_t, const int * );
    868     }
    869     reqs[] =
    870     {
    871         { gl_starthashes,  client_start  },
    872         { gl_stophashes,   client_stop   },
    873         { gl_removehashes, client_remove },
    874         { gl_verifyhashes, client_verify },
    875     };
    876     struct stritem * jj;
    877     size_t           ii;
    878     int            * ids, count, ret;
    879     struct torhash   key, * found;
    880 
    881     ret = -1;
    882     memset( &key, 0, sizeof key );
    883 
    884     for( ii = 0; ARRAYLEN( reqs ) > ii; ii++)
    885     {
    886         if( NULL == reqs[ii].list || SLIST_EMPTY( reqs[ii].list ) )
    887         {
    888             continue;
    889         }
    890 
    891         count = 0;
    892         SLIST_FOREACH( jj, reqs[ii].list, next )
    893         {
    894             count++;
    895         }
    896         count++;
    897 
    898         ids = calloc( count, sizeof ids[0] );
    899         if( NULL == ids )
    900         {
    901             mallocmsg( count * sizeof ids[0] );
    902             return -1;
    903         }
    904 
    905         count = 0;
    906         SLIST_FOREACH( jj, reqs[ii].list, next )
    907         {
    908             strlcpy( key.hash, jj->str, sizeof key.hash );
    909             found = RB_FIND( torhashes, &gl_hashids, &key );
    910             if( NULL != found && TORRENT_ID_VALID( found->id ) )
    911             {
    912                 ids[count] = found->id;
    913                 count++;
    914             }
    915         }
    916 
    917         if( 0 < count )
    918         {
    919             if( 0 > reqs[ii].func( count, ids ) )
    920             {
    921                 free( ids );
    922                 return -1;
    923             }
    924             ret = 0;
    925         }
    926 
    927         free( ids );
    928     }
    929 
    930     gl_starthashes  = NULL;
    931     gl_stophashes   = NULL;
    932     gl_removehashes = NULL;
    933 
    934     return ret;
    935 }
    936 
    937 void
    938 printlisting( void )
    939 {
    940     struct tornames  names;
    941     struct torinfo * ii, * next;
    942     const char     * units, * name, * upunits, * downunits;
    943     float            size, progress, upspeed, downspeed, ratio;
    944 
    945     /* sort the torrents by name */
    946     RB_INIT( &names );
    947     RB_FOREACH( ii, torlist, &gl_torinfo )
    948     {
    949         RB_INSERT( tornames, &names, ii );
    950     }
    951 
    952     /* print the torrent info while freeing the tree */
    953     for( ii = RB_MIN( tornames, &names ); NULL != ii; ii = next )
    954     {
    955         next = RB_NEXT( tornames, &names, ii );
    956         RB_REMOVE( tornames, &names, ii );
    957         RB_REMOVE( torlist, &gl_torinfo, ii );
    958 
    959         if( !ii->infogood || !ii->statgood )
    960         {
    961             goto free;
    962         }
    963 
    964         /* massage some numbers into a better format for printing */
    965         size      = fmtsize( ii->size, &units );
    966         upspeed   = fmtsize( ii->rateup, &upunits );
    967         downspeed = fmtsize( ii->ratedown, &downunits );
    968         name      = ( NULL == ii->name ? "???" : ii->name );
    969         progress  = ( float )ii->done / ( float )ii->size * 100.0;
    970         progress  = MIN( 100.0, progress );
    971         progress  = MAX( 0.0, progress );
    972 
    973         /* print name and size */
    974         printf( "%s (%.*f %s) - ", name, BESTDECIMAL( size ), size, units );
    975 
    976         /* print hash check progress */
    977         if( 0 == strcasecmp( "checking", ii->state ) )
    978         {
    979             printf( "%.*f%% checking files",
    980                     BESTDECIMAL( progress ), progress );
    981         }
    982         /* print progress */
    983         else if( 0 == strcasecmp( "waiting to checking", ii->state ) )
    984         {
    985             printf( "%.*f%% waiting to check files",
    986                     BESTDECIMAL( progress ), progress );
    987         }
    988         /* print download progress, speeds, and eta */
    989         else if( 0 == strcasecmp( "downloading", ii->state ) )
    990         {
    991             progress = MIN( 99.0, progress );
    992             printf( "%.*f%% downloading at %.*f %s/s (UL at %.*f %s/s), ",
    993                     BESTDECIMAL( progress ), progress,
    994                     BESTDECIMAL( downspeed ), downspeed, downunits,
    995                     BESTDECIMAL( upspeed ), upspeed, upunits );
    996             print_eta( ii->eta );
    997         }
    998         /* print seeding speed */
    999         else if( 0 == strcasecmp( "seeding", ii->state ) )
    1000         {
    1001             if( 0 == ii->totalup && 0 == ii->totaldown )
    1002             {
    1003                 printf( "100%% seeding at %.*f %s/s [N/A]",
    1004                         BESTDECIMAL( upspeed ), upspeed, upunits );
    1005             }
    1006             else if( 0 == ii->totaldown )
    1007             {
    1008                 printf( "100%% seeding at %.*f %s/s [INF]",
    1009                         BESTDECIMAL( upspeed ), upspeed, upunits );
    1010             }
    1011             else
    1012             {
    1013                 ratio = ( float )ii->totalup / ( float )ii->totaldown;
    1014                 printf( "100%% seeding at %.*f %s/s [%.*f]",
    1015                         BESTDECIMAL( upspeed ), upspeed, upunits,
    1016                         BESTDECIMAL( ratio ), ratio );
    1017             }
    1018         }
    1019         /* print stopping message */
    1020         else if( 0 == strcasecmp( "stopping", ii->state ) )
    1021         {
    1022             printf( "%.*f%% stopping...", BESTDECIMAL( progress ), progress );
    1023         }
    1024         /* print stopped message with progress */
    1025         else if( 0 == strcasecmp( "paused", ii->state ) )
    1026         {
    1027             printf( "%.*f%% stopped", BESTDECIMAL( progress ), progress );
    1028         }
    1029         /* unknown status, just print it with progress */
    1030         else
    1031         {
    1032             printf( "%.*f%% %s",
    1033                     BESTDECIMAL( progress ), progress, ii->state );
    1034         }
    1035 
    1036         /* print any error */
    1037         if( NULL != ii->errorcode || NULL != ii->errormsg )
    1038         {
    1039             if( NULL == ii->errorcode )
    1040             {
    1041                 printf( " [error - %s]", ii->errormsg );
    1042             }
    1043             else if( NULL == ii->errormsg )
    1044             {
    1045                 printf( " [error (%s)]", ii->errorcode );
    1046             }
    1047             else
    1048             {
    1049                 printf( " [error (%s) - %s]", ii->errorcode, ii->errormsg );
    1050             }
    1051         }
    1052 
    1053         /* don't forget the newline */
    1054         putchar( '\n' );
    1055 
    1056         /* free the stuff for this torrent */
    1057       free:
    1058         free( ii->name );
    1059         free( ii->state );
    1060         free( ii->errorcode );
    1061         free( ii->errormsg );
    1062         free( ii );
    1063     }
    1064 }
    1065 
    1066 int
    1067 tornamecmp( struct torinfo * left, struct torinfo * right )
    1068 {
    1069     int ret;
    1070 
    1071     /* we know they're equal if they're the same struct */
    1072     if( left == right )
    1073     {
    1074         return 0;
    1075     }
    1076     /* we might be missing a name, fall back on torrent ID */
    1077     else if( NULL == left->name && NULL == right->name )
    1078     {
    1079         return toridcmp( left, right );
    1080     }
    1081     else if( NULL == left->name )
    1082     {
    1083         return -1;
    1084     }
    1085     else if( NULL == right->name )
    1086     {
    1087         return 1;
    1088     }
    1089 
    1090     /* if we have two names, compare them */
    1091     ret = strcasecmp( left->name, right->name );
    1092     if( 0 != ret )
    1093     {
    1094         return ret;
    1095     }
    1096     /* if the names are the same then fall back on the torrent ID,
    1097        this is to handle different torrents with the same name */
    1098     else
    1099     {
    1100         return toridcmp( left, right );
    1101     }
    1102 }
    1103 
    1104 int
    1105 torhashcmp( struct torhash * left, struct torhash * right )
    1106 {
    1107     return strcasecmp( left->hash, right->hash );
    1108 }
    1109 
    1110 INTCMP_FUNC( toridcmp, torinfo, id )
  • trunk/daemon/transmission-daemon.1

    r5646 r5843  
    7070.Nm
    7171program was written by
    72 .An Josh Elsasser Aq josh@elsasser.org ,
    73 .An Eric Petit Aq titer@m0k.org ,
    74 .An Charles Kerr Aq charles@rebelbase.com ,
     72.An Charles Kerr ,
     73.An Josh Elsasser ,
     74.An Eric Petit ,
    7575and
    76 .An Mitchell Livingston Aq livings124@gmail.com .
     76.An Mitchell Livingston .
    7777.Sh SEE ALSO
    7878.Xr transmissioncli 1 ,
    7979.Xr transmission 1 ,
    80 .Xr transmission-proxy 1 ,
    8180.Xr transmission-remote 1
    8281.Pp
  • trunk/daemon/transmission-remote.1

    r5646 r5843  
    198198.Nm
    199199program was written by
    200 .An Josh Elsasser Aq josh@elsasser.org ,
    201 .An Eric Petit Aq titer@m0k.org ,
    202 .An Charles Kerr Aq charles@rebelbase.com ,
     200.An Charles Kerr ,
     201.An Josh Elsasser ,
     202.An Eric Petit ,
    203203and
    204 .An Mitchell Livingston Aq livings124@gmail.com .
     204.An Mitchell Livingston .
    205205.Sh SEE ALSO
    206206.Xr transmissioncli 1 ,
    207207.Xr transmission-daemon 1 ,
    208 .Xr transmission 1 ,
    209 .Xr transmission-proxy 1
     208.Xr transmission 1
    210209.Pp
    211210http://www.transmissionbt.com/
  • trunk/doc/rpc-spec.txt

    r5842 r5843  
    8787   Method name: "torrent-info".
    8888
    89    Request arguments: an "id" number specifying a torrent id number
    90 
    91    Response arguments: "info", an array of objects based on libtransmission's
    92    tr_info struct but different in the following ways:
    93 
    94    (1) tr_info's "hash" field is omitted.
    95    (2) tr_info's "pieces" field is omitted.
    96    (3) tr_file's "firstPiece", "lastPiece", and "offset" fields are omitted.
     89   Request arguments: 3.1's optional "ids" argument.
     90
     91   Response arguments: "torrent-info", an array of objects based on
     92   libtransmission's tr_info struct but different in the following ways:
     93   (1) the torrent's "id" field is added.
     94   (2) tr_info's "hash" field is omitted.
     95   (3) tr_info's "pieces" field is omitted.
     96   (4) tr_file's "firstPiece", "lastPiece", and "offset" fields are omitted.
     97
     98   Note that this is a fairly high-bandwidth request and that its results
     99   don't change.  You should try to cache its results instead of re-calling it.
    97100
    98101   Example Request:
    99102
    100103      {
    101          "arguments": { "id": 7 }
     104         "arguments": { "ids": [ 7, 10 ] }
    102105         "method": "torrent-info",
    103106         "tag": 39693
     
    110113         "result": "success",
    111114         "arguments": {
    112             "info": {
    113                "id": 7,
    114                "totalSize": 9803930483,
    115                "pieceCount": 1209233,
    116                "pieceSize": 4096,
    117                "name": "Ubuntu x86_64 DVD",
    118                ...
    119             }
     115            "torrent-info": [
     116               {
     117                  "id": 7,
     118                  "name": "Ubuntu x86_64 DVD",
     119                  "pieceCount": 1209233,
     120                  "pieceSize": 4096,
     121                  "totalSize": 9803930483,
     122                  ...
     123               },
     124               {
     125                  "id": 10,
     126                  "name": "Ubuntu i386 DVD",
     127                  "pieceCount": 83943,
     128                  "pieceSize": 12345,
     129                  "totalSize": 2398480394,
     130                  ...
     131               }
     132            ]
    120133         }
    121134      }
     
    125138   Method name: "torrent-status"
    126139
    127    Request arguments: an "id" int specifying a torrent id number
    128 
    129    Response arguments: "status", an object based on libtransmission's
    130    tr_stat struct but differerent in the following ways:
    131 
    132    (1) tr_stat's "tracker" field is omitted.
    133    (2) a new string, "announce-url", is added.
    134    (3) a new string, "scrape-url", is added.
    135    (4) tr_info's "name" field is added.
     140   Request arguments: 3.1's optional "ids" argument.
     141
     142   Response arguments: "torrent-status", an array of objects based
     143   on libtransmission's tr_stat struct but differerent in the
     144   following ways:
     145
     146   (1) the torrent's "id" field is added.
     147   (2) tr_info's "name" field is added.
     148   (3) tr_stat's "tracker" field is omitted, and is instead
     149       replaced with two strings: "announce-url" and scrape-url"
    136150
    1371513.5.  Adding a Torrent
  • trunk/gtk/Makefile.am

    r5735 r5843  
    2323    dialogs.h \
    2424    hig.h \
    25     ipc.h \
    2625    file-list.h \
    2726    lock.h \
     
    5251    file-list.c \
    5352    hig.c \
    54     ipc.c \
    5553    main.c \
    5654    makemeta-ui.c \
     
    7573    $(top_builddir)/third-party/miniupnp/libminiupnp.a \
    7674    $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
     75    $(top_builddir)/third-party/shttpd/libshttpd.a \
    7776    $(GTK_LIBS) \
    7877    $(GIO_LIBS) \
  • trunk/gtk/add-dialog.c

    r5750 r5843  
    2626    GtkWidget * trash_check;
    2727    char * filename;
    28     char * destination;
     28    char * downloadDir;
    2929    TrTorrent * gtor;
    3030    tr_ctor * ctor;
     
    6464    tr_ctorFree( data->ctor );
    6565    g_free( data->filename );
    66     g_free( data->destination );
     66    g_free( data->downloadDir );
    6767    g_free( data );
    6868    gtk_widget_destroy( GTK_WIDGET( dialog ) );
     
    7373{
    7474    if( o->gtor )
    75         tr_torrentSetFolder( tr_torrent_handle( o->gtor ), o->destination );
     75        tr_torrentSetDownloadDir( tr_torrent_handle( o->gtor ), o->downloadDir );
    7676
    7777    file_list_set_torrent( o->list, o->gtor );
     
    9494        tr_handle * handle = tr_core_handle( data->core );
    9595        tr_ctorSetMetainfoFromFile( data->ctor, data->filename );
    96         tr_ctorSetDestination( data->ctor, TR_FORCE, data->destination );
     96        tr_ctorSetDownloadDir( data->ctor, TR_FORCE, data->downloadDir );
    9797        tr_ctorSetPaused( data->ctor, TR_FORCE, TRUE );
    9898        tr_ctorSetDeleteSource( data->ctor, FALSE );
     
    113113
    114114static void
    115 destinationChanged( GtkFileChooserButton * b, gpointer gdata )
     115downloadDirChanged( GtkFileChooserButton * b, gpointer gdata )
    116116{
    117117    char * fname = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( b ) );
     
    119119    {
    120120        struct AddData * data = gdata;
    121         g_free( data->destination );
    122         data->destination = fname;
     121        g_free( data->downloadDir );
     122        data->downloadDir = fname;
    123123
    124124        updateTorrent( data );
     
    175175                                             -1 );
    176176
    177     if( tr_ctorGetDestination( ctor, TR_FORCE, &str ) )
     177    if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &str ) )
    178178        g_assert_not_reached( );
    179179    g_assert( str );
     
    183183    data->ctor = ctor;
    184184    data->filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
    185     data->destination = g_strdup( str );
     185    data->downloadDir = g_strdup( str );
    186186    data->list = file_list_new( NULL );
    187187    data->trash_check = gtk_check_button_new_with_mnemonic( _( "Mo_ve source file to Trash" ) );
     
    219219    ++col;
    220220    w = gtk_file_chooser_button_new( _( "Select Destination Folder" ), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER );
    221     if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->destination ) )
    222         g_warning( "couldn't select '%s'", data->destination );
     221    if( !gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( w ), data->downloadDir ) )
     222        g_warning( "couldn't select '%s'", data->downloadDir );
    223223    gtk_table_attach( GTK_TABLE( t ), w, col, col+1, row, row+1, ~0, 0, 0, 0 );
    224224    gtk_label_set_mnemonic_widget( GTK_LABEL( l ), w );
    225     g_signal_connect( w, "selection-changed", G_CALLBACK( destinationChanged ), data );
     225    g_signal_connect( w, "selection-changed", G_CALLBACK( downloadDirChanged ), data );
    226226
    227227    ++row;
  • trunk/gtk/details.c

    r5819 r5843  
    780780  hig_workarea_add_section_title (t, &row, _("Location"));
    781781
    782     l = g_object_new( GTK_TYPE_LABEL, "label", tr_torrentGetFolder( tor ), "selectable", TRUE,
     782    l = g_object_new( GTK_TYPE_LABEL, "label", tr_torrentGetDownloadDir( tor ), "selectable", TRUE,
    783783                                      "ellipsize", PANGO_ELLIPSIZE_END, NULL );
    784784    hig_workarea_add_row (t, &row, _( "Destination folder:" ), l, NULL);
     
    858858  gtk_label_set_text( GTK_LABEL( a->ratio_lb ), buf );
    859859
    860   tr_strlspeed( buf, stat->swarmspeed, sizeof(buf) );
     860  tr_strlspeed( buf, stat->swarmSpeed, sizeof(buf) );
    861861  gtk_label_set_text (GTK_LABEL(a->swarm_lb), buf );
    862862
     
    12141214
    12151215    l = page->last_scrape_time_lb;
    1216     t = torStat->tracker_stat.lastScrapeTime;
     1216    t = torStat->trackerStat.lastScrapeTime;
    12171217    refresh_time_lb( l, t );
    12181218
    12191219    l = page->last_scrape_response_lb;
    1220     gtk_label_set_text( GTK_LABEL( l ), torStat->tracker_stat.scrapeResponse );
     1220    gtk_label_set_text( GTK_LABEL( l ), torStat->trackerStat.scrapeResponse );
    12211221
    12221222    l = page->next_scrape_countdown_lb;
    1223     t = torStat->tracker_stat.nextScrapeTime;
     1223    t = torStat->trackerStat.nextScrapeTime;
    12241224    refresh_countdown_lb( l, t );
    12251225
    12261226    l = page->last_announce_time_lb;
    1227     t = torStat->tracker_stat.lastAnnounceTime;
     1227    t = torStat->trackerStat.lastAnnounceTime;
    12281228    refresh_time_lb( l, t );
    12291229
    12301230    l = page->last_announce_response_lb;
    1231     gtk_label_set_text( GTK_LABEL( l ), torStat->tracker_stat.announceResponse );
     1231    gtk_label_set_text( GTK_LABEL( l ), torStat->trackerStat.announceResponse );
    12321232
    12331233    l = page->next_announce_countdown_lb;
    1234     t = torStat->tracker_stat.nextAnnounceTime;
     1234    t = torStat->trackerStat.nextAnnounceTime;
    12351235    refresh_countdown_lb( l, t );
    12361236
    12371237    l = page->manual_announce_countdown_lb;
    1238     t = torStat->tracker_stat.nextManualAnnounceTime;
     1238    t = torStat->trackerStat.nextManualAnnounceTime;
    12391239    refresh_countdown_lb( l, t );
    12401240}
  • trunk/gtk/main.c

    r5819 r5843  
    4949#include "dialogs.h"
    5050#include "hig.h"
    51 #include "ipc.h"
    5251#include "makemeta-ui.h"
    5352#include "msgwin.h"
     
    124123static GtkUIManager * myUIManager = NULL;
    125124
    126 static gboolean
    127 sendremote( GSList * files, gboolean sendquit );
    128125static void
    129126appsetup( TrWindow * wind, GSList * args,
     
    283280}
    284281
     282struct rpc_data
     283{
     284    int type;
     285    int torrentId;
     286    tr_torrent * tor;
     287    struct cbdata * cbdata;
     288};
     289
     290static int
     291onRPCIdle( void * vdata )
     292{
     293    struct rpc_data * data = vdata;
     294    switch( data->type )
     295    {
     296        case TR_RPC_TORRENT_ADDED:
     297            tr_core_add_torrent( data->cbdata->core, tr_torrent_new_preexisting( data->tor ) );
     298            break;
     299        case TR_RPC_TORRENT_STARTED:
     300            /* this should be automatic */
     301            break;
     302        case TR_RPC_TORRENT_STOPPED:
     303            /* this should be automatic */
     304            break;
     305        case TR_RPC_TORRENT_CLOSING:
     306            /* FIXME */
     307            break;
     308        case TR_RPC_TORRENT_CHANGED:
     309        case TR_RPC_SESSION_CHANGED:
     310            /* nothing interesting to do here */
     311            break;
     312    }
     313    g_free( data );
     314    return FALSE;
     315}
     316
     317static void
     318onRPCChanged( tr_handle            * handle UNUSED,
     319              tr_rpc_callback_type   type,
     320              struct tr_torrent    * tor,
     321              void                 * cbdata )
     322{
     323    /* this callback is being invoked from the libtransmission thread,
     324     * so let's push the information over to the gtk+ thread where
     325     * it's safe to update the gui */
     326    struct rpc_data * data = g_new0( struct rpc_data, 1 );
     327    data->type = type;
     328    data->torrentId = tor ? tr_torrentId( tor ) : -1;
     329    data->tor = type == TR_RPC_TORRENT_CLOSING ? NULL : tor;
     330    data->cbdata = cbdata;
     331    g_idle_add( onRPCIdle, data );
     332}
     333
    285334int
    286335main( int argc, char ** argv )
    287336{
    288     gboolean do_inhibit;
    289     guint inhibit_cookie;
    290337    char * err = NULL;
    291338    struct cbdata * cbdata;
     
    294341    gboolean didinit = FALSE;
    295342    gboolean didlock = FALSE;
    296     gboolean sendquit = FALSE;
    297343    gboolean startpaused = FALSE;
    298344    gboolean startminimized = FALSE;
     
    303349        { "paused", 'p', 0, G_OPTION_ARG_NONE, &startpaused,
    304350          _("Start with all torrents paused"), NULL },
    305         { "quit", 'q', 0, G_OPTION_ARG_NONE, &sendquit,
    306           _( "Ask the running instance to quit"), NULL },
    307351#ifdef STATUS_ICON_SUPPORTED
    308352        { "minimized", 'm', 0, G_OPTION_ARG_NONE, &startminimized,
     
    332376        return 0;
    333377    }
    334     if( !configDir )
     378    if( configDir == NULL )
    335379        configDir = (char*) tr_getDefaultConfigDir( );
    336380
     
    345389    gtk_window_set_default_icon_name ( "transmission" );
    346390
     391    setupsighandlers( ); /* set up handlers for fatal signals */
     392
     393    /* either get a lockfile s.t. this is the one instance of
     394     * transmission that's running, OR if there are files to
     395     * be added, delegate that to the running instance via dbus */
     396    didlock = cf_lock( &err );
    347397    argfiles = checkfilenames( argc-1, argv+1 );
    348     didlock = didinit && sendremote( argfiles, sendquit );
    349     setupsighandlers( ); /* set up handlers for fatal signals */
    350 
    351     if( ( didinit || cf_init( configDir, &err ) ) &&
    352         ( didlock || cf_lock( &err ) ) )
    353     {
    354         tr_handle * h = tr_initFull( configDir,
    355                                      "gtk",
    356                                      pref_flag_get( PREF_KEY_PEX ),
    357                                      pref_flag_get( PREF_KEY_NAT ),
    358                                      pref_int_get( PREF_KEY_PORT ),
    359                                      pref_flag_get( PREF_KEY_ENCRYPTED_ONLY )
    360                                          ? TR_ENCRYPTION_REQUIRED
    361                                          : TR_ENCRYPTION_PREFERRED,
    362                                      pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED ),
    363                                      pref_int_get( PREF_KEY_UL_LIMIT ),
    364                                      pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED ),
    365                                      pref_int_get( PREF_KEY_DL_LIMIT ),
    366                                      pref_int_get( PREF_KEY_MAX_PEERS_GLOBAL ),
    367                                      pref_int_get( PREF_KEY_MSGLEVEL ),
    368                                      TRUE, /* message queueing */
    369                                      pref_flag_get( PREF_KEY_BLOCKLIST_ENABLED ),
    370                                      pref_int_get( PREF_KEY_PEER_SOCKET_TOS ) );
     398    if( !didlock && argfiles )
     399    {
     400        GSList * l;
     401        gboolean delegated = FALSE;
     402        for( l=argfiles; l; l=l->next )
     403            delegated |= gtr_dbus_add_torrent( l->data );
     404        if( delegated )
     405            err = NULL;
     406    }
     407
     408    if( didlock && ( didinit || cf_init( configDir, &err ) ) )
     409    {
     410        gboolean do_inhibit = FALSE;
     411        guint inhibit_cookie = 0;
     412
     413        tr_handle * h = tr_sessionInitFull(
     414                            configDir,
     415                            "gtk",
     416                            pref_string_get( PREF_KEY_DOWNLOAD_DIR ),
     417                            pref_flag_get( PREF_KEY_PEX ),
     418                            pref_flag_get( PREF_KEY_NAT ),
     419                            pref_int_get( PREF_KEY_PORT ),
     420                            pref_flag_get( PREF_KEY_ENCRYPTED_ONLY )
     421                                ? TR_ENCRYPTION_REQUIRED
     422                                : TR_ENCRYPTION_PREFERRED,
     423                            pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED ),
     424                            pref_int_get( PREF_KEY_UL_LIMIT ),
     425                            pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED ),
     426                            pref_int_get( PREF_KEY_DL_LIMIT ),
     427                            pref_int_get( PREF_KEY_MAX_PEERS_GLOBAL ),
     428                            pref_int_get( PREF_KEY_MSGLEVEL ),
     429                            TRUE, /* message queueing */
     430                            pref_flag_get( PREF_KEY_BLOCKLIST_ENABLED ),
     431                            pref_int_get( PREF_KEY_PEER_SOCKET_TOS ),
     432                            pref_flag_get( PREF_KEY_RPC_ENABLED ),
     433                            pref_int_get( PREF_KEY_RPC_PORT ),
     434                            pref_string_get( PREF_KEY_RPC_ACL ) );
    371435        cbdata->core = tr_core_new( h );
    372436
     
    377441
    378442        appsetup( win, argfiles, cbdata, startpaused, startminimized );
    379     }
    380     else
     443        tr_sessionSetRPCCallback( h, onRPCChanged, cbdata );
     444
     445        if(( do_inhibit = pref_flag_get( PREF_KEY_INHIBIT_HIBERNATION )))
     446            inhibit_cookie = gtr_inhibit_hibernation( );
     447
     448        gtk_main();
     449
     450        if( do_inhibit && inhibit_cookie )
     451            gtr_uninhibit_hibernation( inhibit_cookie );
     452    }
     453    else if( err )
    381454    {
    382455        gtk_widget_show( errmsg_full( NULL, (callbackfunc_t)gtk_main_quit,
    383456                                      NULL, "%s", err ) );
    384457        g_free( err );
    385     }
    386 
    387     do_inhibit = pref_flag_get( PREF_KEY_INHIBIT_HIBERNATION );
    388     if( do_inhibit )
    389         inhibit_cookie = gtr_inhibit_hibernation( );
    390 
    391     gtk_main();
    392 
    393     if( do_inhibit && inhibit_cookie )
    394         gtr_uninhibit_hibernation( inhibit_cookie );
     458        gtk_main();
     459    }
    395460
    396461    return 0;
    397 }
    398 
    399 static gboolean
    400 sendremote( GSList * files, gboolean sendquit )
    401 {
    402     const gboolean didlock = cf_lock( NULL );
    403 
    404     /* send files if there's another instance, otherwise start normally */
    405     if( !didlock && files )
    406         exit( ipc_sendfiles_blocking( files ) ? 0 : 1 );
    407 
    408     /* either send a quit message or exit if no other instance */
    409     if( sendquit )
    410         exit( didlock ? 0 : !ipc_sendquit_blocking() );
    411 
    412     return didlock;
    413462}
    414463
     
    447496    torrentFiles = NULL;
    448497    tr_core_torrents_added( cbdata->core );
    449 
    450     /* set up the ipc socket */
    451     ipc_socket_setup( GTK_WINDOW( wind ), cbdata->core );
    452498
    453499    /* set up main window */
     
    890936    {
    891937        const gboolean b = pref_flag_get( key );
    892         tr_sessionSetPortForwardingEnabled( tr_core_handle( cbdata->core ), b );
     938        tr_sessionSetPortForwardingEnabled( tr, b );
     939    }
     940    else if( !strcmp( key, PREF_KEY_RPC_ENABLED ) )
     941    {
     942        tr_sessonSetRPCEnabled( tr, pref_flag_get( key ) );
     943    }
     944    else if( !strcmp( key, PREF_KEY_RPC_PORT ) )
     945    {
     946        tr_sessonSetRPCPort( tr, pref_int_get( key ) );
     947    }
     948    else if( !strcmp( key, PREF_KEY_RPC_ENABLED ) )
     949    {
     950        g_message( "preferences option not recognized: %s", key );
    893951    }
    894952}
  • trunk/gtk/notify.c

    r5583 r5843  
    4747        tr_torrent * tor = tr_torrent_handle( gtor );
    4848        const tr_info * info = tr_torrent_info( gtor );
    49         char * path = g_build_filename( tr_torrentGetFolder(tor), info->files[0].name, NULL );
     49        char * path = g_build_filename( tr_torrentGetDownloadDir(tor), info->files[0].name, NULL );
    5050        gtr_open_file( path );
    5151        g_free( path );
  • trunk/gtk/tr-core.c

    r5819 r5843  
    3030#include <gio/gio.h>
    3131#endif
     32#ifdef HAVE_DBUS_GLIB
     33#include <dbus/dbus-glib.h>
     34#endif
    3235
    3336#include <libtransmission/transmission.h>
     
    3639#include "conf.h"
    3740#include "tr-core.h"
     41#ifdef HAVE_DBUS_GLIB
     42#include "tr-core-dbus.h"
     43#endif
    3844#include "tr-prefs.h"
    3945#include "tr-torrent.h"
     
    5157    GtkTreeModel     * model;
    5258    tr_handle        * handle;
    53     int                nextid;
    5459};
    5560
     
    153158                                        g_cclosure_marshal_VOID__STRING,
    154159                                        G_TYPE_NONE, 1, G_TYPE_STRING );
     160
     161#ifdef HAVE_DBUS_GLIB
     162    {
     163        DBusGConnection * bus = dbus_g_bus_get( DBUS_BUS_SESSION, NULL );
     164        DBusGProxy * bus_proxy = NULL;
     165        if( bus )
     166            bus_proxy = dbus_g_proxy_new_for_name( bus, "org.freedesktop.DBus",
     167                                                        "/org/freedesktop/DBus",
     168                                                        "org.freedesktop.DBus" );
     169        if( bus_proxy ) {
     170            int result = 0;
     171            dbus_g_proxy_call( bus_proxy, "RequestName", NULL,
     172                               G_TYPE_STRING, "com.transmissionbt.Transmission",
     173                               G_TYPE_UINT, 0,
     174                               G_TYPE_INVALID,
     175                               G_TYPE_UINT, &result,
     176                               G_TYPE_INVALID );
     177            if( result == 1 )
     178                dbus_g_object_type_install_info( TR_CORE_TYPE,
     179                                                 &dbus_glib_tr_core_object_info );
     180        }
     181    }
     182#endif
    155183}
    156184
     
    328356                             pref_int_get( PREF_KEY_MAX_PEERS_PER_TORRENT ) );
    329357
    330     if( tr_ctorGetDestination( ctor, TR_FORCE, NULL ) ) {
    331         char * path = pref_string_get( PREF_KEY_DIR_DEFAULT );
    332         tr_ctorSetDestination( ctor, TR_FORCE, path );
     358    if( tr_ctorGetDownloadDir( ctor, TR_FORCE, NULL ) ) {
     359        char * path = pref_string_get( PREF_KEY_DOWNLOAD_DIR );
     360        tr_ctorSetDownloadDir( ctor, TR_FORCE, path );
    333361        g_free( path );
    334362    }
     
    471499        G_TYPE_POINTER,   /* tr_torrent* */
    472500        G_TYPE_INT,       /* tr_stat()->status */
    473         G_TYPE_INT        /* ID for IPC */
     501        G_TYPE_INT        /* tr_torrentId() */
    474502    };
    475503
     
    483511
    484512    p->model    = GTK_TREE_MODEL( store );
    485     p->nextid   = 1;
     513
     514#ifdef HAVE_DBUS_GLIB
     515    {
     516        DBusGConnection * bus = dbus_g_bus_get( DBUS_BUS_SESSION, NULL );
     517        if( bus )
     518            dbus_g_connection_register_g_object( bus,
     519                                                 "/com/transmissionbt/Transmission",
     520                                                 G_OBJECT( self ));
     521    }
     522#endif
     523
    486524}
    487525
     
    539577    {
    540578        core->priv->handle = NULL;
    541         tr_close( handle );
     579        tr_sessionClose( handle );
    542580    }
    543581}
     
    620658
    621659void
    622 tr_core_add_torrent( TrCore * self, TrTorrent * tor )
    623 {
    624     const tr_info * inf = tr_torrent_info( tor );
    625     const tr_stat * torStat = tr_torrent_stat( tor );
     660tr_core_add_torrent( TrCore * self, TrTorrent * gtor )
     661{
     662    const tr_info * inf = tr_torrent_info( gtor );
     663    const tr_stat * torStat = tr_torrent_stat( gtor );
     664    tr_torrent * tor = tr_torrent_handle( gtor );
    626665    char * collated = doCollate( inf->name );
    627666    GtkListStore * store = GTK_LIST_STORE( tr_core_model( self ) );
     
    632671                                       MC_NAME_COLLATED, collated,
    633672                                       MC_HASH,          inf->hashString,
    634                                        MC_TORRENT,       tor,
    635                                        MC_TORRENT_RAW,   tr_torrent_handle( tor ),
     673                                       MC_TORRENT,       gtor,
     674                                       MC_TORRENT_RAW,   tor,
    636675                                       MC_STATUS,        torStat->status,
    637                                        MC_ID,            self->priv->nextid,
     676                                       MC_ID,            tr_torrentId( tor ),
    638677                                       -1);
    639     ++self->priv->nextid;
    640678
    641679    /* cleanup */
    642     g_object_unref( G_OBJECT( tor ) );
     680    g_object_unref( G_OBJECT( gtor ) );
    643681    g_free( collated );
    644682}
     
    650688    int count = 0;
    651689    tr_torrent ** torrents;
    652     char * path;
    653690    tr_ctor * ctor;
    654 
    655     path = getdownloaddir( );
    656691
    657692    ctor = tr_ctorNew( tr_core_handle( self ) );
    658693    if( forcePaused )
    659694        tr_ctorSetPaused( ctor, TR_FORCE, TRUE );
    660     tr_ctorSetDestination( ctor, TR_FALLBACK, path );
    661695    tr_ctorSetPeerLimit( ctor, TR_FALLBACK,
    662696                         pref_int_get( PREF_KEY_MAX_PEERS_PER_TORRENT ) );
    663697
    664     torrents = tr_loadTorrents ( tr_core_handle( self ), ctor, &count );
     698    torrents = tr_sessionLoadTorrents ( tr_core_handle( self ), ctor, &count );
    665699    for( i=0; i<count; ++i )
    666700        tr_core_add_torrent( self, tr_torrent_new_preexisting( torrents[i] ) );
     
    668702    tr_free( torrents );
    669703    tr_ctorFree( ctor );
    670     g_free( path );
    671704
    672705    return count;
     
    698731}
    699732
     733static void
     734add_filename( TrCore       * core,
     735              const char   * filename,
     736              gboolean       doStart,
     737              gboolean       doPrompt )
     738{
     739    tr_handle * handle = tr_core_handle( core );
     740
     741    if( filename && handle )
     742    {
     743        tr_ctor * ctor = tr_ctorNew( handle );
     744        tr_core_apply_defaults( ctor );
     745        tr_ctorSetPaused( ctor, TR_FORCE, !doStart );
     746        if( tr_ctorSetMetainfoFromFile( ctor, filename ) )
     747            tr_ctorFree( ctor );
     748        else if( tr_torrentParse( handle, ctor, NULL ) )
     749            tr_ctorFree( ctor );
     750        else if( doPrompt )
     751            g_signal_emit( core, TR_CORE_GET_CLASS(core)->promptsig, 0, ctor );
     752        else
     753            tr_core_add_ctor( core, ctor );
     754    }
     755}
     756
     757gboolean
     758tr_core_add_file( TrCore      * core,
     759                  const char  * filename,
     760                  gboolean    * success,
     761                  GError     ** err UNUSED )
     762{
     763    add_filename( core, filename,
     764                  pref_flag_get( PREF_KEY_START ),
     765                  pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) );
     766    *success = TRUE;
     767    return TRUE;
     768}
     769
    700770void
    701771tr_core_add_list( TrCore      * core,
     
    705775{
    706776    const gboolean doStart = pref_flag_eval( start, PREF_KEY_START );
    707     const gboolean doPrompt = pref_flag_eval( prompt, PREF_KEY_OPTIONS_PROMPT );
    708 
    709     if( torrentFiles && !isDisposed( core ) )
    710     {
    711         GSList * l;
    712         tr_handle * handle = core->priv->handle;
    713 
    714         for( l=torrentFiles; l!=NULL; l=l->next )
    715         {
    716             tr_ctor * ctor = tr_ctorNew( handle );
    717             tr_core_apply_defaults( ctor );
    718             tr_ctorSetPaused( ctor, TR_FORCE, !doStart );
    719             if( tr_ctorSetMetainfoFromFile( ctor, l->data ) )
    720                 tr_ctorFree( ctor );
    721             else if( tr_torrentParse( handle, ctor, NULL ) )
    722                 tr_ctorFree( ctor );
    723             else if( doPrompt )
    724                 g_signal_emit( core, TR_CORE_GET_CLASS(core)->promptsig, 0, ctor );
    725             else
    726                 tr_core_add_ctor( core, ctor );
    727         }
    728     }
    729 
     777    const gboolean doPrompt = pref_flag_eval( prompt,PREF_KEY_OPTIONS_PROMPT );
     778    GSList * l;
     779    for( l=torrentFiles; l!=NULL; l=l->next )
     780        add_filename( core, l->data, doStart, doPrompt );
    730781    freestrlist( torrentFiles );
    731782}
     
    736787    tr_core_update( self );
    737788    tr_core_errsig( self, TR_CORE_ERR_NO_MORE_TORRENTS, NULL );
    738 }
    739 
    740 void
    741 tr_core_delete_torrent( TrCore * self, GtkTreeIter * iter )
    742 {
    743     TrTorrent * tor;
    744     GtkTreeModel * model = tr_core_model( self );
    745 
    746     gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );
    747     gtk_list_store_remove( GTK_LIST_STORE( model ), iter );
    748     tr_torrentRemoveSaved( tr_torrent_handle( tor ) );
    749 
    750     g_object_unref( G_OBJECT( tor ) );
    751789}
    752790
  • trunk/gtk/tr-core.h

    r5646 r5843  
    135135        tr_core_add_list(c,l,PREF_FLAG_DEFAULT,PREF_FLAG_DEFAULT)
    136136
    137 /**
    138  * Add a torrent.
    139  */
     137
     138/** Add a torrent. */
     139gboolean tr_core_add_file( TrCore*, const char * filename, gboolean * setme_success, GError ** err );
     140
     141/** Add a torrent. */
    140142void tr_core_add_torrent( TrCore*, TrTorrent* );
    141143
     
    149151*******
    150152******/
    151 
    152 void tr_core_delete_torrent( TrCore * self, GtkTreeIter * iter );
    153153
    154154void tr_core_remove_torrent( TrCore * self, TrTorrent * gtor, int deleteFiles );
  • trunk/gtk/tr-prefs.c

    r5782 r5843  
    4646    pref_int_set_default    ( PREF_KEY_PEER_SOCKET_TOS, TR_DEFAULT_PEER_SOCKET_TOS );
    4747    pref_flag_set_default   ( PREF_KEY_INHIBIT_HIBERNATION, TRUE );
    48     pref_flag_set_default   ( PREF_KEY_BLOCKLIST_ENABLED, FALSE );
     48    pref_flag_set_default   ( PREF_KEY_BLOCKLIST_ENABLED, TR_DEFAULT_BLOCKLIST_ENABLED );
    4949
    5050    pref_string_set_default ( PREF_KEY_OPEN_DIALOG_FOLDER, g_get_home_dir( ) );
     
    7474#endif
    7575    if( !str ) str = g_get_home_dir( );
    76     pref_string_set_default ( PREF_KEY_DIR_DEFAULT, str );
     76    pref_string_set_default ( PREF_KEY_DOWNLOAD_DIR, str );
    7777
    7878    pref_int_set_default    ( PREF_KEY_PORT, TR_DEFAULT_PORT );
     
    9191    pref_flag_set_default   ( PREF_KEY_START, TRUE );
    9292    pref_flag_set_default   ( PREF_KEY_TRASH_ORIGINAL, FALSE );
     93
     94    pref_flag_set_default   ( PREF_KEY_RPC_ENABLED, TR_DEFAULT_RPC_ENABLED );
     95    pref_int_set_default    ( PREF_KEY_RPC_PORT, TR_DEFAULT_RPC_PORT );
     96    pref_string_set_default ( PREF_KEY_RPC_ACL, TR_DEFAULT_RPC_ACL );
    9397
    9498    pref_save( NULL );
     
    269273        hig_workarea_add_wide_control( t, &row, w );
    270274
    271         w = new_path_chooser_button( PREF_KEY_DIR_DEFAULT, core );
     275        w = new_path_chooser_button( PREF_KEY_DOWNLOAD_DIR, core );
    272276        hig_workarea_add_row( t, &row, _( "_Destination folder:" ), w, NULL );
    273277
     
    525529        hig_workarea_add_row_w( t, &row, w, w2, NULL );
    526530
    527     hig_workarea_add_section_title (t, &row, _("Ports"));
     531    hig_workarea_add_section_title (t, &row, _( "Ports" ) );
    528532       
    529533        s = _("_Forward port from router" );
     
    546550        g_signal_connect( w, "toggled", G_CALLBACK(testing_port_cb), l );
    547551        g_signal_connect( w2, "value-changed", G_CALLBACK(testing_port_cb), l );
     552
     553        s = _( "Listen for _RPC requests on port:" );
     554        w = new_check_button( s, PREF_KEY_RPC_ENABLED, core );
     555        w2 = new_spin_button( PREF_KEY_RPC_PORT, core, 0, 65535, 1 );
     556        gtk_widget_set_sensitive( GTK_WIDGET(w2), pref_flag_get( PREF_KEY_RPC_ENABLED ) );
     557        g_signal_connect( w, "toggled", G_CALLBACK(target_cb), w2 );
     558        hig_workarea_add_row_w( t, &row, w, w2, NULL );
    548559
    549560    hig_workarea_finish( t, &row );
  • trunk/gtk/tr-prefs.h

    r5662 r5843  
    2626#define PREF_KEY_UL_LIMIT               "upload-limit"
    2727#define PREF_KEY_OPTIONS_PROMPT         "show-options-window"
    28 #define PREF_KEY_DIR_DEFAULT            "default-download-directory"
     28#define PREF_KEY_DOWNLOAD_DIR           "default-download-directory"
    2929#define PREF_KEY_OPEN_DIALOG_FOLDER     "open-dialog-folder"
    3030#define PREF_KEY_INHIBIT_HIBERNATION    "inhibit-hibernation"
     
    5454#define PREF_KEY_MAIN_WINDOW_X          "main-window-x"
    5555#define PREF_KEY_MAIN_WINDOW_Y          "main-window-y"
     56#define PREF_KEY_RPC_PORT               "rpc-port"
     57#define PREF_KEY_RPC_ENABLED            "rpc-enabled"
     58#define PREF_KEY_RPC_ACL                "rpc-access-control-list"
    5659
    5760
  • trunk/gtk/tr-torrent.c

    r5583 r5843  
    330330    tr_file_index_t i;
    331331    const tr_info * info = tr_torrent_info( gtor );
    332     const char * stop = tr_torrentGetFolder( tr_torrent_handle( gtor ) );
     332    const char * stop = tr_torrentGetDownloadDir( tr_torrent_handle( gtor ) );
    333333
    334334    for( i=0; info && i<info->fileCount; ++i )
     
    352352    const tr_info * info = tr_torrent_info( gtor );
    353353    char * path = info->fileCount == 1
    354         ? g_build_filename( tr_torrentGetFolder(tor), NULL )
    355         : g_build_filename( tr_torrentGetFolder(tor), info->name, NULL );
     354        ? g_build_filename( tr_torrentGetDownloadDir(tor), NULL )
     355        : g_build_filename( tr_torrentGetDownloadDir(tor), info->name, NULL );
    356356    gtr_open_file( path );
    357357    g_free( path );
  • trunk/gtk/util.c

    r5735 r5843  
    272272}
    273273
    274 char *
    275 getdownloaddir( void )
    276 {
    277     static char * wd = NULL;
    278     char * dir = pref_string_get( PREF_KEY_DIR_DEFAULT );
    279     if ( dir == NULL ) {
    280         if( wd == NULL )
    281             wd = g_get_current_dir();
    282         dir = g_strdup( wd );
    283     }
    284     return dir;
    285 }
    286 
    287274static void
    288275onErrorResponse(GtkWidget * dialog, int resp UNUSED, gpointer glist)
     
    455442
    456443#ifdef HAVE_DBUS_GLIB
     444
    457445static DBusGProxy*
    458446get_hibernation_inhibit_proxy( void )
     
    527515#endif
    528516}
     517
     518#define VALUE_SERVICE_NAME        "com.transmissionbt.Transmission"
     519#define VALUE_SERVICE_OBJECT_PATH "/com/transmissionbt/Transmission"
     520#define VALUE_SERVICE_INTERFACE   "com.transmissionbt.Transmission"
     521
     522gboolean
     523gtr_dbus_add_torrent( const char * filename )
     524{
     525    static gboolean success = FALSE;
     526#ifdef HAVE_DBUS_GLIB
     527    DBusGProxy * proxy = NULL;
     528    GError * err = NULL;
     529    DBusGConnection * conn;
     530    if(( conn = dbus_g_bus_get( DBUS_BUS_SESSION, &err )))
     531        proxy = dbus_g_proxy_new_for_name (conn, VALUE_SERVICE_NAME,
     532                                                 VALUE_SERVICE_OBJECT_PATH,
     533                                                 VALUE_SERVICE_INTERFACE );
     534    else if( err )
     535       g_message( "err: %s", err->message );
     536    if( proxy )
     537        dbus_g_proxy_call( proxy, "AddFile", &err,
     538                           G_TYPE_STRING, filename,
     539                           G_TYPE_INVALID,
     540                           G_TYPE_BOOLEAN, &success,
     541                           G_TYPE_INVALID );
     542    if( err )
     543       g_message( "err: %s", err->message );
     544#endif
     545    return success;
     546}
  • trunk/gtk/util.h

    r5662 r5843  
    3030
    3131/* macro to shut up "unused parameter" warnings */
     32#ifndef UNUSED
    3233#define UNUSED G_GNUC_UNUSED
     34#endif
    3335
    3436/* NULL-safe version of strcmp */
     
    8082checkfilenames( int argc, char ** argv );
    8183
    82 /* retrieve the global download directory */
    83 char *
    84 getdownloaddir( void );
    85 
    8684void gtr_open_file( const char * path );
    8785
     
    8987
    9088void gtr_uninhibit_hibernation( guint );
     89
     90gboolean gtr_dbus_add_torrent( const char * filename );
     91
    9192
    9293#ifdef GTK_MAJOR_VERSION
  • trunk/libtransmission/Makefile.am

    r5828 r5843  
    1717    handshake.c \
    1818    inout.c \
    19     ipcparse.c \
    2019    json.c \
    2120    list.c \
     
    3433    resume.c \
    3534    rpc.c \
     35    rpc-server.c \
    3636    session.c \
    3737    stats.c \
     
    5858    handshake.h \
    5959    inout.h \
    60     ipcparse.h \
    6160    json.h \
    6261    list.h \
     
    7675    resume.h \
    7776    rpc.h \
     77    rpc-server.h \
    7878    session.h \
    7979    stats.h \
     
    8181    tracker.h \
    8282    transmission.h \
    83     trcompat.h \
    8483    trevent.h \
    8584    upnp.h \
     
    10099APPS_LDADD = \
    101100    ./libtransmission.a  \
     101    $(top_builddir)/third-party/shttpd/libshttpd.a \
    102102    $(top_builddir)/third-party/miniupnp/libminiupnp.a \
    103103    $(top_builddir)/third-party/libnatpmp/libnatpmp.a \
  • trunk/libtransmission/bencode-test.c

    r5829 r5843  
    276276{
    277277    char * serialized = tr_rison2json( rison_str, -1 );
     278#if 0
    278279fprintf( stderr, " expected: [%s]\n", expected );
    279280fprintf( stderr, "      got: [%s]\n", serialized );
     281#endif
    280282    check( !strcmp( serialized, expected ) );
    281283    tr_free( serialized );
  • trunk/libtransmission/bencode.c

    r5828 r5843  
    10941094            case '\t': evbuffer_add_printf( data->out, "\\n" ); break;
    10951095            case '\\': evbuffer_add_printf( data->out, "\\\\" ); break;
    1096             default:   evbuffer_add_printf( data->out, "%c", *it ); break;
     1096            default: {
     1097                if( isascii( *it ) )
     1098                    evbuffer_add_printf( data->out, "%c", *it );
     1099                else
     1100                    evbuffer_add_printf( data->out, "\\u%0x", (unsigned int)*it );
     1101                break;
     1102            }
    10971103        }
    10981104    }
  • trunk/libtransmission/bencode.h

    r5821 r5843  
    5656/* backwards compatability */
    5757typedef tr_benc benc_val_t;
    58 
    59 int tr_jsonParse( const void      * buf,
    60                   const void      * bufend,
    61                   tr_benc         * setme_benc,
    62                   const uint8_t  ** setme_end );
    6358
    6459int tr_bencParse( const void      * buf,
  • trunk/libtransmission/blocklist.c

    r5515 r5843  
    9090    b->ruleCount = st.st_size / sizeof( struct tr_ip_range );
    9191    b->fd = fd;
    92     tr_inf( _( "Blocklist contains %'d entries" ), b->ruleCount );
     92    tr_inf( _( "Blocklist contains %'u entries" ), (unsigned int)b->ruleCount );
    9393}
    9494
  • trunk/libtransmission/clients.c

    r5736 r5843  
    3131
    3232#include "transmission.h"
    33 #include "trcompat.h" /* strlcpy */
    3433#include "utils.h"
    3534
     
    9190no_version( char * buf, size_t buflen, const char * name )
    9291{
    93     strlcpy( buf, name, buflen );
     92    tr_strlcpy( buf, name, buflen );
    9493}
    9594
  • trunk/libtransmission/fastresume.c

    r5764 r5843  
    101101    FR_ID_PEERS = 11,
    102102
    103     /* destination of the torrent: zero-terminated string */
    104     FR_ID_DESTINATION = 12,
     103    /* download dir of the torrent: zero-terminated string */
     104    FR_ID_DOWNLOAD_DIR = 12,
    105105
    106106    /* pex flag
     
    153153        struct stat sb;
    154154        tr_buildPath( fname, sizeof(fname),
    155                       tor->destination, tor->info.files[i].name, NULL );
     155                      tor->downloadDir, tor->info.files[i].name, NULL );
    156156        if ( !stat( fname, &sb ) && S_ISREG( sb.st_mode ) ) {
    157157#ifdef SYS_DARWIN
     
    200200    fwrite( &version, 4, 1, file );
    201201
    202     if( TRUE ) /* FR_ID_DESTINATION */
    203     {
    204         const char * d = tor->destination ? tor->destination : "";
     202    if( TRUE ) /* FR_ID_DOWNLOAD_DIR */
     203    {
     204        const char * d = tor->downloadDir ? tor->downloadDir : "";
    205205        const int byteCount = strlen( d ) + 1;
    206         fastResumeWriteData( FR_ID_DESTINATION, d, 1, byteCount, file );
     206        fastResumeWriteData( FR_ID_DOWNLOAD_DIR, d, 1, byteCount, file );
    207207    }
    208208
     
    350350        case FR_ID_CORRUPT:        ret = TR_FR_CORRUPT;       break;
    351351        case FR_ID_PEERS:          ret = TR_FR_PEERS;         break;
    352         case FR_ID_DESTINATION:    ret = TR_FR_DESTINATION;   break;
     352        case FR_ID_DOWNLOAD_DIR:   ret = TR_FR_DOWNLOAD_DIR;  break;
    353353        case FR_ID_MAX_PEERS:      ret = TR_FR_MAX_PEERS;     break;
    354354    }
     
    560560
    561561static uint64_t
    562 parseDestination( tr_torrent * tor, const uint8_t * buf, uint32_t len )
     562parseDownloadDir( tr_torrent * tor, const uint8_t * buf, uint32_t len )
    563563{
    564564    uint64_t ret = 0;
    565565
    566566    if( buf && *buf && len ) {
    567         tr_free( tor->destination );
    568         tor->destination = tr_strndup( (char*)buf, len );
    569         ret = TR_FR_DESTINATION;
     567        tr_free( tor->downloadDir );
     568        tor->downloadDir = tr_strndup( (char*)buf, len );
     569        ret = TR_FR_DOWNLOAD_DIR;
    570570    }
    571571
     
    601601            case FR_ID_PEERS:        ret |= parsePeers( tor, buf, len ); break;
    602602            case FR_ID_MAX_PEERS:    ret |= parseConnections( tor, buf, len ); break;
    603             case FR_ID_DESTINATION:  ret |= parseDestination( tor, buf, len ); break;
     603            case FR_ID_DOWNLOAD_DIR: ret |= parseDownloadDir( tor, buf, len ); break;
    604604            default:                 tr_tordbg( tor, "Skipping unknown resume code %d", (int)id ); break;
    605605        }
  • trunk/libtransmission/fdlimit.c

    r5689 r5843  
    5151#include "net.h"
    5252#include "platform.h" /* tr_lock */
    53 #include "trcompat.h" /* strlcpy */
    5453#include "utils.h"
    5554
     
    265264
    266265        dbgmsg( "opened '%s' in slot %d, write %c", filename, winner, write?'y':'n' );
    267         strlcpy( o->filename, filename, sizeof( o->filename ) );
     266        tr_strlcpy( o->filename, filename, sizeof( o->filename ) );
    268267        o->isWritable = write;
    269268    }
  • trunk/libtransmission/inout.c

    r5655 r5843  
    6161    assert( fileOffset + buflen <= file->length );
    6262
    63     tr_buildPath ( path, sizeof(path), tor->destination, file->name, NULL );
     63    tr_buildPath ( path, sizeof(path), tor->downloadDir, file->name, NULL );
    6464    fileExists = !stat( path, &sb );
    6565
     
    6969    if ((ioMode==TR_IO_READ) && !fileExists ) /* does file exist? */
    7070        err = tr_ioErrorFromErrno( errno );
    71     else if ((fd = tr_fdFileCheckout ( tor->destination,
     71    else if ((fd = tr_fdFileCheckout ( tor->downloadDir,
    7272                                       file->name,
    7373                                       ioMode==TR_IO_WRITE )) < 0)
     
    136136    assert( minBytes <= file->length );
    137137
    138     fd = tr_fdFileCheckout( tor->destination, file->name, TRUE );
     138    fd = tr_fdFileCheckout( tor->downloadDir, file->name, TRUE );
    139139    if( fd < 0 ) /* bad fd */
    140140        err = fd;
  • trunk/libtransmission/json-test.c

    r5810 r5843  
    22#include "transmission.h"
    33#include "bencode.h"
     4#include "json.h"
    45#include "utils.h" /* tr_free */
    56
     
    4041    int64_t i;
    4142    const uint8_t * end = NULL;
    42     const int err = tr_jsonParse( in, in+strlen(in), &top, &end );
     43    const int err = tr_jsonParse( in, strlen(in), &top, &end );
    4344
    4445    check( !err );
  • trunk/libtransmission/json.c

    r5829 r5843  
    121121int
    122122tr_jsonParse( const void      * vbuf,
    123               const void      * bufend,
     123              size_t            len,
    124124              tr_benc         * setme_benc,
    125125              const uint8_t  ** setme_end )
     
    127127    int err = 0;
    128128    const char * buf = vbuf;
     129    const void * bufend = buf + len;
    129130    struct JSON_checker_struct * checker;
    130131    struct json_benc_data data;
  • trunk/libtransmission/json.h

    r5828 r5843  
    1414
    1515int tr_jsonParse( const void       * vbuf,
    16                   const void       * bufend,
     16                  size_t             len,
    1717                  struct tr_benc   * setme_benc,
    1818                  const uint8_t   ** setme_end );
  • trunk/libtransmission/makemeta.c

    r5764 r5843  
    2323
    2424#include "crypto.h" /* tr_sha1 */
    25 #include "trcompat.h" /* strlcpy */
    2625#include "transmission.h"
    2726#include "bencode.h"
     
    127126        char dirbuf[MAX_PATH_LENGTH];
    128127        char basebuf[MAX_PATH_LENGTH];
    129         strlcpy( dirbuf, topFile, sizeof( dirbuf ) );
    130         strlcpy( basebuf, topFile, sizeof( basebuf ) );
     128        tr_strlcpy( dirbuf, topFile, sizeof( dirbuf ) );
     129        tr_strlcpy( basebuf, topFile, sizeof( basebuf ) );
    131130        dir = dirname( dirbuf );
    132131        base = basename( basebuf );
     
    327326    }
    328327
    329     strlcpy( base, builder->top, sizeof( base ) );
     328    tr_strlcpy( base, builder->top, sizeof( base ) );
    330329    tr_bencDictAddStr( dict, "name", basename( base ) );
    331330
     
    368367        if( tr_bencSaveFile( builder->outputFile, &top ) ) {
    369368            builder->my_errno = errno;
    370             strlcpy( builder->errfile, builder->outputFile, sizeof( builder->errfile ) );
     369            tr_strlcpy( builder->errfile, builder->outputFile, sizeof( builder->errfile ) );
    371370            builder->result = TR_MAKEMETA_IO_WRITE;
    372371        }
  • trunk/libtransmission/metainfo.c

    r5739 r5843  
    4040#include "metainfo.h"
    4141#include "platform.h"
    42 #include "trcompat.h" /* strlcpy */
    4342#include "utils.h"
    4443
  • trunk/libtransmission/peer-mgr.c

    r5764 r5843  
    3333#include "ratecontrol.h"
    3434#include "torrent.h"
    35 #include "trcompat.h" /* strlcpy */
    3635#include "trevent.h"
    3736#include "utils.h"
     
    933932            if( TR_ERROR_IS_IO( e->err ) ) {
    934933                t->tor->error = e->err;
    935                 strlcpy( t->tor->errorString, tr_errorString( e->err ), sizeof(t->tor->errorString) );
     934                tr_strlcpy( t->tor->errorString, tr_errorString( e->err ), sizeof(t->tor->errorString) );
    936935                tr_torrentStop( t->tor );
    937936            } else if( e->err == TR_ERROR_ASSERT ) {
     
    14931492
    14941493        tr_netNtop( &peer->in_addr, stat->addr, sizeof(stat->addr) );
    1495         strlcpy( stat->client, (peer->client ? peer->client : ""), sizeof(stat->client) );
     1494        tr_strlcpy( stat->client, (peer->client ? peer->client : ""), sizeof(stat->client) );
    14961495        stat->port               = peer->port;
    14971496        stat->from               = atom->from;
  • trunk/libtransmission/peer-msgs.c

    r5819 r5843  
    11/*
    2  * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
     2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
    33 *
    44 * This file is licensed by the GPL version 2.  Works owned by the
     
    12761276                fireError( msgs, TR_ERROR_PEER_MESSAGE );
    12771277            updatePeerProgress( msgs );
    1278             tr_rcTransferred( msgs->torrent->swarmspeed, msgs->torrent->info.pieceSize );
     1278            tr_rcTransferred( msgs->torrent->swarmSpeed, msgs->torrent->info.pieceSize );
    12791279            break;
    12801280
  • trunk/libtransmission/platform.c

    r5672 r5843  
    5252#include "transmission.h"
    5353#include "platform.h"
    54 #include "trcompat.h"
    5554#include "utils.h"
    5655
     
    310309                       "Transmission", NULL );
    311310#elif defined(__AMIGAOS4__)
    312         strlcpy( buf, "PROGDIR:.transmission", sizeof( buf ) );
     311        tr_strlcpy( buf, "PROGDIR:.transmission", sizeof( buf ) );
    313312#elif defined(WIN32)
    314313        char appdata[MAX_PATH_LENGTH];
     
    449448
    450449const char *
    451 tr_getConfigDir( const tr_handle * handle )
     450tr_sessionGetConfigDir( const tr_handle * handle )
    452451{
    453452    return handle->configDir;
  • trunk/libtransmission/resume.c

    r5819 r5843  
    2525#include "utils.h" /* tr_buildPath */
    2626
    27 #define KEY_CORRUPT     "corrupt"
    28 #define KEY_DESTINATION "destination"
    29 #define KEY_DND         "dnd"
    30 #define KEY_DOWNLOADED  "downloaded"
    31 #define KEY_MAX_PEERS   "max-peers"
    32 #define KEY_PAUSED      "paused"
    33 #define KEY_PEERS       "peers"
    34 #define KEY_PRIORITY    "priority"
    35 #define KEY_PROGRESS    "progress"
    36 #define KEY_SPEEDLIMIT  "speed-limit"
    37 #define KEY_UPLOADED    "uploaded"
     27#define KEY_CORRUPT      "corrupt"
     28#define KEY_DOWNLOAD_DIR "destination"
     29#define KEY_DND          "dnd"
     30#define KEY_DOWNLOADED   "downloaded"
     31#define KEY_MAX_PEERS    "max-peers"
     32#define KEY_PAUSED       "paused"
     33#define KEY_PEERS        "peers"
     34#define KEY_PRIORITY     "priority"
     35#define KEY_PROGRESS     "progress"
     36#define KEY_SPEEDLIMIT   "speed-limit"
     37#define KEY_UPLOADED     "uploaded"
    3838
    3939#define KEY_SPEEDLIMIT_DOWN_SPEED "down-speed"
     
    350350    tr_bencDictAddInt( &top, KEY_CORRUPT,
    351351                             tor->corruptPrev + tor->corruptCur );
    352     tr_bencDictAddStr( &top, KEY_DESTINATION,
    353                              tor->destination );
     352    tr_bencDictAddStr( &top, KEY_DOWNLOAD_DIR,
     353                             tor->downloadDir );
    354354    tr_bencDictAddInt( &top, KEY_DOWNLOADED,
    355355                             tor->downloadedPrev + tor->downloadedCur );
     
    407407    }
    408408
    409     if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DESTINATION ) )
    410             && tr_bencDictFindStr( &top, KEY_DESTINATION, &str ) ) {
    411         tr_free( tor->destination );
    412         tor->destination = tr_strdup( str );
    413         fieldsLoaded |= TR_FR_DESTINATION;
     409    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) )
     410            && tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) ) {
     411        tr_free( tor->downloadDir );
     412        tor->downloadDir = tr_strdup( str );
     413        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
    414414    }
    415415
     
    474474            ret |= TR_FR_MAX_PEERS;
    475475
    476     if( fields & TR_FR_DESTINATION ) {
    477         const char * destination;
    478         if( !tr_ctorGetDestination( ctor, mode, &destination ) ) {
    479             ret |= TR_FR_DESTINATION;
    480             tr_free( tor->destination );
    481             tor->destination = tr_strdup( destination );
     476    if( fields & TR_FR_DOWNLOAD_DIR ) {
     477        const char * downloadDir;
     478        if( !tr_ctorGetDownloadDir( ctor, mode, &downloadDir ) ) {
     479            ret |= TR_FR_DOWNLOAD_DIR;
     480            tr_free( tor->downloadDir );
     481            tor->downloadDir = tr_strdup( downloadDir );
    482482        }
    483483    }
  • trunk/libtransmission/resume.h

    r5614 r5843  
    1616enum
    1717{
    18   TR_FR_DOWNLOADED   = (1<<0),
    19   TR_FR_UPLOADED     = (1<<1),
    20   TR_FR_CORRUPT      = (1<<2),
    21   TR_FR_PEERS        = (1<<3),
    22   TR_FR_PROGRESS     = (1<<4),
    23   TR_FR_DND          = (1<<5),
    24   TR_FR_PRIORITY     = (1<<6),
    25   TR_FR_SPEEDLIMIT   = (1<<7),
    26   TR_FR_RUN          = (1<<8),
    27   TR_FR_DESTINATION  = (1<<9),
    28   TR_FR_MAX_PEERS    = (1<<10)
     18  TR_FR_DOWNLOADED    = (1<<0),
     19  TR_FR_UPLOADED      = (1<<1),
     20  TR_FR_CORRUPT       = (1<<2),
     21  TR_FR_PEERS         = (1<<3),
     22  TR_FR_PROGRESS      = (1<<4),
     23  TR_FR_DND           = (1<<5),
     24  TR_FR_PRIORITY      = (1<<6),
     25  TR_FR_SPEEDLIMIT    = (1<<7),
     26  TR_FR_RUN           = (1<<8),
     27  TR_FR_DOWNLOAD_DIR  = (1<<9),
     28  TR_FR_MAX_PEERS     = (1<<10)
    2929};
    3030
  • trunk/libtransmission/rpc.c

    r5829 r5843  
    1212
    1313#include <assert.h>
     14#include <ctype.h> /* isdigit */
     15#include <stdlib.h> /* strtol */
    1416#include <string.h> /* strcmp */
    1517
     
    1820#include "rpc.h"
    1921#include "json.h"
     22#include "session.h"
    2023#include "torrent.h"
    2124#include "utils.h"
    2225
    23 #define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( (ary)[0] ) )
     26#define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( *ary ) )
    2427
    2528/***
     
    2730***/
    2831
     32static void
     33notify( tr_handle * session, int type, tr_torrent * tor )
     34{
     35    if( session->rpc_func != NULL )
     36        session->rpc_func( session, type, tor, session->rpc_func_user_data );
     37}
     38
     39/***
     40****
     41***/
     42
    2943static tr_torrent **
    3044getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
    3145{
     46    int64_t id;
    3247    tr_torrent ** torrents = NULL;
    3348    int torrentCount = 0;
     
    5570        }
    5671    }
     72    else if( tr_bencDictFindInt( args, "ids", &id )
     73          || tr_bencDictFindInt( args, "id", &id ) )
     74    {
     75        tr_torrent * tor;
     76        torrents = tr_new0( tr_torrent*, 1 );
     77        if(( tor = tr_torrentFindFromId( handle, id )))
     78            torrents[torrentCount++] = tor;
     79    }
    5780    else /* all of them */
    5881    {
     
    6891}
    6992
    70 typedef void( *tor_func )( tr_torrent * tor );
    71 
    72 static void
    73 callTorrentFunc( tr_handle * h, tr_benc * args_in, tor_func func )
     93static const char*
     94torrentStart( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
    7495{
    7596    int i, torrentCount;
    7697    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
    7798    for( i=0; i<torrentCount; ++i )
    78         ( *func )( torrents[i] );
    79     tr_free( torrents );
    80 }
    81 
    82 static const char*
    83 torrentStart( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
    84 {
    85     callTorrentFunc( h, args_in, tr_torrentStart );
     99    {
     100        tr_torrent * tor = torrents[i];
     101        tr_torrentStart( tor );
     102        notify( h, TR_RPC_TORRENT_STARTED, tor );
     103    }
     104    tr_free( torrents );
    86105    return NULL;
    87106}
     
    90109torrentStop( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
    91110{
    92     callTorrentFunc( h, args_in, tr_torrentStop );
     111    int i, torrentCount;
     112    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
     113    for( i=0; i<torrentCount; ++i )
     114    {
     115        tr_torrent * tor = torrents[i];
     116        tr_torrentStop( tor );
     117        notify( h, TR_RPC_TORRENT_STOPPED, tor );
     118    }
     119    tr_free( torrents );
    93120    return NULL;
    94121}
     
    97124torrentClose( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
    98125{
    99     callTorrentFunc( h, args_in, tr_torrentClose );
     126    int i, torrentCount;
     127    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
     128    for( i=0; i<torrentCount; ++i )
     129    {
     130        tr_torrent * tor = torrents[i];
     131        notify( h, TR_RPC_TORRENT_CLOSING, tor );
     132        tr_torrentClose( tor );
     133    }
     134    tr_free( torrents );
    100135    return NULL;
    101136}
     
    104139torrentVerify( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
    105140{
    106     callTorrentFunc( h, args_in, tr_torrentVerify );
    107     return NULL;
    108 }
     141    int i, torrentCount;
     142    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
     143    for( i=0; i<torrentCount; ++i )
     144    {
     145        tr_torrent * tor = torrents[i];
     146        tr_torrentVerify( tor );
     147        notify( h, TR_RPC_TORRENT_CHANGED, tor );
     148    }
     149    tr_free( torrents );
     150    return NULL;
     151}
     152
     153/***
     154****
     155***/
    109156
    110157static const char*
     
    113160    int i, torrentCount;
    114161    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
    115     tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount );
     162    tr_benc * list = tr_bencDictAddList( args_out, "torrent-status", torrentCount );
    116163
    117164    for( i=0; i<torrentCount; ++i )
     
    119166        tr_torrent * tor = torrents[i];
    120167        const tr_stat * st = tr_torrentStat( tor );
    121         tr_benc * d = tr_bencListAddDict( list, 32 );
     168        const int * f = st->peersFrom;
     169        const struct tr_tracker_stat * s = &st->trackerStat;
     170        tr_benc * d = tr_bencListAddDict( list, 33 );
    122171        tr_benc * t;
    123         const int * f = st->peersFrom;
    124         const struct tr_tracker_stat * s = &st->tracker_stat;
    125 
    126         tr_bencDictAddInt( d, "id", tor->uniqueId );
    127         tr_bencDictAddInt( d, "status", st->status );
     172
     173        tr_bencDictAddInt( d, "activityDate", st->activityDate );
     174        tr_bencDictAddInt( d, "completedFromTracker", st->completedFromTracker );
     175        tr_bencDictAddInt( d, "corruptEver", st->corruptEver );
     176        tr_bencDictAddInt( d, "desiredAvailable", st->desiredAvailable );
     177        tr_bencDictAddInt( d, "downloadedEver", st->downloadedEver );
    128178        tr_bencDictAddInt( d, "error", st->error );
    129179        tr_bencDictAddStr( d, "errorString", st->errorString );
    130         tr_bencDictAddDouble( d, "recheckProgress", st->recheckProgress );
    131         tr_bencDictAddDouble( d, "percentComplete", st->percentComplete );
    132         tr_bencDictAddDouble( d, "percentDone", st->percentDone );
    133         tr_bencDictAddDouble( d, "rateDownload", st->rateDownload );
    134         tr_bencDictAddDouble( d, "rateUpload", st->rateUpload );
    135         tr_bencDictAddDouble( d, "swarmspeed", st->swarmspeed );
    136         tr_bencDictAddDouble( d, "ratio", st->ratio );
    137180        tr_bencDictAddInt( d, "eta", st->eta );
    138         tr_bencDictAddInt( d, "peersKnown", st->peersKnown );
     181        tr_bencDictAddInt( d, "haveUnchecked", st->haveUnchecked );
     182        tr_bencDictAddInt( d, "haveValid", st->haveValid );
     183        tr_bencDictAddInt( d, "id", tr_torrentId( tor ) );
     184        tr_bencDictAddInt( d, "leechers", st->leechers );
     185        tr_bencDictAddInt( d, "leftUntilDone", st->leftUntilDone );
     186        tr_bencDictAddInt( d, "manualAnnounceTime", st->manualAnnounceTime );
     187        tr_bencDictAddStr( d, "name", tor->info.name );
    139188        tr_bencDictAddInt( d, "peersConnected", st->peersConnected );
    140         tr_bencDictAddInt( d, "peersSendingToUs", st->peersSendingToUs );
    141         tr_bencDictAddInt( d, "peersGettingFromUs", st->peersGettingFromUs );
    142         tr_bencDictAddInt( d, "seeders", st->seeders );
    143         tr_bencDictAddInt( d, "leechers", st->leechers );
    144         tr_bencDictAddInt( d, "completedFromTracker", st->completedFromTracker );
    145         tr_bencDictAddInt( d, "manualAnnounceTime", st->manualAnnounceTime );
    146         tr_bencDictAddInt( d, "sizeWhenDone", st->sizeWhenDone );
    147         tr_bencDictAddInt( d, "leftUntilDone", st->leftUntilDone );
    148         tr_bencDictAddInt( d, "desiredAvailable", st->desiredAvailable );
    149         tr_bencDictAddInt( d, "corruptEver", st->corruptEver );
    150         tr_bencDictAddInt( d, "uploadedEver", st->uploadedEver );
    151         tr_bencDictAddInt( d, "downloadedEver", st->downloadedEver );
    152         tr_bencDictAddInt( d, "haveValid", st->haveValid );
    153         tr_bencDictAddInt( d, "haveUnchecked", st->haveUnchecked );
    154         tr_bencDictAddInt( d, "startDate", st->startDate );
    155         tr_bencDictAddInt( d, "activityDate", st->activityDate );
    156189        t = tr_bencDictAddDict( d, "peersFrom", 4 );
    157190            tr_bencDictAddInt( t, "cache",    f[TR_PEER_FROM_CACHE] );
     
    159192            tr_bencDictAddInt( t, "pex",      f[TR_PEER_FROM_PEX] );
    160193            tr_bencDictAddInt( t, "tracker",  f[TR_PEER_FROM_TRACKER] );
    161         t = tr_bencDictAddDict( d, "tracker_stat", 7 );
     194        tr_bencDictAddInt( d, "peersGettingFromUs", st->peersGettingFromUs );
     195        tr_bencDictAddInt( d, "peersKnown", st->peersKnown );
     196        tr_bencDictAddInt( d, "peersSendingToUs", st->peersSendingToUs );
     197        tr_bencDictAddDouble( d, "percentComplete", st->percentComplete );
     198        tr_bencDictAddDouble( d, "percentDone", st->percentDone );
     199        tr_bencDictAddDouble( d, "rateDownload", st->rateDownload );
     200        tr_bencDictAddDouble( d, "rateUpload", st->rateUpload );
     201        tr_bencDictAddDouble( d, "ratio", st->ratio );
     202        tr_bencDictAddDouble( d, "recheckProgress", st->recheckProgress );
     203        tr_bencDictAddInt( d, "seeders", st->seeders );
     204        tr_bencDictAddInt( d, "sizeWhenDone", st->sizeWhenDone );
     205        tr_bencDictAddInt( d, "startDate", st->startDate );
     206        tr_bencDictAddInt( d, "status", st->status );
     207        tr_bencDictAddDouble( d, "swarmSpeed", st->swarmSpeed );
     208        t = tr_bencDictAddDict( d, "trackerStat", 7 );
     209            tr_bencDictAddStr( t, "announceResponse", s->announceResponse );
     210            tr_bencDictAddInt( t, "lastAnnounceTime", s->lastAnnounceTime );
     211            tr_bencDictAddInt( t, "lastScrapeTime", s->lastScrapeTime );
     212            tr_bencDictAddInt( t, "nextAnnounceTime", s->nextAnnounceTime );
     213            tr_bencDictAddInt( t, "nextScrapeTime", s->nextScrapeTime );
     214            tr_bencDictAddInt( t, "nextScrapeTime", s->nextScrapeTime );
    162215            tr_bencDictAddStr( t, "scrapeResponse", s->scrapeResponse );
    163             tr_bencDictAddStr( t, "announceResponse", s->announceResponse );
    164             tr_bencDictAddInt( t, "lastScrapeTime", s->lastScrapeTime );
    165             tr_bencDictAddInt( t, "nextScrapeTime", s->nextScrapeTime );
    166             tr_bencDictAddInt( t, "lastAnnounceTime", s->lastAnnounceTime );
    167             tr_bencDictAddInt( t, "nextAnnounceTime", s->nextAnnounceTime );
    168             tr_bencDictAddInt( t, "nextManualAnnounceTime",
    169                                                 s->nextManualAnnounceTime );
    170     }
    171 
    172     /* cleanup */
     216        tr_bencDictAddInt( d, "uploadedEver", st->uploadedEver );
     217    }
     218
    173219    tr_free( torrents );
    174220    return NULL;
     
    182228addFiles( const tr_info * info, tr_benc * files )
    183229{
    184     unsigned int i;
     230    tr_file_index_t i;
    185231    for( i=0; i<info->fileCount; ++i )
    186232    {
    187233        const tr_file * file = &info->files[i];
    188234        tr_benc * d = tr_bencListAddDict( files, 4 );
     235        tr_bencDictAddInt( d, "dnd", file->dnd );
    189236        tr_bencDictAddInt( d, "length", file->length );
    190237        tr_bencDictAddStr( d, "name", file->name );
    191238        tr_bencDictAddInt( d, "priority", file->priority );
    192         tr_bencDictAddInt( d, "dnd", file->dnd );
    193239    }
    194240}
     
    202248        const tr_tracker_info * t = &info->trackers[i];
    203249        tr_benc * d = tr_bencListAddDict( trackers, 3 );
    204         tr_bencDictAddInt( d, "tier", t->tier );
    205250        tr_bencDictAddStr( d, "announce", t->announce );
    206251        tr_bencDictAddStr( d, "scrape", t->scrape );
     252        tr_bencDictAddInt( d, "tier", t->tier );
    207253    }
    208254}
     
    216262    tr_bencDictAddStr( d, "creator", inf->creator ? inf->creator : "" );
    217263    tr_bencDictAddInt( d, "dateCreated", inf->dateCreated );
     264    addFiles( inf, tr_bencDictAddList( d, "files", inf->fileCount ) );
    218265    tr_bencDictAddStr( d, "hashString", inf->hashString );
    219     tr_bencDictAddInt( d, "id", tor->uniqueId );
     266    tr_bencDictAddInt( d, "id", tr_torrentId( tor ) );
    220267    tr_bencDictAddInt( d, "isMultifile", inf->isMultifile );
    221268    tr_bencDictAddInt( d, "isPrivate", inf->isPrivate );
     
    225272    tr_bencDictAddStr( d, "torrent", inf->torrent );
    226273    tr_bencDictAddInt( d, "totalSize", inf->totalSize );
    227     addFiles   ( inf, tr_bencDictAddList( d, "files", inf->fileCount ) );
    228274    addTrackers( inf, tr_bencDictAddList( d, "trackers", inf->trackerCount ) );
    229275}
     
    234280    int i, torrentCount;
    235281    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
    236     tr_benc * list = tr_bencDictAddList( args_out, "info", torrentCount );
     282    tr_benc * list = tr_bencDictAddList( args_out, "torrent-info", torrentCount );
    237283
    238284    for( i=0; i<torrentCount; ++i )
     
    248294
    249295static const char*
     296torrentList( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
     297{
     298    int i, torrentCount;
     299    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
     300    tr_benc * list = tr_bencDictAddList( args_out, "list", torrentCount );
     301
     302    for( i=0; i<torrentCount; ++i ) {
     303        tr_torrent * tor = torrents[i];
     304        const tr_stat * st = tr_torrentStat( tor );
     305        tr_benc * d = tr_bencListAddDict( list, 6 );
     306        tr_bencDictAddInt( d, "id", tr_torrentId( tor ) );
     307        tr_bencDictAddStr( d, "name", tor->info.name );
     308        tr_bencDictAddDouble( d, "rateDownload", st->rateDownload );
     309        tr_bencDictAddDouble( d, "rateUpload", st->rateUpload );
     310        tr_bencDictAddDouble( d, "ratio", st->ratio );
     311        tr_bencDictAddInt( d, "status", st->status );
     312    }
     313
     314    tr_free( torrents );
     315    return NULL;
     316}
     317
     318/**
     319***
     320**/
     321
     322static const char*
    250323torrentGet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
    251324{
     
    258331        tr_torrent * tor = torrents[i];
    259332        tr_benc * d = tr_bencListAddDict( list, 6 );
    260         tr_bencDictAddInt( d, "id", tor->uniqueId );
     333        tr_bencDictAddInt( d, "id", tr_torrentId( tor ) );
    261334        tr_bencDictAddInt( d, "peer-limit",
    262335                           tr_torrentGetPeerLimit( tor ) );
     
    278351
    279352static const char*
    280 torrentSet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
    281 {
    282     int i, torrentCount;
    283     tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
     353torrentSet( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
     354{
     355    int i, torrentCount;
     356    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
    284357
    285358    for( i=0; i<torrentCount; ++i )
     
    299372            tr_torrentSetSpeedMode( tor, TR_UP, tmp ? TR_SPEEDLIMIT_SINGLE
    300373                                                    : TR_SPEEDLIMIT_GLOBAL );
     374        notify( h, TR_RPC_TORRENT_CHANGED, tor );
    301375    }
    302376
     
    356430
    357431static const char*
    358 torrentGetPriorities( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
     432torrentGetPriorities( tr_handle * handle,
     433                      tr_benc * args_in, tr_benc * args_out )
    359434{
    360435    int i, torrentCount;
     
    366441        const tr_torrent * tor = torrents[i];
    367442        tr_benc * d = tr_bencListAddDict( list, 6 );
    368         tr_bencDictAddInt( d, "id", tor->uniqueId );
    369         buildFileList( tor, d, "download", testFileDownload );
    370         buildFileList( tor, d, "no-download", testFileDND );
     443        tr_bencDictAddInt( d, "id", tr_torrentId( tor ) );
     444        buildFileList( tor, d, "files-unwanted", testFileDND );
     445        buildFileList( tor, d, "files-wanted", testFileDownload );
    371446        buildFileList( tor, d, "priority-low", testFileLow );
    372447        buildFileList( tor, d, "priority-normal", testFileNormal );
     
    388463
    389464    for( i=0; i<n; ++i )
    390         if( tr_bencGetInt( tr_bencListChild(list,i), &tmp ) )
     465        if( tr_bencGetInt( tr_bencListChild( list, i ), &tmp ) )
    391466            files[fileCount++] = tmp;
    392467
     
    407482
    408483    for( i=0; i<n; ++i )
    409         if( tr_bencGetInt( tr_bencListChild(list,i), &tmp ) )
     484        if( tr_bencGetInt( tr_bencListChild( list, i ), &tmp ) )
    410485            files[fileCount++] = tmp;
    411486
     
    417492
    418493static const char*
    419 torrentSetPriorities( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
     494torrentSetPriorities( tr_handle * h,
     495                      tr_benc * args_in, tr_benc * args_out UNUSED )
    420496{
    421497    int i, torrentCount;
     
    427503        tr_torrent * tor = torrents[i];
    428504
     505        if( tr_bencDictFindList( args_in, "files-unwanted", &files ) )
     506            setFileDLs( tor, FALSE, files );
     507        if( tr_bencDictFindList( args_in, "files-wanted", &files ) )
     508            setFileDLs( tor, TRUE, files );
    429509        if( tr_bencDictFindList( args_in, "priority-high", &files ) )
    430510            setFilePriorities( tor, TR_PRI_HIGH, files );
     
    433513        if( tr_bencDictFindList( args_in, "priority-normal", &files ) )
    434514            setFilePriorities( tor, TR_PRI_NORMAL, files );
    435         if( tr_bencDictFindList( args_in, "download", &files ) )
    436             setFileDLs( tor, TRUE, files );
    437         if( tr_bencDictFindList( args_in, "no-download", &files ) )
    438             setFileDLs( tor, FALSE, files );
     515
     516        notify( h, TR_RPC_TORRENT_CHANGED, tor );
    439517    }
    440518
     
    453531    if( !tr_bencDictFindStr( args_in, "filename", &filename ) )
    454532        return "no filename specified";
    455     else {
     533    else
     534    {
    456535        int64_t i;
    457536        int err = 0;
     
    462541        ctor = tr_ctorNew( h );
    463542        tr_ctorSetMetainfoFromFile( ctor, filename );
    464         if( tr_bencDictFindStr( args_in, "destination", &str ) )
    465             tr_ctorSetDestination( ctor, TR_FORCE, str );
     543        if( tr_bencDictFindStr( args_in, "download-dir", &str ) )
     544            tr_ctorSetDownloadDir( ctor, TR_FORCE, str );
    466545        if( tr_bencDictFindInt( args_in, "paused", &i ) )
    467546            tr_ctorSetPaused( ctor, TR_FORCE, i );
     
    471550        tr_ctorFree( ctor );
    472551
    473         if( tor )
     552        if( tor ) {
    474553            addInfo( tor, tr_bencDictAdd( args_out, "torrent-added" ) );
    475         else if( err == TR_EDUPLICATE )
     554            notify( h, TR_RPC_TORRENT_ADDED, tor );
     555        } else if( err == TR_EDUPLICATE ) {
    476556            return "duplicate torrent";
    477         else if( err == TR_EINVALID )
     557        } else if( err == TR_EINVALID ) {
    478558            return "invalid or corrupt torrent file";
     559        }
    479560    }
    480561
     
    492573    const char * str;
    493574
     575    if( tr_bencDictFindStr( args_in, "download-dir", &str ) )
     576        tr_sessionSetDownloadDir( h, str );
    494577    if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
    495578        tr_sessionSetPeerLimit( h, i );
     
    517600    }
    518601
     602    notify( h, TR_RPC_SESSION_CHANGED, NULL );
     603
    519604    return NULL;
    520605}
     
    524609{
    525610    const char * str;
    526     tr_benc * d = tr_bencDictAddDict( args_out, "session", 9 );
    527 
     611    tr_benc * d = tr_bencDictAddDict( args_out, "session", 10 );
     612
     613    tr_bencDictAddStr( d, "download-dir",
     614                          tr_sessionGetDownloadDir( h ) );
    528615    tr_bencDictAddInt( d, "peer-limit",
    529616                          tr_sessionGetPeerLimit( h ) );
     
    560647typedef const char* (handler)( tr_handle*, tr_benc*, tr_benc* );
    561648
    562 struct method
    563 {
     649struct method {
    564650    const char * name;
    565651    handler * func;
    566652} methods[] = {
     653    { "session-get", sessionGet },
     654    { "session-set", sessionSet },
     655    { "torrent-add", torrentAdd },
     656    { "torrent-close", torrentClose },
     657    { "torrent-get-priorities", torrentGetPriorities },
     658    { "torrent-get", torrentGet },
     659    { "torrent-info", torrentInfo },
     660    { "torrent-list", torrentList },
     661    { "torrent-set-priorities", torrentSetPriorities },
     662    { "torrent-set", torrentSet },
    567663    { "torrent-start", torrentStart },
     664    { "torrent-status", torrentStatus },
    568665    { "torrent-stop", torrentStop },
    569     { "torrent-close", torrentClose },
    570     { "torrent-verify", torrentVerify },
    571     { "torrent-status", torrentStatus },
    572     { "torrent-info", torrentInfo },
    573     { "torrent-add", torrentAdd },
    574     { "torrent-set", torrentSet },
    575     { "torrent-get", torrentGet },
    576     { "torrent-set-priorities", torrentSetPriorities },
    577     { "torrent-get-priorities", torrentGetPriorities },
    578     { "session-set", sessionSet },
    579     { "session-get", sessionGet }
     666    { "torrent-verify", torrentVerify }
    580667};
    581668
     
    589676    char * out;
    590677    tr_benc response;
    591     tr_benc * args_in = tr_bencDictFind( request, "args" );
     678    tr_benc * args_in = tr_bencDictFind( request, "arguments" );
    592679    tr_benc * args_out = NULL;
    593680    const char * result = NULL;
     
    595682    /* build the response skeleton */
    596683    tr_bencInitDict( &response, 3 );
    597     if( tr_bencDictFindInt( request, "tag", &i ) )
    598         tr_bencDictAddInt( request, "tag", i );
    599     args_out = tr_bencDictAddDict( &response, "args", 0 );
     684    args_out = tr_bencDictAddDict( &response, "arguments", 0 );
    600685
    601686    /* parse the request */
     
    616701         result = "success";
    617702    tr_bencDictAddStr( &response, "result", result );
    618 fprintf( stderr, "response [%s]", tr_bencSave( &response, NULL ) );
    619 tr_bencPrint( &response );
     703    if( tr_bencDictFindInt( request, "tag", &i ) )
     704        tr_bencDictAddInt( &response, "tag", i );
    620705    out = tr_bencSaveAsJSON( &response, response_len );
    621706    tr_bencFree( &response );
     
    625710char*
    626711tr_rpc_request_exec_json( struct tr_handle  * handle,
    627                          const void         * request_json,
    628                          int                  request_len,
    629                          int                * response_len )
     712                          const void        * request_json,
     713                          int                 request_len,
     714                          int               * response_len )
    630715{
    631716    tr_benc top;
     
    636721        request_len = strlen( request_json );
    637722
    638     have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
     723    have_content = !tr_jsonParse( request_json, request_len, &top, NULL );
    639724    ret = request_exec( handle, have_content ? &top : NULL, response_len );
    640725
     
    645730
    646731char*
    647 tr_rpc_request_exec_rison( struct tr_handle  * handle,
    648                            const void        * request_rison,
    649                            int                 request_len,
    650                            int               * response_len )
     732tr_rpc_request_exec_uri( struct tr_handle  * handle,
     733                         const void        * request_uri,
     734                         int                 request_len,
     735                         int               * response_len )
    651736{
    652737    char * ret = NULL;
    653     tr_benc top;
    654     int have_content;
    655     char * request = tr_strndup( request_rison, request_len );;
    656 
    657 fprintf( stderr, "passed in: --> %s <--\n", request );
    658     /* possibly convert o-rison to rison */
    659     if( request && ( *request != '(' ) )
    660     {
    661         const int n = strlen( request );
    662         char * tmp = tr_new( char, n + 3 );
    663         tmp[0] = '(';
    664         memcpy( tmp+1, request, n );
    665         tmp[n+1] = ')';
    666         tmp[n+2] = '\0';
    667         tr_free( request );
    668         request = tmp;
    669     }
    670 fprintf( stderr, "after o-rison conversion: --> %s <--\n", request );
    671 
    672     /* convert rison to json */
    673     {
    674         char * tmp = tr_rison2json( request, strlen( request ) );
    675         tr_free( request );
    676         request = tmp;
    677     }
    678 fprintf( stderr, "after json conversion: --> %s <--\n", request );
    679 
    680     /* parse the json */
    681     have_content = !tr_jsonParse( request, request+strlen(request), &top, NULL );
    682     if( have_content )
    683     {
    684         /* for convenience' sake, our URI rpc notation allows the
    685          * `args' object to be declared implicitly... */
    686         tr_benc tmp, *args;
    687         int64_t i;
    688         const char * str;
    689         tr_bencInitDict( &tmp, 3 );
    690         if( tr_bencDictFindInt( &top, "tag", &i ) )
    691             tr_bencDictAddInt( &tmp, "tag", i );
    692         if( tr_bencDictFindStr( &top, "method", &str ) )
    693             tr_bencDictAddStr( &tmp, "method", str );
    694         args = tr_bencDictAdd( &tmp, "args" );
    695         *args = top;
    696 tr_bencPrint( &tmp);
    697         ret = request_exec( handle, &tmp, response_len );
    698         tr_bencInitInt( args, 0 );
    699         tr_bencFree( &tmp );
    700         tr_bencFree( &top );
    701     }
    702 
     738    tr_benc top, * args;
     739    char * request = tr_strndup( request_uri, request_len );
     740    const char * pch;
     741
     742    tr_bencInitDict( &top, 3 );
     743    args = tr_bencDictAddDict( &top, "arguments", 0 );
     744
     745    /* munge the URI into a usable form.
     746     * we have very loose typing on this to make the URIs as simple as possible:
     747     * - anything not a 'tag' or 'method' is automatically in 'arguments'
     748     * - values that are all-digits are numbers
     749     * - values that are all-digits or commas are number lists
     750     * - all other values are strings
     751     */
     752
     753    pch = strchr( request, '?' );
     754    if( !pch ) pch = request;
     755    while( pch )
     756    {
     757        const char * delim = strchr( pch, '=' );
     758        const char * next = strchr( pch, '&' );
     759        if( delim )
     760        {
     761            int isNum = 1;
     762            int isNumList = 1;
     763            const char * walk;
     764            char * key = tr_strndup( pch, delim-pch );
     765            int isArg = strcmp( key, "method" ) && strcmp( key, "tag" );
     766            tr_benc * parent = isArg ? args : &top;
     767            char * val = next ? tr_strndup( delim+1, next-(delim+1) )
     768                              : tr_strdup( delim+1 );
     769            for( walk=val; *walk && ( isNumList || isNum ); ++walk ) {
     770                if( isNumList ) isNumList = *walk=='-' || isdigit(*walk) || *walk==',';
     771                if( isNum     ) isNum     = *walk=='-' || isdigit(*walk);
     772            }
     773            if( isNum )
     774                tr_bencDictAddInt( parent, key, strtol( val, NULL, 10 ) );
     775            else if( !isNumList )
     776                tr_bencDictAddStr( parent, key, val );
     777            else {
     778                tr_benc * numList = tr_bencDictAddList( parent, key, 10 );
     779                walk = val;
     780                for( ;; ) {
     781                    char * end;
     782                    tr_bencListAddInt( numList, strtol( walk, &end, 10 ) );
     783                    if( *end!=',' )
     784                        break;
     785                    walk = end + 1;
     786                }
     787            }
     788        }
     789        pch = next ? next+1 : NULL;
     790    }
     791
     792    ret = request_exec( handle, &top, response_len );
     793
     794    /* cleanup */
     795    tr_bencFree( &top );
    703796    tr_free( request );
    704797    return ret;
  • trunk/libtransmission/rpc.h

    r5828 r5843  
    1414#define TR_RPC_H
    1515
     16/***
     17****  RPC processing
     18***/
     19
    1620struct tr_handle;
    1721
     
    2327                          int               * response_len );
    2428
    25 /* http://mjtemplate.org/examples/rison.html */
     29/* see the RPC spec's "Request URI Notation" section */
    2630char*
    27 tr_rpc_request_exec_rison( struct tr_handle  * handle,
    28                            const void        * request_rison,
    29                            int                 request_len,
    30                            int               * response_len );
     31tr_rpc_request_exec_uri( struct tr_handle  * handle,
     32                         const void        * request_uri,
     33                         int                 request_len,
     34                         int               * response_len );
    3135
    3236#endif
  • trunk/libtransmission/session.c

    r5819 r5843  
    4343#include "port-forwarding.h"
    4444#include "ratecontrol.h"
     45#include "rpc-server.h"
    4546#include "stats.h"
    4647#include "torrent.h"
     
    119120
    120121tr_handle *
    121 tr_initFull( const char * configDir,
    122              const char * tag,
    123              int          isPexEnabled,
    124              int          isPortForwardingEnabled,
    125              int          publicPort,
    126              int          encryptionMode,
    127              int          isUploadLimitEnabled,
    128              int          uploadLimit,
    129              int          isDownloadLimitEnabled,
    130              int          downloadLimit,
    131              int          globalPeerLimit,
    132              int          messageLevel,
    133              int          isMessageQueueingEnabled,
    134              int          isBlocklistEnabled,
    135              int          peerSocketTOS )
     122tr_sessionInitFull( const char * configDir,
     123                    const char * downloadDir,
     124                    const char * tag,
     125                    int          isPexEnabled,
     126                    int          isPortForwardingEnabled,
     127                    int          publicPort,
     128                    int          encryptionMode,
     129                    int          isUploadLimitEnabled,
     130                    int          uploadLimit,
     131                    int          isDownloadLimitEnabled,
     132                    int          downloadLimit,
     133                    int          globalPeerLimit,
     134                    int          messageLevel,
     135                    int          isMessageQueueingEnabled,
     136                    int          isBlocklistEnabled,
     137                    int          peerSocketTOS,
     138                    int          rpcIsEnabled,
     139                    int          rpcPort,
     140                    const char * rpcACL )
    136141{
    137142    tr_handle * h;
     
    155160    h->encryptionMode = encryptionMode;
    156161    h->peerSocketTOS = peerSocketTOS;
     162    h->downloadDir = tr_strdup( downloadDir );
    157163
    158164    tr_setConfigDir( h, configDir );
     
    194200
    195201    h->web = tr_webInit( h );
     202    h->rpcServer = tr_rpcInit( h, rpcIsEnabled, rpcPort, rpcACL );
    196203
    197204    metainfoLookupRescan( h );
     
    201208
    202209tr_handle *
    203 tr_init( const char * configDir,
    204          const char * tag )
    205 {
    206     return tr_initFull( configDir,
    207                         tag,
    208                         TR_DEFAULT_PEX_ENABLED,
    209                         TR_DEFAULT_PORT_FORWARDING_ENABLED,
    210                         -1, /* public port */
    211                         TR_ENCRYPTION_PREFERRED, /* encryption mode */
    212                         FALSE, /* use upload speed limit? */
    213                         -1, /* upload speed limit */
    214                         FALSE, /* use download speed limit? */
    215                         -1, /* download speed limit */
    216                         TR_DEFAULT_GLOBAL_PEER_LIMIT,
    217                         TR_MSG_INF, /* message level */
    218                         FALSE, /* is message queueing enabled? */
    219                         FALSE, /* is the blocklist enabled? */
    220                         TR_DEFAULT_PEER_SOCKET_TOS );
     210tr_sessionInit( const char * configDir,
     211                const char * downloadDir,
     212                const char * tag )
     213{
     214    return tr_sessionInitFull( configDir,
     215                               downloadDir,
     216                               tag,
     217                               TR_DEFAULT_PEX_ENABLED,
     218                               TR_DEFAULT_PORT_FORWARDING_ENABLED,
     219                               -1, /* public port */
     220                               TR_ENCRYPTION_PREFERRED, /* encryption mode */
     221                               FALSE, /* use upload speed limit? */
     222                               -1, /* upload speed limit */
     223                               FALSE, /* use download speed limit? */
     224                               -1, /* download speed limit */
     225                               TR_DEFAULT_GLOBAL_PEER_LIMIT,
     226                               TR_MSG_INF, /* message level */
     227                               FALSE, /* is message queueing enabled? */
     228                               FALSE, /* is the blocklist enabled? */
     229                               TR_DEFAULT_PEER_SOCKET_TOS,
     230                               TR_DEFAULT_RPC_ENABLED,
     231                               TR_DEFAULT_RPC_PORT,
     232                               TR_DEFAULT_RPC_ACL );
     233}
     234
     235/***
     236****
     237***/
     238
     239void
     240tr_sessionSetDownloadDir( tr_handle * handle, const char * dir )
     241{
     242    if( handle->downloadDir != dir )
     243    {
     244        tr_free( handle->downloadDir );
     245        handle->downloadDir = tr_strdup( dir );
     246    }
     247}
     248
     249const char *
     250tr_sessionGetDownloadDir( const tr_handle * handle )
     251{
     252    return handle->downloadDir;
    221253}
    222254
     
    391423    tr_sharedShuttingDown( h->shared );
    392424    tr_trackerShuttingDown( h );
     425    tr_rpcClose( &h->rpcServer );
    393426
    394427    while(( tor = tr_torrentNext( h, NULL )))
     
    412445
    413446void
    414 tr_close( tr_handle * h )
     447tr_sessionClose( tr_handle * h )
    415448{
    416449    int i;
     
    446479
    447480tr_torrent **
    448 tr_loadTorrents ( tr_handle   * h,
    449                   tr_ctor     * ctor,
    450                   int         * setmeCount )
     481tr_sessionLoadTorrents ( tr_handle   * h,
     482                         tr_ctor     * ctor,
     483                         int         * setmeCount )
    451484{
    452485    int i, n = 0;
     
    492525        tr_inf( _( "Loaded %d torrents" ), n );
    493526
    494     *setmeCount = n;
     527    if( setmeCount )
     528        *setmeCount = n;
    495529    return torrents;
    496530}
     
    702736    return tor ? tor->next : session->torrentList;
    703737}
     738
     739/***
     740****
     741***/
     742
     743void
     744tr_sessionSetRPCEnabled( tr_handle * session, int isEnabled )
     745{
     746    tr_rpcSetEnabled( session->rpcServer, isEnabled );
     747}
     748int
     749tr_sessionIsRPCEnabled( const tr_handle * session )
     750{
     751    return tr_rpcIsEnabled( session->rpcServer );
     752}
     753void
     754tr_sessionSetRPCPort( tr_handle * session, int port )
     755{
     756    tr_rpcSetPort( session->rpcServer, port );
     757}
     758int
     759tr_sessionGetRPCPort( const tr_handle * session )
     760{
     761    return tr_rpcGetPort( session->rpcServer );
     762}
     763void
     764tr_sessionSetRPCCallback( tr_handle    * session,
     765                          tr_rpc_func    func,
     766                          void         * user_data )
     767{
     768    session->rpc_func = func;
     769    session->rpc_func_user_data = user_data;
     770}
     771
     772void
     773tr_sessionSetRPCACL( tr_handle * session, const char * acl )
     774{
     775    tr_rpcSetACL( session->rpcServer, acl );
     776}
     777
     778const char*
     779tr_sessionGetRPCACL( const tr_session * session )
     780{
     781    return tr_rpcGetACL( session->rpcServer );
     782}
  • trunk/libtransmission/session.h

    r5673 r5843  
    2626#define TR_INTERNAL_H 1
    2727
     28#include <libtransmission/rpc.h>
     29
    2830#define TR_NAME "Transmission"
    2931
     32#ifndef UNUSED
    3033#ifdef __GNUC__
    3134#define UNUSED __attribute__((unused))
     
    3336#define UNUSED
    3437#endif
     38#endif
    3539
    3640typedef enum { TR_NET_OK, TR_NET_ERROR, TR_NET_WAIT } tr_tristate_t;
    37 
    38 #ifndef TRUE
    39 #define TRUE 1
    40 #endif
    41 
    42 #ifndef FALSE
    43 #define FALSE 0
    44 #endif
    4541
    4642uint8_t* tr_peerIdNew( void );
     
    6258    unsigned int                 useDownloadLimit : 1;
    6359
     60    tr_rpc_func                  rpc_func;
     61    void                       * rpc_func_user_data;
     62
    6463    tr_encryption_mode           encryptionMode;
    6564
     
    7473
    7574    char                       * configDir;
     75    char                       * downloadDir;
     76    char                       * resumeDir;
    7677    char                       * torrentDir;
    77     char                       * resumeDir;
    7878
    7979    struct tr_ratecontrol      * upload;
     
    8787
    8888    struct tr_web              * web;
     89
     90    struct tr_rpc_server       * rpcServer;
    8991
    9092    tr_handle_status             stats[2];
  • trunk/libtransmission/stats.c

    r5726 r5843  
    1313#include "transmission.h"
    1414#include "bencode.h"
    15 #include "platform.h" /* tr_getConfigDir() */
     15#include "platform.h" /* tr_sessionGetConfigDir() */
    1616#include "utils.h" /* tr_buildPath */
    1717
     
    3030getFilename( const tr_handle * handle, char * buf, size_t buflen )
    3131{
    32     tr_buildPath( buf, buflen, tr_getConfigDir(handle), "stats.benc", NULL );
     32    tr_buildPath( buf, buflen, tr_sessionGetConfigDir(handle),
     33                               "stats.benc",
     34                               NULL );
    3335    return buf;
    3436}
  • trunk/libtransmission/torrent-ctor.c

    r5819 r5843  
    1616#include "platform.h"
    1717#include "session.h" /* tr_sessionFindTorrentFile */
    18 #include "trcompat.h" /* strlcpy */
    1918#include "utils.h"
    2019
     
    2524    unsigned int isSet_paused : 1;
    2625    unsigned int isSet_connected : 1;
    27     unsigned int isSet_destination : 1;
     26    unsigned int isSet_downloadDir : 1;
    2827
    2928    unsigned int isPaused : 1;
    3029    uint16_t peerLimit;
    31     char destination[MAX_PATH_LENGTH];
     30    char downloadDir[MAX_PATH_LENGTH];
    3231};
    3332
     
    202201
    203202void
    204 tr_ctorSetDestination( tr_ctor        * ctor,
     203tr_ctorSetDownloadDir( tr_ctor        * ctor,
    205204                       tr_ctorMode      mode,
    206205                       const char     * directory )
    207206{
    208207    struct optional_args * args = &ctor->optionalArgs[mode];
    209     args->isSet_destination = 1;
    210     strlcpy( args->destination, directory, sizeof( args->destination ) );
     208    args->isSet_downloadDir = 1;
     209    tr_strlcpy( args->downloadDir, directory, sizeof( args->downloadDir ) );
    211210}
    212211
     
    244243
    245244int
    246 tr_ctorGetDestination( const tr_ctor  * ctor,
     245tr_ctorGetDownloadDir( const tr_ctor  * ctor,
    247246                       tr_ctorMode      mode,
    248                        const char    ** setmeDestination )
     247                       const char    ** setmeDownloadDir )
    249248{
    250249    int err = 0;
    251250    const struct optional_args * args = &ctor->optionalArgs[mode];
    252251
    253     if( !args->isSet_destination )
    254         err = 1;
    255     else if( setmeDestination )
    256         *setmeDestination = args->destination;
     252    if( !args->isSet_downloadDir )
     253        err = 1;
     254    else if( setmeDownloadDir )
     255        *setmeDownloadDir = args->downloadDir;
    257256
    258257    return err;
     
    284283    tr_ctorSetPeerLimit( ctor, TR_FALLBACK, DEFAULT_MAX_CONNECTED_PEERS );
    285284    tr_ctorSetPaused( ctor, TR_FALLBACK, FALSE );
     285    tr_ctorSetDownloadDir( ctor, TR_FALLBACK, handle->downloadDir );
    286286    tr_ctorSetSave( ctor, TRUE );
    287287    return ctor;
  • trunk/libtransmission/torrent.c

    r5819 r5843  
    4343#include "torrent.h"
    4444#include "tracker.h"
    45 #include "trcompat.h" /* for strlcpy */
    4645#include "trevent.h"
    4746#include "utils.h"
     
    5352****
    5453***/
     54
     55int
     56tr_torrentId( const tr_torrent * tor )
     57{
     58    return tor->uniqueId;
     59}
    5560
    5661tr_torrent*
     
    203208            tr_torerr( tor, _( "Tracker warning: \"%s\"" ), event->text );
    204209            tor->error = TR_ERROR_TC_WARNING;
    205             strlcpy( tor->errorString, event->text, sizeof(tor->errorString) );
     210            tr_strlcpy( tor->errorString, event->text, sizeof(tor->errorString) );
    206211            break;
    207212
     
    209214            tr_torerr( tor, _( "Tracker error: \"%s\"" ), event->text );
    210215            tor->error = TR_ERROR_TC_ERROR;
    211             strlcpy( tor->errorString, event->text, sizeof(tor->errorString) );
     216            tr_strlcpy( tor->errorString, event->text, sizeof(tor->errorString) );
    212217            break;
    213218
     
    451456    tor->upload         = tr_rcInit();
    452457    tor->download       = tr_rcInit();
    453     tor->swarmspeed     = tr_rcInit();
     458    tor->swarmSpeed     = tr_rcInit();
    454459
    455460    tr_sha1( tor->obfuscatedHash, "req2", 4,
     
    486491    tor->trackerSubscription = tr_trackerSubscribe( tor->tracker, onTrackerResponse, tor );
    487492
    488     tor->next = h->torrentList;
    489     h->torrentList = tor;
    490     h->torrentCount++;
     493    {
     494        tr_torrent * it = NULL;
     495        tr_torrent * last = NULL;
     496        while(( it = tr_torrentNext( h, it )))
     497            last = it;
     498        if( !last )
     499            h->torrentList = tor;
     500        else
     501            last->next = tor;
     502        ++h->torrentCount;
     503    }
    491504
    492505    tr_globalUnlock( h );
     
    563576
    564577void
    565 tr_torrentSetFolder( tr_torrent * tor, const char * path )
    566 {
    567     if( !path || !tor->destination || strcmp( path, tor->destination ) )
     578tr_torrentSetDownloadDir( tr_torrent * tor, const char * path )
     579{
     580    if( !path || !tor->downloadDir || strcmp( path, tor->downloadDir ) )
    568581    {
    569         tr_free( tor->destination );
    570         tor->destination = tr_strdup( path );
     582        tr_free( tor->downloadDir );
     583        tor->downloadDir = tr_strdup( path );
    571584        tr_torrentSaveResume( tor );
    572585    }
     
    574587
    575588const char*
    576 tr_torrentGetFolder( const tr_torrent * tor )
    577 {
    578     return tor->destination;
     589tr_torrentGetDownloadDir( const tr_torrent * tor )
     590{
     591    return tor->downloadDir;
    579592}
    580593
     
    691704    s->tracker = tr_trackerGetAddress( tor->tracker );
    692705
    693     tr_trackerStat( tor->tracker, &s->tracker_stat );
     706    tr_trackerStat( tor->tracker, &s->trackerStat );
    694707
    695708    tr_peerMgrTorrentStats( tor->handle->peerMgr,
     
    719732                         &s->seeders );
    720733
    721     s->swarmspeed = tr_rcRate( tor->swarmspeed );
     734    s->swarmSpeed = tr_rcRate( tor->swarmSpeed );
    722735   
    723736    s->startDate = tor->startDate;
     
    930943    tr_rcClose( tor->upload );
    931944    tr_rcClose( tor->download );
    932     tr_rcClose( tor->swarmspeed );
     945    tr_rcClose( tor->swarmSpeed );
    933946
    934947    tr_trackerUnsubscribe( tor->tracker, tor->trackerSubscription );
     
    938951    tr_bitfieldFree( tor->checkedPieces );
    939952
    940     tr_free( tor->destination );
     953    tr_free( tor->downloadDir );
    941954
    942955    if( tor == h->torrentList )
     
    951964    assert( h->torrentCount >= 1 );
    952965    h->torrentCount--;
    953 
    954     tr_torinf( tor, _( "Closing torrent; %d left" ), h->torrentCount );
    955966
    956967    tr_metainfoFree( inf );
     
    10771088        char path[MAX_PATH_LENGTH];
    10781089        const tr_file * file = &tor->info.files[i];
    1079         tr_buildPath( path, sizeof(path), tor->destination, file->name, NULL );
     1090        tr_buildPath( path, sizeof(path), tor->downloadDir, file->name, NULL );
    10801091        tr_fdFileClose( path );
    10811092    }
     
    15181529        struct stat sb;
    15191530        tr_buildPath( fname, sizeof(fname),
    1520                       tor->destination, tor->info.files[i].name, NULL );
     1531                      tor->downloadDir, tor->info.files[i].name, NULL );
    15211532        if ( !stat( fname, &sb ) ) {
    15221533#ifdef SYS_DARWIN
  • trunk/libtransmission/torrent.h

    r5813 r5843  
    125125    struct tr_ratecontrol    * upload;
    126126    struct tr_ratecontrol    * download;
    127     struct tr_ratecontrol    * swarmspeed;
     127    struct tr_ratecontrol    * swarmSpeed;
    128128
    129129    int                        error;
     
    133133
    134134    /* Where to download */
    135     char                     * destination;
     135    char                     * downloadDir;
    136136   
    137137    /* How many bytes we ask for per request */
  • trunk/libtransmission/tracker.c

    r5774 r5843  
    2626#include "torrent.h"
    2727#include "tracker.h"
    28 #include "trcompat.h" /* strlcpy */
    2928#include "trevent.h"
    3029#include "utils.h"
     
    313312        return;
    314313
    315     dbgmsg( t->name, "tracker response: %d", responseCode );
    316     tr_ndbg( t->name, "tracker response: %d", responseCode );
     314    dbgmsg( t->name, "tracker response: %ld", responseCode );
     315    tr_ndbg( t->name, "tracker response: %ld", responseCode );
    317316    t->lastAnnounceResponse = responseCode;
    318317
     
    453452
    454453    dbgmsg( t->name, "scrape response: %ld\n", responseCode );
    455     tr_ndbg( t->name, "scrape response: %d", responseCode );
     454    tr_ndbg( t->name, "scrape response: %ld", responseCode );
    456455    t->lastScrapeResponse = responseCode;
    457456
     
    526525    {
    527526        const int interval = t->retryScrapeIntervalSec + t->randOffset;
    528         dbgmsg( t->name, "Tracker responded to scrape with %d.  Retrying in %d seconds.",
     527        dbgmsg( t->name, "Tracker responded to scrape with %ld.  Retrying in %d seconds.",
    529528                   responseCode,  interval );
    530529        t->retryScrapeIntervalSec *= 2;
  • trunk/libtransmission/transmission.h

    r5819 r5843  
    6363
    6464/***********************************************************************
    65  * tr_init
     65 * tr_sessionInit
    6666 ***********************************************************************
    6767 * Initializes and returns an opaque libtransmission handle
    6868 * to be passed to functions below. The tag argument is a short string
    69  * unique to the program invoking tr_init(), it is currently used as
    70  * part of saved torrent files' names to prevent one frontend from
     69 * unique to the program invoking tr_sessionInit(), it is currently used
     70 * as part of saved torrent files' names to prevent one frontend from
    7171 * deleting a torrent used by another. The following tags are used:
    7272 *   beos cli daemon gtk macosx wx
     
    8383#define TR_DEFAULT_GLOBAL_PEER_LIMIT           200
    8484#define TR_DEFAULT_PEER_SOCKET_TOS             8
    85 
    86 tr_handle * tr_initFull( const char * configDir,
    87                          const char * tag,
    88                          int          isPexEnabled,
    89                          int          isPortForwardingEnabled,
    90                          int          publicPort,
    91                          int          encryptionMode,
    92                          int          isUploadLimitEnabled,
    93                          int          uploadLimit,
    94                          int          isDownloadLimitEnabled,
    95                          int          downloadLimit,
    96                          int          globalPeerLimit,
    97                          int          messageLevel,
    98                          int          isMessageQueueingEnabled,
    99                          int          isBlocklistEnabled,
    100                          int          peerSocketTOS );
    101 
    102 /**
    103  * Like tr_initFull() but with default values supplied.
     85#define TR_DEFAULT_BLOCKLIST_ENABLED           0
     86#define TR_DEFAULT_RPC_ENABLED                 0
     87#define TR_DEFAULT_RPC_PORT                    9091
     88#define TR_DEFAULT_RPC_PORT_STR                "9091"
     89#define TR_DEFAULT_RPC_ACL                     "+127.0.0.1"
     90
     91tr_handle * tr_sessionInitFull( const char * configDir,
     92                                const char * downloadDir,
     93                                const char * tag,
     94                                int          isPexEnabled,
     95                                int          isPortForwardingEnabled,
     96                                int          publicPort,
     97                                int          encryptionMode,
     98                                int          isUploadLimitEnabled,
     99                                int          uploadLimit,
     100                                int          isDownloadLimitEnabled,
     101                                int          downloadLimit,
     102                                int          globalPeerLimit,
     103                                int          messageLevel,
     104                                int          isMessageQueueingEnabled,
     105                                int          isBlocklistEnabled,
     106                                int          peerSocketTOS,
     107                                int          rpcIsEnabled,
     108                                int          rpcPort,
     109                                const char * rpcACL );
     110
     111/**
     112 * Like tr_sessionInitFull() but with default values supplied.
    104113 */
    105 tr_handle * tr_init( const char * configDir,
    106                      const char * tag );
    107 
    108 /**
    109  * Shut down a libtransmission instance created by tr_init*()
    110  */
    111 void tr_close( tr_handle * );
     114tr_handle * tr_sessionInit( const char * configDir,
     115                            const char * downloadDir,
     116                            const char * tag );
     117
     118/**
     119 * Shut down a libtransmission instance created by tr_sessionInit*()
     120 */
     121void tr_sessionClose( tr_handle * );
     122
     123void tr_sessionSetDownloadDir( tr_handle *, const char * downloadDir );
     124
     125const char * tr_sessionGetDownloadDir( const tr_handle * );
     126
     127void tr_sessionSetRPCEnabled( tr_handle *, int isEnabled );
     128
     129int tr_sessionIsRPCEnabled( const tr_handle * handle );
     130
     131void tr_sessionSetRPCPort( tr_handle *, int port );
     132
     133int tr_sessionGetRPCPort( const tr_handle * );
     134
     135/**
     136 * Specify access control list (ACL). ACL is a comma separated list
     137 * of IP subnets, each subnet is prepended by ’-’ or ’+’ sign. Plus
     138 * means allow, minus means deny. If subnet mask is omitted, like
     139 * "-1.2.3.4", then it means single IP address. Mask may vary from 0
     140 * to 32 inclusive.
     141 *
     142 * The default string is "+127.0.0.1"
     143 *
     144 * IMPORTANT: a malformed ACL is likely to cause Transmission to crash.
     145 * Client applications need to validate user input, or better yet
     146 * generate it from a higher-level interface that doesn't allow user error,
     147 * before calling this function.
     148 */
     149void tr_sessionSetRPCACL( tr_handle *, const char * acl );
     150
     151const char* tr_sessionGetRPCACL( const tr_handle * );
     152
     153typedef enum
     154{
     155    TR_RPC_TORRENT_ADDED,
     156    TR_RPC_TORRENT_STARTED,
     157    TR_RPC_TORRENT_STOPPED,
     158    TR_RPC_TORRENT_CLOSING,
     159    TR_RPC_TORRENT_CHANGED,
     160    TR_RPC_SESSION_CHANGED
     161}
     162tr_rpc_callback_type;
     163
     164struct tr_torrent;
     165
     166typedef void ( *tr_rpc_func )( tr_handle            * handle,
     167                               tr_rpc_callback_type   type,
     168                               struct tr_torrent    * tor_or_null,
     169                               void                 * user_data );
     170
     171void tr_sessionSetRPCCallback( tr_handle    * handle,
     172                               tr_rpc_func    func,
     173                               void         * user_data );
    112174
    113175
     
    160222 * preferences. The string belongs to libtransmission, do not free it.
    161223 **********************************************************************/
    162 const char * tr_getConfigDir( const tr_handle * );
     224const char * tr_sessionGetConfigDir( const tr_handle * );
    163225
    164226
     
    460522                                         uint16_t         peerLimit  );
    461523
    462 void     tr_ctorSetDestination         ( tr_ctor        * ctor,
     524void     tr_ctorSetDownloadDir         ( tr_ctor        * ctor,
    463525                                         tr_ctorMode      mode,
    464526                                         const char     * directory );
     
    476538                                         uint8_t        * setmeIsPaused );
    477539
    478 int      tr_ctorGetDestination         ( const tr_ctor  * ctor,
     540int      tr_ctorGetDownloadDir         ( const tr_ctor  * ctor,
    479541                                         tr_ctorMode      mode,
    480                                          const char    ** setmeDestination );
     542                                         const char    ** setmeDownloadDir );
    481543
    482544int      tr_ctorGetMetainfo            ( const tr_ctor  * ctor,
     
    491553const char* tr_ctorGetSourceFile       ( const tr_ctor  * ctor );
    492554
     555/**
     556 * Returns this torrent's unique ID.
     557 * IDs are allocated when the torrent is constructed and are
     558 * good until tr_sessionClose() is called.
     559 */
     560int tr_torrentId( const tr_torrent * );
    493561
    494562typedef struct tr_info tr_info;
     
    499567 * Returns TR_EINVALID if it couldn't be parsed.
    500568 * Returns TR_EDUPLICATE if it parsed but can't be added.
    501  *     "destination" must be set to test for TR_EDUPLICATE.
     569 *     "download-dir" must be set to test for TR_EDUPLICATE.
    502570 *
    503571 * If setme_info is non-NULL and parsing is successful
     
    525593 *  from the previous session.
    526594 */
    527 tr_torrent ** tr_loadTorrents ( tr_handle  * h,
    528                                 tr_ctor    * ctor,
    529                                 int        * setmeCount );
     595tr_torrent ** tr_sessionLoadTorrents ( tr_handle  * h,
     596                                       tr_ctor    * ctor,
     597                                       int        * setmeCount );
    530598
    531599
     
    542610const tr_info * tr_torrentInfo( const tr_torrent * );
    543611
    544 void tr_torrentSetFolder( tr_torrent *, const char * );
    545 
    546 const char * tr_torrentGetFolder( const tr_torrent * );
     612void tr_torrentSetDownloadDir( tr_torrent *, const char * );
     613
     614const char * tr_torrentGetDownloadDir( const tr_torrent * );
    547615
    548616void tr_torrentStart( tr_torrent * );
     
    840908    tr_torrent_status status;
    841909
    842     struct tr_tracker_stat tracker_stat;
     910    struct tr_tracker_stat trackerStat;
    843911    const tr_tracker_info * tracker;
    844912
     
    914982    uint64_t haveUnchecked;
    915983
    916     float swarmspeed;
     984    float swarmSpeed;
    917985
    918986#define TR_RATIO_NA  -1
  • trunk/libtransmission/utils.c

    r5839 r5843  
    4646
    4747#include "transmission.h"
    48 #include "trcompat.h"
    4948#include "utils.h"
    5049#include "platform.h"
     
    507506    }
    508507    if( EVBUFFER_LENGTH(evbuf) )
    509         strlcpy( buf, (char*)EVBUFFER_DATA(evbuf), buflen );
     508        tr_strlcpy( buf, (char*)EVBUFFER_DATA(evbuf), buflen );
    510509    else
    511510        *buf = '\0';
     
    878877***/
    879878
    880 
    881 #ifndef HAVE_STRLCPY
    882 
    883879/*
    884880 * Copy src to string dst of size siz.  At most siz-1 characters
     
    887883 */
    888884size_t
    889 strlcpy(char *dst, const char *src, size_t siz)
    890 {
    891         char *d = dst;
    892         const char *s = src;
    893         size_t n = siz;
    894 
    895         assert( s != NULL );
    896         assert( d != NULL );
    897 
    898         /* Copy as many bytes as will fit */
    899         if (n != 0) {
    900                 while (--n != 0) {
    901                         if ((*d++ = *s++) == '\0')
    902                                 break;
    903                 }
    904         }
    905 
    906         /* Not enough room in dst, add NUL and traverse rest of src */
    907         if (n == 0) {
    908                 if (siz != 0)
    909                         *d = '\0';              /* NUL-terminate dst */
    910                 while (*s++)
    911                         ;
    912         }
    913 
    914         return(s - src - 1);    /* count does not include NUL */
    915 }
    916 
    917 #endif /* HAVE_STRLCPY */
     885tr_strlcpy(char *dst, const char *src, size_t siz)
     886{
     887#ifdef HAVE_STRLCPY
     888    return strlcpy( dst, src, siz );
     889#else
     890    char *d = dst;
     891    const char *s = src;
     892    size_t n = siz;
     893
     894    assert( s != NULL );
     895    assert( d != NULL );
     896
     897    /* Copy as many bytes as will fit */
     898    if (n != 0) {
     899        while (--n != 0) {
     900            if ((*d++ = *s++) == '\0')
     901                break;
     902        }
     903    }
     904
     905    /* Not enough room in dst, add NUL and traverse rest of src */
     906    if (n == 0) {
     907        if (siz != 0)
     908            *d = '\0'; /* NUL-terminate dst */
     909        while (*s++)
     910            ;
     911    }
     912
     913    return(s - src - 1); /* count does not include NUL */
     914#endif
     915}
    918916
    919917/***
  • trunk/libtransmission/utils.h

    r5838 r5843  
    3535***/
    3636
     37#ifndef FALSE
     38#define FALSE 0
     39#endif
     40
     41#ifndef TRUE
     42#define TRUE 1
     43#endif
     44
    3745#ifndef UNUSED
    3846#ifdef __GNUC__
     
    192200char* tr_strndup( const char * str, int len ) TR_GNUC_MALLOC;
    193201char* tr_strdup_printf( const char * fmt, ... )  TR_GNUC_PRINTF( 1, 2 ) TR_GNUC_MALLOC;
     202size_t tr_strlcpy( char * dst, const char * src, size_t siz );
     203
     204
    194205
    195206const char* tr_strerror( int );
  • trunk/libtransmission/verify.c

    r5750 r5843  
    6969    const tr_file * file = &tor->info.files[fileIndex];
    7070
    71     tr_buildPath ( path, sizeof(path), tor->destination, file->name, NULL );
     71    tr_buildPath ( path, sizeof(path), tor->downloadDir, file->name, NULL );
    7272    nofile = stat( path, &sb ) || !S_ISREG( sb.st_mode );
    7373
  • trunk/po/POTFILES.in

    r5585 r5843  
    77gtk/file-list.c
    88gtk/hig.c
    9 gtk/ipc.c
    109gtk/main.c
    1110gtk/makemeta-ui.c
  • trunk/third-party/shttpd/config.h

    r5841 r5843  
    1616#define CONFIG_FILE     "shttpd.conf"   /* Configuration file           */
    1717#define HTPASSWD        ".htpasswd"     /* Passwords file name          */
    18 #define URI_MAX         65536           /* Default max request size     */
     18#define URI_MAX         16384           /* Default max request size     */
    1919#define LISTENING_PORTS "80"            /* Default listening ports      */
    2020#define INDEX_FILES     "index.html,index.htm,index.php,index.cgi"
  • trunk/wx/xmission.cc

    r4495 r5843  
    392392MyApp :: OnInit( )
    393393{
    394     handle = tr_init( "wx" );
     394    handle = tr_sessionInit( "wx" );
    395395
    396396    wxCmdLineParser cmdParser( cmdLineDesc, argc, argv );
     
    701701    ApplyCurrentFilter( );
    702702
    703     tr_close( handle );
     703    tr_sessionClose( handle );
    704704
    705705    /* give the connections a max of 10 seconds to shut themselves down */
Note: See TracChangeset for help on using the changeset viewer.