Annotation of src/usr.bin/telnet/commands.c, Revision 1.1.1.1
1.1 deraadt 1: /*
2: * Copyright (c) 1988, 1990, 1993
3: * The Regents of the University of California. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: #ifndef lint
35: /* from: static char sccsid[] = "@(#)commands.c 8.1 (Berkeley) 6/6/93"; */
36: static char *rcsid = "$Id: commands.c,v 1.8 1995/01/03 06:24:48 hpeyerl Exp $";
37: #endif /* not lint */
38:
39: #if defined(unix)
40: #include <sys/param.h>
41: #if defined(CRAY) || defined(sysV88)
42: #include <sys/types.h>
43: #endif
44: #include <sys/file.h>
45: #else
46: #include <sys/types.h>
47: #endif /* defined(unix) */
48: #include <sys/socket.h>
49: #include <netinet/in.h>
50: #ifdef CRAY
51: #include <fcntl.h>
52: #endif /* CRAY */
53:
54: #include <signal.h>
55: #include <netdb.h>
56: #include <ctype.h>
57: #include <pwd.h>
58: #include <varargs.h>
59: #include <errno.h>
60:
61: #include <arpa/telnet.h>
62:
63: #include "general.h"
64:
65: #include "ring.h"
66:
67: #include "externs.h"
68: #include "defines.h"
69: #include "types.h"
70:
71: #if !defined(CRAY) && !defined(sysV88)
72: #include <netinet/in_systm.h>
73: # if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
74: # include <machine/endian.h>
75: # endif /* vax */
76: #endif /* !defined(CRAY) && !defined(sysV88) */
77: #include <netinet/ip.h>
78:
79:
80: #ifndef MAXHOSTNAMELEN
81: #define MAXHOSTNAMELEN 64
82: #endif MAXHOSTNAMELEN
83:
84: #if defined(IPPROTO_IP) && defined(IP_TOS)
85: int tos = -1;
86: #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
87:
88: char *hostname;
89: static char _hostname[MAXHOSTNAMELEN];
90:
91: extern char *getenv();
92:
93: extern int isprefix();
94: extern char **genget();
95: extern int Ambiguous();
96:
97: static call();
98:
99: typedef struct {
100: char *name; /* command name */
101: char *help; /* help string (NULL for no help) */
102: int (*handler)(); /* routine which executes command */
103: int needconnect; /* Do we need to be connected to execute? */
104: } Command;
105:
106: static char line[256];
107: static char saveline[256];
108: static int margc;
109: static char *margv[20];
110:
111: static void
112: makeargv()
113: {
114: register char *cp, *cp2, c;
115: register char **argp = margv;
116:
117: margc = 0;
118: cp = line;
119: if (*cp == '!') { /* Special case shell escape */
120: strcpy(saveline, line); /* save for shell command */
121: *argp++ = "!"; /* No room in string to get this */
122: margc++;
123: cp++;
124: }
125: while (c = *cp) {
126: register int inquote = 0;
127: while (isspace(c))
128: c = *++cp;
129: if (c == '\0')
130: break;
131: *argp++ = cp;
132: margc += 1;
133: for (cp2 = cp; c != '\0'; c = *++cp) {
134: if (inquote) {
135: if (c == inquote) {
136: inquote = 0;
137: continue;
138: }
139: } else {
140: if (c == '\\') {
141: if ((c = *++cp) == '\0')
142: break;
143: } else if (c == '"') {
144: inquote = '"';
145: continue;
146: } else if (c == '\'') {
147: inquote = '\'';
148: continue;
149: } else if (isspace(c))
150: break;
151: }
152: *cp2++ = c;
153: }
154: *cp2 = '\0';
155: if (c == '\0')
156: break;
157: cp++;
158: }
159: *argp++ = 0;
160: }
161:
162: /*
163: * Make a character string into a number.
164: *
165: * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
166: */
167:
168: static
169: special(s)
170: register char *s;
171: {
172: register char c;
173: char b;
174:
175: switch (*s) {
176: case '^':
177: b = *++s;
178: if (b == '?') {
179: c = b | 0x40; /* DEL */
180: } else {
181: c = b & 0x1f;
182: }
183: break;
184: default:
185: c = *s;
186: break;
187: }
188: return c;
189: }
190:
191: /*
192: * Construct a control character sequence
193: * for a special character.
194: */
195: static char *
196: control(c)
197: register cc_t c;
198: {
199: static char buf[5];
200: /*
201: * The only way I could get the Sun 3.5 compiler
202: * to shut up about
203: * if ((unsigned int)c >= 0x80)
204: * was to assign "c" to an unsigned int variable...
205: * Arggg....
206: */
207: register unsigned int uic = (unsigned int)c;
208:
209: if (uic == 0x7f)
210: return ("^?");
211: if (c == (cc_t)_POSIX_VDISABLE) {
212: return "off";
213: }
214: if (uic >= 0x80) {
215: buf[0] = '\\';
216: buf[1] = ((c>>6)&07) + '0';
217: buf[2] = ((c>>3)&07) + '0';
218: buf[3] = (c&07) + '0';
219: buf[4] = 0;
220: } else if (uic >= 0x20) {
221: buf[0] = c;
222: buf[1] = 0;
223: } else {
224: buf[0] = '^';
225: buf[1] = '@'+c;
226: buf[2] = 0;
227: }
228: return (buf);
229: }
230:
231:
232:
233: /*
234: * The following are data structures and routines for
235: * the "send" command.
236: *
237: */
238:
239: struct sendlist {
240: char *name; /* How user refers to it (case independent) */
241: char *help; /* Help information (0 ==> no help) */
242: int needconnect; /* Need to be connected */
243: int narg; /* Number of arguments */
244: int (*handler)(); /* Routine to perform (for special ops) */
245: int nbyte; /* Number of bytes to send this command */
246: int what; /* Character to be sent (<0 ==> special) */
247: };
248:
249:
250: static int
251: send_esc P((void)),
252: send_help P((void)),
253: send_docmd P((char *)),
254: send_dontcmd P((char *)),
255: send_willcmd P((char *)),
256: send_wontcmd P((char *));
257:
258: static struct sendlist Sendlist[] = {
259: { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO },
260: { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT },
261: { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK },
262: { "break", 0, 1, 0, 0, 2, BREAK },
263: { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC },
264: { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL },
265: { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 },
266: { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA },
267: { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP },
268: { "intp", 0, 1, 0, 0, 2, IP },
269: { "interrupt", 0, 1, 0, 0, 2, IP },
270: { "intr", 0, 1, 0, 0, 2, IP },
271: { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP },
272: { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR },
273: { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT },
274: { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP },
275: { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF },
276: { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 },
277: { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 },
278: { "?", "Display send options", 0, 0, send_help, 0, 0 },
279: { "help", 0, 0, 0, send_help, 0, 0 },
280: { "do", 0, 0, 1, send_docmd, 3, 0 },
281: { "dont", 0, 0, 1, send_dontcmd, 3, 0 },
282: { "will", 0, 0, 1, send_willcmd, 3, 0 },
283: { "wont", 0, 0, 1, send_wontcmd, 3, 0 },
284: { 0 }
285: };
286:
287: #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
288: sizeof(struct sendlist)))
289:
290: static int
291: sendcmd(argc, argv)
292: int argc;
293: char **argv;
294: {
295: int count; /* how many bytes we are going to need to send */
296: int i;
297: int question = 0; /* was at least one argument a question */
298: struct sendlist *s; /* pointer to current command */
299: int success = 0;
300: int needconnect = 0;
301:
302: if (argc < 2) {
303: printf("need at least one argument for 'send' command\n");
304: printf("'send ?' for help\n");
305: return 0;
306: }
307: /*
308: * First, validate all the send arguments.
309: * In addition, we see how much space we are going to need, and
310: * whether or not we will be doing a "SYNCH" operation (which
311: * flushes the network queue).
312: */
313: count = 0;
314: for (i = 1; i < argc; i++) {
315: s = GETSEND(argv[i]);
316: if (s == 0) {
317: printf("Unknown send argument '%s'\n'send ?' for help.\n",
318: argv[i]);
319: return 0;
320: } else if (Ambiguous(s)) {
321: printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
322: argv[i]);
323: return 0;
324: }
325: if (i + s->narg >= argc) {
326: fprintf(stderr,
327: "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
328: s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
329: return 0;
330: }
331: count += s->nbyte;
332: if (s->handler == send_help) {
333: send_help();
334: return 0;
335: }
336:
337: i += s->narg;
338: needconnect += s->needconnect;
339: }
340: if (!connected && needconnect) {
341: printf("?Need to be connected first.\n");
342: printf("'send ?' for help\n");
343: return 0;
344: }
345: /* Now, do we have enough room? */
346: if (NETROOM() < count) {
347: printf("There is not enough room in the buffer TO the network\n");
348: printf("to process your request. Nothing will be done.\n");
349: printf("('send synch' will throw away most data in the network\n");
350: printf("buffer, if this might help.)\n");
351: return 0;
352: }
353: /* OK, they are all OK, now go through again and actually send */
354: count = 0;
355: for (i = 1; i < argc; i++) {
356: if ((s = GETSEND(argv[i])) == 0) {
357: fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
358: (void) quit();
359: /*NOTREACHED*/
360: }
361: if (s->handler) {
362: count++;
363: success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
364: (s->narg > 1) ? argv[i+2] : 0);
365: i += s->narg;
366: } else {
367: NET2ADD(IAC, s->what);
368: printoption("SENT", IAC, s->what);
369: }
370: }
371: return (count == success);
372: }
373:
374: static int
375: send_esc()
376: {
377: NETADD(escape);
378: return 1;
379: }
380:
381: static int
382: send_docmd(name)
383: char *name;
384: {
385: return(send_tncmd(send_do, "do", name));
386: }
387:
388: static int
389: send_dontcmd(name)
390: char *name;
391: {
392: return(send_tncmd(send_dont, "dont", name));
393: }
394: static int
395: send_willcmd(name)
396: char *name;
397: {
398: return(send_tncmd(send_will, "will", name));
399: }
400: static int
401: send_wontcmd(name)
402: char *name;
403: {
404: return(send_tncmd(send_wont, "wont", name));
405: }
406:
407: int
408: send_tncmd(func, cmd, name)
409: void (*func)();
410: char *cmd, *name;
411: {
412: char **cpp;
413: extern char *telopts[];
414: register int val = 0;
415:
416: if (isprefix(name, "help") || isprefix(name, "?")) {
417: register int col, len;
418:
419: printf("Usage: send %s <value|option>\n", cmd);
420: printf("\"value\" must be from 0 to 255\n");
421: printf("Valid options are:\n\t");
422:
423: col = 8;
424: for (cpp = telopts; *cpp; cpp++) {
425: len = strlen(*cpp) + 3;
426: if (col + len > 65) {
427: printf("\n\t");
428: col = 8;
429: }
430: printf(" \"%s\"", *cpp);
431: col += len;
432: }
433: printf("\n");
434: return 0;
435: }
436: cpp = (char **)genget(name, telopts, sizeof(char *));
437: if (Ambiguous(cpp)) {
438: fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
439: name, cmd);
440: return 0;
441: }
442: if (cpp) {
443: val = cpp - telopts;
444: } else {
445: register char *cp = name;
446:
447: while (*cp >= '0' && *cp <= '9') {
448: val *= 10;
449: val += *cp - '0';
450: cp++;
451: }
452: if (*cp != 0) {
453: fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
454: name, cmd);
455: return 0;
456: } else if (val < 0 || val > 255) {
457: fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
458: name, cmd);
459: return 0;
460: }
461: }
462: if (!connected) {
463: printf("?Need to be connected first.\n");
464: return 0;
465: }
466: (*func)(val, 1);
467: return 1;
468: }
469:
470: static int
471: send_help()
472: {
473: struct sendlist *s; /* pointer to current command */
474: for (s = Sendlist; s->name; s++) {
475: if (s->help)
476: printf("%-15s %s\n", s->name, s->help);
477: }
478: return(0);
479: }
480:
481: /*
482: * The following are the routines and data structures referred
483: * to by the arguments to the "toggle" command.
484: */
485:
486: static int
487: lclchars()
488: {
489: donelclchars = 1;
490: return 1;
491: }
492:
493: static int
494: togdebug()
495: {
496: #ifndef NOT43
497: if (net > 0 &&
498: (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
499: perror("setsockopt (SO_DEBUG)");
500: }
501: #else /* NOT43 */
502: if (debug) {
503: if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
504: perror("setsockopt (SO_DEBUG)");
505: } else
506: printf("Cannot turn off socket debugging\n");
507: #endif /* NOT43 */
508: return 1;
509: }
510:
511:
512: static int
513: togcrlf()
514: {
515: if (crlf) {
516: printf("Will send carriage returns as telnet <CR><LF>.\n");
517: } else {
518: printf("Will send carriage returns as telnet <CR><NUL>.\n");
519: }
520: return 1;
521: }
522:
523: int binmode;
524:
525: static int
526: togbinary(val)
527: int val;
528: {
529: donebinarytoggle = 1;
530:
531: if (val >= 0) {
532: binmode = val;
533: } else {
534: if (my_want_state_is_will(TELOPT_BINARY) &&
535: my_want_state_is_do(TELOPT_BINARY)) {
536: binmode = 1;
537: } else if (my_want_state_is_wont(TELOPT_BINARY) &&
538: my_want_state_is_dont(TELOPT_BINARY)) {
539: binmode = 0;
540: }
541: val = binmode ? 0 : 1;
542: }
543:
544: if (val == 1) {
545: if (my_want_state_is_will(TELOPT_BINARY) &&
546: my_want_state_is_do(TELOPT_BINARY)) {
547: printf("Already operating in binary mode with remote host.\n");
548: } else {
549: printf("Negotiating binary mode with remote host.\n");
550: tel_enter_binary(3);
551: }
552: } else {
553: if (my_want_state_is_wont(TELOPT_BINARY) &&
554: my_want_state_is_dont(TELOPT_BINARY)) {
555: printf("Already in network ascii mode with remote host.\n");
556: } else {
557: printf("Negotiating network ascii mode with remote host.\n");
558: tel_leave_binary(3);
559: }
560: }
561: return 1;
562: }
563:
564: static int
565: togrbinary(val)
566: int val;
567: {
568: donebinarytoggle = 1;
569:
570: if (val == -1)
571: val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
572:
573: if (val == 1) {
574: if (my_want_state_is_do(TELOPT_BINARY)) {
575: printf("Already receiving in binary mode.\n");
576: } else {
577: printf("Negotiating binary mode on input.\n");
578: tel_enter_binary(1);
579: }
580: } else {
581: if (my_want_state_is_dont(TELOPT_BINARY)) {
582: printf("Already receiving in network ascii mode.\n");
583: } else {
584: printf("Negotiating network ascii mode on input.\n");
585: tel_leave_binary(1);
586: }
587: }
588: return 1;
589: }
590:
591: static int
592: togxbinary(val)
593: int val;
594: {
595: donebinarytoggle = 1;
596:
597: if (val == -1)
598: val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
599:
600: if (val == 1) {
601: if (my_want_state_is_will(TELOPT_BINARY)) {
602: printf("Already transmitting in binary mode.\n");
603: } else {
604: printf("Negotiating binary mode on output.\n");
605: tel_enter_binary(2);
606: }
607: } else {
608: if (my_want_state_is_wont(TELOPT_BINARY)) {
609: printf("Already transmitting in network ascii mode.\n");
610: } else {
611: printf("Negotiating network ascii mode on output.\n");
612: tel_leave_binary(2);
613: }
614: }
615: return 1;
616: }
617:
618:
619: static int togglehelp P((void));
620: #if defined(AUTHENTICATION)
621: extern int auth_togdebug P((int));
622: #endif
623:
624: struct togglelist {
625: char *name; /* name of toggle */
626: char *help; /* help message */
627: int (*handler)(); /* routine to do actual setting */
628: int *variable;
629: char *actionexplanation;
630: };
631:
632: static struct togglelist Togglelist[] = {
633: { "autoflush",
634: "flushing of output when sending interrupt characters",
635: 0,
636: &autoflush,
637: "flush output when sending interrupt characters" },
638: { "autosynch",
639: "automatic sending of interrupt characters in urgent mode",
640: 0,
641: &autosynch,
642: "send interrupt characters in urgent mode" },
643: #if defined(AUTHENTICATION)
644: { "autologin",
645: "automatic sending of login and/or authentication info",
646: 0,
647: &autologin,
648: "send login name and/or authentication information" },
649: { "authdebug",
650: "Toggle authentication debugging",
651: auth_togdebug,
652: 0,
653: "print authentication debugging information" },
654: #endif
655: { "skiprc",
656: "don't read ~/.telnetrc file",
657: 0,
658: &skiprc,
659: "skip reading of ~/.telnetrc file" },
660: { "binary",
661: "sending and receiving of binary data",
662: togbinary,
663: 0,
664: 0 },
665: { "inbinary",
666: "receiving of binary data",
667: togrbinary,
668: 0,
669: 0 },
670: { "outbinary",
671: "sending of binary data",
672: togxbinary,
673: 0,
674: 0 },
675: { "crlf",
676: "sending carriage returns as telnet <CR><LF>",
677: togcrlf,
678: &crlf,
679: 0 },
680: { "crmod",
681: "mapping of received carriage returns",
682: 0,
683: &crmod,
684: "map carriage return on output" },
685: { "localchars",
686: "local recognition of certain control characters",
687: lclchars,
688: &localchars,
689: "recognize certain control characters" },
690: { " ", "", 0 }, /* empty line */
691: #if defined(unix) && defined(TN3270)
692: { "apitrace",
693: "(debugging) toggle tracing of API transactions",
694: 0,
695: &apitrace,
696: "trace API transactions" },
697: { "cursesdata",
698: "(debugging) toggle printing of hexadecimal curses data",
699: 0,
700: &cursesdata,
701: "print hexadecimal representation of curses data" },
702: #endif /* defined(unix) && defined(TN3270) */
703: { "debug",
704: "debugging",
705: togdebug,
706: &debug,
707: "turn on socket level debugging" },
708: { "netdata",
709: "printing of hexadecimal network data (debugging)",
710: 0,
711: &netdata,
712: "print hexadecimal representation of network traffic" },
713: { "prettydump",
714: "output of \"netdata\" to user readable format (debugging)",
715: 0,
716: &prettydump,
717: "print user readable output for \"netdata\"" },
718: { "options",
719: "viewing of options processing (debugging)",
720: 0,
721: &showoptions,
722: "show option processing" },
723: #if defined(unix)
724: { "termdata",
725: "(debugging) toggle printing of hexadecimal terminal data",
726: 0,
727: &termdata,
728: "print hexadecimal representation of terminal traffic" },
729: #endif /* defined(unix) */
730: { "?",
731: 0,
732: togglehelp },
733: { "help",
734: 0,
735: togglehelp },
736: { 0 }
737: };
738:
739: static int
740: togglehelp()
741: {
742: struct togglelist *c;
743:
744: for (c = Togglelist; c->name; c++) {
745: if (c->help) {
746: if (*c->help)
747: printf("%-15s toggle %s\n", c->name, c->help);
748: else
749: printf("\n");
750: }
751: }
752: printf("\n");
753: printf("%-15s %s\n", "?", "display help information");
754: return 0;
755: }
756:
757: static void
758: settogglehelp(set)
759: int set;
760: {
761: struct togglelist *c;
762:
763: for (c = Togglelist; c->name; c++) {
764: if (c->help) {
765: if (*c->help)
766: printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
767: c->help);
768: else
769: printf("\n");
770: }
771: }
772: }
773:
774: #define GETTOGGLE(name) (struct togglelist *) \
775: genget(name, (char **) Togglelist, sizeof(struct togglelist))
776:
777: static int
778: toggle(argc, argv)
779: int argc;
780: char *argv[];
781: {
782: int retval = 1;
783: char *name;
784: struct togglelist *c;
785:
786: if (argc < 2) {
787: fprintf(stderr,
788: "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
789: return 0;
790: }
791: argc--;
792: argv++;
793: while (argc--) {
794: name = *argv++;
795: c = GETTOGGLE(name);
796: if (Ambiguous(c)) {
797: fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
798: name);
799: return 0;
800: } else if (c == 0) {
801: fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
802: name);
803: return 0;
804: } else {
805: if (c->variable) {
806: *c->variable = !*c->variable; /* invert it */
807: if (c->actionexplanation) {
808: printf("%s %s.\n", *c->variable? "Will" : "Won't",
809: c->actionexplanation);
810: }
811: }
812: if (c->handler) {
813: retval &= (*c->handler)(-1);
814: }
815: }
816: }
817: return retval;
818: }
819:
820: /*
821: * The following perform the "set" command.
822: */
823:
824: #ifdef USE_TERMIO
825: struct termio new_tc = { 0 };
826: #endif
827:
828: struct setlist {
829: char *name; /* name */
830: char *help; /* help information */
831: void (*handler)();
832: cc_t *charp; /* where it is located at */
833: };
834:
835: static struct setlist Setlist[] = {
836: #ifdef KLUDGELINEMODE
837: { "echo", "character to toggle local echoing on/off", 0, &echoc },
838: #endif
839: { "escape", "character to escape back to telnet command mode", 0, &escape },
840: { "rlogin", "rlogin escape character", 0, &rlogin },
841: { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
842: { " ", "" },
843: { " ", "The following need 'localchars' to be toggled true", 0, 0 },
844: { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
845: { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
846: { "quit", "character to cause an Abort process", 0, termQuitCharp },
847: { "eof", "character to cause an EOF ", 0, termEofCharp },
848: { " ", "" },
849: { " ", "The following are for local editing in linemode", 0, 0 },
850: { "erase", "character to use to erase a character", 0, termEraseCharp },
851: { "kill", "character to use to erase a line", 0, termKillCharp },
852: { "lnext", "character to use for literal next", 0, termLiteralNextCharp },
853: { "susp", "character to cause a Suspend Process", 0, termSuspCharp },
854: { "reprint", "character to use for line reprint", 0, termRprntCharp },
855: { "worderase", "character to use to erase a word", 0, termWerasCharp },
856: { "start", "character to use for XON", 0, termStartCharp },
857: { "stop", "character to use for XOFF", 0, termStopCharp },
858: { "forw1", "alternate end of line character", 0, termForw1Charp },
859: { "forw2", "alternate end of line character", 0, termForw2Charp },
860: { "ayt", "alternate AYT character", 0, termAytCharp },
861: { 0 }
862: };
863:
864: #if defined(CRAY) && !defined(__STDC__)
865: /* Work around compiler bug in pcc 4.1.5 */
866: void
867: _setlist_init()
868: {
869: #ifndef KLUDGELINEMODE
870: #define N 5
871: #else
872: #define N 6
873: #endif
874: Setlist[N+0].charp = &termFlushChar;
875: Setlist[N+1].charp = &termIntChar;
876: Setlist[N+2].charp = &termQuitChar;
877: Setlist[N+3].charp = &termEofChar;
878: Setlist[N+6].charp = &termEraseChar;
879: Setlist[N+7].charp = &termKillChar;
880: Setlist[N+8].charp = &termLiteralNextChar;
881: Setlist[N+9].charp = &termSuspChar;
882: Setlist[N+10].charp = &termRprntChar;
883: Setlist[N+11].charp = &termWerasChar;
884: Setlist[N+12].charp = &termStartChar;
885: Setlist[N+13].charp = &termStopChar;
886: Setlist[N+14].charp = &termForw1Char;
887: Setlist[N+15].charp = &termForw2Char;
888: Setlist[N+16].charp = &termAytChar;
889: #undef N
890: }
891: #endif /* defined(CRAY) && !defined(__STDC__) */
892:
893: static struct setlist *
894: getset(name)
895: char *name;
896: {
897: return (struct setlist *)
898: genget(name, (char **) Setlist, sizeof(struct setlist));
899: }
900:
901: void
902: set_escape_char(s)
903: char *s;
904: {
905: if (rlogin != _POSIX_VDISABLE) {
906: rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
907: printf("Telnet rlogin escape character is '%s'.\n",
908: control(rlogin));
909: } else {
910: escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
911: printf("Telnet escape character is '%s'.\n", control(escape));
912: }
913: }
914:
915: static int
916: setcmd(argc, argv)
917: int argc;
918: char *argv[];
919: {
920: int value;
921: struct setlist *ct;
922: struct togglelist *c;
923:
924: if (argc < 2 || argc > 3) {
925: printf("Format is 'set Name Value'\n'set ?' for help.\n");
926: return 0;
927: }
928: if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
929: for (ct = Setlist; ct->name; ct++)
930: printf("%-15s %s\n", ct->name, ct->help);
931: printf("\n");
932: settogglehelp(1);
933: printf("%-15s %s\n", "?", "display help information");
934: return 0;
935: }
936:
937: ct = getset(argv[1]);
938: if (ct == 0) {
939: c = GETTOGGLE(argv[1]);
940: if (c == 0) {
941: fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
942: argv[1]);
943: return 0;
944: } else if (Ambiguous(c)) {
945: fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
946: argv[1]);
947: return 0;
948: }
949: if (c->variable) {
950: if ((argc == 2) || (strcmp("on", argv[2]) == 0))
951: *c->variable = 1;
952: else if (strcmp("off", argv[2]) == 0)
953: *c->variable = 0;
954: else {
955: printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
956: return 0;
957: }
958: if (c->actionexplanation) {
959: printf("%s %s.\n", *c->variable? "Will" : "Won't",
960: c->actionexplanation);
961: }
962: }
963: if (c->handler)
964: (*c->handler)(1);
965: } else if (argc != 3) {
966: printf("Format is 'set Name Value'\n'set ?' for help.\n");
967: return 0;
968: } else if (Ambiguous(ct)) {
969: fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
970: argv[1]);
971: return 0;
972: } else if (ct->handler) {
973: (*ct->handler)(argv[2]);
974: printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
975: } else {
976: if (strcmp("off", argv[2])) {
977: value = special(argv[2]);
978: } else {
979: value = _POSIX_VDISABLE;
980: }
981: *(ct->charp) = (cc_t)value;
982: printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
983: }
984: slc_check();
985: return 1;
986: }
987:
988: static int
989: unsetcmd(argc, argv)
990: int argc;
991: char *argv[];
992: {
993: struct setlist *ct;
994: struct togglelist *c;
995: register char *name;
996:
997: if (argc < 2) {
998: fprintf(stderr,
999: "Need an argument to 'unset' command. 'unset ?' for help.\n");
1000: return 0;
1001: }
1002: if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
1003: for (ct = Setlist; ct->name; ct++)
1004: printf("%-15s %s\n", ct->name, ct->help);
1005: printf("\n");
1006: settogglehelp(0);
1007: printf("%-15s %s\n", "?", "display help information");
1008: return 0;
1009: }
1010:
1011: argc--;
1012: argv++;
1013: while (argc--) {
1014: name = *argv++;
1015: ct = getset(name);
1016: if (ct == 0) {
1017: c = GETTOGGLE(name);
1018: if (c == 0) {
1019: fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
1020: name);
1021: return 0;
1022: } else if (Ambiguous(c)) {
1023: fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
1024: name);
1025: return 0;
1026: }
1027: if (c->variable) {
1028: *c->variable = 0;
1029: if (c->actionexplanation) {
1030: printf("%s %s.\n", *c->variable? "Will" : "Won't",
1031: c->actionexplanation);
1032: }
1033: }
1034: if (c->handler)
1035: (*c->handler)(0);
1036: } else if (Ambiguous(ct)) {
1037: fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
1038: name);
1039: return 0;
1040: } else if (ct->handler) {
1041: (*ct->handler)(0);
1042: printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
1043: } else {
1044: *(ct->charp) = _POSIX_VDISABLE;
1045: printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
1046: }
1047: }
1048: return 1;
1049: }
1050:
1051: /*
1052: * The following are the data structures and routines for the
1053: * 'mode' command.
1054: */
1055: #ifdef KLUDGELINEMODE
1056: extern int kludgelinemode;
1057:
1058: static int
1059: dokludgemode()
1060: {
1061: kludgelinemode = 1;
1062: send_wont(TELOPT_LINEMODE, 1);
1063: send_dont(TELOPT_SGA, 1);
1064: send_dont(TELOPT_ECHO, 1);
1065: }
1066: #endif
1067:
1068: static int
1069: dolinemode()
1070: {
1071: #ifdef KLUDGELINEMODE
1072: if (kludgelinemode)
1073: send_dont(TELOPT_SGA, 1);
1074: #endif
1075: send_will(TELOPT_LINEMODE, 1);
1076: send_dont(TELOPT_ECHO, 1);
1077: return 1;
1078: }
1079:
1080: static int
1081: docharmode()
1082: {
1083: #ifdef KLUDGELINEMODE
1084: if (kludgelinemode)
1085: send_do(TELOPT_SGA, 1);
1086: else
1087: #endif
1088: send_wont(TELOPT_LINEMODE, 1);
1089: send_do(TELOPT_ECHO, 1);
1090: return 1;
1091: }
1092:
1093: static int
1094: dolmmode(bit, on)
1095: int bit, on;
1096: {
1097: unsigned char c;
1098: extern int linemode;
1099:
1100: if (my_want_state_is_wont(TELOPT_LINEMODE)) {
1101: printf("?Need to have LINEMODE option enabled first.\n");
1102: printf("'mode ?' for help.\n");
1103: return 0;
1104: }
1105:
1106: if (on)
1107: c = (linemode | bit);
1108: else
1109: c = (linemode & ~bit);
1110: lm_mode(&c, 1, 1);
1111: return 1;
1112: }
1113:
1114: int
1115: setmode(bit)
1116: {
1117: return dolmmode(bit, 1);
1118: }
1119:
1120: int
1121: clearmode(bit)
1122: {
1123: return dolmmode(bit, 0);
1124: }
1125:
1126: struct modelist {
1127: char *name; /* command name */
1128: char *help; /* help string */
1129: int (*handler)(); /* routine which executes command */
1130: int needconnect; /* Do we need to be connected to execute? */
1131: int arg1;
1132: };
1133:
1134: extern int modehelp();
1135:
1136: static struct modelist ModeList[] = {
1137: { "character", "Disable LINEMODE option", docharmode, 1 },
1138: #ifdef KLUDGELINEMODE
1139: { "", "(or disable obsolete line-by-line mode)", 0 },
1140: #endif
1141: { "line", "Enable LINEMODE option", dolinemode, 1 },
1142: #ifdef KLUDGELINEMODE
1143: { "", "(or enable obsolete line-by-line mode)", 0 },
1144: #endif
1145: { "", "", 0 },
1146: { "", "These require the LINEMODE option to be enabled", 0 },
1147: { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG },
1148: { "+isig", 0, setmode, 1, MODE_TRAPSIG },
1149: { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG },
1150: { "edit", "Enable character editing", setmode, 1, MODE_EDIT },
1151: { "+edit", 0, setmode, 1, MODE_EDIT },
1152: { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT },
1153: { "softtabs", "Enable tab expansion", setmode, 1, MODE_SOFT_TAB },
1154: { "+softtabs", 0, setmode, 1, MODE_SOFT_TAB },
1155: { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB },
1156: { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO },
1157: { "+litecho", 0, setmode, 1, MODE_LIT_ECHO },
1158: { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
1159: { "help", 0, modehelp, 0 },
1160: #ifdef KLUDGELINEMODE
1161: { "kludgeline", 0, dokludgemode, 1 },
1162: #endif
1163: { "", "", 0 },
1164: { "?", "Print help information", modehelp, 0 },
1165: { 0 },
1166: };
1167:
1168:
1169: int
1170: modehelp()
1171: {
1172: struct modelist *mt;
1173:
1174: printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
1175: for (mt = ModeList; mt->name; mt++) {
1176: if (mt->help) {
1177: if (*mt->help)
1178: printf("%-15s %s\n", mt->name, mt->help);
1179: else
1180: printf("\n");
1181: }
1182: }
1183: return 0;
1184: }
1185:
1186: #define GETMODECMD(name) (struct modelist *) \
1187: genget(name, (char **) ModeList, sizeof(struct modelist))
1188:
1189: static int
1190: modecmd(argc, argv)
1191: int argc;
1192: char *argv[];
1193: {
1194: struct modelist *mt;
1195:
1196: if (argc != 2) {
1197: printf("'mode' command requires an argument\n");
1198: printf("'mode ?' for help.\n");
1199: } else if ((mt = GETMODECMD(argv[1])) == 0) {
1200: fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
1201: } else if (Ambiguous(mt)) {
1202: fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
1203: } else if (mt->needconnect && !connected) {
1204: printf("?Need to be connected first.\n");
1205: printf("'mode ?' for help.\n");
1206: } else if (mt->handler) {
1207: return (*mt->handler)(mt->arg1);
1208: }
1209: return 0;
1210: }
1211:
1212: /*
1213: * The following data structures and routines implement the
1214: * "display" command.
1215: */
1216:
1217: static int
1218: display(argc, argv)
1219: int argc;
1220: char *argv[];
1221: {
1222: struct togglelist *tl;
1223: struct setlist *sl;
1224:
1225: #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1226: if (*tl->variable) { \
1227: printf("will"); \
1228: } else { \
1229: printf("won't"); \
1230: } \
1231: printf(" %s.\n", tl->actionexplanation); \
1232: }
1233:
1234: #define doset(sl) if (sl->name && *sl->name != ' ') { \
1235: if (sl->handler == 0) \
1236: printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
1237: else \
1238: printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
1239: }
1240:
1241: if (argc == 1) {
1242: for (tl = Togglelist; tl->name; tl++) {
1243: dotog(tl);
1244: }
1245: printf("\n");
1246: for (sl = Setlist; sl->name; sl++) {
1247: doset(sl);
1248: }
1249: } else {
1250: int i;
1251:
1252: for (i = 1; i < argc; i++) {
1253: sl = getset(argv[i]);
1254: tl = GETTOGGLE(argv[i]);
1255: if (Ambiguous(sl) || Ambiguous(tl)) {
1256: printf("?Ambiguous argument '%s'.\n", argv[i]);
1257: return 0;
1258: } else if (!sl && !tl) {
1259: printf("?Unknown argument '%s'.\n", argv[i]);
1260: return 0;
1261: } else {
1262: if (tl) {
1263: dotog(tl);
1264: }
1265: if (sl) {
1266: doset(sl);
1267: }
1268: }
1269: }
1270: }
1271: /*@*/optionstatus();
1272: return 1;
1273: #undef doset
1274: #undef dotog
1275: }
1276:
1277: /*
1278: * The following are the data structures, and many of the routines,
1279: * relating to command processing.
1280: */
1281:
1282: /*
1283: * Set the escape character.
1284: */
1285: static int
1286: setescape(argc, argv)
1287: int argc;
1288: char *argv[];
1289: {
1290: register char *arg;
1291: char buf[50];
1292:
1293: printf(
1294: "Deprecated usage - please use 'set escape%s%s' in the future.\n",
1295: (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
1296: if (argc > 2)
1297: arg = argv[1];
1298: else {
1299: printf("new escape character: ");
1300: (void) fgets(buf, sizeof(buf), stdin);
1301: arg = buf;
1302: }
1303: if (arg[0] != '\0')
1304: escape = arg[0];
1305: if (!In3270) {
1306: printf("Escape character is '%s'.\n", control(escape));
1307: }
1308: (void) fflush(stdout);
1309: return 1;
1310: }
1311:
1312: /*VARARGS*/
1313: static int
1314: togcrmod()
1315: {
1316: crmod = !crmod;
1317: printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
1318: printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
1319: (void) fflush(stdout);
1320: return 1;
1321: }
1322:
1323: /*VARARGS*/
1324: int
1325: suspend()
1326: {
1327: #ifdef SIGTSTP
1328: setcommandmode();
1329: {
1330: long oldrows, oldcols, newrows, newcols, err;
1331:
1332: err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1333: (void) kill(0, SIGTSTP);
1334: /*
1335: * If we didn't get the window size before the SUSPEND, but we
1336: * can get them now (???), then send the NAWS to make sure that
1337: * we are set up for the right window size.
1338: */
1339: if (TerminalWindowSize(&newrows, &newcols) && connected &&
1340: (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1341: sendnaws();
1342: }
1343: }
1344: /* reget parameters in case they were changed */
1345: TerminalSaveState();
1346: setconnmode(0);
1347: #else
1348: printf("Suspend is not supported. Try the '!' command instead\n");
1349: #endif
1350: return 1;
1351: }
1352:
1353: #if !defined(TN3270)
1354: /*ARGSUSED*/
1355: int
1356: shell(argc, argv)
1357: int argc;
1358: char *argv[];
1359: {
1360: long oldrows, oldcols, newrows, newcols, err;
1361:
1362: setcommandmode();
1363:
1364: err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1365: switch(vfork()) {
1366: case -1:
1367: perror("Fork failed\n");
1368: break;
1369:
1370: case 0:
1371: {
1372: /*
1373: * Fire up the shell in the child.
1374: */
1375: register char *shellp, *shellname;
1376: extern char *rindex();
1377:
1378: shellp = getenv("SHELL");
1379: if (shellp == NULL)
1380: shellp = "/bin/sh";
1381: if ((shellname = rindex(shellp, '/')) == 0)
1382: shellname = shellp;
1383: else
1384: shellname++;
1385: if (argc > 1)
1386: execl(shellp, shellname, "-c", &saveline[1], 0);
1387: else
1388: execl(shellp, shellname, 0);
1389: perror("Execl");
1390: _exit(1);
1391: }
1392: default:
1393: (void)wait((int *)0); /* Wait for the shell to complete */
1394:
1395: if (TerminalWindowSize(&newrows, &newcols) && connected &&
1396: (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1397: sendnaws();
1398: }
1399: break;
1400: }
1401: return 1;
1402: }
1403: #else /* !defined(TN3270) */
1404: extern int shell();
1405: #endif /* !defined(TN3270) */
1406:
1407: /*VARARGS*/
1408: static
1409: bye(argc, argv)
1410: int argc; /* Number of arguments */
1411: char *argv[]; /* arguments */
1412: {
1413: extern int resettermname;
1414:
1415: if (connected) {
1416: (void) shutdown(net, 2);
1417: printf("Connection closed.\n");
1418: (void) NetClose(net);
1419: connected = 0;
1420: resettermname = 1;
1421: #if defined(AUTHENTICATION)
1422: auth_encrypt_connect(connected);
1423: #endif /* defined(AUTHENTICATION) */
1424: /* reset options */
1425: tninit();
1426: #if defined(TN3270)
1427: SetIn3270(); /* Get out of 3270 mode */
1428: #endif /* defined(TN3270) */
1429: }
1430: if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
1431: longjmp(toplevel, 1);
1432: /* NOTREACHED */
1433: }
1434: return 1; /* Keep lint, etc., happy */
1435: }
1436:
1437: /*VARARGS*/
1438: quit()
1439: {
1440: (void) call(bye, "bye", "fromquit", 0);
1441: Exit(0);
1442: /*NOTREACHED*/
1443: }
1444:
1445: /*VARARGS*/
1446: int
1447: logout()
1448: {
1449: send_do(TELOPT_LOGOUT, 1);
1450: (void) netflush();
1451: return 1;
1452: }
1453:
1454:
1455: /*
1456: * The SLC command.
1457: */
1458:
1459: struct slclist {
1460: char *name;
1461: char *help;
1462: void (*handler)();
1463: int arg;
1464: };
1465:
1466: static void slc_help();
1467:
1468: struct slclist SlcList[] = {
1469: { "export", "Use local special character definitions",
1470: slc_mode_export, 0 },
1471: { "import", "Use remote special character definitions",
1472: slc_mode_import, 1 },
1473: { "check", "Verify remote special character definitions",
1474: slc_mode_import, 0 },
1475: { "help", 0, slc_help, 0 },
1476: { "?", "Print help information", slc_help, 0 },
1477: { 0 },
1478: };
1479:
1480: static void
1481: slc_help()
1482: {
1483: struct slclist *c;
1484:
1485: for (c = SlcList; c->name; c++) {
1486: if (c->help) {
1487: if (*c->help)
1488: printf("%-15s %s\n", c->name, c->help);
1489: else
1490: printf("\n");
1491: }
1492: }
1493: }
1494:
1495: static struct slclist *
1496: getslc(name)
1497: char *name;
1498: {
1499: return (struct slclist *)
1500: genget(name, (char **) SlcList, sizeof(struct slclist));
1501: }
1502:
1503: static
1504: slccmd(argc, argv)
1505: int argc;
1506: char *argv[];
1507: {
1508: struct slclist *c;
1509:
1510: if (argc != 2) {
1511: fprintf(stderr,
1512: "Need an argument to 'slc' command. 'slc ?' for help.\n");
1513: return 0;
1514: }
1515: c = getslc(argv[1]);
1516: if (c == 0) {
1517: fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
1518: argv[1]);
1519: return 0;
1520: }
1521: if (Ambiguous(c)) {
1522: fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
1523: argv[1]);
1524: return 0;
1525: }
1526: (*c->handler)(c->arg);
1527: slcstate();
1528: return 1;
1529: }
1530:
1531: /*
1532: * The ENVIRON command.
1533: */
1534:
1535: struct envlist {
1536: char *name;
1537: char *help;
1538: void (*handler)();
1539: int narg;
1540: };
1541:
1542: extern struct env_lst *
1543: env_define P((unsigned char *, unsigned char *));
1544: extern void
1545: env_undefine P((unsigned char *)),
1546: env_export P((unsigned char *)),
1547: env_unexport P((unsigned char *)),
1548: env_send P((unsigned char *)),
1549: #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1550: env_varval P((unsigned char *)),
1551: #endif
1552: env_list P((void));
1553: static void
1554: env_help P((void));
1555:
1556: struct envlist EnvList[] = {
1557: { "define", "Define an environment variable",
1558: (void (*)())env_define, 2 },
1559: { "undefine", "Undefine an environment variable",
1560: env_undefine, 1 },
1561: { "export", "Mark an environment variable for automatic export",
1562: env_export, 1 },
1563: { "unexport", "Don't mark an environment variable for automatic export",
1564: env_unexport, 1 },
1565: { "send", "Send an environment variable", env_send, 1 },
1566: { "list", "List the current environment variables",
1567: env_list, 0 },
1568: #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1569: { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1570: env_varval, 1 },
1571: #endif
1572: { "help", 0, env_help, 0 },
1573: { "?", "Print help information", env_help, 0 },
1574: { 0 },
1575: };
1576:
1577: static void
1578: env_help()
1579: {
1580: struct envlist *c;
1581:
1582: for (c = EnvList; c->name; c++) {
1583: if (c->help) {
1584: if (*c->help)
1585: printf("%-15s %s\n", c->name, c->help);
1586: else
1587: printf("\n");
1588: }
1589: }
1590: }
1591:
1592: static struct envlist *
1593: getenvcmd(name)
1594: char *name;
1595: {
1596: return (struct envlist *)
1597: genget(name, (char **) EnvList, sizeof(struct envlist));
1598: }
1599:
1600: env_cmd(argc, argv)
1601: int argc;
1602: char *argv[];
1603: {
1604: struct envlist *c;
1605:
1606: if (argc < 2) {
1607: fprintf(stderr,
1608: "Need an argument to 'environ' command. 'environ ?' for help.\n");
1609: return 0;
1610: }
1611: c = getenvcmd(argv[1]);
1612: if (c == 0) {
1613: fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
1614: argv[1]);
1615: return 0;
1616: }
1617: if (Ambiguous(c)) {
1618: fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
1619: argv[1]);
1620: return 0;
1621: }
1622: if (c->narg + 2 != argc) {
1623: fprintf(stderr,
1624: "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n",
1625: c->narg < argc + 2 ? "only " : "",
1626: c->narg, c->narg == 1 ? "" : "s", c->name);
1627: return 0;
1628: }
1629: (*c->handler)(argv[2], argv[3]);
1630: return 1;
1631: }
1632:
1633: struct env_lst {
1634: struct env_lst *next; /* pointer to next structure */
1635: struct env_lst *prev; /* pointer to previous structure */
1636: unsigned char *var; /* pointer to variable name */
1637: unsigned char *value; /* pointer to variable value */
1638: int export; /* 1 -> export with default list of variables */
1639: int welldefined; /* A well defined variable */
1640: };
1641:
1642: struct env_lst envlisthead;
1643:
1644: struct env_lst *
1645: env_find(var)
1646: unsigned char *var;
1647: {
1648: register struct env_lst *ep;
1649:
1650: for (ep = envlisthead.next; ep; ep = ep->next) {
1651: if (strcmp((char *)ep->var, (char *)var) == 0)
1652: return(ep);
1653: }
1654: return(NULL);
1655: }
1656:
1657: void
1658: env_init()
1659: {
1660: extern char **environ;
1661: register char **epp, *cp;
1662: register struct env_lst *ep;
1663: extern char *index();
1664:
1665: for (epp = environ; *epp; epp++) {
1666: if (cp = index(*epp, '=')) {
1667: *cp = '\0';
1668: ep = env_define((unsigned char *)*epp,
1669: (unsigned char *)cp+1);
1670: ep->export = 0;
1671: *cp = '=';
1672: }
1673: }
1674: /*
1675: * Special case for DISPLAY variable. If it is ":0.0" or
1676: * "unix:0.0", we have to get rid of "unix" and insert our
1677: * hostname.
1678: */
1679: if ((ep = env_find("DISPLAY"))
1680: && ((*ep->value == ':')
1681: || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
1682: char hbuf[256+1];
1683: char *cp2 = index((char *)ep->value, ':');
1684:
1685: gethostname(hbuf, 256);
1686: hbuf[256] = '\0';
1687: cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
1688: sprintf((char *)cp, "%s%s", hbuf, cp2);
1689: free(ep->value);
1690: ep->value = (unsigned char *)cp;
1691: }
1692: /*
1693: * If USER is not defined, but LOGNAME is, then add
1694: * USER with the value from LOGNAME. By default, we
1695: * don't export the USER variable.
1696: */
1697: if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
1698: env_define((unsigned char *)"USER", ep->value);
1699: env_unexport((unsigned char *)"USER");
1700: }
1701: env_export((unsigned char *)"DISPLAY");
1702: env_export((unsigned char *)"PRINTER");
1703: }
1704:
1705: struct env_lst *
1706: env_define(var, value)
1707: unsigned char *var, *value;
1708: {
1709: register struct env_lst *ep;
1710:
1711: if (ep = env_find(var)) {
1712: if (ep->var)
1713: free(ep->var);
1714: if (ep->value)
1715: free(ep->value);
1716: } else {
1717: ep = (struct env_lst *)malloc(sizeof(struct env_lst));
1718: ep->next = envlisthead.next;
1719: envlisthead.next = ep;
1720: ep->prev = &envlisthead;
1721: if (ep->next)
1722: ep->next->prev = ep;
1723: }
1724: ep->welldefined = opt_welldefined(var);
1725: ep->export = 1;
1726: ep->var = (unsigned char *)strdup((char *)var);
1727: ep->value = (unsigned char *)strdup((char *)value);
1728: return(ep);
1729: }
1730:
1731: void
1732: env_undefine(var)
1733: unsigned char *var;
1734: {
1735: register struct env_lst *ep;
1736:
1737: if (ep = env_find(var)) {
1738: ep->prev->next = ep->next;
1739: if (ep->next)
1740: ep->next->prev = ep->prev;
1741: if (ep->var)
1742: free(ep->var);
1743: if (ep->value)
1744: free(ep->value);
1745: free(ep);
1746: }
1747: }
1748:
1749: void
1750: env_export(var)
1751: unsigned char *var;
1752: {
1753: register struct env_lst *ep;
1754:
1755: if (ep = env_find(var))
1756: ep->export = 1;
1757: }
1758:
1759: void
1760: env_unexport(var)
1761: unsigned char *var;
1762: {
1763: register struct env_lst *ep;
1764:
1765: if (ep = env_find(var))
1766: ep->export = 0;
1767: }
1768:
1769: void
1770: env_send(var)
1771: unsigned char *var;
1772: {
1773: register struct env_lst *ep;
1774:
1775: if (my_state_is_wont(TELOPT_NEW_ENVIRON)
1776: #ifdef OLD_ENVIRON
1777: && my_state_is_wont(TELOPT_OLD_ENVIRON)
1778: #endif
1779: ) {
1780: fprintf(stderr,
1781: "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1782: var);
1783: return;
1784: }
1785: ep = env_find(var);
1786: if (ep == 0) {
1787: fprintf(stderr, "Cannot send '%s': variable not defined\n",
1788: var);
1789: return;
1790: }
1791: env_opt_start_info();
1792: env_opt_add(ep->var);
1793: env_opt_end(0);
1794: }
1795:
1796: void
1797: env_list()
1798: {
1799: register struct env_lst *ep;
1800:
1801: for (ep = envlisthead.next; ep; ep = ep->next) {
1802: printf("%c %-20s %s\n", ep->export ? '*' : ' ',
1803: ep->var, ep->value);
1804: }
1805: }
1806:
1807: unsigned char *
1808: env_default(init, welldefined)
1809: int init;
1810: {
1811: static struct env_lst *nep = NULL;
1812:
1813: if (init) {
1814: nep = &envlisthead;
1815: return;
1816: }
1817: if (nep) {
1818: while (nep = nep->next) {
1819: if (nep->export && (nep->welldefined == welldefined))
1820: return(nep->var);
1821: }
1822: }
1823: return(NULL);
1824: }
1825:
1826: unsigned char *
1827: env_getvalue(var)
1828: unsigned char *var;
1829: {
1830: register struct env_lst *ep;
1831:
1832: if (ep = env_find(var))
1833: return(ep->value);
1834: return(NULL);
1835: }
1836:
1837: #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1838: void
1839: env_varval(what)
1840: unsigned char *what;
1841: {
1842: extern int old_env_var, old_env_value, env_auto;
1843: int len = strlen((char *)what);
1844:
1845: if (len == 0)
1846: goto unknown;
1847:
1848: if (strncasecmp((char *)what, "status", len) == 0) {
1849: if (env_auto)
1850: printf("%s%s", "VAR and VALUE are/will be ",
1851: "determined automatically\n");
1852: if (old_env_var == OLD_ENV_VAR)
1853: printf("VAR and VALUE set to correct definitions\n");
1854: else
1855: printf("VAR and VALUE definitions are reversed\n");
1856: } else if (strncasecmp((char *)what, "auto", len) == 0) {
1857: env_auto = 1;
1858: old_env_var = OLD_ENV_VALUE;
1859: old_env_value = OLD_ENV_VAR;
1860: } else if (strncasecmp((char *)what, "right", len) == 0) {
1861: env_auto = 0;
1862: old_env_var = OLD_ENV_VAR;
1863: old_env_value = OLD_ENV_VALUE;
1864: } else if (strncasecmp((char *)what, "wrong", len) == 0) {
1865: env_auto = 0;
1866: old_env_var = OLD_ENV_VALUE;
1867: old_env_value = OLD_ENV_VAR;
1868: } else {
1869: unknown:
1870: printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
1871: }
1872: }
1873: #endif
1874:
1875: #if defined(AUTHENTICATION)
1876: /*
1877: * The AUTHENTICATE command.
1878: */
1879:
1880: struct authlist {
1881: char *name;
1882: char *help;
1883: int (*handler)();
1884: int narg;
1885: };
1886:
1887: extern int
1888: auth_enable P((int)),
1889: auth_disable P((int)),
1890: auth_status P((void));
1891: static int
1892: auth_help P((void));
1893:
1894: struct authlist AuthList[] = {
1895: { "status", "Display current status of authentication information",
1896: auth_status, 0 },
1897: { "disable", "Disable an authentication type ('auth disable ?' for more)",
1898: auth_disable, 1 },
1899: { "enable", "Enable an authentication type ('auth enable ?' for more)",
1900: auth_enable, 1 },
1901: { "help", 0, auth_help, 0 },
1902: { "?", "Print help information", auth_help, 0 },
1903: { 0 },
1904: };
1905:
1906: static int
1907: auth_help()
1908: {
1909: struct authlist *c;
1910:
1911: for (c = AuthList; c->name; c++) {
1912: if (c->help) {
1913: if (*c->help)
1914: printf("%-15s %s\n", c->name, c->help);
1915: else
1916: printf("\n");
1917: }
1918: }
1919: return 0;
1920: }
1921:
1922: auth_cmd(argc, argv)
1923: int argc;
1924: char *argv[];
1925: {
1926: struct authlist *c;
1927:
1928: c = (struct authlist *)
1929: genget(argv[1], (char **) AuthList, sizeof(struct authlist));
1930: if (c == 0) {
1931: fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
1932: argv[1]);
1933: return 0;
1934: }
1935: if (Ambiguous(c)) {
1936: fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
1937: argv[1]);
1938: return 0;
1939: }
1940: if (c->narg + 2 != argc) {
1941: fprintf(stderr,
1942: "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n",
1943: c->narg < argc + 2 ? "only " : "",
1944: c->narg, c->narg == 1 ? "" : "s", c->name);
1945: return 0;
1946: }
1947: return((*c->handler)(argv[2], argv[3]));
1948: }
1949: #endif
1950:
1951:
1952: #if defined(unix) && defined(TN3270)
1953: static void
1954: filestuff(fd)
1955: int fd;
1956: {
1957: int res;
1958:
1959: #ifdef F_GETOWN
1960: setconnmode(0);
1961: res = fcntl(fd, F_GETOWN, 0);
1962: setcommandmode();
1963:
1964: if (res == -1) {
1965: perror("fcntl");
1966: return;
1967: }
1968: printf("\tOwner is %d.\n", res);
1969: #endif
1970:
1971: setconnmode(0);
1972: res = fcntl(fd, F_GETFL, 0);
1973: setcommandmode();
1974:
1975: if (res == -1) {
1976: perror("fcntl");
1977: return;
1978: }
1979: #ifdef notdef
1980: printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
1981: #endif
1982: }
1983: #endif /* defined(unix) && defined(TN3270) */
1984:
1985: /*
1986: * Print status about the connection.
1987: */
1988: /*ARGSUSED*/
1989: static
1990: status(argc, argv)
1991: int argc;
1992: char *argv[];
1993: {
1994: if (connected) {
1995: printf("Connected to %s.\n", hostname);
1996: if ((argc < 2) || strcmp(argv[1], "notmuch")) {
1997: int mode = getconnmode();
1998:
1999: if (my_want_state_is_will(TELOPT_LINEMODE)) {
2000: printf("Operating with LINEMODE option\n");
2001: printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
2002: printf("%s catching of signals\n",
2003: (mode&MODE_TRAPSIG) ? "Local" : "No");
2004: slcstate();
2005: #ifdef KLUDGELINEMODE
2006: } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
2007: printf("Operating in obsolete linemode\n");
2008: #endif
2009: } else {
2010: printf("Operating in single character mode\n");
2011: if (localchars)
2012: printf("Catching signals locally\n");
2013: }
2014: printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
2015: if (my_want_state_is_will(TELOPT_LFLOW))
2016: printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
2017: }
2018: } else {
2019: printf("No connection.\n");
2020: }
2021: # if !defined(TN3270)
2022: printf("Escape character is '%s'.\n", control(escape));
2023: (void) fflush(stdout);
2024: # else /* !defined(TN3270) */
2025: if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
2026: printf("Escape character is '%s'.\n", control(escape));
2027: }
2028: # if defined(unix)
2029: if ((argc >= 2) && !strcmp(argv[1], "everything")) {
2030: printf("SIGIO received %d time%s.\n",
2031: sigiocount, (sigiocount == 1)? "":"s");
2032: if (In3270) {
2033: printf("Process ID %d, process group %d.\n",
2034: getpid(), getpgrp(getpid()));
2035: printf("Terminal input:\n");
2036: filestuff(tin);
2037: printf("Terminal output:\n");
2038: filestuff(tout);
2039: printf("Network socket:\n");
2040: filestuff(net);
2041: }
2042: }
2043: if (In3270 && transcom) {
2044: printf("Transparent mode command is '%s'.\n", transcom);
2045: }
2046: # endif /* defined(unix) */
2047: (void) fflush(stdout);
2048: if (In3270) {
2049: return 0;
2050: }
2051: # endif /* defined(TN3270) */
2052: return 1;
2053: }
2054:
2055: #ifdef SIGINFO
2056: /*
2057: * Function that gets called when SIGINFO is received.
2058: */
2059: ayt_status()
2060: {
2061: (void) call(status, "status", "notmuch", 0);
2062: }
2063: #endif
2064:
2065: unsigned long inet_addr();
2066:
2067: int
2068: tn(argc, argv)
2069: int argc;
2070: char *argv[];
2071: {
2072: register struct hostent *host = 0;
2073: struct sockaddr_in sin;
2074: struct servent *sp = 0;
2075: unsigned long temp;
2076: extern char *inet_ntoa();
2077: #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
2078: char *srp = 0, *strrchr();
2079: unsigned long sourceroute(), srlen;
2080: #endif
2081: char *cmd, *hostp = 0, *portp = 0, *user = 0;
2082:
2083: /* clear the socket address prior to use */
2084: bzero((char *)&sin, sizeof(sin));
2085:
2086: if (connected) {
2087: printf("?Already connected to %s\n", hostname);
2088: setuid(getuid());
2089: return 0;
2090: }
2091: if (argc < 2) {
2092: (void) strcpy(line, "open ");
2093: printf("(to) ");
2094: (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
2095: makeargv();
2096: argc = margc;
2097: argv = margv;
2098: }
2099: cmd = *argv;
2100: --argc; ++argv;
2101: while (argc) {
2102: if (isprefix(*argv, "help") || isprefix(*argv, "?"))
2103: goto usage;
2104: if (strcmp(*argv, "-l") == 0) {
2105: --argc; ++argv;
2106: if (argc == 0)
2107: goto usage;
2108: user = *argv++;
2109: --argc;
2110: continue;
2111: }
2112: if (strcmp(*argv, "-a") == 0) {
2113: --argc; ++argv;
2114: autologin = 1;
2115: continue;
2116: }
2117: if (hostp == 0) {
2118: hostp = *argv++;
2119: --argc;
2120: continue;
2121: }
2122: if (portp == 0) {
2123: portp = *argv++;
2124: --argc;
2125: continue;
2126: }
2127: usage:
2128: printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
2129: setuid(getuid());
2130: return 0;
2131: }
2132: if (hostp == 0)
2133: goto usage;
2134:
2135: #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
2136: if (hostp[0] == '@' || hostp[0] == '!') {
2137: if ((hostname = strrchr(hostp, ':')) == NULL)
2138: hostname = strrchr(hostp, '@');
2139: hostname++;
2140: srp = 0;
2141: temp = sourceroute(hostp, &srp, &srlen);
2142: if (temp == 0) {
2143: herror(srp);
2144: setuid(getuid());
2145: return 0;
2146: } else if (temp == -1) {
2147: printf("Bad source route option: %s\n", hostp);
2148: setuid(getuid());
2149: return 0;
2150: } else {
2151: sin.sin_addr.s_addr = temp;
2152: sin.sin_family = AF_INET;
2153: }
2154: } else {
2155: #endif
2156: temp = inet_addr(hostp);
2157: if (temp != INADDR_NONE) {
2158: sin.sin_addr.s_addr = temp;
2159: sin.sin_family = AF_INET;
2160: (void) strcpy(_hostname, hostp);
2161: hostname = _hostname;
2162: } else {
2163: host = gethostbyname(hostp);
2164: if (host) {
2165: sin.sin_family = host->h_addrtype;
2166: #if defined(h_addr) /* In 4.3, this is a #define */
2167: memcpy((caddr_t)&sin.sin_addr,
2168: host->h_addr_list[0], host->h_length);
2169: #else /* defined(h_addr) */
2170: memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
2171: #endif /* defined(h_addr) */
2172: strncpy(_hostname, host->h_name, sizeof(_hostname));
2173: _hostname[sizeof(_hostname)-1] = '\0';
2174: hostname = _hostname;
2175: } else {
2176: herror(hostp);
2177: setuid(getuid());
2178: return 0;
2179: }
2180: }
2181: #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
2182: }
2183: #endif
2184: if (portp) {
2185: if (*portp == '-') {
2186: portp++;
2187: telnetport = 1;
2188: } else
2189: telnetport = 0;
2190: sin.sin_port = atoi(portp);
2191: if (sin.sin_port == 0) {
2192: sp = getservbyname(portp, "tcp");
2193: if (sp)
2194: sin.sin_port = sp->s_port;
2195: else {
2196: printf("%s: bad port number\n", portp);
2197: setuid(getuid());
2198: return 0;
2199: }
2200: } else {
2201: #if !defined(htons)
2202: u_short htons P((unsigned short));
2203: #endif /* !defined(htons) */
2204: sin.sin_port = htons(sin.sin_port);
2205: }
2206: } else {
2207: if (sp == 0) {
2208: sp = getservbyname("telnet", "tcp");
2209: if (sp == 0) {
2210: fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
2211: setuid(getuid());
2212: return 0;
2213: }
2214: sin.sin_port = sp->s_port;
2215: }
2216: telnetport = 1;
2217: }
2218: printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
2219: do {
2220: net = socket(AF_INET, SOCK_STREAM, 0);
2221: setuid(getuid());
2222: if (net < 0) {
2223: perror("telnet: socket");
2224: return 0;
2225: }
2226: #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
2227: if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
2228: perror("setsockopt (IP_OPTIONS)");
2229: #endif
2230: #if defined(IPPROTO_IP) && defined(IP_TOS)
2231: {
2232: # if defined(HAS_GETTOS)
2233: struct tosent *tp;
2234: if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
2235: tos = tp->t_tos;
2236: # endif
2237: if (tos < 0)
2238: tos = IPTOS_LOWDELAY;
2239: if (tos
2240: && (setsockopt(net, IPPROTO_IP, IP_TOS,
2241: (char *)&tos, sizeof(int)) < 0)
2242: && (errno != ENOPROTOOPT))
2243: perror("telnet: setsockopt (IP_TOS) (ignored)");
2244: }
2245: #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
2246:
2247: if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
2248: perror("setsockopt (SO_DEBUG)");
2249: }
2250:
2251: if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2252: #if defined(h_addr) /* In 4.3, this is a #define */
2253: if (host && host->h_addr_list[1]) {
2254: int oerrno = errno;
2255:
2256: fprintf(stderr, "telnet: connect to address %s: ",
2257: inet_ntoa(sin.sin_addr));
2258: errno = oerrno;
2259: perror((char *)0);
2260: host->h_addr_list++;
2261: memcpy((caddr_t)&sin.sin_addr,
2262: host->h_addr_list[0], host->h_length);
2263: (void) NetClose(net);
2264: continue;
2265: }
2266: #endif /* defined(h_addr) */
2267: perror("telnet: Unable to connect to remote host");
2268: return 0;
2269: }
2270: connected++;
2271: #if defined(AUTHENTICATION)
2272: auth_encrypt_connect(connected);
2273: #endif /* defined(AUTHENTICATION) */
2274: } while (connected == 0);
2275: cmdrc(hostp, hostname);
2276: if (autologin && user == NULL) {
2277: struct passwd *pw;
2278:
2279: user = getenv("USER");
2280: if (user == NULL ||
2281: (pw = getpwnam(user)) && pw->pw_uid != getuid()) {
2282: if (pw = getpwuid(getuid()))
2283: user = pw->pw_name;
2284: else
2285: user = NULL;
2286: }
2287: }
2288: if (user) {
2289: env_define((unsigned char *)"USER", (unsigned char *)user);
2290: env_export((unsigned char *)"USER");
2291: }
2292: (void) call(status, "status", "notmuch", 0);
2293: if (setjmp(peerdied) == 0)
2294: telnet(user);
2295: (void) NetClose(net);
2296: ExitString("Connection closed by foreign host.\n",1);
2297: /*NOTREACHED*/
2298: }
2299:
2300: #define HELPINDENT (sizeof ("connect"))
2301:
2302: static char
2303: openhelp[] = "connect to a site",
2304: closehelp[] = "close current connection",
2305: logouthelp[] = "forcibly logout remote user and close the connection",
2306: quithelp[] = "exit telnet",
2307: statushelp[] = "print status information",
2308: helphelp[] = "print help information",
2309: sendhelp[] = "transmit special characters ('send ?' for more)",
2310: sethelp[] = "set operating parameters ('set ?' for more)",
2311: unsethelp[] = "unset operating parameters ('unset ?' for more)",
2312: togglestring[] ="toggle operating parameters ('toggle ?' for more)",
2313: slchelp[] = "change state of special charaters ('slc ?' for more)",
2314: displayhelp[] = "display operating parameters",
2315: #if defined(TN3270) && defined(unix)
2316: transcomhelp[] = "specify Unix command for transparent mode pipe",
2317: #endif /* defined(TN3270) && defined(unix) */
2318: #if defined(AUTHENTICATION)
2319: authhelp[] = "turn on (off) authentication ('auth ?' for more)",
2320: #endif
2321: #if defined(unix)
2322: zhelp[] = "suspend telnet",
2323: #endif /* defined(unix) */
2324: shellhelp[] = "invoke a subshell",
2325: envhelp[] = "change environment variables ('environ ?' for more)",
2326: modestring[] = "try to enter line or character mode ('mode ?' for more)";
2327:
2328: static int help();
2329:
2330: static Command cmdtab[] = {
2331: { "close", closehelp, bye, 1 },
2332: { "logout", logouthelp, logout, 1 },
2333: { "display", displayhelp, display, 0 },
2334: { "mode", modestring, modecmd, 0 },
2335: { "open", openhelp, tn, 0 },
2336: { "quit", quithelp, quit, 0 },
2337: { "send", sendhelp, sendcmd, 0 },
2338: { "set", sethelp, setcmd, 0 },
2339: { "unset", unsethelp, unsetcmd, 0 },
2340: { "status", statushelp, status, 0 },
2341: { "toggle", togglestring, toggle, 0 },
2342: { "slc", slchelp, slccmd, 0 },
2343: #if defined(TN3270) && defined(unix)
2344: { "transcom", transcomhelp, settranscom, 0 },
2345: #endif /* defined(TN3270) && defined(unix) */
2346: #if defined(AUTHENTICATION)
2347: { "auth", authhelp, auth_cmd, 0 },
2348: #endif
2349: #if defined(unix)
2350: { "z", zhelp, suspend, 0 },
2351: #endif /* defined(unix) */
2352: #if defined(TN3270)
2353: { "!", shellhelp, shell, 1 },
2354: #else
2355: { "!", shellhelp, shell, 0 },
2356: #endif
2357: { "environ", envhelp, env_cmd, 0 },
2358: { "?", helphelp, help, 0 },
2359: 0
2360: };
2361:
2362: static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
2363: static char escapehelp[] = "deprecated command -- use 'set escape' instead";
2364:
2365: static Command cmdtab2[] = {
2366: { "help", 0, help, 0 },
2367: { "escape", escapehelp, setescape, 0 },
2368: { "crmod", crmodhelp, togcrmod, 0 },
2369: 0
2370: };
2371:
2372:
2373: /*
2374: * Call routine with argc, argv set from args (terminated by 0).
2375: */
2376:
2377: /*VARARGS1*/
2378: static
2379: call(va_alist)
2380: va_dcl
2381: {
2382: va_list ap;
2383: typedef int (*intrtn_t)();
2384: intrtn_t routine;
2385: char *args[100];
2386: int argno = 0;
2387:
2388: va_start(ap);
2389: routine = (va_arg(ap, intrtn_t));
2390: while ((args[argno++] = va_arg(ap, char *)) != 0) {
2391: ;
2392: }
2393: va_end(ap);
2394: return (*routine)(argno-1, args);
2395: }
2396:
2397:
2398: static Command *
2399: getcmd(name)
2400: char *name;
2401: {
2402: Command *cm;
2403:
2404: if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))
2405: return cm;
2406: return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
2407: }
2408:
2409: void
2410: command(top, tbuf, cnt)
2411: int top;
2412: char *tbuf;
2413: int cnt;
2414: {
2415: register Command *c;
2416:
2417: setcommandmode();
2418: if (!top) {
2419: putchar('\n');
2420: #if defined(unix)
2421: } else {
2422: (void) signal(SIGINT, SIG_DFL);
2423: (void) signal(SIGQUIT, SIG_DFL);
2424: #endif /* defined(unix) */
2425: }
2426: for (;;) {
2427: if (rlogin == _POSIX_VDISABLE)
2428: printf("%s> ", prompt);
2429: if (tbuf) {
2430: register char *cp;
2431: cp = line;
2432: while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
2433: cnt--;
2434: tbuf = 0;
2435: if (cp == line || *--cp != '\n' || cp == line)
2436: goto getline;
2437: *cp = '\0';
2438: if (rlogin == _POSIX_VDISABLE)
2439: printf("%s\n", line);
2440: } else {
2441: getline:
2442: if (rlogin != _POSIX_VDISABLE)
2443: printf("%s> ", prompt);
2444: if (fgets(line, sizeof(line), stdin) == NULL) {
2445: if (feof(stdin) || ferror(stdin)) {
2446: (void) quit();
2447: /*NOTREACHED*/
2448: }
2449: break;
2450: }
2451: }
2452: if (line[0] == 0)
2453: break;
2454: makeargv();
2455: if (margv[0] == 0) {
2456: break;
2457: }
2458: c = getcmd(margv[0]);
2459: if (Ambiguous(c)) {
2460: printf("?Ambiguous command\n");
2461: continue;
2462: }
2463: if (c == 0) {
2464: printf("?Invalid command\n");
2465: continue;
2466: }
2467: if (c->needconnect && !connected) {
2468: printf("?Need to be connected first.\n");
2469: continue;
2470: }
2471: if ((*c->handler)(margc, margv)) {
2472: break;
2473: }
2474: }
2475: if (!top) {
2476: if (!connected) {
2477: longjmp(toplevel, 1);
2478: /*NOTREACHED*/
2479: }
2480: #if defined(TN3270)
2481: if (shell_active == 0) {
2482: setconnmode(0);
2483: }
2484: #else /* defined(TN3270) */
2485: setconnmode(0);
2486: #endif /* defined(TN3270) */
2487: }
2488: }
2489:
2490: /*
2491: * Help command.
2492: */
2493: static
2494: help(argc, argv)
2495: int argc;
2496: char *argv[];
2497: {
2498: register Command *c;
2499:
2500: if (argc == 1) {
2501: printf("Commands may be abbreviated. Commands are:\n\n");
2502: for (c = cmdtab; c->name; c++)
2503: if (c->help) {
2504: printf("%-*s\t%s\n", HELPINDENT, c->name,
2505: c->help);
2506: }
2507: return 0;
2508: }
2509: while (--argc > 0) {
2510: register char *arg;
2511: arg = *++argv;
2512: c = getcmd(arg);
2513: if (Ambiguous(c))
2514: printf("?Ambiguous help command %s\n", arg);
2515: else if (c == (Command *)0)
2516: printf("?Invalid help command %s\n", arg);
2517: else
2518: printf("%s\n", c->help);
2519: }
2520: return 0;
2521: }
2522:
2523: static char *rcname = 0;
2524: static char rcbuf[128];
2525:
2526: cmdrc(m1, m2)
2527: char *m1, *m2;
2528: {
2529: register Command *c;
2530: FILE *rcfile;
2531: int gotmachine = 0;
2532: int l1 = strlen(m1);
2533: int l2 = strlen(m2);
2534: char m1save[64];
2535:
2536: if (skiprc)
2537: return;
2538:
2539: strcpy(m1save, m1);
2540: m1 = m1save;
2541:
2542: if (rcname == 0) {
2543: rcname = getenv("HOME");
2544: if (rcname)
2545: strcpy(rcbuf, rcname);
2546: else
2547: rcbuf[0] = '\0';
2548: strcat(rcbuf, "/.telnetrc");
2549: rcname = rcbuf;
2550: }
2551:
2552: if ((rcfile = fopen(rcname, "r")) == 0) {
2553: return;
2554: }
2555:
2556: for (;;) {
2557: if (fgets(line, sizeof(line), rcfile) == NULL)
2558: break;
2559: if (line[0] == 0)
2560: break;
2561: if (line[0] == '#')
2562: continue;
2563: if (gotmachine) {
2564: if (!isspace(line[0]))
2565: gotmachine = 0;
2566: }
2567: if (gotmachine == 0) {
2568: if (isspace(line[0]))
2569: continue;
2570: if (strncasecmp(line, m1, l1) == 0)
2571: strncpy(line, &line[l1], sizeof(line) - l1);
2572: else if (strncasecmp(line, m2, l2) == 0)
2573: strncpy(line, &line[l2], sizeof(line) - l2);
2574: else if (strncasecmp(line, "DEFAULT", 7) == 0)
2575: strncpy(line, &line[7], sizeof(line) - 7);
2576: else
2577: continue;
2578: if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
2579: continue;
2580: gotmachine = 1;
2581: }
2582: makeargv();
2583: if (margv[0] == 0)
2584: continue;
2585: c = getcmd(margv[0]);
2586: if (Ambiguous(c)) {
2587: printf("?Ambiguous command: %s\n", margv[0]);
2588: continue;
2589: }
2590: if (c == 0) {
2591: printf("?Invalid command: %s\n", margv[0]);
2592: continue;
2593: }
2594: /*
2595: * This should never happen...
2596: */
2597: if (c->needconnect && !connected) {
2598: printf("?Need to be connected first for %s.\n", margv[0]);
2599: continue;
2600: }
2601: (*c->handler)(margc, margv);
2602: }
2603: fclose(rcfile);
2604: }
2605:
2606: #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
2607:
2608: /*
2609: * Source route is handed in as
2610: * [!]@hop1@hop2...[@|:]dst
2611: * If the leading ! is present, it is a
2612: * strict source route, otherwise it is
2613: * assmed to be a loose source route.
2614: *
2615: * We fill in the source route option as
2616: * hop1,hop2,hop3...dest
2617: * and return a pointer to hop1, which will
2618: * be the address to connect() to.
2619: *
2620: * Arguments:
2621: * arg: pointer to route list to decipher
2622: *
2623: * cpp: If *cpp is not equal to NULL, this is a
2624: * pointer to a pointer to a character array
2625: * that should be filled in with the option.
2626: *
2627: * lenp: pointer to an integer that contains the
2628: * length of *cpp if *cpp != NULL.
2629: *
2630: * Return values:
2631: *
2632: * Returns the address of the host to connect to. If the
2633: * return value is -1, there was a syntax error in the
2634: * option, either unknown characters, or too many hosts.
2635: * If the return value is 0, one of the hostnames in the
2636: * path is unknown, and *cpp is set to point to the bad
2637: * hostname.
2638: *
2639: * *cpp: If *cpp was equal to NULL, it will be filled
2640: * in with a pointer to our static area that has
2641: * the option filled in. This will be 32bit aligned.
2642: *
2643: * *lenp: This will be filled in with how long the option
2644: * pointed to by *cpp is.
2645: *
2646: */
2647: unsigned long
2648: sourceroute(arg, cpp, lenp)
2649: char *arg;
2650: char **cpp;
2651: int *lenp;
2652: {
2653: static char lsr[44];
2654: #ifdef sysV88
2655: static IOPTN ipopt;
2656: #endif
2657: char *cp, *cp2, *lsrp, *lsrep;
2658: register int tmp;
2659: struct in_addr sin_addr;
2660: register struct hostent *host = 0;
2661: register char c;
2662:
2663: /*
2664: * Verify the arguments, and make sure we have
2665: * at least 7 bytes for the option.
2666: */
2667: if (cpp == NULL || lenp == NULL)
2668: return((unsigned long)-1);
2669: if (*cpp != NULL && *lenp < 7)
2670: return((unsigned long)-1);
2671: /*
2672: * Decide whether we have a buffer passed to us,
2673: * or if we need to use our own static buffer.
2674: */
2675: if (*cpp) {
2676: lsrp = *cpp;
2677: lsrep = lsrp + *lenp;
2678: } else {
2679: *cpp = lsrp = lsr;
2680: lsrep = lsrp + 44;
2681: }
2682:
2683: cp = arg;
2684:
2685: /*
2686: * Next, decide whether we have a loose source
2687: * route or a strict source route, and fill in
2688: * the begining of the option.
2689: */
2690: #ifndef sysV88
2691: if (*cp == '!') {
2692: cp++;
2693: *lsrp++ = IPOPT_SSRR;
2694: } else
2695: *lsrp++ = IPOPT_LSRR;
2696: #else
2697: if (*cp == '!') {
2698: cp++;
2699: ipopt.io_type = IPOPT_SSRR;
2700: } else
2701: ipopt.io_type = IPOPT_LSRR;
2702: #endif
2703:
2704: if (*cp != '@')
2705: return((unsigned long)-1);
2706:
2707: #ifndef sysV88
2708: lsrp++; /* skip over length, we'll fill it in later */
2709: *lsrp++ = 4;
2710: #endif
2711:
2712: cp++;
2713:
2714: sin_addr.s_addr = 0;
2715:
2716: for (c = 0;;) {
2717: if (c == ':')
2718: cp2 = 0;
2719: else for (cp2 = cp; c = *cp2; cp2++) {
2720: if (c == ',') {
2721: *cp2++ = '\0';
2722: if (*cp2 == '@')
2723: cp2++;
2724: } else if (c == '@') {
2725: *cp2++ = '\0';
2726: } else if (c == ':') {
2727: *cp2++ = '\0';
2728: } else
2729: continue;
2730: break;
2731: }
2732: if (!c)
2733: cp2 = 0;
2734:
2735: if ((tmp = inet_addr(cp)) != INADDR_NONE) {
2736: sin_addr.s_addr = tmp;
2737: } else if (host = gethostbyname(cp)) {
2738: #if defined(h_addr)
2739: memcpy((caddr_t)&sin_addr,
2740: host->h_addr_list[0], host->h_length);
2741: #else
2742: memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
2743: #endif
2744: } else {
2745: *cpp = cp;
2746: return(0);
2747: }
2748: memcpy(lsrp, (char *)&sin_addr, 4);
2749: lsrp += 4;
2750: if (cp2)
2751: cp = cp2;
2752: else
2753: break;
2754: /*
2755: * Check to make sure there is space for next address
2756: */
2757: if (lsrp + 4 > lsrep)
2758: return((unsigned long)-1);
2759: }
2760: #ifndef sysV88
2761: if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
2762: *cpp = 0;
2763: *lenp = 0;
2764: return((unsigned long)-1);
2765: }
2766: *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
2767: *lenp = lsrp - *cpp;
2768: #else
2769: ipopt.io_len = lsrp - *cpp;
2770: if (ipopt.io_len <= 5) { /* Is 3 better ? */
2771: *cpp = 0;
2772: *lenp = 0;
2773: return((unsigned long)-1);
2774: }
2775: *lenp = sizeof(ipopt);
2776: *cpp = (char *) &ipopt;
2777: #endif
2778: return(sin_addr.s_addr);
2779: }
2780: #endif