Annotation of src/usr.bin/telnet/commands.c, Revision 1.88
1.88 ! jmc 1: /* $OpenBSD: commands.c,v 1.87 2019/06/28 13:35:04 deraadt Exp $ */
1.4 deraadt 2: /* $NetBSD: commands.c,v 1.14 1996/03/24 22:03:48 jtk Exp $ */
1.3 niklas 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1988, 1990, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.45 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
1.10 art 33: #include "telnet_locl.h"
1.59 guenther 34:
1.62 guenther 35: #include <sys/socket.h>
1.59 guenther 36: #include <netinet/in.h>
37: #include <netinet/ip.h>
38: #include <arpa/inet.h>
1.62 guenther 39: #include <arpa/telnet.h>
1.59 guenther 40:
1.60 guenther 41: #include <ctype.h>
1.15 art 42: #include <err.h>
1.62 guenther 43: #include <errno.h>
1.61 guenther 44: #include <netdb.h>
1.59 guenther 45: #include <pwd.h>
46: #include <stdarg.h>
1.62 guenther 47: #include <stdlib.h>
48: #include <string.h>
1.60 guenther 49: #include <unistd.h>
1.71 deraadt 50: #include <limits.h>
1.1 deraadt 51:
52: char *hostname;
53:
54: typedef struct {
55: char *name; /* command name */
56: char *help; /* help string (NULL for no help) */
1.63 guenther 57: int (*handler)(int, char **);/* routine which executes command */
1.1 deraadt 58: int needconnect; /* Do we need to be connected to execute? */
59: } Command;
60:
1.86 deraadt 61: #define MAXARGV 20
62:
1.1 deraadt 63: static char line[256];
64: static int margc;
1.86 deraadt 65: static char *margv[MAXARGV+1];
1.1 deraadt 66:
1.86 deraadt 67: static int
1.69 jsg 68: makeargv(void)
1.1 deraadt 69: {
1.39 mpech 70: char *cp, *cp2, c;
71: char **argp = margv;
1.86 deraadt 72: int ret = 0;
1.1 deraadt 73:
74: margc = 0;
75: cp = line;
1.10 art 76: while ((c = *cp)) {
1.86 deraadt 77: if (margc >= MAXARGV) {
78: printf("too many arguments\n");
79: ret = 1;
80: break;
81: }
1.39 mpech 82: int inquote = 0;
1.60 guenther 83: while (isspace((unsigned char)c))
1.1 deraadt 84: c = *++cp;
85: if (c == '\0')
86: break;
87: *argp++ = cp;
88: margc += 1;
89: for (cp2 = cp; c != '\0'; c = *++cp) {
90: if (inquote) {
91: if (c == inquote) {
92: inquote = 0;
93: continue;
94: }
95: } else {
96: if (c == '\\') {
97: if ((c = *++cp) == '\0')
98: break;
99: } else if (c == '"') {
100: inquote = '"';
101: continue;
102: } else if (c == '\'') {
103: inquote = '\'';
104: continue;
1.60 guenther 105: } else if (isspace((unsigned char)c))
1.1 deraadt 106: break;
107: }
108: *cp2++ = c;
109: }
110: *cp2 = '\0';
111: if (c == '\0')
112: break;
113: cp++;
114: }
115: *argp++ = 0;
1.86 deraadt 116: return (ret);
1.1 deraadt 117: }
118:
119: /*
120: * Make a character string into a number.
121: *
122: * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
123: */
124:
1.69 jsg 125: static char
126: special(char *s)
1.1 deraadt 127: {
1.39 mpech 128: char c;
1.1 deraadt 129: char b;
130:
131: switch (*s) {
132: case '^':
133: b = *++s;
134: if (b == '?') {
135: c = b | 0x40; /* DEL */
136: } else {
137: c = b & 0x1f;
138: }
139: break;
140: default:
141: c = *s;
142: break;
143: }
144: return c;
145: }
146:
147: /*
148: * Construct a control character sequence
149: * for a special character.
150: */
1.69 jsg 151: static char *
152: control(cc_t c)
1.1 deraadt 153: {
154: static char buf[5];
155: /*
156: * The only way I could get the Sun 3.5 compiler
157: * to shut up about
158: * if ((unsigned int)c >= 0x80)
159: * was to assign "c" to an unsigned int variable...
160: * Arggg....
161: */
1.39 mpech 162: unsigned int uic = (unsigned int)c;
1.1 deraadt 163:
164: if (uic == 0x7f)
165: return ("^?");
166: if (c == (cc_t)_POSIX_VDISABLE) {
167: return "off";
168: }
169: if (uic >= 0x80) {
170: buf[0] = '\\';
171: buf[1] = ((c>>6)&07) + '0';
172: buf[2] = ((c>>3)&07) + '0';
173: buf[3] = (c&07) + '0';
174: buf[4] = 0;
175: } else if (uic >= 0x20) {
176: buf[0] = c;
177: buf[1] = 0;
178: } else {
179: buf[0] = '^';
180: buf[1] = '@'+c;
181: buf[2] = 0;
182: }
183: return (buf);
184: }
185:
186: /*
187: * The following are data structures and routines for
188: * the "send" command.
189: *
190: */
1.3 niklas 191:
1.1 deraadt 192: struct sendlist {
193: char *name; /* How user refers to it (case independent) */
194: char *help; /* Help information (0 ==> no help) */
195: int needconnect; /* Need to be connected */
196: int narg; /* Number of arguments */
197: int (*handler)(); /* Routine to perform (for special ops) */
198: int nbyte; /* Number of bytes to send this command */
199: int what; /* Character to be sent (<0 ==> special) */
200: };
201:
202:
203: static int
1.41 millert 204: send_esc(void),
205: send_help(void),
206: send_docmd(char *),
207: send_dontcmd(char *),
208: send_willcmd(char *),
209: send_wontcmd(char *);
1.1 deraadt 210:
211: static struct sendlist Sendlist[] = {
212: { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO },
213: { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT },
214: { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK },
215: { "break", 0, 1, 0, 0, 2, BREAK },
216: { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC },
217: { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL },
218: { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 },
219: { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA },
220: { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP },
221: { "intp", 0, 1, 0, 0, 2, IP },
222: { "interrupt", 0, 1, 0, 0, 2, IP },
223: { "intr", 0, 1, 0, 0, 2, IP },
224: { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP },
225: { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR },
226: { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT },
227: { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP },
228: { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF },
229: { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 },
230: { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 },
231: { "?", "Display send options", 0, 0, send_help, 0, 0 },
232: { "help", 0, 0, 0, send_help, 0, 0 },
233: { "do", 0, 0, 1, send_docmd, 3, 0 },
234: { "dont", 0, 0, 1, send_dontcmd, 3, 0 },
235: { "will", 0, 0, 1, send_willcmd, 3, 0 },
236: { "wont", 0, 0, 1, send_wontcmd, 3, 0 },
237: { 0 }
238: };
239:
240: #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
241: sizeof(struct sendlist)))
242:
1.69 jsg 243: static int
244: sendcmd(int argc, char **argv)
1.1 deraadt 245: {
246: int count; /* how many bytes we are going to need to send */
247: int i;
248: struct sendlist *s; /* pointer to current command */
249: int success = 0;
250: int needconnect = 0;
251:
252: if (argc < 2) {
1.10 art 253: printf("need at least one argument for 'send' command\r\n");
254: printf("'send ?' for help\r\n");
1.1 deraadt 255: return 0;
256: }
257: /*
258: * First, validate all the send arguments.
259: * In addition, we see how much space we are going to need, and
260: * whether or not we will be doing a "SYNCH" operation (which
261: * flushes the network queue).
262: */
263: count = 0;
264: for (i = 1; i < argc; i++) {
265: s = GETSEND(argv[i]);
266: if (s == 0) {
1.10 art 267: printf("Unknown send argument '%s'\r\n'send ?' for help.\r\n",
1.1 deraadt 268: argv[i]);
269: return 0;
270: } else if (Ambiguous(s)) {
1.10 art 271: printf("Ambiguous send argument '%s'\r\n'send ?' for help.\r\n",
1.1 deraadt 272: argv[i]);
273: return 0;
274: }
275: if (i + s->narg >= argc) {
276: fprintf(stderr,
1.10 art 277: "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\r\n",
1.1 deraadt 278: s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
279: return 0;
280: }
281: count += s->nbyte;
282: if (s->handler == send_help) {
283: send_help();
284: return 0;
285: }
286:
287: i += s->narg;
288: needconnect += s->needconnect;
289: }
290: if (!connected && needconnect) {
1.10 art 291: printf("?Need to be connected first.\r\n");
292: printf("'send ?' for help\r\n");
1.1 deraadt 293: return 0;
294: }
295: /* Now, do we have enough room? */
296: if (NETROOM() < count) {
1.10 art 297: printf("There is not enough room in the buffer TO the network\r\n");
298: printf("to process your request. Nothing will be done.\r\n");
299: printf("('send synch' will throw away most data in the network\r\n");
300: printf("buffer, if this might help.)\r\n");
1.1 deraadt 301: return 0;
302: }
303: /* OK, they are all OK, now go through again and actually send */
304: count = 0;
305: for (i = 1; i < argc; i++) {
306: if ((s = GETSEND(argv[i])) == 0) {
1.10 art 307: fprintf(stderr, "Telnet 'send' error - argument disappeared!\r\n");
1.63 guenther 308: quit();
1.1 deraadt 309: }
310: if (s->handler) {
311: count++;
312: success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
313: (s->narg > 1) ? argv[i+2] : 0);
314: i += s->narg;
315: } else {
316: NET2ADD(IAC, s->what);
317: printoption("SENT", IAC, s->what);
318: }
319: }
320: return (count == success);
321: }
322:
1.69 jsg 323: static int send_tncmd(void (*func)(int, int), char *cmd, char *name);
1.10 art 324:
1.69 jsg 325: static int
326: send_esc(void)
1.1 deraadt 327: {
328: NETADD(escape);
329: return 1;
330: }
331:
1.69 jsg 332: static int
333: send_docmd(char *name)
1.1 deraadt 334: {
335: return(send_tncmd(send_do, "do", name));
336: }
337:
1.69 jsg 338: static int
339: send_dontcmd(char *name)
1.1 deraadt 340: {
341: return(send_tncmd(send_dont, "dont", name));
342: }
1.69 jsg 343:
344: static int
345: send_willcmd(char *name)
1.1 deraadt 346: {
347: return(send_tncmd(send_will, "will", name));
348: }
1.69 jsg 349:
350: static int
351: send_wontcmd(char *name)
1.1 deraadt 352: {
353: return(send_tncmd(send_wont, "wont", name));
354: }
355:
1.69 jsg 356: int
357: send_tncmd(void (*func)(int, int), char *cmd, char *name)
1.1 deraadt 358: {
359: char **cpp;
360: extern char *telopts[];
1.39 mpech 361: int val = 0;
1.1 deraadt 362:
1.10 art 363: if (isprefix(name, "help") || isprefix(name, "?")) {
1.39 mpech 364: int col, len;
1.1 deraadt 365:
1.10 art 366: printf("Usage: send %s <value|option>\r\n", cmd);
367: printf("\"value\" must be from 0 to 255\r\n");
368: printf("Valid options are:\r\n\t");
1.1 deraadt 369:
370: col = 8;
371: for (cpp = telopts; *cpp; cpp++) {
372: len = strlen(*cpp) + 3;
373: if (col + len > 65) {
1.10 art 374: printf("\r\n\t");
1.1 deraadt 375: col = 8;
376: }
377: printf(" \"%s\"", *cpp);
378: col += len;
379: }
1.10 art 380: printf("\r\n");
1.1 deraadt 381: return 0;
382: }
383: cpp = (char **)genget(name, telopts, sizeof(char *));
384: if (Ambiguous(cpp)) {
1.10 art 385: fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\r\n",
1.1 deraadt 386: name, cmd);
387: return 0;
388: }
389: if (cpp) {
390: val = cpp - telopts;
391: } else {
1.39 mpech 392: char *cp = name;
1.1 deraadt 393:
394: while (*cp >= '0' && *cp <= '9') {
395: val *= 10;
396: val += *cp - '0';
397: cp++;
398: }
399: if (*cp != 0) {
1.10 art 400: fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\r\n",
1.1 deraadt 401: name, cmd);
402: return 0;
403: } else if (val < 0 || val > 255) {
1.10 art 404: fprintf(stderr, "'%s': bad value ('send %s ?' for help).\r\n",
1.1 deraadt 405: name, cmd);
406: return 0;
407: }
408: }
409: if (!connected) {
1.10 art 410: printf("?Need to be connected first.\r\n");
1.1 deraadt 411: return 0;
412: }
413: (*func)(val, 1);
414: return 1;
415: }
416:
1.69 jsg 417: static int
418: send_help(void)
1.1 deraadt 419: {
420: struct sendlist *s; /* pointer to current command */
421: for (s = Sendlist; s->name; s++) {
422: if (s->help)
1.10 art 423: printf("%-15s %s\r\n", s->name, s->help);
1.1 deraadt 424: }
425: return(0);
426: }
427:
428: /*
429: * The following are the routines and data structures referred
430: * to by the arguments to the "toggle" command.
431: */
432:
1.69 jsg 433: static int
434: lclchars(int unused)
1.1 deraadt 435: {
436: donelclchars = 1;
437: return 1;
438: }
439:
1.69 jsg 440: static int
441: togcrlf(int unused)
1.1 deraadt 442: {
443: if (crlf) {
1.10 art 444: printf("Will send carriage returns as telnet <CR><LF>.\r\n");
1.1 deraadt 445: } else {
1.10 art 446: printf("Will send carriage returns as telnet <CR><NUL>.\r\n");
1.1 deraadt 447: }
448: return 1;
449: }
450:
451: int binmode;
452:
1.69 jsg 453: static int
454: togbinary(int val)
1.1 deraadt 455: {
456: donebinarytoggle = 1;
457:
458: if (val >= 0) {
459: binmode = val;
460: } else {
461: if (my_want_state_is_will(TELOPT_BINARY) &&
462: my_want_state_is_do(TELOPT_BINARY)) {
463: binmode = 1;
464: } else if (my_want_state_is_wont(TELOPT_BINARY) &&
465: my_want_state_is_dont(TELOPT_BINARY)) {
466: binmode = 0;
467: }
468: val = binmode ? 0 : 1;
469: }
470:
471: if (val == 1) {
472: if (my_want_state_is_will(TELOPT_BINARY) &&
473: my_want_state_is_do(TELOPT_BINARY)) {
1.10 art 474: printf("Already operating in binary mode with remote host.\r\n");
1.1 deraadt 475: } else {
1.10 art 476: printf("Negotiating binary mode with remote host.\r\n");
1.1 deraadt 477: tel_enter_binary(3);
478: }
479: } else {
480: if (my_want_state_is_wont(TELOPT_BINARY) &&
481: my_want_state_is_dont(TELOPT_BINARY)) {
1.10 art 482: printf("Already in network ascii mode with remote host.\r\n");
1.1 deraadt 483: } else {
1.10 art 484: printf("Negotiating network ascii mode with remote host.\r\n");
1.1 deraadt 485: tel_leave_binary(3);
486: }
487: }
488: return 1;
489: }
490:
1.69 jsg 491: static int
492: togrbinary(int val)
1.1 deraadt 493: {
494: donebinarytoggle = 1;
495:
496: if (val == -1)
497: val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
498:
499: if (val == 1) {
500: if (my_want_state_is_do(TELOPT_BINARY)) {
1.10 art 501: printf("Already receiving in binary mode.\r\n");
1.1 deraadt 502: } else {
1.10 art 503: printf("Negotiating binary mode on input.\r\n");
1.1 deraadt 504: tel_enter_binary(1);
505: }
506: } else {
507: if (my_want_state_is_dont(TELOPT_BINARY)) {
1.10 art 508: printf("Already receiving in network ascii mode.\r\n");
1.1 deraadt 509: } else {
1.10 art 510: printf("Negotiating network ascii mode on input.\r\n");
1.1 deraadt 511: tel_leave_binary(1);
512: }
513: }
514: return 1;
515: }
516:
1.69 jsg 517: static int
518: togxbinary(int val)
1.1 deraadt 519: {
520: donebinarytoggle = 1;
521:
522: if (val == -1)
523: val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
524:
525: if (val == 1) {
526: if (my_want_state_is_will(TELOPT_BINARY)) {
1.10 art 527: printf("Already transmitting in binary mode.\r\n");
1.1 deraadt 528: } else {
1.10 art 529: printf("Negotiating binary mode on output.\r\n");
1.1 deraadt 530: tel_enter_binary(2);
531: }
532: } else {
533: if (my_want_state_is_wont(TELOPT_BINARY)) {
1.10 art 534: printf("Already transmitting in network ascii mode.\r\n");
1.1 deraadt 535: } else {
1.10 art 536: printf("Negotiating network ascii mode on output.\r\n");
1.1 deraadt 537: tel_leave_binary(2);
538: }
539: }
540: return 1;
541: }
542:
543:
1.63 guenther 544: static int togglehelp(int);
1.1 deraadt 545:
546: struct togglelist {
1.63 guenther 547: char *name; /* name of toggle */
548: char *help; /* help message */
549: int (*handler)(int); /* routine to do actual setting */
1.1 deraadt 550: int *variable;
551: char *actionexplanation;
1.8 robin 552: int needconnect; /* Need to be connected */
1.1 deraadt 553: };
554:
555: static struct togglelist Togglelist[] = {
556: { "autoflush",
557: "flushing of output when sending interrupt characters",
558: 0,
559: &autoflush,
1.10 art 560: "flush output when sending interrupt characters" },
1.1 deraadt 561: { "autosynch",
562: "automatic sending of interrupt characters in urgent mode",
563: 0,
564: &autosynch,
1.10 art 565: "send interrupt characters in urgent mode" },
1.1 deraadt 566: { "autologin",
1.57 guenther 567: "automatic sending of login name",
1.1 deraadt 568: 0,
569: &autologin,
1.57 guenther 570: "send login name" },
1.1 deraadt 571: { "skiprc",
572: "don't read ~/.telnetrc file",
573: 0,
574: &skiprc,
1.10 art 575: "skip reading of ~/.telnetrc file" },
1.1 deraadt 576: { "binary",
577: "sending and receiving of binary data",
578: togbinary,
579: 0,
1.10 art 580: 0 },
1.1 deraadt 581: { "inbinary",
582: "receiving of binary data",
583: togrbinary,
584: 0,
1.10 art 585: 0 },
1.1 deraadt 586: { "outbinary",
587: "sending of binary data",
588: togxbinary,
589: 0,
1.10 art 590: 0 },
1.1 deraadt 591: { "crlf",
592: "sending carriage returns as telnet <CR><LF>",
593: togcrlf,
594: &crlf,
1.10 art 595: 0 },
1.1 deraadt 596: { "crmod",
597: "mapping of received carriage returns",
598: 0,
599: &crmod,
1.10 art 600: "map carriage return on output" },
1.1 deraadt 601: { "localchars",
602: "local recognition of certain control characters",
603: lclchars,
604: &localchars,
1.10 art 605: "recognize certain control characters" },
1.8 robin 606: { " ", "", 0, 0 }, /* empty line */
1.1 deraadt 607: { "netdata",
608: "printing of hexadecimal network data (debugging)",
609: 0,
610: &netdata,
1.10 art 611: "print hexadecimal representation of network traffic" },
1.1 deraadt 612: { "prettydump",
613: "output of \"netdata\" to user readable format (debugging)",
614: 0,
615: &prettydump,
1.10 art 616: "print user readable output for \"netdata\"" },
1.1 deraadt 617: { "options",
618: "viewing of options processing (debugging)",
619: 0,
620: &showoptions,
1.10 art 621: "show option processing" },
1.1 deraadt 622: { "termdata",
623: "(debugging) toggle printing of hexadecimal terminal data",
624: 0,
625: &termdata,
1.10 art 626: "print hexadecimal representation of terminal traffic" },
1.1 deraadt 627: { "?",
628: 0,
1.10 art 629: togglehelp },
1.1 deraadt 630: { "help",
631: 0,
1.10 art 632: togglehelp },
1.1 deraadt 633: { 0 }
634: };
635:
1.69 jsg 636: static int
1.63 guenther 637: togglehelp(int unused)
1.1 deraadt 638: {
639: struct togglelist *c;
640:
641: for (c = Togglelist; c->name; c++) {
642: if (c->help) {
643: if (*c->help)
1.10 art 644: printf("%-15s toggle %s\r\n", c->name, c->help);
1.1 deraadt 645: else
1.10 art 646: printf("\r\n");
1.1 deraadt 647: }
648: }
1.10 art 649: printf("\r\n");
650: printf("%-15s %s\r\n", "?", "display help information");
1.1 deraadt 651: return 0;
652: }
653:
1.69 jsg 654: static void
655: settogglehelp(int set)
1.1 deraadt 656: {
657: struct togglelist *c;
658:
659: for (c = Togglelist; c->name; c++) {
660: if (c->help) {
661: if (*c->help)
1.10 art 662: printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable",
1.1 deraadt 663: c->help);
664: else
1.10 art 665: printf("\r\n");
1.1 deraadt 666: }
667: }
668: }
669:
670: #define GETTOGGLE(name) (struct togglelist *) \
671: genget(name, (char **) Togglelist, sizeof(struct togglelist))
672:
1.69 jsg 673: static int
674: toggle(int argc, char *argv[])
1.1 deraadt 675: {
676: int retval = 1;
677: char *name;
678: struct togglelist *c;
679:
680: if (argc < 2) {
681: fprintf(stderr,
1.10 art 682: "Need an argument to 'toggle' command. 'toggle ?' for help.\r\n");
1.1 deraadt 683: return 0;
684: }
685: argc--;
686: argv++;
687: while (argc--) {
688: name = *argv++;
689: c = GETTOGGLE(name);
690: if (Ambiguous(c)) {
1.10 art 691: fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\r\n",
1.1 deraadt 692: name);
693: return 0;
694: } else if (c == 0) {
1.10 art 695: fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\r\n",
1.1 deraadt 696: name);
697: return 0;
1.8 robin 698: } else if (!connected && c->needconnect) {
1.10 art 699: printf("?Need to be connected first.\r\n");
700: printf("'send ?' for help\r\n");
1.8 robin 701: return 0;
1.1 deraadt 702: } else {
703: if (c->variable) {
704: *c->variable = !*c->variable; /* invert it */
705: if (c->actionexplanation) {
1.10 art 706: printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
1.1 deraadt 707: c->actionexplanation);
708: }
709: }
710: if (c->handler) {
711: retval &= (*c->handler)(-1);
712: }
713: }
714: }
715: return retval;
716: }
717:
718: /*
719: * The following perform the "set" command.
720: */
721:
1.10 art 722: struct termios new_tc = { 0 };
1.1 deraadt 723:
724: struct setlist {
725: char *name; /* name */
726: char *help; /* help information */
1.70 guenther 727: void (*handler)(const char *);
1.1 deraadt 728: cc_t *charp; /* where it is located at */
729: };
730:
731: static struct setlist Setlist[] = {
732: #ifdef KLUDGELINEMODE
733: { "echo", "character to toggle local echoing on/off", 0, &echoc },
734: #endif
735: { "escape", "character to escape back to telnet command mode", 0, &escape },
736: { "rlogin", "rlogin escape character", 0, &rlogin },
737: { " ", "" },
738: { " ", "The following need 'localchars' to be toggled true", 0, 0 },
1.10 art 739: { "flushoutput", "character to cause an Abort Output", 0, &termFlushChar },
740: { "interrupt", "character to cause an Interrupt Process", 0, &termIntChar },
741: { "quit", "character to cause an Abort process", 0, &termQuitChar },
742: { "eof", "character to cause an EOF ", 0, &termEofChar },
1.1 deraadt 743: { " ", "" },
744: { " ", "The following are for local editing in linemode", 0, 0 },
1.10 art 745: { "erase", "character to use to erase a character", 0, &termEraseChar },
746: { "kill", "character to use to erase a line", 0, &termKillChar },
747: { "lnext", "character to use for literal next", 0, &termLiteralNextChar },
748: { "susp", "character to cause a Suspend Process", 0, &termSuspChar },
749: { "reprint", "character to use for line reprint", 0, &termRprntChar },
750: { "worderase", "character to use to erase a word", 0, &termWerasChar },
751: { "start", "character to use for XON", 0, &termStartChar },
752: { "stop", "character to use for XOFF", 0, &termStopChar },
753: { "forw1", "alternate end of line character", 0, &termForw1Char },
754: { "forw2", "alternate end of line character", 0, &termForw2Char },
755: { "ayt", "alternate AYT character", 0, &termAytChar },
1.1 deraadt 756: { 0 }
757: };
758:
1.69 jsg 759: static struct setlist *
760: getset(char *name)
1.1 deraadt 761: {
762: return (struct setlist *)
763: genget(name, (char **) Setlist, sizeof(struct setlist));
764: }
765:
1.69 jsg 766: void
767: set_escape_char(char *s)
1.1 deraadt 768: {
769: if (rlogin != _POSIX_VDISABLE) {
770: rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
1.10 art 771: printf("Telnet rlogin escape character is '%s'.\r\n",
1.1 deraadt 772: control(rlogin));
773: } else {
774: escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
1.10 art 775: printf("Telnet escape character is '%s'.\r\n", control(escape));
1.1 deraadt 776: }
777: }
778:
1.69 jsg 779: static int
780: setcmd(int argc, char *argv[])
1.1 deraadt 781: {
782: int value;
783: struct setlist *ct;
784: struct togglelist *c;
785:
786: if (argc < 2 || argc > 3) {
1.10 art 787: printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n");
1.1 deraadt 788: return 0;
789: }
790: if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
791: for (ct = Setlist; ct->name; ct++)
1.10 art 792: printf("%-15s %s\r\n", ct->name, ct->help);
793: printf("\r\n");
1.1 deraadt 794: settogglehelp(1);
1.10 art 795: printf("%-15s %s\r\n", "?", "display help information");
1.1 deraadt 796: return 0;
797: }
798:
799: ct = getset(argv[1]);
800: if (ct == 0) {
801: c = GETTOGGLE(argv[1]);
802: if (c == 0) {
1.10 art 803: fprintf(stderr, "'%s': unknown argument ('set ?' for help).\r\n",
1.1 deraadt 804: argv[1]);
805: return 0;
806: } else if (Ambiguous(c)) {
1.10 art 807: fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n",
1.1 deraadt 808: argv[1]);
809: return 0;
1.8 robin 810: } else if (!connected && c->needconnect) {
1.10 art 811: printf("?Need to be connected first.\r\n");
812: printf("'send ?' for help\r\n");
1.8 robin 813: return 0;
1.1 deraadt 814: }
1.8 robin 815:
1.1 deraadt 816: if (c->variable) {
817: if ((argc == 2) || (strcmp("on", argv[2]) == 0))
818: *c->variable = 1;
819: else if (strcmp("off", argv[2]) == 0)
820: *c->variable = 0;
821: else {
1.10 art 822: printf("Format is 'set togglename [on|off]'\r\n'set ?' for help.\r\n");
1.1 deraadt 823: return 0;
824: }
825: if (c->actionexplanation) {
1.10 art 826: printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
1.1 deraadt 827: c->actionexplanation);
828: }
829: }
830: if (c->handler)
831: (*c->handler)(1);
832: } else if (argc != 3) {
1.10 art 833: printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n");
1.1 deraadt 834: return 0;
835: } else if (Ambiguous(ct)) {
1.10 art 836: fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n",
1.1 deraadt 837: argv[1]);
838: return 0;
839: } else if (ct->handler) {
840: (*ct->handler)(argv[2]);
1.10 art 841: printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp);
1.1 deraadt 842: } else {
843: if (strcmp("off", argv[2])) {
844: value = special(argv[2]);
845: } else {
846: value = _POSIX_VDISABLE;
847: }
848: *(ct->charp) = (cc_t)value;
1.10 art 849: printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
1.1 deraadt 850: }
851: slc_check();
852: return 1;
853: }
854:
1.69 jsg 855: static int
856: unsetcmd(int argc, char *argv[])
1.1 deraadt 857: {
858: struct setlist *ct;
859: struct togglelist *c;
1.39 mpech 860: char *name;
1.1 deraadt 861:
862: if (argc < 2) {
863: fprintf(stderr,
1.10 art 864: "Need an argument to 'unset' command. 'unset ?' for help.\r\n");
1.1 deraadt 865: return 0;
866: }
867: if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
868: for (ct = Setlist; ct->name; ct++)
1.10 art 869: printf("%-15s %s\r\n", ct->name, ct->help);
870: printf("\r\n");
1.1 deraadt 871: settogglehelp(0);
1.10 art 872: printf("%-15s %s\r\n", "?", "display help information");
1.1 deraadt 873: return 0;
874: }
875:
876: argc--;
877: argv++;
878: while (argc--) {
879: name = *argv++;
880: ct = getset(name);
881: if (ct == 0) {
882: c = GETTOGGLE(name);
883: if (c == 0) {
1.10 art 884: fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\r\n",
1.1 deraadt 885: name);
886: return 0;
887: } else if (Ambiguous(c)) {
1.10 art 888: fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n",
1.1 deraadt 889: name);
890: return 0;
891: }
892: if (c->variable) {
893: *c->variable = 0;
894: if (c->actionexplanation) {
1.10 art 895: printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
1.1 deraadt 896: c->actionexplanation);
897: }
898: }
899: if (c->handler)
900: (*c->handler)(0);
901: } else if (Ambiguous(ct)) {
1.10 art 902: fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n",
1.1 deraadt 903: name);
904: return 0;
905: } else if (ct->handler) {
1.63 guenther 906: (*ct->handler)(NULL);
1.10 art 907: printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp);
1.1 deraadt 908: } else {
909: *(ct->charp) = _POSIX_VDISABLE;
1.10 art 910: printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
1.1 deraadt 911: }
912: }
913: return 1;
914: }
915:
916: /*
917: * The following are the data structures and routines for the
918: * 'mode' command.
919: */
920: #ifdef KLUDGELINEMODE
1.69 jsg 921: static int
922: dokludgemode(int unused)
1.1 deraadt 923: {
924: kludgelinemode = 1;
925: send_wont(TELOPT_LINEMODE, 1);
926: send_dont(TELOPT_SGA, 1);
927: send_dont(TELOPT_ECHO, 1);
1.10 art 928: return 1;
1.1 deraadt 929: }
930: #endif
931:
1.69 jsg 932: static int
933: dolinemode(int unused)
1.1 deraadt 934: {
935: #ifdef KLUDGELINEMODE
936: if (kludgelinemode)
937: send_dont(TELOPT_SGA, 1);
938: #endif
939: send_will(TELOPT_LINEMODE, 1);
940: send_dont(TELOPT_ECHO, 1);
941: return 1;
942: }
943:
1.69 jsg 944: static int
945: docharmode(int unused)
1.1 deraadt 946: {
947: #ifdef KLUDGELINEMODE
948: if (kludgelinemode)
949: send_do(TELOPT_SGA, 1);
950: else
951: #endif
952: send_wont(TELOPT_LINEMODE, 1);
953: send_do(TELOPT_ECHO, 1);
954: return 1;
955: }
956:
1.69 jsg 957: static int
958: dolmmode(int bit, int on)
1.1 deraadt 959: {
960: unsigned char c;
961:
962: if (my_want_state_is_wont(TELOPT_LINEMODE)) {
1.10 art 963: printf("?Need to have LINEMODE option enabled first.\r\n");
964: printf("'mode ?' for help.\r\n");
1.1 deraadt 965: return 0;
966: }
967:
968: if (on)
969: c = (linemode | bit);
970: else
971: c = (linemode & ~bit);
972: lm_mode(&c, 1, 1);
973: return 1;
974: }
975:
1.69 jsg 976: int
977: tn_setmode(int bit)
1.1 deraadt 978: {
979: return dolmmode(bit, 1);
980: }
981:
1.69 jsg 982: int
983: tn_clearmode(int bit)
1.1 deraadt 984: {
985: return dolmmode(bit, 0);
986: }
987:
988: struct modelist {
989: char *name; /* command name */
990: char *help; /* help string */
1.63 guenther 991: int (*handler)(int);/* routine which executes command */
1.1 deraadt 992: int needconnect; /* Do we need to be connected to execute? */
993: int arg1;
994: };
995:
1.63 guenther 996: static int modehelp(int);
1.1 deraadt 997:
998: static struct modelist ModeList[] = {
999: { "character", "Disable LINEMODE option", docharmode, 1 },
1000: #ifdef KLUDGELINEMODE
1001: { "", "(or disable obsolete line-by-line mode)", 0 },
1002: #endif
1003: { "line", "Enable LINEMODE option", dolinemode, 1 },
1004: #ifdef KLUDGELINEMODE
1005: { "", "(or enable obsolete line-by-line mode)", 0 },
1006: #endif
1007: { "", "", 0 },
1008: { "", "These require the LINEMODE option to be enabled", 0 },
1.10 art 1009: { "isig", "Enable signal trapping", tn_setmode, 1, MODE_TRAPSIG },
1010: { "+isig", 0, tn_setmode, 1, MODE_TRAPSIG },
1011: { "-isig", "Disable signal trapping", tn_clearmode, 1, MODE_TRAPSIG },
1012: { "edit", "Enable character editing", tn_setmode, 1, MODE_EDIT },
1013: { "+edit", 0, tn_setmode, 1, MODE_EDIT },
1014: { "-edit", "Disable character editing", tn_clearmode, 1, MODE_EDIT },
1015: { "softtabs", "Enable tab expansion", tn_setmode, 1, MODE_SOFT_TAB },
1016: { "+softtabs", 0, tn_setmode, 1, MODE_SOFT_TAB },
1017: { "-softtabs", "Disable character editing", tn_clearmode, 1, MODE_SOFT_TAB },
1018: { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO },
1019: { "+litecho", 0, tn_setmode, 1, MODE_LIT_ECHO },
1020: { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO },
1.1 deraadt 1021: { "help", 0, modehelp, 0 },
1022: #ifdef KLUDGELINEMODE
1023: { "kludgeline", 0, dokludgemode, 1 },
1024: #endif
1025: { "", "", 0 },
1026: { "?", "Print help information", modehelp, 0 },
1027: { 0 },
1028: };
1029:
1.69 jsg 1030: static int
1.63 guenther 1031: modehelp(int unused)
1.1 deraadt 1032: {
1033: struct modelist *mt;
1034:
1.10 art 1035: printf("format is: 'mode Mode', where 'Mode' is one of:\r\n\r\n");
1.1 deraadt 1036: for (mt = ModeList; mt->name; mt++) {
1037: if (mt->help) {
1038: if (*mt->help)
1.10 art 1039: printf("%-15s %s\r\n", mt->name, mt->help);
1.1 deraadt 1040: else
1.10 art 1041: printf("\r\n");
1.1 deraadt 1042: }
1043: }
1044: return 0;
1045: }
1046:
1047: #define GETMODECMD(name) (struct modelist *) \
1048: genget(name, (char **) ModeList, sizeof(struct modelist))
1049:
1.69 jsg 1050: static int
1051: modecmd(int argc, char *argv[])
1.1 deraadt 1052: {
1053: struct modelist *mt;
1054:
1055: if (argc != 2) {
1.10 art 1056: printf("'mode' command requires an argument\r\n");
1057: printf("'mode ?' for help.\r\n");
1.1 deraadt 1058: } else if ((mt = GETMODECMD(argv[1])) == 0) {
1.10 art 1059: fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]);
1.1 deraadt 1060: } else if (Ambiguous(mt)) {
1.10 art 1061: fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]);
1.1 deraadt 1062: } else if (mt->needconnect && !connected) {
1.10 art 1063: printf("?Need to be connected first.\r\n");
1064: printf("'mode ?' for help.\r\n");
1.1 deraadt 1065: } else if (mt->handler) {
1066: return (*mt->handler)(mt->arg1);
1067: }
1068: return 0;
1069: }
1070:
1071: /*
1072: * The following data structures and routines implement the
1073: * "display" command.
1074: */
1075:
1.69 jsg 1076: static int
1077: display(int argc, char *argv[])
1.1 deraadt 1078: {
1079: struct togglelist *tl;
1080: struct setlist *sl;
1081:
1082: #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1083: if (*tl->variable) { \
1084: printf("will"); \
1085: } else { \
1086: printf("won't"); \
1087: } \
1.10 art 1088: printf(" %s.\r\n", tl->actionexplanation); \
1.1 deraadt 1089: }
1090:
1091: #define doset(sl) if (sl->name && *sl->name != ' ') { \
1092: if (sl->handler == 0) \
1.10 art 1093: printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \
1.1 deraadt 1094: else \
1.10 art 1095: printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \
1.1 deraadt 1096: }
1097:
1098: if (argc == 1) {
1099: for (tl = Togglelist; tl->name; tl++) {
1100: dotog(tl);
1101: }
1.10 art 1102: printf("\r\n");
1.1 deraadt 1103: for (sl = Setlist; sl->name; sl++) {
1104: doset(sl);
1105: }
1106: } else {
1107: int i;
1108:
1109: for (i = 1; i < argc; i++) {
1110: sl = getset(argv[i]);
1111: tl = GETTOGGLE(argv[i]);
1112: if (Ambiguous(sl) || Ambiguous(tl)) {
1.10 art 1113: printf("?Ambiguous argument '%s'.\r\n", argv[i]);
1.1 deraadt 1114: return 0;
1115: } else if (!sl && !tl) {
1.10 art 1116: printf("?Unknown argument '%s'.\r\n", argv[i]);
1.1 deraadt 1117: return 0;
1118: } else {
1119: if (tl) {
1120: dotog(tl);
1121: }
1122: if (sl) {
1123: doset(sl);
1124: }
1125: }
1126: }
1127: }
1128: /*@*/optionstatus();
1129: return 1;
1130: #undef doset
1131: #undef dotog
1132: }
1.10 art 1133:
1.1 deraadt 1134: /*
1135: * The following are the data structures, and many of the routines,
1136: * relating to command processing.
1137: */
1138:
1139: /*
1140: * Set the escape character.
1141: */
1.69 jsg 1142: static int
1143: setescape(int argc, char *argv[])
1.1 deraadt 1144: {
1.39 mpech 1145: char *arg;
1.1 deraadt 1146: char buf[50];
1147:
1148: printf(
1.10 art 1149: "Deprecated usage - please use 'set escape%s%s' in the future.\r\n",
1.1 deraadt 1150: (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
1151: if (argc > 2)
1152: arg = argv[1];
1153: else {
1154: printf("new escape character: ");
1155: (void) fgets(buf, sizeof(buf), stdin);
1156: arg = buf;
1157: }
1158: if (arg[0] != '\0')
1159: escape = arg[0];
1.56 guenther 1160: printf("Escape character is '%s'.\r\n", control(escape));
1.1 deraadt 1161: (void) fflush(stdout);
1162: return 1;
1163: }
1164:
1.69 jsg 1165: static int
1166: togcrmod(int unused1, char *unused2[])
1.1 deraadt 1167: {
1168: crmod = !crmod;
1.10 art 1169: printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n");
1170: printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't");
1.1 deraadt 1171: (void) fflush(stdout);
1172: return 1;
1173: }
1174:
1.69 jsg 1175: int
1176: telnetsuspend(int unused1, char *unused2[])
1.1 deraadt 1177: {
1178: setcommandmode();
1179: {
1180: long oldrows, oldcols, newrows, newcols, err;
1181:
1182: err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1183: (void) kill(0, SIGTSTP);
1184: /*
1185: * If we didn't get the window size before the SUSPEND, but we
1.3 niklas 1186: * can get them now (?), then send the NAWS to make sure that
1.1 deraadt 1187: * we are set up for the right window size.
1188: */
1189: if (TerminalWindowSize(&newrows, &newcols) && connected &&
1190: (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1191: sendnaws();
1192: }
1193: }
1194: /* reget parameters in case they were changed */
1195: TerminalSaveState();
1196: setconnmode(0);
1197: return 1;
1198: }
1199:
1.68 guenther 1200: static void
1201: close_connection(void)
1202: {
1203: if (connected) {
1.80 jca 1204: (void) shutdown(net, SHUT_RDWR);
1.68 guenther 1205: printf("Connection closed.\r\n");
1206: (void)close(net);
1207: connected = 0;
1208: resettermname = 1;
1209: /* reset options */
1210: tninit();
1211: }
1212: }
1213:
1214: static int
1.69 jsg 1215: bye(int argc, char *argv[])
1.1 deraadt 1216: {
1.68 guenther 1217: close_connection();
1.1 deraadt 1218: longjmp(toplevel, 1);
1219: }
1220:
1.63 guenther 1221: void
1.59 guenther 1222: quit(void)
1.1 deraadt 1223: {
1.68 guenther 1224: close_connection();
1.1 deraadt 1225: Exit(0);
1226: }
1227:
1.63 guenther 1228: static int
1229: quitcmd(int unused1, char *unused2[])
1230: {
1231: quit();
1232: }
1233:
1.69 jsg 1234: static int
1235: logout(int unused1, char *unused2[])
1.1 deraadt 1236: {
1237: send_do(TELOPT_LOGOUT, 1);
1238: (void) netflush();
1239: return 1;
1240: }
1241:
1242:
1243: /*
1244: * The SLC command.
1245: */
1246:
1247: struct slclist {
1248: char *name;
1249: char *help;
1.63 guenther 1250: void (*handler)(int);
1.1 deraadt 1251: int arg;
1252: };
1253:
1.63 guenther 1254: static void slc_help(int);
1.1 deraadt 1255:
1256: struct slclist SlcList[] = {
1257: { "export", "Use local special character definitions",
1258: slc_mode_export, 0 },
1259: { "import", "Use remote special character definitions",
1260: slc_mode_import, 1 },
1261: { "check", "Verify remote special character definitions",
1262: slc_mode_import, 0 },
1263: { "help", 0, slc_help, 0 },
1264: { "?", "Print help information", slc_help, 0 },
1265: { 0 },
1266: };
1267:
1.69 jsg 1268: static void
1.63 guenther 1269: slc_help(int unused)
1.1 deraadt 1270: {
1271: struct slclist *c;
1272:
1273: for (c = SlcList; c->name; c++) {
1274: if (c->help) {
1275: if (*c->help)
1.10 art 1276: printf("%-15s %s\r\n", c->name, c->help);
1.1 deraadt 1277: else
1.10 art 1278: printf("\r\n");
1.1 deraadt 1279: }
1280: }
1281: }
1282:
1.69 jsg 1283: static struct slclist *
1284: getslc(char *name)
1.1 deraadt 1285: {
1286: return (struct slclist *)
1287: genget(name, (char **) SlcList, sizeof(struct slclist));
1288: }
1289:
1.69 jsg 1290: static int
1291: slccmd(int argc, char *argv[])
1.1 deraadt 1292: {
1293: struct slclist *c;
1294:
1295: if (argc != 2) {
1296: fprintf(stderr,
1.10 art 1297: "Need an argument to 'slc' command. 'slc ?' for help.\r\n");
1.1 deraadt 1298: return 0;
1299: }
1300: c = getslc(argv[1]);
1301: if (c == 0) {
1.10 art 1302: fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\r\n",
1.1 deraadt 1303: argv[1]);
1.3 niklas 1304: return 0;
1.1 deraadt 1305: }
1306: if (Ambiguous(c)) {
1.10 art 1307: fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\r\n",
1.1 deraadt 1308: argv[1]);
1.3 niklas 1309: return 0;
1.1 deraadt 1310: }
1311: (*c->handler)(c->arg);
1312: slcstate();
1313: return 1;
1314: }
1315:
1316: /*
1317: * The ENVIRON command.
1318: */
1319:
1320: struct envlist {
1321: char *name;
1322: char *help;
1323: void (*handler)();
1324: int narg;
1325: };
1326:
1.41 millert 1327: static void env_help(void);
1.70 guenther 1328: static void env_undefine(const char *);
1329: static void env_export(const char *);
1330: static void env_unexport(const char *);
1331: static void env_send(const char *);
1.67 guenther 1332: static void env_list(void);
1.70 guenther 1333: static struct env_lst *env_find(const char *var);
1.1 deraadt 1334:
1335: struct envlist EnvList[] = {
1336: { "define", "Define an environment variable",
1337: (void (*)())env_define, 2 },
1338: { "undefine", "Undefine an environment variable",
1339: env_undefine, 1 },
1340: { "export", "Mark an environment variable for automatic export",
1341: env_export, 1 },
1342: { "unexport", "Don't mark an environment variable for automatic export",
1343: env_unexport, 1 },
1344: { "send", "Send an environment variable", env_send, 1 },
1345: { "list", "List the current environment variables",
1346: env_list, 0 },
1347: { "help", 0, env_help, 0 },
1348: { "?", "Print help information", env_help, 0 },
1349: { 0 },
1350: };
1351:
1.67 guenther 1352: static void
1.69 jsg 1353: env_help(void)
1.1 deraadt 1354: {
1355: struct envlist *c;
1356:
1357: for (c = EnvList; c->name; c++) {
1358: if (c->help) {
1359: if (*c->help)
1.10 art 1360: printf("%-15s %s\r\n", c->name, c->help);
1.1 deraadt 1361: else
1.10 art 1362: printf("\r\n");
1.1 deraadt 1363: }
1364: }
1365: }
1366:
1.67 guenther 1367: static struct envlist *
1.69 jsg 1368: getenvcmd(char *name)
1.1 deraadt 1369: {
1370: return (struct envlist *)
1371: genget(name, (char **) EnvList, sizeof(struct envlist));
1372: }
1373:
1.67 guenther 1374: static int
1.69 jsg 1375: env_cmd(int argc, char *argv[])
1.1 deraadt 1376: {
1377: struct envlist *c;
1378:
1379: if (argc < 2) {
1380: fprintf(stderr,
1.10 art 1381: "Need an argument to 'environ' command. 'environ ?' for help.\r\n");
1.1 deraadt 1382: return 0;
1383: }
1384: c = getenvcmd(argv[1]);
1385: if (c == 0) {
1.10 art 1386: fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\r\n",
1.1 deraadt 1387: argv[1]);
1.3 niklas 1388: return 0;
1.1 deraadt 1389: }
1390: if (Ambiguous(c)) {
1.10 art 1391: fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\r\n",
1.1 deraadt 1392: argv[1]);
1.3 niklas 1393: return 0;
1.1 deraadt 1394: }
1395: if (c->narg + 2 != argc) {
1396: fprintf(stderr,
1.10 art 1397: "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\r\n",
1.1 deraadt 1398: c->narg < argc + 2 ? "only " : "",
1399: c->narg, c->narg == 1 ? "" : "s", c->name);
1400: return 0;
1401: }
1402: (*c->handler)(argv[2], argv[3]);
1403: return 1;
1404: }
1405:
1406: struct env_lst {
1407: struct env_lst *next; /* pointer to next structure */
1408: struct env_lst *prev; /* pointer to previous structure */
1.70 guenther 1409: char *var; /* pointer to variable name */
1410: char *value; /* pointer to variable value */
1.1 deraadt 1411: int export; /* 1 -> export with default list of variables */
1412: int welldefined; /* A well defined variable */
1413: };
1414:
1415: struct env_lst envlisthead;
1416:
1.67 guenther 1417: static struct env_lst *
1.70 guenther 1418: env_find(const char *var)
1.1 deraadt 1419: {
1.39 mpech 1420: struct env_lst *ep;
1.1 deraadt 1421:
1422: for (ep = envlisthead.next; ep; ep = ep->next) {
1.70 guenther 1423: if (strcmp(ep->var, var) == 0)
1.1 deraadt 1424: return(ep);
1425: }
1426: return(NULL);
1427: }
1428:
1.69 jsg 1429: void
1430: env_init(void)
1.1 deraadt 1431: {
1432: extern char **environ;
1.10 art 1433: char **epp, *cp;
1434: struct env_lst *ep;
1.1 deraadt 1435:
1436: for (epp = environ; *epp; epp++) {
1.10 art 1437: if ((cp = strchr(*epp, '='))) {
1.1 deraadt 1438: *cp = '\0';
1.70 guenther 1439: ep = env_define(*epp, cp+1);
1.1 deraadt 1440: ep->export = 0;
1441: *cp = '=';
1442: }
1443: }
1444: /*
1445: * Special case for DISPLAY variable. If it is ":0.0" or
1446: * "unix:0.0", we have to get rid of "unix" and insert our
1447: * hostname.
1448: */
1449: if ((ep = env_find("DISPLAY"))
1450: && ((*ep->value == ':')
1.70 guenther 1451: || (strncmp(ep->value, "unix:", 5) == 0))) {
1.71 deraadt 1452: char hbuf[HOST_NAME_MAX+1];
1.70 guenther 1453: char *cp2 = strchr(ep->value, ':');
1.1 deraadt 1454:
1.18 deraadt 1455: gethostname(hbuf, sizeof hbuf);
1.10 art 1456:
1.44 pvalchev 1457: if (asprintf (&cp, "%s%s", hbuf, cp2) == -1)
1.14 art 1458: err(1, "asprintf");
1.10 art 1459:
1.1 deraadt 1460: free(ep->value);
1.70 guenther 1461: ep->value = cp;
1.1 deraadt 1462: }
1463: /*
1464: * If USER is not defined, but LOGNAME is, then add
1465: * USER with the value from LOGNAME. By default, we
1466: * don't export the USER variable.
1467: */
1468: if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
1.70 guenther 1469: env_define("USER", ep->value);
1470: env_unexport("USER");
1.1 deraadt 1471: }
1.70 guenther 1472: env_export("DISPLAY");
1473: env_export("PRINTER");
1474: env_export("XAUTHORITY");
1.1 deraadt 1475: }
1476:
1.69 jsg 1477: struct env_lst *
1.70 guenther 1478: env_define(const char *var, const char *value)
1.1 deraadt 1479: {
1.39 mpech 1480: struct env_lst *ep;
1.1 deraadt 1481:
1.10 art 1482: if ((ep = env_find(var))) {
1.82 mmcc 1483: free(ep->var);
1484: free(ep->value);
1.1 deraadt 1485: } else {
1.14 art 1486: if ((ep = malloc(sizeof(struct env_lst))) == NULL)
1487: err(1, "malloc");
1.1 deraadt 1488: ep->next = envlisthead.next;
1489: envlisthead.next = ep;
1490: ep->prev = &envlisthead;
1491: if (ep->next)
1492: ep->next->prev = ep;
1493: }
1.70 guenther 1494: ep->welldefined = opt_welldefined(var);
1.1 deraadt 1495: ep->export = 1;
1.70 guenther 1496: if ((ep->var = strdup(var)) == NULL)
1.14 art 1497: err(1, "strdup");
1.70 guenther 1498: if ((ep->value = strdup(value)) == NULL)
1.14 art 1499: err(1, "strdup");
1.1 deraadt 1500: return(ep);
1501: }
1502:
1.67 guenther 1503: static void
1.70 guenther 1504: env_undefine(const char *var)
1.1 deraadt 1505: {
1.39 mpech 1506: struct env_lst *ep;
1.1 deraadt 1507:
1.10 art 1508: if ((ep = env_find(var))) {
1.1 deraadt 1509: ep->prev->next = ep->next;
1510: if (ep->next)
1511: ep->next->prev = ep->prev;
1.82 mmcc 1512: free(ep->var);
1513: free(ep->value);
1.1 deraadt 1514: free(ep);
1515: }
1516: }
1517:
1.67 guenther 1518: static void
1.70 guenther 1519: env_export(const char *var)
1.1 deraadt 1520: {
1.39 mpech 1521: struct env_lst *ep;
1.1 deraadt 1522:
1.10 art 1523: if ((ep = env_find(var)))
1.1 deraadt 1524: ep->export = 1;
1525: }
1526:
1.67 guenther 1527: static void
1.70 guenther 1528: env_unexport(const char *var)
1.1 deraadt 1529: {
1.39 mpech 1530: struct env_lst *ep;
1.1 deraadt 1531:
1.15 art 1532: if ((ep = env_find(var)) != NULL)
1.1 deraadt 1533: ep->export = 0;
1534: }
1535:
1.67 guenther 1536: static void
1.70 guenther 1537: env_send(const char *var)
1.1 deraadt 1538: {
1.39 mpech 1539: struct env_lst *ep;
1.1 deraadt 1540:
1.3 niklas 1541: if (my_state_is_wont(TELOPT_NEW_ENVIRON)
1.1 deraadt 1542: ) {
1543: fprintf(stderr,
1.10 art 1544: "Cannot send '%s': Telnet ENVIRON option not enabled\r\n",
1.1 deraadt 1545: var);
1546: return;
1547: }
1548: ep = env_find(var);
1549: if (ep == 0) {
1.10 art 1550: fprintf(stderr, "Cannot send '%s': variable not defined\r\n",
1.1 deraadt 1551: var);
1552: return;
1553: }
1554: env_opt_start_info();
1555: env_opt_add(ep->var);
1556: env_opt_end(0);
1557: }
1558:
1.67 guenther 1559: static void
1.69 jsg 1560: env_list(void)
1.1 deraadt 1561: {
1.39 mpech 1562: struct env_lst *ep;
1.1 deraadt 1563:
1564: for (ep = envlisthead.next; ep; ep = ep->next) {
1.10 art 1565: printf("%c %-20s %s\r\n", ep->export ? '*' : ' ',
1.1 deraadt 1566: ep->var, ep->value);
1567: }
1568: }
1569:
1.70 guenther 1570: char *
1.69 jsg 1571: env_default(int init, int welldefined)
1.1 deraadt 1572: {
1573: static struct env_lst *nep = NULL;
1574:
1575: if (init) {
1576: nep = &envlisthead;
1.10 art 1577: return NULL;
1.1 deraadt 1578: }
1579: if (nep) {
1.10 art 1580: while ((nep = nep->next)) {
1.1 deraadt 1581: if (nep->export && (nep->welldefined == welldefined))
1582: return(nep->var);
1583: }
1584: }
1585: return(NULL);
1586: }
1587:
1.70 guenther 1588: char *
1589: env_getvalue(const char *var, int exported_only)
1.1 deraadt 1590: {
1.39 mpech 1591: struct env_lst *ep;
1.1 deraadt 1592:
1.48 otto 1593: if ((ep = env_find(var)) && (!exported_only || ep->export))
1.1 deraadt 1594: return(ep->value);
1595: return(NULL);
1596: }
1597:
1.68 guenther 1598: static void
1599: connection_status(int local_only)
1600: {
1601: if (!connected)
1602: printf("No connection.\r\n");
1603: else {
1604: printf("Connected to %s.\r\n", hostname);
1605: if (!local_only) {
1606: int mode = getconnmode();
1607:
1608: printf("Operating ");
1609: if (my_want_state_is_will(TELOPT_LINEMODE)) {
1610: printf("with LINEMODE option\r\n"
1611: "%s line editing\r\n"
1612: "%s catching of signals\r\n",
1613: (mode & MODE_EDIT) ? "Local" : "No",
1614: (mode & MODE_TRAPSIG) ? "Local" : "No");
1615: slcstate();
1616: #ifdef KLUDGELINEMODE
1617: } else if (kludgelinemode &&
1618: my_want_state_is_dont(TELOPT_SGA)) {
1619: printf("in obsolete linemode\r\n");
1620: #endif
1621: } else {
1622: printf("in single character mode\r\n");
1623: if (localchars)
1624: printf("Catching signals locally\r\n");
1625: }
1626:
1627: printf("%s character echo\r\n",
1628: (mode & MODE_ECHO) ? "Local" : "Remote");
1629: if (my_want_state_is_will(TELOPT_LFLOW))
1630: printf("%s flow control\r\n",
1631: (mode & MODE_FLOW) ? "Local" : "No");
1632: }
1633: }
1634: printf("Escape character is '%s'.\r\n", control(escape));
1635: (void) fflush(stdout);
1636: }
1637:
1.1 deraadt 1638: /*
1639: * Print status about the connection.
1640: */
1.68 guenther 1641: static int
1642: status(int argc, char *argv[])
1.1 deraadt 1643: {
1.68 guenther 1644: connection_status(0);
1645: return 1;
1.1 deraadt 1646: }
1647:
1648: /*
1649: * Function that gets called when SIGINFO is received.
1650: */
1.10 art 1651: void
1.68 guenther 1652: ayt_status(int sig)
1.1 deraadt 1653: {
1.68 guenther 1654: connection_status(1);
1.1 deraadt 1655: }
1656:
1.10 art 1657: static Command *getcmd(char *name);
1658:
1659: static void
1660: cmdrc(char *m1, char *m2)
1661: {
1662: static char rcname[128];
1663: Command *c;
1664: FILE *rcfile;
1665: int gotmachine = 0;
1666: int l1 = strlen(m1);
1667: int l2 = strlen(m2);
1.71 deraadt 1668: char m1save[HOST_NAME_MAX+1];
1.10 art 1669:
1670: if (skiprc)
1671: return;
1672:
1.34 aaron 1673: strlcpy(m1save, m1, sizeof(m1save));
1.10 art 1674: m1 = m1save;
1675:
1676: if (rcname[0] == 0) {
1677: char *home = getenv("HOME");
1678:
1.29 millert 1679: if (home == NULL || *home == '\0')
1680: return;
1.10 art 1681: snprintf (rcname, sizeof(rcname), "%s/.telnetrc",
1682: home ? home : "");
1683: }
1684:
1685: if ((rcfile = fopen(rcname, "r")) == 0) {
1686: return;
1687: }
1688:
1689: for (;;) {
1690: if (fgets(line, sizeof(line), rcfile) == NULL)
1691: break;
1692: if (line[0] == 0)
1693: break;
1694: if (line[0] == '#')
1695: continue;
1696: if (gotmachine) {
1.60 guenther 1697: if (!isspace((unsigned char)line[0]))
1.10 art 1698: gotmachine = 0;
1699: }
1700: if (gotmachine == 0) {
1.60 guenther 1701: if (isspace((unsigned char)line[0]))
1.10 art 1702: continue;
1703: if (strncasecmp(line, m1, l1) == 0)
1704: strncpy(line, &line[l1], sizeof(line) - l1);
1705: else if (strncasecmp(line, m2, l2) == 0)
1706: strncpy(line, &line[l2], sizeof(line) - l2);
1707: else if (strncasecmp(line, "DEFAULT", 7) == 0)
1708: strncpy(line, &line[7], sizeof(line) - 7);
1709: else
1710: continue;
1711: if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
1712: continue;
1713: gotmachine = 1;
1714: }
1.86 deraadt 1715: if (makeargv())
1716: continue;
1.10 art 1717: if (margv[0] == 0)
1718: continue;
1719: c = getcmd(margv[0]);
1720: if (Ambiguous(c)) {
1721: printf("?Ambiguous command: %s\r\n", margv[0]);
1722: continue;
1723: }
1724: if (c == 0) {
1725: printf("?Invalid command: %s\r\n", margv[0]);
1726: continue;
1727: }
1728: /*
1729: * This should never happen...
1730: */
1731: if (c->needconnect && !connected) {
1732: printf("?Need to be connected first for %s.\r\n", margv[0]);
1733: continue;
1734: }
1735: (*c->handler)(margc, margv);
1736: }
1737: fclose(rcfile);
1738: }
1739:
1.69 jsg 1740: int
1741: tn(int argc, char *argv[])
1.1 deraadt 1742: {
1.23 itojun 1743: struct addrinfo hints, *res, *res0;
1.5 niklas 1744: char *cmd, *hostp = 0, *portp = 0, *user = 0, *aliasp = 0;
1.73 jca 1745: int error, retry;
1.74 jca 1746: const int niflags = NI_NUMERICHOST, tos = IPTOS_LOWDELAY;
1.1 deraadt 1747:
1748: if (connected) {
1.10 art 1749: printf("?Already connected to %s\r\n", hostname);
1.81 beck 1750: return 0;
1751: }
1752: if (connections) {
1753: printf("Repeated connections not supported\r\n");
1.1 deraadt 1754: return 0;
1755: }
1756: if (argc < 2) {
1.43 hin 1757: strlcpy(line, "open ", sizeof(line));
1.1 deraadt 1758: printf("(to) ");
1759: (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
1.86 deraadt 1760: if (makeargv())
1761: return 0;
1.1 deraadt 1762: argc = margc;
1763: argv = margv;
1764: }
1765: cmd = *argv;
1766: --argc; ++argv;
1767: while (argc) {
1.3 niklas 1768: if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
1.1 deraadt 1769: goto usage;
1770: if (strcmp(*argv, "-l") == 0) {
1771: --argc; ++argv;
1772: if (argc == 0)
1773: goto usage;
1.14 art 1774: if ((user = strdup(*argv++)) == NULL)
1775: err(1, "strdup");
1.1 deraadt 1776: --argc;
1777: continue;
1778: }
1.5 niklas 1779: if (strcmp(*argv, "-b") == 0) {
1780: --argc; ++argv;
1781: if (argc == 0)
1782: goto usage;
1783: aliasp = *argv++;
1784: --argc;
1785: continue;
1786: }
1.1 deraadt 1787: if (strcmp(*argv, "-a") == 0) {
1788: --argc; ++argv;
1789: autologin = 1;
1790: continue;
1791: }
1792: if (hostp == 0) {
1793: hostp = *argv++;
1794: --argc;
1795: continue;
1796: }
1797: if (portp == 0) {
1798: portp = *argv++;
1799: --argc;
1800: continue;
1801: }
1802: usage:
1.56 guenther 1803: printf("usage: %s [-a] [-b hostalias] [-l user] host-name [port]\r\n", cmd);
1.1 deraadt 1804: return 0;
1805: }
1806: if (hostp == 0)
1807: goto usage;
1808:
1.72 jca 1809: hostname = hostp;
1810: memset(&hints, 0, sizeof(hints));
1811: hints.ai_family = family;
1812: hints.ai_socktype = SOCK_STREAM;
1813: hints.ai_flags = AI_CANONNAME;
1814: if (portp == NULL) {
1815: portp = "telnet";
1816: telnetport = 1;
1817: } else if (*portp == '-') {
1818: portp++;
1819: telnetport = 1;
1.23 itojun 1820: } else
1.72 jca 1821: telnetport = 0;
1822: error = getaddrinfo(hostp, portp, &hints, &res0);
1823: if (error) {
1824: if (error == EAI_SERVICE)
1825: warnx("%s: bad port", portp);
1826: else
1827: warnx("%s: %s", hostp, gai_strerror(error));
1828: return 0;
1.1 deraadt 1829: }
1.10 art 1830:
1.23 itojun 1831: net = -1;
1832: retry = 0;
1833: for (res = res0; res; res = res->ai_next) {
1834: if (1 /* retry */) {
1.31 itojun 1835: char hbuf[NI_MAXHOST];
1.23 itojun 1836:
1.31 itojun 1837: if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
1838: NULL, 0, niflags) != 0) {
1.43 hin 1839: strlcpy(hbuf, "(invalid)", sizeof(hbuf));
1.31 itojun 1840: }
1.23 itojun 1841: printf("Trying %s...\r\n", hbuf);
1842: }
1843: net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1.87 deraadt 1844: if (net == -1)
1.23 itojun 1845: continue;
1.10 art 1846:
1.5 niklas 1847: if (aliasp) {
1.23 itojun 1848: struct addrinfo ahints, *ares;
1849:
1850: memset(&ahints, 0, sizeof(ahints));
1.46 otto 1851: ahints.ai_family = family;
1.23 itojun 1852: ahints.ai_socktype = SOCK_STREAM;
1853: ahints.ai_flags = AI_PASSIVE;
1854: error = getaddrinfo(aliasp, "0", &ahints, &ares);
1855: if (error) {
1856: warn("%s: %s", aliasp, gai_strerror(error));
1857: close(net);
1.49 otto 1858: net = -1;
1.23 itojun 1859: continue;
1.5 niklas 1860: }
1.87 deraadt 1861: if (bind(net, ares->ai_addr, ares->ai_addrlen) == -1) {
1.31 itojun 1862: perror(aliasp);
1863: (void) close(net); /* dump descriptor */
1.49 otto 1864: net = -1;
1.23 itojun 1865: freeaddrinfo(ares);
1866: continue;
1.5 niklas 1867: }
1.23 itojun 1868: freeaddrinfo(ares);
1869: }
1.74 jca 1870:
1871: switch (res->ai_family) {
1872: case AF_INET:
1.87 deraadt 1873: if (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1
1.74 jca 1874: && errno != ENOPROTOOPT)
1875: perror("telnet: setsockopt (IP_TOS) (ignored)");
1876: break;
1877: case AF_INET6:
1878: if (setsockopt(net, IPPROTO_IPV6, IPV6_TCLASS, &tos,
1.87 deraadt 1879: sizeof(tos)) == -1 && errno != ENOPROTOOPT)
1.74 jca 1880: perror("telnet: setsockopt (IPV6_TCLASS) (ignored)");
1881: break;
1.1 deraadt 1882: }
1883:
1.87 deraadt 1884: if (connect(net, res->ai_addr, res->ai_addrlen) == -1) {
1.31 itojun 1885: char hbuf[NI_MAXHOST];
1.16 deraadt 1886:
1.31 itojun 1887: if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
1888: NULL, 0, niflags) != 0) {
1.43 hin 1889: strlcpy(hbuf, "(invalid)", sizeof(hbuf));
1.31 itojun 1890: }
1.25 itojun 1891: fprintf(stderr, "telnet: connect to address %s: %s\n", hbuf,
1892: strerror(errno));
1.23 itojun 1893:
1894: close(net);
1895: net = -1;
1896: retry++;
1897: continue;
1.1 deraadt 1898: }
1.23 itojun 1899:
1.1 deraadt 1900: connected++;
1.23 itojun 1901: break;
1902: }
1903: freeaddrinfo(res0);
1904: if (net < 0) {
1905: return 0;
1906: }
1.1 deraadt 1907: cmdrc(hostp, hostname);
1908: if (autologin && user == NULL) {
1909: struct passwd *pw;
1910:
1.58 guenther 1911: user = getlogin();
1.1 deraadt 1912: if (user == NULL ||
1.58 guenther 1913: (pw = getpwnam(user)) == NULL || pw->pw_uid != getuid()) {
1.15 art 1914: if ((pw = getpwuid(getuid())) != NULL)
1.1 deraadt 1915: user = pw->pw_name;
1916: else
1917: user = NULL;
1918: }
1919: }
1920: if (user) {
1.70 guenther 1921: env_define("USER", user);
1922: env_export("USER");
1.1 deraadt 1923: }
1.68 guenther 1924: connection_status(1);
1.1 deraadt 1925: if (setjmp(peerdied) == 0)
1926: telnet(user);
1.67 guenther 1927: (void)close(net);
1.10 art 1928: ExitString("Connection closed by foreign host.\r\n",1);
1.1 deraadt 1929: }
1930:
1931: #define HELPINDENT (sizeof ("connect"))
1932:
1933: static char
1934: openhelp[] = "connect to a site",
1935: closehelp[] = "close current connection",
1936: logouthelp[] = "forcibly logout remote user and close the connection",
1937: quithelp[] = "exit telnet",
1938: statushelp[] = "print status information",
1939: helphelp[] = "print help information",
1940: sendhelp[] = "transmit special characters ('send ?' for more)",
1941: sethelp[] = "set operating parameters ('set ?' for more)",
1942: unsethelp[] = "unset operating parameters ('unset ?' for more)",
1943: togglestring[] ="toggle operating parameters ('toggle ?' for more)",
1.88 ! jmc 1944: slchelp[] = "change state of special characters ('slc ?' for more)",
1.1 deraadt 1945: displayhelp[] = "display operating parameters",
1946: zhelp[] = "suspend telnet",
1947: envhelp[] = "change environment variables ('environ ?' for more)",
1948: modestring[] = "try to enter line or character mode ('mode ?' for more)";
1949:
1.40 millert 1950: static int help(int, char**);
1.1 deraadt 1951:
1952: static Command cmdtab[] = {
1953: { "close", closehelp, bye, 1 },
1954: { "logout", logouthelp, logout, 1 },
1955: { "display", displayhelp, display, 0 },
1956: { "mode", modestring, modecmd, 0 },
1957: { "open", openhelp, tn, 0 },
1.63 guenther 1958: { "quit", quithelp, quitcmd, 0 },
1.1 deraadt 1959: { "send", sendhelp, sendcmd, 0 },
1960: { "set", sethelp, setcmd, 0 },
1961: { "unset", unsethelp, unsetcmd, 0 },
1962: { "status", statushelp, status, 0 },
1963: { "toggle", togglestring, toggle, 0 },
1964: { "slc", slchelp, slccmd, 0 },
1.10 art 1965:
1966: { "z", zhelp, telnetsuspend, 0 },
1.1 deraadt 1967: { "environ", envhelp, env_cmd, 0 },
1968: { "?", helphelp, help, 0 },
1.10 art 1969: { 0, 0, 0, 0 }
1.1 deraadt 1970: };
1971:
1972: static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
1973: static char escapehelp[] = "deprecated command -- use 'set escape' instead";
1974:
1975: static Command cmdtab2[] = {
1976: { "help", 0, help, 0 },
1977: { "escape", escapehelp, setescape, 0 },
1978: { "crmod", crmodhelp, togcrmod, 0 },
1.10 art 1979: { 0, 0, 0, 0 }
1.1 deraadt 1980: };
1981:
1982:
1.69 jsg 1983: static Command *
1984: getcmd(char *name)
1.1 deraadt 1985: {
1986: Command *cm;
1987:
1.10 art 1988: if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
1.1 deraadt 1989: return cm;
1990: return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
1991: }
1992:
1.69 jsg 1993: void
1994: command(int top, char *tbuf, int cnt)
1.1 deraadt 1995: {
1.39 mpech 1996: Command *c;
1.1 deraadt 1997:
1998: setcommandmode();
1999: if (!top) {
2000: putchar('\n');
2001: } else {
2002: (void) signal(SIGINT, SIG_DFL);
2003: (void) signal(SIGQUIT, SIG_DFL);
2004: }
2005: for (;;) {
2006: if (rlogin == _POSIX_VDISABLE)
2007: printf("%s> ", prompt);
2008: if (tbuf) {
1.39 mpech 2009: char *cp;
1.1 deraadt 2010: cp = line;
2011: while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
2012: cnt--;
2013: tbuf = 0;
2014: if (cp == line || *--cp != '\n' || cp == line)
2015: goto getline;
2016: *cp = '\0';
2017: if (rlogin == _POSIX_VDISABLE)
1.10 art 2018: printf("%s\r\n", line);
1.1 deraadt 2019: } else {
2020: getline:
2021: if (rlogin != _POSIX_VDISABLE)
2022: printf("%s> ", prompt);
2023: if (fgets(line, sizeof(line), stdin) == NULL) {
1.66 guenther 2024: if (feof(stdin) || ferror(stdin))
1.63 guenther 2025: quit();
1.1 deraadt 2026: break;
2027: }
2028: }
2029: if (line[0] == 0)
2030: break;
1.86 deraadt 2031: if (makeargv())
2032: break;
1.1 deraadt 2033: if (margv[0] == 0) {
2034: break;
2035: }
2036: c = getcmd(margv[0]);
2037: if (Ambiguous(c)) {
1.10 art 2038: printf("?Ambiguous command\r\n");
1.1 deraadt 2039: continue;
2040: }
2041: if (c == 0) {
1.10 art 2042: printf("?Invalid command\r\n");
1.1 deraadt 2043: continue;
2044: }
2045: if (c->needconnect && !connected) {
1.10 art 2046: printf("?Need to be connected first.\r\n");
1.1 deraadt 2047: continue;
2048: }
2049: if ((*c->handler)(margc, margv)) {
2050: break;
2051: }
2052: }
2053: if (!top) {
1.66 guenther 2054: if (!connected)
1.1 deraadt 2055: longjmp(toplevel, 1);
2056: setconnmode(0);
2057: }
2058: }
2059:
2060: /*
2061: * Help command.
2062: */
1.69 jsg 2063: static int
2064: help(int argc, char *argv[])
1.1 deraadt 2065: {
1.39 mpech 2066: Command *c;
1.1 deraadt 2067:
2068: if (argc == 1) {
1.10 art 2069: printf("Commands may be abbreviated. Commands are:\r\n\r\n");
1.1 deraadt 2070: for (c = cmdtab; c->name; c++)
2071: if (c->help) {
1.37 deraadt 2072: printf("%-*s\t%s\r\n", (int)HELPINDENT, c->name,
1.1 deraadt 2073: c->help);
2074: }
2075: return 0;
2076: }
2077: while (--argc > 0) {
1.39 mpech 2078: char *arg;
1.1 deraadt 2079: arg = *++argv;
2080: c = getcmd(arg);
2081: if (Ambiguous(c))
1.10 art 2082: printf("?Ambiguous help command %s\r\n", arg);
1.83 krw 2083: else if (c == NULL)
1.10 art 2084: printf("?Invalid help command %s\r\n", arg);
1.1 deraadt 2085: else
1.10 art 2086: printf("%s\r\n", c->help);
1.1 deraadt 2087: }
2088: return 0;
2089: }