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