]> granicus.if.org Git - transmission/commitdiff
(daemon) allow wildcards to be used when adding torrents again, such as "transmission...
authorCharles Kerr <charles@transmissionbt.com>
Mon, 7 Jul 2008 21:23:34 +0000 (21:23 +0000)
committerCharles Kerr <charles@transmissionbt.com>
Mon, 7 Jul 2008 21:23:34 +0000 (21:23 +0000)
daemon/Makefile.am
daemon/getopts.c [new file with mode: 0644]
daemon/getopts.h [new file with mode: 0644]
daemon/remote.c

index 3f1f6f64baac6e0d705d24e422ce3aa361afb5ea..f07ddecaa0ca1b29e7400f27d79cdc40688e4669 100644 (file)
@@ -20,5 +20,7 @@ LDADD = \
     $(LIBCURL_LIBS) \
     $(PTHREAD_LIBS) -lm
 
+noinst_HEADERS = getopts.h
+
 transmission_daemon_SOURCES = daemon.c
-transmission_remote_SOURCES = remote.c
+transmission_remote_SOURCES = remote.c getopts.c
diff --git a/daemon/getopts.c b/daemon/getopts.c
new file mode 100644 (file)
index 0000000..19e825a
--- /dev/null
@@ -0,0 +1,208 @@
+/* getopts.c - Command line argument parser
+ *
+ * Whom: Steve Mertz <steve@dragon-ware.com>
+ * Date: 20010111
+ * Why:  Because I couldn't find one that I liked. So I wrote this one.
+ *
+*/
+/*
+ * Copyright (c) 2001-2004 Steve Mertz <steve@dragon-ware.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of Dragon Ware nor the names of its contributors may be 
+ * used to endorse or promote products derived from this software without 
+ * specific prior written permission. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ *
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "getopts.h"
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+int option_index = 1;
+
+static const char*
+getArgName( const struct options * opt )
+{
+    if( !opt->args )   return "";
+    if( opt->argName ) return opt->argName;
+    return "<args>";
+}
+
+static void
+getopts_usage_line( const struct options * opt, int nameWidth, int shortWidth, int argWidth )
+{
+    const char * name       = opt->name ? opt->name : "";
+    const char * shortName  = opt->shortName ? opt->shortName : "";
+    const char * arg        = getArgName( opt );
+    printf( "  -%*s, --%-*s %-*s  %s\n", shortWidth, shortName, nameWidth, name, argWidth, arg, opt->description );
+}
+
+/* int getopts_usage()
+ *
+ *  Returns: 1 - Successful
+ */
+int getopts_usage(const char *progName, const char *usage, struct options opts[])
+{
+  int count;
+  int nameWidth = 0;
+  int shortWidth = 0;
+  int argWidth = 0;
+  struct options help;
+
+  for( count=0; opts[count].description; ++count )
+  {
+    const char * arg;
+
+    if( opts[count].name ) 
+      nameWidth = MAX( nameWidth, (int)strlen( opts[count].name ) );
+
+    if( opts[count].shortName )
+      shortWidth = MAX( shortWidth, (int)strlen( opts[count].shortName ) );
+
+    if(( arg = getArgName( &opts[count] )))
+      argWidth = MAX( argWidth, (int)strlen( arg ) );
+  }
+
+  if( !usage )
+    usage = "Usage: %s [options]";
+  printf( usage, progName );
+  printf( "\n\n" );
+  printf( "Usage:\n" );
+
+  help.number = -1;
+  help.name = "help";
+  help.description = "Display this help page and exit";
+  help.shortName = "h";
+  help.args = 0;
+  getopts_usage_line( &help, nameWidth, shortWidth, argWidth );
+  
+  for( count=0; opts[count].description; ++count )
+      getopts_usage_line( &opts[count], nameWidth, shortWidth, argWidth );
+
+  return 1;
+}
+
+/* int getopts()
+ *
+ * Returns: -1 - Couldn't allocate memory.  Please handle me. 
+ *          0  - No arguements to parse
+ *          #  - The number in the struct for the matched arg.
+ *
+*/
+int
+getopts( const char      * usage,
+         int               argc,
+         char           ** argv,
+         struct options  * opts,
+         char           ** args )
+{
+  int argCounter, sizeOfArgs;
+  if (argc == 1 || option_index == argc)
+    return 0;
+  
+/* Search for '-h' or '--help' first.  Then we can just exit */
+  for (argCounter = 1; argCounter < argc; argCounter++)
+    {
+      if (!strcmp(argv[argCounter], "-h") || !strcmp(argv[argCounter], "--help"))
+        {
+useage:
+fprintf( stderr, "dkdkdkdkdkd\n" );
+          getopts_usage(argv[0], usage, opts);
+          exit(0);
+        }
+    }
+/* End of -h --help section */
+  
+  *args = NULL;
+  if (option_index <= argc)
+    {
+      for (argCounter = 0; opts[argCounter].number!=0; argCounter++)
+        {
+          if ((opts[argCounter].name && !strcmp(opts[argCounter].name, (argv[option_index]+2))) || 
+              (opts[argCounter].shortName && !strcmp(opts[argCounter].shortName, (argv[option_index]+1))))
+            {
+              if (opts[argCounter].args)
+                {
+                  option_index++;
+                  if (option_index >= argc)
+                    goto useage;
+/* This grossness that follows is to support having a '-' in the argument.  */
+                  if (*argv[option_index] == '-')
+                    {
+                      int optionSeeker;
+                      for (optionSeeker = 0; opts[optionSeeker].description; optionSeeker++)
+                        {
+                          if ((opts[optionSeeker].name && 
+                               !strcmp(opts[optionSeeker].name, (argv[option_index]+2))) ||
+                               (opts[optionSeeker].shortName && 
+                               !strcmp(opts[optionSeeker].shortName, (argv[option_index]+1))))
+                            {
+                              goto useage;
+                            }
+                        }
+/* End of gross hack for supporting '-' in arguments. */
+                    }
+                  sizeOfArgs = strlen(argv[option_index]);
+#ifdef __cplusplus
+                  if ((*args = (char *)calloc(1, sizeOfArgs+1)) == NULL)
+#else
+                  if ((*args = calloc(1, sizeOfArgs+1)) == NULL)
+#endif
+                    return -1;
+                  strncpy(*args, argv[option_index], sizeOfArgs);
+                }
+              option_index++;
+              return opts[argCounter].number;
+            }
+        }
+/** The Option doesn't exist.  We should warn them. */
+      //if (*argv[option_index] == '-')
+        {
+          sizeOfArgs = strlen(argv[option_index]);
+#ifdef __cplusplus
+          if ((*args = (char *)calloc(1, sizeOfArgs+1)) == NULL)
+#else
+          if ((*args = calloc(1, sizeOfArgs+1)) == NULL)
+#endif
+            return -1;
+          strncpy(*args, argv[option_index], sizeOfArgs);
+          option_index++;
+          return -2;
+        }
+    }
+  return 0;
+}
+
+
+
+
+
+
diff --git a/daemon/getopts.h b/daemon/getopts.h
new file mode 100644 (file)
index 0000000..43a25b4
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2001-2004 Steve Mertz <steve@dragon-ware.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this 
+ * list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation 
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of Dragon Ware nor the names of its contributors may be 
+ * used to endorse or promote products derived from this software without 
+ * specific prior written permission. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ *
+*/
+#ifndef __GET_OPT_H__
+#define __GET_OPT_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern int option_index;
+
+struct options
+{
+  int number;          /* Number, which is returned from getopt() */
+  char *name;          /* Long name */
+  char *description;   /* Description */
+  char *shortName;     /* Short name */
+  int args;            /* Does the option take an argument? */
+  char *argName;       /* Argument name, for the `help' option */
+};
+
+int getopts(const char * summary, int argc, char **argv, struct options opts[], char **args);
+int getopts_usage(const char *progName, const char * summary, struct options opts[]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                 /* __GET_OPT_H__ */
index fcac570d27918a1f5e94ffae594692d6f4ff8df1..1588ca296cb817a9b10842b8f6ee21ea59104690 100644 (file)
@@ -14,7 +14,6 @@
 #include <stdlib.h>
 #include <string.h> /* strcmp */
 
-#include <getopt.h>
 #include <unistd.h> /* getcwd */
 
 #include <libevent/event.h>
 #include <libtransmission/utils.h>
 #include <libtransmission/version.h>
 
+#include "getopts.h"
+
 #define MY_NAME "transmission-remote"
 #define DEFAULT_HOST "localhost"
 #define DEFAULT_PORT TR_DEFAULT_RPC_PORT
 
 enum { TAG_LIST, TAG_DETAILS, TAG_FILES, TAG_PEERS };
 
+static const char*
+getUsage( void )
+{
+    return "Transmission "LONG_VERSION_STRING"  http://www.transmissionbt.com/\n"
+           "A fast and easy BitTorrent client\n"
+           "\n"
+           "Usage: "MY_NAME" [host] [options]\n"
+           "       "MY_NAME" [port] [options]\n"
+           "       "MY_NAME" [host:port] [options]";
+}
+
+static struct options opts[] =
+{
+    { 'a', "add",          "Add torrent files", "a", 0, NULL },
+    { 'd', "downlimit",    "Set the maximum download speed in KB/s", "d", 1, "<number>" },
+    { 'D', "no-downlimit", "Don't limit the download speed", "D", 0, NULL },
+    { 'e', "encryption",   "Set encryption mode [required, preferred, tolerated]", "e", 1, "<mode>" },
+    { 'f', "files",        "Get a file list for the current torrent(s)", "f", 0, NULL },
+    { 'g', "debug",        "Print debugging information", "g", 0, NULL },
+    { 'h', "help",         "Show this help page and exit", "h", 0, NULL },
+    { 'i', "info",         "Show details of the current torrent(s)", "i", 0, NULL },
+    { 'l', "list",         "List all torrents", "l", 0, NULL },
+    { 'm', "portmap",      "Enable portmapping via NAT-PMP or UPnP", "m", 0, NULL },
+    { 'M', "no-portmap",   "Disable portmapping", "M", 0, NULL },
+    { 'n', "auth",         "Set username for authentication", "n", 1, "<user>:<pass>" },
+    { 'p', "port",         "Port to listen for incoming peers", "p", 1, "<port>" },
+    { 'r', "remove",       "Remove the current torrent(s)", "r", 0, NULL },
+    { 's', "start",        "Start the current torrent(s)", "s", 0, NULL },
+    { 'S', "stop",         "Stop the current torrent(s)", "S", 0, NULL },
+    { 't', "torrent",      "Set the current torrent(s)", "t", 1, "<id|hash|all>" },
+    { 'u', "uplimit",      "Set the maximum upload speed in KB/s", "u", 1, "<number>" },
+    { 'U', "no-uplimit",   "Don't limit the upload speed", "U", 0, NULL },
+    { 'v', "verify",       "Verify the current torrent(s)", "v", 0, NULL },
+    { 'w', "download-dir", "Set the download folder for new torrents", "w", 1, "<path>" },
+    { 'x', "pex",          "Enable peer exchange (PEX)", "x", 0, NULL },
+    { 'X', "no-pex",       "Disable peer exchange (PEX)", "X", 0, NULL },
+    { 0, NULL, NULL, NULL, 0, NULL }
+};
+
 static void
 showUsage( void )
 {
-    puts( "Transmission "LONG_VERSION_STRING"  http://www.transmissionbt.com/\n"
-            "A fast and easy BitTorrent client\n"
-            "\n"
-            "Usage: "MY_NAME" [host] [options]\n"
-            "       "MY_NAME" [port] [options]\n"
-            "       "MY_NAME" [host:port] [options]\n"
-            "\n"
-            "Options:\n"
-            "  -a --add <torrent>        Add a torrent\n"
-            "  -d --download-limit <int> Max download rate in KiB/s\n"
-            "  -D --download-unlimited   No download rate limit\n"
-            "  -e --encryption required  Require encryption for all peers\n"
-            "  -e --encryption preferred Prefer peers to use encryption\n"
-            "  -e --encryption tolerated Prefer peers to use plaintext\n"
-            "  -f --files <id>           Get a file list for the specified torrent\n"
-            "  -g --debug                Print debugging information\n"
-            "  -h --help                 Display this message and exit\n"
-            "  -i --info                 Detailed information for the specified torrent\n"
-            "  -l --list                 List all torrents\n"
-            "  -m --port-mapping         Automatic port mapping via NAT-PMP or UPnP\n"
-            "  -M --no-port-mapping      Disable automatic port mapping\n"
-            "  -p --port <id>            Port to listen for incoming peers\n"
-            "  -r --remove <id>          Remove the torrent with the given ID\n"
-            "  -r --remove all           Remove all torrents\n"
-            "  -s --start <id>           Start the torrent with the given ID\n"
-            "  -s --start all            Start all stopped torrents\n"
-            "  -S --stop <id>            Stop the torrent with the given ID\n"
-            "  -S --stop all             Stop all running torrents\n"
-            "  -t --auth <user>:<pass>   Username and password for authentication\n"
-            "  -u --upload-limit <int>   Max upload rate in KiB/s\n"
-            "  -U --upload-unlimited     No upload rate limit\n"
-            "  -v --verify <id>          Verify the torrent's local data\n"
-            "  -w --download-dir <path>  Folder to set for new torrents\n"
-            "  -x --enable-pex           Enable peer exchange\n"
-            "  -X --disable-pex          Disable peer exchange\n" );
+fprintf( stderr, "asdfasdfasdfasdfasdfasdf\n");
+    getopts_usage( MY_NAME, getUsage(), opts );
     exit( 0 );
 }
 
@@ -114,63 +121,61 @@ getEncodedMetainfo( const char * filename )
     return b64;
 }
 
