Index: telnet/main.c =================================================================== RCS file: /sources/inetutils/inetutils/telnet/main.c,v retrieving revision 1.17 diff -u -p -r1.17 main.c --- telnet/main.c 21 Oct 2006 18:08:45 -0000 1.17 +++ telnet/main.c 4 Sep 2008 18:41:18 -0000 @@ -30,11 +30,12 @@ #ifdef HAVE_CONFIG_H # include #endif +#include #include -#include #include +#include #include "ring.h" #include "externs.h" @@ -45,6 +46,9 @@ #define OPTS_FORWARD_CREDS 0x00000002 #define OPTS_FORWARDABLE_CREDS 0x00000001 +/* Based on buffer size for 'tline' in tn3270.c */ +#define MAX_TLINE_BUF 200 + #if 0 # define FORWARD #endif @@ -68,118 +72,268 @@ tninit () #endif } -#define USAGE "Usage: %s [OPTION...] [HOST [PORT]]\n" -/* Print a help message describing all options to STDOUT and exit with a - status of 0. */ -static void -help () +struct cmd_args { - fprintf (stdout, USAGE, prompt); + char *argv[8]; + char **argptr; +}; +typedef struct cmd_args cmd_args_t; - puts ("Login to remote system HOST (optionally, on service port PORT)\n\n\ - -4, --ipv4 Use only IPv4\n\ - -6, --ipv6 Use only IPv6\n\ - -8, --binary Use an 8-bit data path\n\ - -a, --login Attempt automatic login\n\ - -c, --no-rc Don't read the user's .telnetrc file\n\ - -d, --debug Turn on debugging\n\ - -e CHAR, --escape=CHAR Use CHAR as an escape character\n\ - -E, --no-escape Use no escape character\n\ - -K, --no-login Don't automatically login to the remote system\n\ - -l USER, --user=USER Attempt automatic login as USER\n\ - -L, --binary-output Use an 8-bit data path for output only\n\ - -n FILE, --trace=FILE Record trace information into FILE\n\ - -r, --rlogin Use a user-interface similar to rlogin\n\ - -X ATYPE, --disable-auth=ATYPE Disable type ATYPE authentication"); - -#ifdef ENCRYPTION - puts ("\ - -x, --encrypt Encrypt the data stream, if possible"); -#endif +ARGP_PROGRAM_DATA ("telnet", "2008", "FIXME unknown"); + +const char args_doc[] = "[HOST [PORT]]"; +const char doc[] = "TELNET protocol client."; + +/* Define keys for long options that do not have short counterparts. */ +enum { + ARG_NOASYNCH = 256, + ARG_NOASYNCTTY, + ARG_NOASYNCNET +}; + +static struct argp_option argp_options[] = { +#define GRP 0 + {"debug", 'd', NULL, 0, "Turn on debugging", GRP+1}, + {"ipv4", '4', NULL, 0, "Use only IPv4", GRP+1}, + {"ipv6", '6', NULL, 0, "Use only IPv6", GRP+1}, + {"binary", '8', NULL, 0, "Use an 8-bit data path", GRP+1}, + {"login", 'a', NULL, 0, "Attempt automatic login", GRP+1}, + {"no-rc", 'c', NULL, 0, "Don't read the user's .telnetrc file", GRP+1}, + {"escape", 'e', "CHAR", 0, "Use CHAR as an escape character", GRP+1}, + {"no-escape", 'E', NULL, 0, "Use no escape character", GRP+1}, + {"no-login", 'K', NULL, 0, "Don't automatically login to the remote system", + GRP+1}, + {"user", 'l', "USER", 0, "Attempt automatic login as USER", GRP+1}, + {"binary-output", 'L', NULL, 0, "Use an 8-bit data path for output only", + GRP+1}, + {"trace", 'n', "FILE", 0, "Record trace information into FILE", GRP+1}, + {"rlogin", 'r', NULL, 0, "Use a user-interface similar to rlogin", GRP+1}, + {"disable-auth", 'X', "ATYPE", 0, "Disable type ATYPE authentication", GRP+1}, + {"encrypt", 'x', NULL, 0, "Encrypt the data stream, if possible", GRP+1}, +#undef GRP +#define GRP 10 + {NULL, 0, NULL, 0, "When using Kerberos authentication:", GRP}, + {"fwd-credentials", 'f', NULL, 0, "Allow the the local credentials to be" + " forwarded", GRP+2}, + {"realm", 'k', "REALM", 0, "Obtain tickets for the remote host in REALM" + " instead of the remote host's realm", GRP+2}, +#undef GRP +#define GRP 20 + {NULL, 0, NULL, 0, "TN3270 options:", GRP}, + {"transcom", 't', "LINE", 0, "Encrypt the data stream, if possible", GRP+3}, + {"noasynch", ARG_NOASYNCH, NULL, 0, NULL, GRP+3}, + {"noasynctty", ARG_NOASYNCTTY, NULL, 0, NULL, GRP+3}, + {"noasyncnet", ARG_NOASYNCNET, NULL, 0, NULL, GRP+3}, +#undef GRP + {NULL} +}; +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + static int family; + static char *user; + static cmd_args_t *c_args; + + c_args = (cmd_args_t*) (state->input); + + switch (key) + { + case '4': + family = 4; + break; + + case '6': + family = 6; + break; + + case '8': + eight = 3; /* binary output and input */ + break; + + case 'E': + rlogin = escape = _POSIX_VDISABLE; + break; + + case 'K': #ifdef AUTHENTICATION - puts ("\n\ - When using Kerberos authentication:\n\ - -f, --fwd-credentials Allow the the local credentials to be forwarded\n\ - -k REALM, --realm=REALM Obtain tickets for the remote host in REALM\n\ - instead of the remote host's realm"); + autologin = 0; +#else + argp_error (state, "'-%c' is currently not supported on this machine.", + key); #endif + break; + + case 'L': + eight |= 2; /* binary output only */ + break; + + case 'X': +#ifdef AUTHENTICATION + auth_disable_name (arg); +#else + argp_error (state, "'-%c' is currently not supported on this machine.", + key); +#endif + break; + + case 'a': + autologin = 1; + break; + + case 'c': + skiprc = 1; + break; + + case 'd': + debug = 1; + break; + + case 'e': + set_escape_char (arg); + break; + + case 'f': +#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) + if (forward_flags & OPTS_FORWARD_CREDS) + argp_error (state, "%s: Only one of -f and -F allowed.\n", prompt); + forward_flags |= OPTS_FORWARD_CREDS; +#else + argp_error (state, "'-%c' is currently not supported on this machine.", + key); +#endif + break; + case 'F': +#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) + if (forward_flags & OPTS_FORWARD_CREDS) + argp_error (state, "%s: Only one of -f and -F allowed.\n", prompt); + forward_flags |= OPTS_FORWARD_CREDS; + forward_flags |= OPTS_FORWARDABLE_CREDS; +#else + argp_error (state, "'-%c' is currently not supported on this machine.", + key); +#endif + break; + + case 'k': +#if defined(AUTHENTICATION) && defined(KRB4) + { + extern char *dest_realm, dst_realm_buf[], dst_realm_sz; + dest_realm = dst_realm_buf; + strncpy (dest_realm, arg, dst_realm_sz); + } +#else + argp_error (state, "'-%c' is currently not supported on this machine.", + key); +#endif + break; + + case 'l': + autologin = 1; + user = arg; + break; + + case 'n': + SetNetTrace (arg); + break; + + case ARG_NOASYNCH: #if defined(TN3270) && defined(unix) - puts ("\n\ - TN3270 options (note non-standard option syntax):\n\ - -noasynch\n\ - -noasynctty\n\ - -noasyncnet\n\ - -t LINE, --transcom=LINE"); + noasynchtty = 1; + noasynchnet = 1; +#else + argp_error (state, "'--noasynch' is currently not supported" + " on this machine."); #endif + break; -#if defined (ENCRYPTION) || defined (AUTHENTICATION) || defined (TN3270) - putc ('\n', stdout); + case ARG_NOASYNCTTY: +#if defined(TN3270) && defined(unix) + noasynchtty = 1; +#else + argp_error (state, "'--noasynctty' is currently not supported" + " on this machine."); #endif + break; - puts ("\ - --help Give this help list\n\ - -V, --version Print program version"); + case ARG_NOASYNCNET: +#if defined(TN3270) && defined(unix) + noasynchnet = 1; +#else + argp_error (state, "'--noasyncnet' is currently not supported" + " on this machine."); + break; +#endif - fprintf (stdout, "\nSubmit bug reports to %s.\n", PACKAGE_BUGREPORT); + case 'r': + rlogin = '~'; + break; - exit (0); -} + case 't': +#if defined(TN3270) && defined(unix) + transcom = tline; + strncpy (transcom, arg, MAX_TLINE_BUF); +#else + argp_error (state, "'-%c' is currently not supported on this machine.", + key); +#endif + break; -/* Print a message saying to use --help to STDERR, and exit with a status of - 1. */ -static void -try_help () -{ - fprintf (stderr, "Try `%s --help' for more information.\n", prompt); - exit (1); -} + case 'x': +#ifdef ENCRYPTION + encrypt_auto (1); + decrypt_auto (1); +#else /* ENCRYPTION */ + argp_error (state, "'-%c' is currently not supported on this machine.", + key); +#endif /* ENCRYPTION */ + break; -/* Print a usage message to STDERR and exit with a status of 1. */ -static void -usage () -{ - fprintf (stderr, USAGE, prompt); - try_help (); + case ARGP_KEY_ARG: + if (state->arg_num == 0) + /* More than 2 arguments */ + if ((state->argc - state->next) > 1) + argp_usage (state); + + if (user) + { + *(c_args->argptr)++ = "-l"; + *(c_args->argptr)++ = user; + } + if (family == 4) + *(c_args->argptr)++ = "-4"; + else if (family == 6) + *(c_args->argptr)++ = "-6"; + + *(c_args->argptr)++ = arg; /* host */ + if (state->argc - state->next) + *(c_args->argptr)++ = state->argv[state->next]; /* port */ + + *(c_args->argptr) = NULL; + + /* Froce argp to stop processing remaining args, + * as we've got them all. */ + state->next = state->argc; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; } -static struct option long_options[] = { - {"ipv4", no_argument, 0, '4'}, - {"ipv6", no_argument, 0, '6'}, - {"binary", no_argument, 0, '8'}, - {"login", no_argument, 0, 'a'}, - {"no-rc", no_argument, 0, 'c'}, - {"debug", no_argument, 0, 'd'}, - {"escape", required_argument, 0, 'e'}, - {"no-escape", no_argument, 0, 'E'}, - {"no-login", no_argument, 0, 'K'}, - {"user", required_argument, 0, 'l'}, - {"binary-output", no_argument, 0, 'L'}, - {"trace", required_argument, 0, 'n'}, - {"rlogin", no_argument, 0, 'r'}, - {"disable-auth", required_argument, 0, 'X'}, - {"encrypt", no_argument, 0, 'x'}, - {"fwd-credentials", no_argument, 0, 'f'}, - {"realm", required_argument, 0, 'k'}, - {"transcom", required_argument, 0, 't'}, - {"help", no_argument, 0, '&'}, - {"version", no_argument, 0, 'V'}, - {0} -}; - +static struct argp argp = {argp_options, parse_opt, args_doc, doc}; + /* * main. Parse arguments, invoke the protocol or command parser. */ int main (int argc, char *argv[]) { - extern char *optarg; - extern int optind; - int ch; - int family = 0; - char *user; + cmd_args_t c_args = {0}; #ifndef strrchr char *strrchr (); #endif @@ -199,189 +353,23 @@ main (int argc, char *argv[]) else prompt = argv[0]; - user = NULL; - rlogin = (strncmp (prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE; autologin = -1; - while ((ch = getopt_long (argc, argv, "468EKLS:X:acde:fFk:l:n:rt:x", - long_options, 0)) != EOF) - { - switch (ch) - { - case '4': - family = 4; - break; - - case '6': - family = 6; - break; - - case '8': - eight = 3; /* binary output and input */ - break; - case 'E': - rlogin = escape = _POSIX_VDISABLE; - break; - case 'K': -#ifdef AUTHENTICATION - autologin = 0; -#endif - break; - case 'L': - eight |= 2; /* binary output only */ - break; - case 'X': -#ifdef AUTHENTICATION - auth_disable_name (optarg); -#endif - break; - case 'a': - autologin = 1; - break; - case 'c': - skiprc = 1; - break; - case 'd': - debug = 1; - break; - case 'e': - set_escape_char (optarg); - break; - case 'f': -#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) - if (forward_flags & OPTS_FORWARD_CREDS) - { - fprintf (stderr, - "%s: Only one of -f and -F allowed.\n", prompt); - help (0); - } - forward_flags |= OPTS_FORWARD_CREDS; -#else - fprintf (stderr, - "%s: Warning: -f ignored, no Kerberos V5 support.\n", - prompt); -#endif - break; - case 'F': -#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) - if (forward_flags & OPTS_FORWARD_CREDS) - { - fprintf (stderr, - "%s: Only one of -f and -F allowed.\n", prompt); - help (0); - } - forward_flags |= OPTS_FORWARD_CREDS; - forward_flags |= OPTS_FORWARDABLE_CREDS; -#else - fprintf (stderr, - "%s: Warning: -F ignored, no Kerberos V5 support.\n", - prompt); -#endif - break; - case 'k': -#if defined(AUTHENTICATION) && defined(KRB4) - { - extern char *dest_realm, dst_realm_buf[], dst_realm_sz; - dest_realm = dst_realm_buf; - strncpy (dest_realm, optarg, dst_realm_sz); - } -#else - fprintf (stderr, - "%s: Warning: -k ignored, no Kerberos V4 support.\n", - prompt); -#endif - break; - case 'l': - autologin = 1; - user = optarg; - break; - case 'n': -#if defined(TN3270) && defined(unix) - /* distinguish between "-n oasynch" and "-noasynch" */ - if (argv[optind - 1][0] == '-' && argv[optind - 1][1] - == 'n' && argv[optind - 1][2] == 'o') - { - if (!strcmp (optarg, "oasynch")) - { - noasynchtty = 1; - noasynchnet = 1; - } - else if (!strcmp (optarg, "oasynchtty")) - noasynchtty = 1; - else if (!strcmp (optarg, "oasynchnet")) - noasynchnet = 1; - } - else -#endif /* defined(TN3270) && defined(unix) */ - SetNetTrace (optarg); - break; - case 'r': - rlogin = '~'; - break; - case 't': -#if defined(TN3270) && defined(unix) - transcom = tline; - strcpy (transcom, optarg); -#else - fprintf (stderr, - "%s: Warning: -t ignored, no TN3270 support.\n", prompt); -#endif - break; - case 'x': -#ifdef ENCRYPTION - encrypt_auto (1); - decrypt_auto (1); -#else /* ENCRYPTION */ - fprintf (stderr, - "%s: Warning: -x ignored, no ENCRYPT support.\n", prompt); -#endif /* ENCRYPTION */ - break; + c_args.argptr = c_args.argv; + *(c_args.argptr)++ = prompt; + /* Parse command line */ + argp_parse (&argp, argc, argv, 0, NULL, &c_args); - case '&': - help (); - case 'V': - printf ("telnet (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); - exit (0); - - case '?': - try_help (); - - default: - usage (); - } - } if (autologin == -1) autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1; - argc -= optind; - argv += optind; - - if (argc) + /* We have command line args */ + if ((c_args.argptr - c_args.argv) > 1) { - char *args[8], **argp = args; - - if (argc > 2) - usage (); - *argp++ = prompt; - if (user) - { - *argp++ = "-l"; - *argp++ = user; - } - if (family == 4) - *argp++ = "-4"; - else if (family == 6) - *argp++ = "-6"; - - *argp++ = argv[0]; /* host */ - if (argc > 1) - *argp++ = argv[1]; /* port */ - *argp = 0; - if (setjmp (toplevel) != 0) Exit (0); - if (tn (argp - args, args) == 1) + if (tn (c_args.argptr - c_args.argv, c_args.argv) == 1) return (0); else return (1);