+static void
+addIdArg( tr_benc * args, const char * id )
+{
+    if( !*id ) {
+        fprintf( stderr, "No torrent specified!  Please use the -t option first.\n" );
+        id = "-1"; /* no torrent will have this ID, so should be a no-op */
+    } else if( strcmp( id, "all" ) ) {
+        tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), id, strlen(id) );
+    }
+}
+
 static void
 readargs( int argc, char ** argv )
 {
-    int opt;
-    char optstr[] = "a:d:De:f:ghi:lmMp:r:s:S:t:u:Uv:w:xX";
-    
-    const struct option longopts[] =
-    {
-        { "add",                required_argument, NULL, 'a' },
-        { "download-limit",     required_argument, NULL, 'd' },
-        { "download-unlimited", no_argument,       NULL, 'D' },
-        { "encryption",         required_argument, NULL, 'e' },
-        { "files",              required_argument, NULL, 'f' },
-        { "debug",              no_argument,       NULL, 'g' },
-        { "help",               no_argument,       NULL, 'h' },
-        { "info",               required_argument, NULL, 'i' },
-        { "list",               no_argument,       NULL, 'l' },
-        { "port-mapping",       no_argument,       NULL, 'm' },
-        { "no-port-mapping",    no_argument,       NULL, 'M' },
-        { "port",               required_argument, NULL, 'p' },
-        { "remove",             required_argument, NULL, 'r' },
-        { "start",              required_argument, NULL, 's' },
-        { "stop",               required_argument, NULL, 'S' },
-        { "auth",               required_argument, NULL, 't' },
-        { "upload-limit",       required_argument, NULL, 'u' },
-        { "upload-unlimited",   no_argument,       NULL, 'U' },
-        { "verify",             required_argument, NULL, 'v' },
-        { "download-dir",       required_argument, NULL, 'w' },
-        { "enable-pex",         no_argument,       NULL, 'x' },
-        { "disable-pex",        no_argument,       NULL, 'X' },
-        { NULL, 0, NULL, 0 }
-    };
-
-    while((( opt = getopt_long( argc, argv, optstr, longopts, NULL ))) != -1 )
+    int c;
+    int addingTorrents = 0;
+    char * optarg;
+    char id[4096];
+
+    *id = '\0';
+
+    while(( c = getopts( getUsage(), argc, argv, opts, &optarg )))
     {
-        char * tmp;
         char buf[MAX_PATH_LENGTH];
         int addArg = TRUE;
-        int64_t fields = 0;
         tr_benc top, *args;
         tr_bencInitDict( &top, 3 );
+        int64_t fields = 0;
         args = tr_bencDictAddDict( &top, "arguments", 0 );
 
-        switch( opt )
+fprintf( stderr, "got opt [%c][%s]\n", (char)c, (optarg?optarg:"(null)") );
+        switch( c )
         {
-            case 'g': debug = 1;
-                      addArg = FALSE;
+            case -2:  /* special case: recognize options we didn't set above */
+fprintf( stderr, "hello world\n" );
+                      if( addingTorrents ) {
+                          char * tmp;
+fprintf( stderr, "adding filename [%s]\n", optarg );
+                          tr_bencDictAddStr( &top, "method", "torrent-add" );
+                          tr_bencDictAddStr( args, "metainfo", ((tmp=getEncodedMetainfo(optarg))) );
+                          tr_free( tmp );
+                      } else {
+                          fprintf( stderr, "Unknown option: %s\n", optarg );
+                          addArg = FALSE;
+                      }
                       break;
-            case 't': auth = tr_strdup( optarg );
+            case 'a': addingTorrents = 1;
                       addArg = FALSE;
                       break;
-            case 'h': showUsage( );
-                      addArg = FALSE;
+            case 'd': tr_bencDictAddStr( &top, "method", "session-set" );
+                      tr_bencDictAddInt( args, "speed-limit-down", numarg( optarg ) );
+                      tr_bencDictAddInt( args, "speed-limit-down-enabled", 1 );
                       break;
-            case 'a': tr_bencDictAddStr( &top, "method", "torrent-add" );
-                      tr_bencDictAddStr( args, "metainfo", ((tmp=getEncodedMetainfo(optarg))) );
-                      tr_free( tmp );
+            case 'D': tr_bencDictAddStr( &top, "method", "session-set" );
+                      tr_bencDictAddInt( args, "speed-limit-down-enabled", 0 );
                       break;
             case 'e': tr_bencDictAddStr( &top, "method", "session-set" );
                       tr_bencDictAddStr( args, "encryption", optarg );
@@ -183,34 +188,23 @@ readargs( int argc, char ** argv )
                              | TR_RPC_TORRENT_FIELD_PRIORITIES;
                       tr_bencDictAddInt( args, "fields", fields );
                       break;
+            case 'g': debug = 1;
+                      addArg = FALSE;
+                      break;
             case 'i': tr_bencDictAddStr( &top, "method", "torrent-get" );
                       tr_bencDictAddInt( &top, "tag", TAG_DETAILS );
-                      tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+                      addIdArg( args, id );
                       fields = TR_RPC_TORRENT_FIELD_ACTIVITY
-                             | TR_RPC_TORRENT_FIELD_ANNOUNCE
-                             | TR_RPC_TORRENT_FIELD_ERROR
-                             | TR_RPC_TORRENT_FIELD_HISTORY
-                             | TR_RPC_TORRENT_FIELD_ID
-                             | TR_RPC_TORRENT_FIELD_INFO
-                             | TR_RPC_TORRENT_FIELD_SCRAPE
-                             | TR_RPC_TORRENT_FIELD_SIZE
-                             | TR_RPC_TORRENT_FIELD_TRACKER_STATS;
+                          | TR_RPC_TORRENT_FIELD_ANNOUNCE
+                          | TR_RPC_TORRENT_FIELD_ERROR
+                          | TR_RPC_TORRENT_FIELD_HISTORY
+                          | TR_RPC_TORRENT_FIELD_ID
+                          | TR_RPC_TORRENT_FIELD_INFO
+                          | TR_RPC_TORRENT_FIELD_SCRAPE
+                          | TR_RPC_TORRENT_FIELD_SIZE
+                          | TR_RPC_TORRENT_FIELD_TRACKER_STATS;
                       tr_bencDictAddInt( args, "fields", fields );
                       break;
-            case 'd': tr_bencDictAddStr( &top, "method", "session-set" );
-                      tr_bencDictAddInt( args, "speed-limit-down", numarg( optarg ) );
-                      tr_bencDictAddInt( args, "speed-limit-down-enabled", 1 );
-                      break;
-            case 'D': tr_bencDictAddStr( &top, "method", "session-set" );
-                      tr_bencDictAddInt( args, "speed-limit-down-enabled", 0 );
-                      break;
-            case 'u': tr_bencDictAddStr( &top, "method", "session-set" );
-                      tr_bencDictAddInt( args, "speed-limit-up", numarg( optarg ) );
-                      tr_bencDictAddInt( args, "speed-limit-up-enabled", 1 );
-                      break;
-            case 'U': tr_bencDictAddStr( &top, "method", "session-set" );
-                      tr_bencDictAddInt( args, "speed-limit-up-enabled", 0 );
-                      break;
             case 'l': tr_bencDictAddStr( &top, "method", "torrent-get" );
                       tr_bencDictAddInt( &top, "tag", TAG_LIST );
                       fields = TR_RPC_TORRENT_FIELD_ID
@@ -224,24 +218,33 @@ readargs( int argc, char ** argv )
             case 'M': tr_bencDictAddStr( &top, "method", "session-set" );
                       tr_bencDictAddInt( args, "port-forwarding-enabled", 0 );
                       break;
+            case 'n': auth = tr_strdup( optarg );
+                      addArg = FALSE;
+                      break;
             case 'p': tr_bencDictAddStr( &top, "method", "session-set" );
                       tr_bencDictAddInt( args, "port", numarg( optarg ) );
                       break;
             case 'r': tr_bencDictAddStr( &top, "method", "torrent-remove" );
-                      if( strcmp( optarg, "all" ) )
-                          tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+                      addIdArg( args, id );
                       break;
             case 's': tr_bencDictAddStr( &top, "method", "torrent-start" );
-                      if( strcmp( optarg, "all" ) )
-                          tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+                      addIdArg( args, id );
                       break;
             case 'S': tr_bencDictAddStr( &top, "method", "torrent-stop" );
-                      if( strcmp( optarg, "all" ) )
-                          tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+                      addIdArg( args, id );
+                      break;
+            case 't': tr_strlcpy( id, optarg, sizeof( id ) );
+                      addArg = FALSE;
+                      break;
+            case 'u': tr_bencDictAddStr( &top, "method", "session-set" );
+                      tr_bencDictAddInt( args, "speed-limit-up", numarg( optarg ) );
+                      tr_bencDictAddInt( args, "speed-limit-up-enabled", 1 );
+                      break;
+            case 'U': tr_bencDictAddStr( &top, "method", "session-set" );
+                      tr_bencDictAddInt( args, "speed-limit-up-enabled", 0 );
                       break;
             case 'v': tr_bencDictAddStr( &top, "method", "torrent-verify" );
-                      if( strcmp( optarg, "all" ) )
-                          tr_rpc_parse_list_str( tr_bencDictAdd( args, "ids" ), optarg, strlen(optarg) );
+                      addIdArg( args, id );
                       break;
             case 'w': tr_bencDictAddStr( &top, "method", "session-set" );
                       tr_bencDictAddStr( args, "download-dir", absolutify(buf,sizeof(buf),optarg) );
@@ -252,9 +255,8 @@ readargs( int argc, char ** argv )
             case 'X': tr_bencDictAddStr( &top, "method", "session-set" );
                       tr_bencDictAddInt( args, "pex-allowed", 0 );
                       break;
-            default:
+            default:  fprintf( stderr, "got opt [%d]\n", (int)c );
                       showUsage( );
-                      addArg = FALSE;
                       break;
         }