Several items:
[unix-history] / usr / src / usr.bin / telnet / commands.c
CommitLineData
897ce52e
KB
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
b36fc510
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
897ce52e
KB
16 */
17
18#ifndef lint
87b60187 19static char sccsid[] = "@(#)commands.c 1.24 (Berkeley) %G%";
897ce52e
KB
20#endif /* not lint */
21
59782978 22#include <sys/types.h>
344def17
GM
23#if defined(unix)
24#include <sys/file.h>
25#endif /* defined(unix) */
59782978
GM
26#include <sys/socket.h>
27#include <netinet/in.h>
6055a9f6
PB
28#ifdef CRAY
29#include <sys/fcntl.h>
3942e0c3 30#endif /* CRAY */
59782978
GM
31
32#include <signal.h>
33#include <netdb.h>
34#include <ctype.h>
f165dbec 35#include <varargs.h>
59782978
GM
36
37#include <arpa/telnet.h>
38
2dde2af0
GM
39#include "general.h"
40
115a5494
GM
41#include "ring.h"
42
59782978
GM
43#include "externs.h"
44#include "defines.h"
45#include "types.h"
46
6055a9f6 47#ifdef SRCRT
3942e0c3
PB
48# ifndef CRAY
49# include <netinet/in_systm.h>
7daa10bf 50# if defined(vax) || defined(tahoe)
3942e0c3 51# include <machine/endian.h>
7daa10bf 52# endif /* vax */
3942e0c3 53# endif /* CRAY */
6055a9f6 54#include <netinet/ip.h>
3942e0c3 55#endif /* SRCRT */
6055a9f6
PB
56
57
59782978 58char *hostname;
6055a9f6 59extern char *getenv();
59782978 60
83f50d4a 61#define Ambiguous(s) ((char **)s == &ambiguous)
59782978
GM
62static char *ambiguous; /* special return value for command routines */
63
64typedef struct {
65 char *name; /* command name */
6055a9f6 66 char *help; /* help string (NULL for no help) */
59782978 67 int (*handler)(); /* routine which executes command */
59782978
GM
68 int needconnect; /* Do we need to be connected to execute? */
69} Command;
70
6055a9f6
PB
71static char line[256];
72static char saveline[256];
59782978
GM
73static int margc;
74static char *margv[20];
75
76/*
77 * Various utility routines.
78 */
79
83f50d4a
GM
80#if !defined(BSD) || (BSD <= 43)
81
82char *h_errlist[] = {
83 "Error 0",
84 "Unknown host", /* 1 HOST_NOT_FOUND */
85 "Host name lookup failure", /* 2 TRY_AGAIN */
86 "Unknown server error", /* 3 NO_RECOVERY */
87 "No address associated with name", /* 4 NO_ADDRESS */
88};
89int h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) };
90
344def17 91int h_errno; /* In some version of SunOS this is necessary */
83f50d4a
GM
92
93/*
94 * herror --
95 * print the error indicated by the h_errno value.
96 */
97herror(s)
98 char *s;
99{
100 if (s && *s) {
101 fprintf(stderr, "%s: ", s);
102 }
103 if ((h_errno < 0) || (h_errno >= h_nerr)) {
104 fprintf(stderr, "Unknown error\n");
344def17
GM
105 } else if (h_errno == 0) {
106#if defined(sun)
107 fprintf(stderr, "Host unknown\n");
108#endif /* defined(sun) */
83f50d4a
GM
109 } else {
110 fprintf(stderr, "%s\n", h_errlist[h_errno]);
111 }
112}
113#endif /* !define(BSD) || (BSD <= 43) */
114
59782978
GM
115static void
116makeargv()
117{
118 register char *cp;
119 register char **argp = margv;
120
121 margc = 0;
122 cp = line;
123 if (*cp == '!') { /* Special case shell escape */
6055a9f6 124 strcpy(saveline, line); /* save for shell command */
59782978
GM
125 *argp++ = "!"; /* No room in string to get this */
126 margc++;
127 cp++;
128 }
129 while (*cp) {
130 while (isspace(*cp))
131 cp++;
132 if (*cp == '\0')
133 break;
134 *argp++ = cp;
135 margc += 1;
136 while (*cp != '\0' && !isspace(*cp))
137 cp++;
138 if (*cp == '\0')
139 break;
140 *cp++ = '\0';
141 }
142 *argp++ = 0;
143}
144
145
146static char **
147genget(name, table, next)
148char *name; /* name to match */
149char **table; /* name entry in table */
150char **(*next)(); /* routine to return next entry in table */
151{
152 register char *p, *q;
153 register char **c, **found;
154 register int nmatches, longest;
155
156 if (name == 0) {
157 return 0;
158 }
159 longest = 0;
160 nmatches = 0;
161 found = 0;
162 for (c = table; (p = *c) != 0; c = (*next)(c)) {
163 for (q = name;
164 (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
165 if (*q == 0) /* exact match? */
166 return (c);
167 if (!*q) { /* the name was a prefix */
168 if (q - name > longest) {
169 longest = q - name;
170 nmatches = 1;
171 found = c;
172 } else if (q - name == longest)
173 nmatches++;
174 }
175 }
176 if (nmatches > 1)
83f50d4a 177 return &ambiguous;
59782978
GM
178 return (found);
179}
180
181/*
182 * Make a character string into a number.
183 *
184 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
185 */
186
187static
188special(s)
189register char *s;
190{
191 register char c;
192 char b;
193
194 switch (*s) {
195 case '^':
196 b = *++s;
197 if (b == '?') {
198 c = b | 0x40; /* DEL */
199 } else {
200 c = b & 0x1f;
201 }
202 break;
203 default:
204 c = *s;
205 break;
206 }
207 return c;
208}
209
210/*
211 * Construct a control character sequence
212 * for a special character.
213 */
214static char *
215control(c)
87b60187 216 register cc_t c;
59782978
GM
217{
218 static char buf[3];
219
220 if (c == 0x7f)
221 return ("^?");
87b60187 222 if (c == (cc_t)-1) {
59782978
GM
223 return "off";
224 }
225 if (c >= 0x20) {
226 buf[0] = c;
227 buf[1] = 0;
228 } else {
229 buf[0] = '^';
230 buf[1] = '@'+c;
231 buf[2] = 0;
232 }
233 return (buf);
234}
235
236
237
238/*
239 * The following are data structures and routines for
240 * the "send" command.
241 *
242 */
243
244struct sendlist {
245 char *name; /* How user refers to it (case independent) */
59782978
GM
246 char *help; /* Help information (0 ==> no help) */
247#if defined(NOT43)
6055a9f6 248 int (*handler)(); /* Routine to perform (for special ops) */
59782978 249#else /* defined(NOT43) */
6055a9f6 250 void (*handler)(); /* Routine to perform (for special ops) */
59782978 251#endif /* defined(NOT43) */
6055a9f6 252 int what; /* Character to be sent (<0 ==> special) */
59782978
GM
253};
254\f
255#define SENDQUESTION -1
256#define SENDESCAPE -3
257
258static struct sendlist Sendlist[] = {
6055a9f6
PB
259 { "ao", "Send Telnet Abort output", 0, AO },
260 { "ayt", "Send Telnet 'Are You There'", 0, AYT },
261 { "brk", "Send Telnet Break", 0, BREAK },
262 { "ec", "Send Telnet Erase Character", 0, EC },
263 { "el", "Send Telnet Erase Line", 0, EL },
264 { "escape", "Send current escape character", 0, SENDESCAPE },
265 { "ga", "Send Telnet 'Go Ahead' sequence", 0, GA },
266 { "ip", "Send Telnet Interrupt Process", 0, IP },
267 { "nop", "Send Telnet 'No operation'", 0, NOP },
268 { "eor", "Send Telnet 'End of Record'", 0, EOR },
269 { "abort", "Send Telnet 'Abort Process'", 0, ABORT },
270 { "susp", "Send Telnet 'Suspend Process'", 0, SUSP },
271 { "eof", "Send Telnet End of File Character", 0, xEOF },
272 { "synch", "Perform Telnet 'Synch operation'", dosynch, SYNCH },
6570c863 273 { "getstatus", "Send request for STATUS", get_status, 0 },
6055a9f6 274 { "?", "Display send options", 0, SENDQUESTION },
59782978
GM
275 { 0 }
276};
277
278static struct sendlist Sendlist2[] = { /* some synonyms */
6055a9f6 279 { "break", 0, 0, BREAK },
59782978 280
6055a9f6
PB
281 { "intp", 0, 0, IP },
282 { "interrupt", 0, 0, IP },
283 { "intr", 0, 0, IP },
59782978 284
6055a9f6 285 { "help", 0, 0, SENDQUESTION },
59782978 286
6055a9f6 287 { 0 }
59782978
GM
288};
289
290static char **
291getnextsend(name)
292char *name;
293{
294 struct sendlist *c = (struct sendlist *) name;
295
296 return (char **) (c+1);
297}
298
299static struct sendlist *
300getsend(name)
301char *name;
302{
303 struct sendlist *sl;
304
305 if ((sl = (struct sendlist *)
306 genget(name, (char **) Sendlist, getnextsend)) != 0) {
307 return sl;
308 } else {
309 return (struct sendlist *)
310 genget(name, (char **) Sendlist2, getnextsend);
311 }
312}
313
314static
315sendcmd(argc, argv)
316int argc;
317char **argv;
318{
319 int what; /* what we are sending this time */
320 int count; /* how many bytes we are going to need to send */
321 int i;
322 int question = 0; /* was at least one argument a question */
323 struct sendlist *s; /* pointer to current command */
324
325 if (argc < 2) {
326 printf("need at least one argument for 'send' command\n");
327 printf("'send ?' for help\n");
328 return 0;
329 }
330 /*
331 * First, validate all the send arguments.
332 * In addition, we see how much space we are going to need, and
333 * whether or not we will be doing a "SYNCH" operation (which
334 * flushes the network queue).
335 */
336 count = 0;
337 for (i = 1; i < argc; i++) {
338 s = getsend(argv[i]);
339 if (s == 0) {
340 printf("Unknown send argument '%s'\n'send ?' for help.\n",
341 argv[i]);
342 return 0;
343 } else if (Ambiguous(s)) {
344 printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
345 argv[i]);
346 return 0;
347 }
348 switch (s->what) {
349 case SENDQUESTION:
6055a9f6 350 question = 1;
59782978
GM
351 break;
352 case SENDESCAPE:
353 count += 1;
354 break;
355 case SYNCH:
356 count += 2;
357 break;
358 default:
359 count += 2;
360 break;
361 }
362 }
6055a9f6
PB
363 if (!connected) {
364 if (count)
365 printf("?Need to be connected first.\n");
366 if (question) {
367 for (s = Sendlist; s->name; s++)
368 if (s->help)
369 printf("%-15s %s\n", s->name, s->help);
370 } else
371 printf("'send ?' for help\n");
372 return !question;
373 }
59782978
GM
374 /* Now, do we have enough room? */
375 if (NETROOM() < count) {
376 printf("There is not enough room in the buffer TO the network\n");
377 printf("to process your request. Nothing will be done.\n");
378 printf("('send synch' will throw away most data in the network\n");
379 printf("buffer, if this might help.)\n");
380 return 0;
381 }
382 /* OK, they are all OK, now go through again and actually send */
383 for (i = 1; i < argc; i++) {
384 if ((s = getsend(argv[i])) == 0) {
385 fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
386 quit();
387 /*NOTREACHED*/
388 }
6055a9f6
PB
389 if (s->handler) {
390 (*s->handler)(s);
59782978
GM
391 } else {
392 switch (what = s->what) {
393 case SYNCH:
394 dosynch();
395 break;
396 case SENDQUESTION:
397 for (s = Sendlist; s->name; s++) {
6055a9f6
PB
398 if (s->help)
399 printf("%-15s %s\n", s->name, s->help);
59782978
GM
400 }
401 question = 1;
402 break;
403 case SENDESCAPE:
404 NETADD(escape);
405 break;
406 default:
407 NET2ADD(IAC, what);
408 break;
409 }
410 }
411 }
412 return !question;
413}
414\f
415/*
416 * The following are the routines and data structures referred
417 * to by the arguments to the "toggle" command.
418 */
419
420static
421lclchars()
422{
423 donelclchars = 1;
424 return 1;
425}
426
427static
428togdebug()
429{
430#ifndef NOT43
431 if (net > 0 &&
432 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
433 perror("setsockopt (SO_DEBUG)");
434 }
435#else /* NOT43 */
436 if (debug) {
437 if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
438 perror("setsockopt (SO_DEBUG)");
439 } else
440 printf("Cannot turn off socket debugging\n");
441#endif /* NOT43 */
442 return 1;
443}
444
445
446static int
447togcrlf()
448{
449 if (crlf) {
450 printf("Will send carriage returns as telnet <CR><LF>.\n");
451 } else {
452 printf("Will send carriage returns as telnet <CR><NUL>.\n");
453 }
454 return 1;
455}
456
6570c863 457int binmode;
59782978
GM
458
459static int
6055a9f6
PB
460togbinary(val)
461int val;
59782978
GM
462{
463 donebinarytoggle = 1;
464
6570c863
PB
465 if (val >= 0) {
466 binmode = val;
467 } else {
468 if (my_want_state_is_will(TELOPT_BINARY) &&
469 my_want_state_is_do(TELOPT_BINARY)) {
470 binmode = 1;
471 } else if (my_want_state_is_wont(TELOPT_BINARY) &&
472 my_want_state_is_dont(TELOPT_BINARY)) {
473 binmode = 0;
474 }
475 val = binmode ? 0 : 1;
476 }
477
478 if (val == 1) {
479 if (my_want_state_is_will(TELOPT_BINARY) &&
480 my_want_state_is_do(TELOPT_BINARY)) {
6055a9f6 481 printf("Already operating in binary mode with remote host.\n");
6570c863
PB
482 } else {
483 printf("Negotiating binary mode with remote host.\n");
484 tel_enter_binary(3);
6055a9f6 485 }
6570c863
PB
486 } else {
487 if (my_want_state_is_wont(TELOPT_BINARY) &&
488 my_want_state_is_dont(TELOPT_BINARY)) {
6055a9f6 489 printf("Already in network ascii mode with remote host.\n");
6570c863
PB
490 } else {
491 printf("Negotiating network ascii mode with remote host.\n");
492 tel_leave_binary(3);
6055a9f6 493 }
59782978
GM
494 }
495 return 1;
496}
497
6570c863
PB
498static int
499togrbinary(val)
500int val;
501{
502 donebinarytoggle = 1;
503
504 if (val == -1)
505 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
506
507 if (val == 1) {
508 if (my_want_state_is_do(TELOPT_BINARY)) {
509 printf("Already receiving in binary mode.\n");
510 } else {
511 printf("Negotiating binary mode on input.\n");
512 tel_enter_binary(1);
513 }
514 } else {
515 if (my_want_state_is_dont(TELOPT_BINARY)) {
516 printf("Already receiving in network ascii mode.\n");
517 } else {
518 printf("Negotiating network ascii mode on input.\n");
519 tel_leave_binary(1);
520 }
521 }
522 return 1;
523}
524
525static int
526togxbinary(val)
527int val;
528{
529 donebinarytoggle = 1;
530
531 if (val == -1)
532 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
533
534 if (val == 1) {
535 if (my_want_state_is_will(TELOPT_BINARY)) {
536 printf("Already transmitting in binary mode.\n");
537 } else {
538 printf("Negotiating binary mode on output.\n");
539 tel_enter_binary(2);
540 }
541 } else {
542 if (my_want_state_is_wont(TELOPT_BINARY)) {
543 printf("Already transmitting in network ascii mode.\n");
544 } else {
545 printf("Negotiating network ascii mode on output.\n");
546 tel_leave_binary(2);
547 }
548 }
549 return 1;
550}
59782978
GM
551
552
553extern int togglehelp();
6055a9f6 554extern int slc_check();
59782978
GM
555
556struct togglelist {
557 char *name; /* name of toggle */
558 char *help; /* help message */
559 int (*handler)(); /* routine to do actual setting */
59782978
GM
560 int *variable;
561 char *actionexplanation;
562};
563
564static struct togglelist Togglelist[] = {
565 { "autoflush",
6055a9f6 566 "flushing of output when sending interrupt characters",
59782978 567 0,
6055a9f6
PB
568 &autoflush,
569 "flush output when sending interrupt characters" },
59782978 570 { "autosynch",
6055a9f6 571 "automatic sending of interrupt characters in urgent mode",
59782978 572 0,
6055a9f6
PB
573 &autosynch,
574 "send interrupt characters in urgent mode" },
59782978 575 { "binary",
6055a9f6 576 "sending and receiving of binary data",
59782978 577 togbinary,
6055a9f6
PB
578 0,
579 0 },
6570c863
PB
580 { "inbinary",
581 "receiving of binary data",
582 togrbinary,
583 0,
584 0 },
585 { "outbinary",
586 "sending of binary data",
587 togxbinary,
588 0,
589 0 },
59782978 590 { "crlf",
6055a9f6 591 "sending carriage returns as telnet <CR><LF>",
59782978 592 togcrlf,
6055a9f6
PB
593 &crlf,
594 0 },
59782978 595 { "crmod",
6055a9f6 596 "mapping of received carriage returns",
59782978 597 0,
6055a9f6
PB
598 &crmod,
599 "map carriage return on output" },
59782978 600 { "localchars",
6055a9f6 601 "local recognition of certain control characters",
59782978 602 lclchars,
6055a9f6
PB
603 &localchars,
604 "recognize certain control characters" },
605 { " ", "", 0 }, /* empty line */
40cc3fc2 606#if defined(unix) && defined(TN3270)
a0b02dfa
GM
607 { "apitrace",
608 "(debugging) toggle tracing of API transactions",
609 0,
610 &apitrace,
611 "trace API transactions" },
40cc3fc2
GM
612 { "cursesdata",
613 "(debugging) toggle printing of hexadecimal curses data",
614 0,
6055a9f6
PB
615 &cursesdata,
616 "print hexadecimal representation of curses data" },
40cc3fc2 617#endif /* defined(unix) && defined(TN3270) */
59782978 618 { "debug",
6055a9f6 619 "debugging",
59782978 620 togdebug,
6055a9f6
PB
621 &debug,
622 "turn on socket level debugging" },
59782978 623 { "netdata",
6055a9f6
PB
624 "printing of hexadecimal network data (debugging)",
625 0,
626 &netdata,
627 "print hexadecimal representation of network traffic" },
628 { "prettydump",
629 "output of \"netdata\" to user readable format (debugging)",
59782978 630 0,
6055a9f6
PB
631 &prettydump,
632 "print user readable output for \"netdata\"" },
59782978 633 { "options",
6055a9f6 634 "viewing of options processing (debugging)",
59782978 635 0,
6055a9f6
PB
636 &showoptions,
637 "show option processing" },
40cc3fc2
GM
638#if defined(unix)
639 { "termdata",
640 "(debugging) toggle printing of hexadecimal terminal data",
641 0,
6055a9f6
PB
642 &termdata,
643 "print hexadecimal representation of terminal traffic" },
40cc3fc2 644#endif /* defined(unix) */
59782978 645 { "?",
6055a9f6
PB
646 0,
647 togglehelp },
59782978 648 { "help",
6055a9f6
PB
649 0,
650 togglehelp },
59782978
GM
651 { 0 }
652};
653
654static
655togglehelp()
656{
657 struct togglelist *c;
658
659 for (c = Togglelist; c->name; c++) {
6055a9f6
PB
660 if (c->help) {
661 if (*c->help)
662 printf("%-15s toggle %s\n", c->name, c->help);
663 else
664 printf("\n");
59782978
GM
665 }
666 }
6055a9f6
PB
667 printf("\n");
668 printf("%-15s %s\n", "?", "display help information");
59782978
GM
669 return 0;
670}
671
6055a9f6
PB
672static
673settogglehelp(set)
674int set;
675{
676 struct togglelist *c;
677
678 for (c = Togglelist; c->name; c++) {
679 if (c->help) {
680 if (*c->help)
681 printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
682 c->help);
683 else
684 printf("\n");
685 }
686 }
687}
688
59782978
GM
689static char **
690getnexttoggle(name)
691char *name;
692{
693 struct togglelist *c = (struct togglelist *) name;
694
695 return (char **) (c+1);
696}
697
698static struct togglelist *
699gettoggle(name)
700char *name;
701{
702 return (struct togglelist *)
703 genget(name, (char **) Togglelist, getnexttoggle);
704}
705
706static
707toggle(argc, argv)
708int argc;
709char *argv[];
710{
711 int retval = 1;
712 char *name;
713 struct togglelist *c;
714
715 if (argc < 2) {
716 fprintf(stderr,
717 "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
718 return 0;
719 }
720 argc--;
721 argv++;
722 while (argc--) {
723 name = *argv++;
724 c = gettoggle(name);
725 if (Ambiguous(c)) {
726 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
727 name);
728 return 0;
729 } else if (c == 0) {
730 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
731 name);
732 return 0;
733 } else {
734 if (c->variable) {
735 *c->variable = !*c->variable; /* invert it */
736 if (c->actionexplanation) {
737 printf("%s %s.\n", *c->variable? "Will" : "Won't",
738 c->actionexplanation);
739 }
59782978
GM
740 }
741 if (c->handler) {
6055a9f6 742 retval &= (*c->handler)(-1);
59782978
GM
743 }
744 }
745 }
746 return retval;
747}
748\f
749/*
750 * The following perform the "set" command.
751 */
752
6055a9f6
PB
753#ifdef USE_TERMIO
754struct termio new_tc = { 0 };
755#endif
756
59782978
GM
757struct setlist {
758 char *name; /* name */
759 char *help; /* help information */
6055a9f6 760 void (*handler)();
87b60187 761 cc_t *charp; /* where it is located at */
59782978
GM
762};
763
764static struct setlist Setlist[] = {
6055a9f6
PB
765 { "echo", "character to toggle local echoing on/off", 0, &echoc },
766 { "escape", "character to escape back to telnet command mode", 0, &escape },
87b60187 767 { "tracefile", "file to write trace intormation to", SetNetTrace, (cc_t *)NetTraceFile},
59782978 768 { " ", "" },
6055a9f6 769 { " ", "The following need 'localchars' to be toggled true", 0, 0 },
6055a9f6 770 { "flushoutput", "character to cause an Abort Oubput", 0, termFlushCharp },
6055a9f6
PB
771 { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
772 { "quit", "character to cause an Abort process", 0, termQuitCharp },
773 { "eof", "character to cause an EOF ", 0, termEofCharp },
774 { " ", "" },
775 { " ", "The following are for local editing in linemode", 0, 0 },
776 { "erase", "character to use to erase a character", 0, termEraseCharp },
777 { "kill", "character to use to erase a line", 0, termKillCharp },
6055a9f6
PB
778 { "lnext", "character to use for literal next", 0, termLiteralNextCharp },
779 { "susp", "character to cuase a Suspend Process", 0, termSuspCharp },
780 { "reprint", "character to use for line reprint", 0, termRprntCharp },
781 { "worderase", "character to use to erase a word", 0, termWerasCharp },
782 { "start", "character to use for XON", 0, termStartCharp },
783 { "stop", "character to sue for XOFF", 0, termStopCharp },
59782978
GM
784 { 0 }
785};
786
6055a9f6
PB
787#ifdef CRAY
788/* Work around compiler bug */
789_setlist_init()
790{
7daa10bf 791 Setlist[5].charp = &termFlushChar;
6055a9f6
PB
792 Setlist[6].charp = &termIntChar;
793 Setlist[7].charp = &termQuitChar;
794 Setlist[8].charp = &termEofChar;
795 Setlist[11].charp = &termEraseChar;
796 Setlist[12].charp = &termKillChar;
7daa10bf
PB
797 Setlist[13].charp = &termLiteralNextChar;
798 Setlist[14].charp = &termSuspChar;
799 Setlist[15].charp = &termRprntChar;
800 Setlist[16].charp = &termWerasChar;
801 Setlist[17].charp = &termStartChar;
802 Setlist[18].charp = &termStopChar;
6055a9f6 803}
3942e0c3 804#endif /* CRAY */
6055a9f6 805
59782978
GM
806static char **
807getnextset(name)
808char *name;
809{
810 struct setlist *c = (struct setlist *)name;
811
812 return (char **) (c+1);
813}
814
815static struct setlist *
816getset(name)
817char *name;
818{
819 return (struct setlist *) genget(name, (char **) Setlist, getnextset);
820}
821
822static
823setcmd(argc, argv)
824int argc;
825char *argv[];
826{
827 int value;
828 struct setlist *ct;
6055a9f6 829 struct togglelist *c;
59782978 830
6055a9f6
PB
831 if (argc < 2 || argc > 3) {
832 printf("Format is 'set Name Value'\n'set ?' for help.\n");
833 return 0;
834 }
835 if ((argc == 2) &&
836 ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
837 for (ct = Setlist; ct->name; ct++)
838 printf("%-15s %s\n", ct->name, ct->help);
839 printf("\n");
840 settogglehelp(1);
841 printf("%-15s %s\n", "?", "display help information");
59782978
GM
842 return 0;
843 }
844
845 ct = getset(argv[1]);
846 if (ct == 0) {
6055a9f6
PB
847 c = gettoggle(argv[1]);
848 if (c == 0) {
849 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
850 argv[1]);
851 return 0;
852 } else if (Ambiguous(c)) {
853 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
59782978 854 argv[1]);
6055a9f6
PB
855 return 0;
856 }
857 if (c->variable) {
858 if ((argc == 2) || (strcmp("on", argv[2]) == 0))
859 *c->variable = 1;
860 else if (strcmp("off", argv[2]) == 0)
861 *c->variable = 0;
862 else {
863 printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
864 return 0;
865 }
866 if (c->actionexplanation) {
867 printf("%s %s.\n", *c->variable? "Will" : "Won't",
868 c->actionexplanation);
869 }
870 }
871 if (c->handler)
872 (*c->handler)(1);
873 } else if (argc != 3) {
874 printf("Format is 'set Name Value'\n'set ?' for help.\n");
59782978
GM
875 return 0;
876 } else if (Ambiguous(ct)) {
877 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
878 argv[1]);
879 return 0;
6055a9f6
PB
880 } else if (ct->handler) {
881 (*ct->handler)(argv[2]);
87b60187 882 printf("%s set to \"%s\".\n", ct->name, (unsigned char *)ct->charp);
59782978
GM
883 } else {
884 if (strcmp("off", argv[2])) {
885 value = special(argv[2]);
886 } else {
887 value = -1;
888 }
87b60187 889 *(ct->charp) = (cc_t)value;
59782978
GM
890 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
891 }
6055a9f6
PB
892 slc_check();
893 return 1;
894}
895
896static
897unsetcmd(argc, argv)
898int argc;
899char *argv[];
900{
901 int value;
902 struct setlist *ct;
903 struct togglelist *c;
904 register char *name;
905
906 if (argc < 2) {
907 fprintf(stderr,
908 "Need an argument to 'unset' command. 'unset ?' for help.\n");
909 return 0;
910 }
911 if ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help"))) {
912 for (ct = Setlist; ct->name; ct++)
913 printf("%-15s %s\n", ct->name, ct->help);
914 printf("\n");
915 settogglehelp(0);
916 printf("%-15s %s\n", "?", "display help information");
917 return 0;
918 }
919
920 argc--;
921 argv++;
922 while (argc--) {
923 name = *argv++;
924 ct = getset(name);
925 if (ct == 0) {
926 c = gettoggle(name);
927 if (c == 0) {
928 fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
929 name);
930 return 0;
931 } else if (Ambiguous(c)) {
932 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
933 name);
934 return 0;
935 }
936 if (c->variable) {
937 *c->variable = 0;
938 if (c->actionexplanation) {
939 printf("%s %s.\n", *c->variable? "Will" : "Won't",
940 c->actionexplanation);
941 }
942 }
943 if (c->handler)
944 (*c->handler)(0);
945 } else if (Ambiguous(ct)) {
946 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
947 name);
948 return 0;
949 } else if (ct->handler) {
950 (*ct->handler)(0);
951 printf("%s reset to \"%s\".\n", ct->name, ct->charp);
952 } else {
953 value = -1;
954 *(ct->charp) = -1;
955 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
956 }
957 }
59782978
GM
958 return 1;
959}
960\f
961/*
962 * The following are the data structures and routines for the
963 * 'mode' command.
964 */
6055a9f6
PB
965#ifdef KLUDGELINEMODE
966extern int kludgelinemode;
967#endif
59782978
GM
968
969static
970dolinemode()
971{
6055a9f6
PB
972#ifdef KLUDGELINEMODE
973 if (kludgelinemode)
974 send_dont(TELOPT_SGA, 1);
975#endif
976 send_will(TELOPT_LINEMODE, 1);
977 send_dont(TELOPT_ECHO, 1);
59782978
GM
978 return 1;
979}
980
981static
982docharmode()
983{
6055a9f6
PB
984#ifdef KLUDGELINEMODE
985 if (kludgelinemode)
986 send_do(TELOPT_SGA, 1);
987 else
988#endif
989 send_wont(TELOPT_LINEMODE, 1);
990 send_do(TELOPT_ECHO, 1);
991 return 1;
992}
993
994setmode(bit)
995{
996 return dolmmode(bit, 1);
997}
998
999clearmode(bit)
1000{
1001 return dolmmode(bit, 0);
1002}
1003
1004dolmmode(bit, on)
1005int bit, on;
1006{
1007 char c;
1008 extern int linemode;
1009
1010 if (my_want_state_is_wont(TELOPT_LINEMODE)) {
1011 printf("?Need to have LINEMODE option enabled first.\n");
1012 printf("'mode ?' for help.\n");
1013 return 0;
59782978 1014 }
6055a9f6
PB
1015
1016 if (on)
1017 c = (linemode | bit);
1018 else
1019 c = (linemode & ~bit);
1020 lm_mode(&c, 1, 1);
59782978
GM
1021 return 1;
1022}
1023
6055a9f6
PB
1024struct modelist {
1025 char *name; /* command name */
1026 char *help; /* help string */
1027 int (*handler)(); /* routine which executes command */
1028 int needconnect; /* Do we need to be connected to execute? */
1029 int arg1;
1030};
1031
1032extern int modehelp();
1033
1034static struct modelist ModeList[] = {
1035 { "character", "Disable LINEMODE option", docharmode, 1 },
7daa10bf
PB
1036#ifdef KLUDGELINEMODE
1037 { "", "(or disable obsolete line-by-line mode)", 0 },
6055a9f6
PB
1038#endif
1039 { "line", "Enable LINEMODE option", dolinemode, 1 },
7daa10bf
PB
1040#ifdef KLUDGELINEMODE
1041 { "", "(or enable obsolete line-by-line mode)", 0 },
6055a9f6
PB
1042#endif
1043 { "", "", 0 },
1044 { "", "These require the LINEMODE option to be enabled", 0 },
1045 { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG },
1046 { "+isig", 0, setmode, 1, MODE_TRAPSIG },
1047 { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG },
1048 { "edit", "Enable character editing", setmode, 1, MODE_EDIT },
1049 { "+edit", 0, setmode, 1, MODE_EDIT },
1050 { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT },
1051 { "help", 0, modehelp, 0 },
1052 { "?", "Print help information", modehelp, 0 },
59782978
GM
1053 { 0 },
1054};
1055
1056static char **
1057getnextmode(name)
1058char *name;
1059{
6055a9f6 1060 return (char **) (((struct modelist *)name)+1);
59782978
GM
1061}
1062
6055a9f6 1063static struct modelist *
59782978
GM
1064getmodecmd(name)
1065char *name;
1066{
6055a9f6
PB
1067 return (struct modelist *) genget(name, (char **) ModeList, getnextmode);
1068}
1069
1070modehelp()
1071{
1072 struct modelist *mt;
1073
1074 printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
1075 for (mt = ModeList; mt->name; mt++) {
1076 if (mt->help) {
1077 if (*mt->help)
1078 printf("%-15s %s\n", mt->name, mt->help);
1079 else
1080 printf("\n");
1081 }
1082 }
1083 return 0;
59782978
GM
1084}
1085
1086static
1087modecmd(argc, argv)
1088int argc;
1089char *argv[];
1090{
6055a9f6 1091 struct modelist *mt;
59782978 1092
6055a9f6
PB
1093 if (argc != 2) {
1094 printf("'mode' command requires an argument\n");
1095 printf("'mode ?' for help.\n");
1096 } else if ((mt = getmodecmd(argv[1])) == 0) {
59782978 1097 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
59782978
GM
1098 } else if (Ambiguous(mt)) {
1099 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
6055a9f6
PB
1100 } else if (mt->needconnect && !connected) {
1101 printf("?Need to be connected first.\n");
1102 printf("'mode ?' for help.\n");
1103 } else if (mt->handler) {
1104 return (*mt->handler)(mt->arg1);
59782978 1105 }
6055a9f6 1106 return 0;
59782978
GM
1107}
1108\f
1109/*
1110 * The following data structures and routines implement the
1111 * "display" command.
1112 */
1113
1114static
1115display(argc, argv)
1116int argc;
1117char *argv[];
1118{
1119#define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1120 if (*tl->variable) { \
1121 printf("will"); \
1122 } else { \
1123 printf("won't"); \
1124 } \
1125 printf(" %s.\n", tl->actionexplanation); \
1126 }
1127
1128#define doset(sl) if (sl->name && *sl->name != ' ') { \
6055a9f6
PB
1129 if (sl->handler == 0) \
1130 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
1131 else \
1132 printf("%-15s \"%s\"\n", sl->name, sl->charp); \
59782978
GM
1133 }
1134
1135 struct togglelist *tl;
1136 struct setlist *sl;
1137
1138 if (argc == 1) {
1139 for (tl = Togglelist; tl->name; tl++) {
1140 dotog(tl);
1141 }
1142 printf("\n");
1143 for (sl = Setlist; sl->name; sl++) {
1144 doset(sl);
1145 }
1146 } else {
1147 int i;
1148
1149 for (i = 1; i < argc; i++) {
1150 sl = getset(argv[i]);
1151 tl = gettoggle(argv[i]);
1152 if (Ambiguous(sl) || Ambiguous(tl)) {
1153 printf("?Ambiguous argument '%s'.\n", argv[i]);
1154 return 0;
1155 } else if (!sl && !tl) {
1156 printf("?Unknown argument '%s'.\n", argv[i]);
1157 return 0;
1158 } else {
1159 if (tl) {
1160 dotog(tl);
1161 }
1162 if (sl) {
1163 doset(sl);
1164 }
1165 }
1166 }
1167 }
6055a9f6 1168/*@*/optionstatus();
59782978
GM
1169 return 1;
1170#undef doset
1171#undef dotog
1172}
1173\f
1174/*
1175 * The following are the data structures, and many of the routines,
1176 * relating to command processing.
1177 */
1178
1179/*
1180 * Set the escape character.
1181 */
1182static
1183setescape(argc, argv)
1184 int argc;
1185 char *argv[];
1186{
1187 register char *arg;
1188 char buf[50];
1189
1190 printf(
1191 "Deprecated usage - please use 'set escape%s%s' in the future.\n",
1192 (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
1193 if (argc > 2)
1194 arg = argv[1];
1195 else {
1196 printf("new escape character: ");
80a47e22 1197 (void) gets(buf);
59782978
GM
1198 arg = buf;
1199 }
1200 if (arg[0] != '\0')
1201 escape = arg[0];
1202 if (!In3270) {
1203 printf("Escape character is '%s'.\n", control(escape));
1204 }
80a47e22 1205 (void) fflush(stdout);
59782978
GM
1206 return 1;
1207}
1208
1209/*VARARGS*/
1210static
1211togcrmod()
1212{
1213 crmod = !crmod;
1214 printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
1215 printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
80a47e22 1216 (void) fflush(stdout);
59782978
GM
1217 return 1;
1218}
1219
1220/*VARARGS*/
1221suspend()
1222{
6055a9f6 1223#ifdef SIGTSTP
445e62ba 1224 setcommandmode();
445e62ba
GM
1225 {
1226 long oldrows, oldcols, newrows, newcols;
1227
1228 TerminalWindowSize(&oldrows, &oldcols);
80a47e22 1229 (void) kill(0, SIGTSTP);
445e62ba
GM
1230 TerminalWindowSize(&newrows, &newcols);
1231 if ((oldrows != newrows) || (oldcols != newcols)) {
1232 if (connected) {
1233 sendnaws();
1234 }
1235 }
1236 }
445e62ba
GM
1237 /* reget parameters in case they were changed */
1238 TerminalSaveState();
6055a9f6
PB
1239 setconnmode(0);
1240#else
1241 printf("Suspend is not supported. Try the '!' command instead\n");
1242#endif
445e62ba 1243 return 1;
59782978
GM
1244}
1245
6055a9f6 1246#if !defined(TN3270)
6055a9f6
PB
1247shell(argc, argv)
1248int argc;
1249char *argv[];
1250{
1251 extern char *rindex();
1252 char cmdbuf[256];
1253
1254 setcommandmode();
1255 switch(vfork()) {
1256 case -1:
1257 perror("Fork failed\n");
1258 break;
1259
1260 case 0:
1261 {
1262 /*
1263 * Fire up the shell in the child.
1264 */
1265 register char *shell, *shellname;
1266
1267 shell = getenv("SHELL");
1268 if (shell == NULL)
1269 shell = "/bin/sh";
1270 if ((shellname = rindex(shell, '/')) == 0)
1271 shellname = shell;
1272 else
1273 shellname++;
1274 if (argc > 1)
1275 execl(shell, shellname, "-c", &saveline[1], 0);
1276 else
1277 execl(shell, shellname, 0);
1278 perror("Execl");
1279 _exit(1);
1280 }
1281 default:
1282 wait((int *)0); /* Wait for the shell to complete */
1283 }
1284}
1285#endif /* !defined(TN3270) */
1286
59782978
GM
1287/*VARARGS*/
1288static
1289bye(argc, argv)
1290int argc; /* Number of arguments */
1291char *argv[]; /* arguments */
1292{
1293 if (connected) {
80a47e22 1294 (void) shutdown(net, 2);
59782978 1295 printf("Connection closed.\n");
80a47e22 1296 (void) NetClose(net);
59782978
GM
1297 connected = 0;
1298 /* reset options */
1299 tninit();
1300#if defined(TN3270)
1301 SetIn3270(); /* Get out of 3270 mode */
1302#endif /* defined(TN3270) */
1303 }
1304 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
1305 longjmp(toplevel, 1);
1306 /* NOTREACHED */
1307 }
1308 return 1; /* Keep lint, etc., happy */
1309}
1310
1311/*VARARGS*/
1312quit()
1313{
1314 (void) call(bye, "bye", "fromquit", 0);
1315 Exit(0);
59782978
GM
1316 return 1; /* just to keep lint happy */
1317}
6055a9f6
PB
1318\f
1319/*
1320 * The SLC command.
1321 */
1322
1323struct slclist {
1324 char *name;
1325 char *help;
1326 int (*handler)();
1327 int arg;
1328};
1329
1330extern int slc_help();
1331extern int slc_mode_export(), slc_mode_import(), slcstate();
1332
1333struct slclist SlcList[] = {
1334 { "export", "Use local special character definitions",
1335 slc_mode_export, 0 },
1336 { "import", "Use remote special character definitions",
1337 slc_mode_import, 1 },
1338 { "check", "Verify remote special character definitions",
1339 slc_mode_import, 0 },
1340 { "help", 0, slc_help, 0 },
1341 { "?", "Print help information", slc_help, 0 },
1342 { 0 },
1343};
1344
1345static
1346slc_help()
1347{
1348 struct slclist *c;
1349
1350 for (c = SlcList; c->name; c++) {
1351 if (c->help) {
1352 if (*c->help)
1353 printf("%-15s %s\n", c->name, c->help);
1354 else
1355 printf("\n");
1356 }
1357 }
1358}
1359
1360static char **
1361getnextslc(name)
1362char *name;
1363{
1364 return (char **)(((struct slclist *)name)+1);
1365}
1366
1367static struct slclist *
1368getslc(name)
1369char *name;
1370{
1371 return (struct slclist *)genget(name, (char **) SlcList, getnextslc);
1372}
1373
1374static
1375slccmd(argc, argv)
1376int argc;
1377char *argv[];
1378{
1379 struct slclist *c;
1380
1381 if (argc != 2) {
1382 fprintf(stderr,
1383 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1384 return 0;
1385 }
1386 c = getslc(argv[1]);
1387 if (c == 0) {
1388 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
1389 argv[1]);
1390 return 0;
1391 }
1392 if (Ambiguous(c)) {
1393 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
1394 argv[1]);
1395 return 0;
1396 }
1397 (*c->handler)(c->arg);
1398 slcstate();
1399 return 1;
1400}
59782978 1401
344def17
GM
1402#if defined(unix)
1403/*
1404 * Some information about our file descriptors.
1405 */
1406
1407char *
1408decodeflags(mask)
1409int mask;
1410{
1411 static char buffer[100];
1412#define do(m,s) \
1413 if (mask&(m)) { \
1414 strcat(buffer, (s)); \
1415 }
1416
1417 buffer[0] = 0; /* Terminate it */
1418
1419#ifdef FREAD
1420 do(FREAD, " FREAD");
1421#endif
1422#ifdef FWRITE
1423 do(FWRITE, " FWRITE");
1424#endif
1425#ifdef F_DUPFP
1426 do(F_DUPFD, " F_DUPFD");
1427#endif
1428#ifdef FNDELAY
1429 do(FNDELAY, " FNDELAY");
1430#endif
1431#ifdef FAPPEND
1432 do(FAPPEND, " FAPPEND");
1433#endif
1434#ifdef FMARK
1435 do(FMARK, " FMARK");
1436#endif
1437#ifdef FDEFER
1438 do(FDEFER, " FDEFER");
1439#endif
1440#ifdef FASYNC
1441 do(FASYNC, " FASYNC");
1442#endif
1443#ifdef FSHLOCK
1444 do(FSHLOCK, " FSHLOCK");
1445#endif
1446#ifdef FEXLOCK
1447 do(FEXLOCK, " FEXLOCK");
1448#endif
1449#ifdef FCREAT
1450 do(FCREAT, " FCREAT");
1451#endif
1452#ifdef FTRUNC
1453 do(FTRUNC, " FTRUNC");
1454#endif
1455#ifdef FEXCL
1456 do(FEXCL, " FEXCL");
1457#endif
1458
1459 return buffer;
1460}
1461#undef do
1462
1463static void
1464filestuff(fd)
1465int fd;
1466{
1467 int res;
1468
6055a9f6
PB
1469#ifdef F_GETOWN
1470 setconnmode(0);
344def17
GM
1471 res = fcntl(fd, F_GETOWN, 0);
1472 setcommandmode();
1473
1474 if (res == -1) {
1475 perror("fcntl");
1476 return;
1477 }
1478 printf("\tOwner is %d.\n", res);
6055a9f6 1479#endif
344def17 1480
6055a9f6 1481 setconnmode(0);
344def17
GM
1482 res = fcntl(fd, F_GETFL, 0);
1483 setcommandmode();
1484
1485 if (res == -1) {
1486 perror("fcntl");
1487 return;
1488 }
1489 printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
1490}
1491
1492
1493#endif /* defined(unix) */
1494
59782978
GM
1495/*
1496 * Print status about the connection.
1497 */
80a47e22 1498/*ARGSUSED*/
59782978
GM
1499static
1500status(argc, argv)
1501int argc;
1502char *argv[];
1503{
1504 if (connected) {
1505 printf("Connected to %s.\n", hostname);
4ad36dea 1506 if ((argc < 2) || strcmp(argv[1], "notmuch")) {
6055a9f6
PB
1507 int mode = getconnmode();
1508
1509 if (my_want_state_is_will(TELOPT_LINEMODE)) {
1510 printf("Operating with LINEMODE option\n");
1511 printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
1512 printf("%s catching of signals\n",
1513 (mode&MODE_TRAPSIG) ? "Local" : "No");
1514 slcstate();
1515#ifdef KLUDGELINEMODE
7daa10bf 1516 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
6055a9f6
PB
1517 printf("Operating in obsolete linemode\n");
1518#endif
1519 } else {
1520 printf("Operating in single character mode\n");
1521 if (localchars)
1522 printf("Catching signals locally\n");
59782978 1523 }
6055a9f6
PB
1524 printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
1525 if (my_want_state_is_will(TELOPT_LFLOW))
1526 printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
59782978
GM
1527 }
1528 } else {
1529 printf("No connection.\n");
1530 }
1531# if !defined(TN3270)
1532 printf("Escape character is '%s'.\n", control(escape));
80a47e22 1533 (void) fflush(stdout);
59782978
GM
1534# else /* !defined(TN3270) */
1535 if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
1536 printf("Escape character is '%s'.\n", control(escape));
1537 }
1538# if defined(unix)
4ad36dea
GM
1539 if ((argc >= 2) && !strcmp(argv[1], "everything")) {
1540 printf("SIGIO received %d time%s.\n",
1541 sigiocount, (sigiocount == 1)? "":"s");
344def17
GM
1542 if (In3270) {
1543 printf("Process ID %d, process group %d.\n",
1544 getpid(), getpgrp(getpid()));
1545 printf("Terminal input:\n");
1546 filestuff(tin);
1547 printf("Terminal output:\n");
1548 filestuff(tout);
1549 printf("Network socket:\n");
1550 filestuff(net);
1551 }
4ad36dea 1552 }
59782978
GM
1553 if (In3270 && transcom) {
1554 printf("Transparent mode command is '%s'.\n", transcom);
1555 }
1556# endif /* defined(unix) */
80a47e22 1557 (void) fflush(stdout);
59782978
GM
1558 if (In3270) {
1559 return 0;
1560 }
1561# endif /* defined(TN3270) */
1562 return 1;
1563}
1564
59782978 1565
87b60187
PB
1566#if defined(IP_TOS) && defined(NEED_GETTOS)
1567struct tosent {
1568 char *t_name; /* name */
1569 char **t_aliases; /* alias list */
1570 char *t_proto; /* protocol */
1571 int t_tos; /* Type Of Service bits */
1572};
1573
1574struct tosent *
1575gettosbyname(name, proto)
1576char *name, *proto;
1577{
1578 static struct tosent te;
1579 static char *aliasp = 0;
1580
1581 te.t_name = name;
1582 te.t_aliases = &aliasp;
1583 te.t_proto = proto;
1584 te.t_tos = 020; /* Low Delay bit */
1585 return(&te);
1586}
1587#endif
59782978
GM
1588
1589int
1590tn(argc, argv)
1591 int argc;
1592 char *argv[];
1593{
1594 register struct hostent *host = 0;
1595 struct sockaddr_in sin;
1596 struct servent *sp = 0;
1597 static char hnamebuf[32];
6055a9f6 1598 unsigned long temp, inet_addr();
445e62ba 1599 extern char *inet_ntoa();
6055a9f6
PB
1600#if defined(SRCRT) && defined(IPPROTO_IP)
1601 char *srp = 0, *strrchr();
1602 unsigned long sourceroute(), srlen;
1603#endif
87b60187
PB
1604#ifdef IP_TOS
1605 struct tosent *tp;
1606#endif /* IP_TOS */
59782978
GM
1607
1608
59782978
GM
1609 if (connected) {
1610 printf("?Already connected to %s\n", hostname);
1611 return 0;
1612 }
1613 if (argc < 2) {
1614 (void) strcpy(line, "Connect ");
1615 printf("(to) ");
80a47e22 1616 (void) gets(&line[strlen(line)]);
59782978
GM
1617 makeargv();
1618 argc = margc;
1619 argv = margv;
1620 }
1621 if ((argc < 2) || (argc > 3)) {
1622 printf("usage: %s host-name [port]\n", argv[0]);
1623 return 0;
1624 }
6055a9f6
PB
1625#if defined(SRCRT) && defined(IPPROTO_IP)
1626 if (argv[1][0] == '@' || argv[1][0] == '!') {
1627 if ((hostname = strrchr(argv[1], ':')) == NULL)
1628 hostname = strrchr(argv[1], '@');
1629 hostname++;
1630 srp = 0;
1631 temp = sourceroute(argv[1], &srp, &srlen);
1632 if (temp == 0) {
1633 herror(srp);
1634 return 0;
1635 } else if (temp == -1) {
1636 printf("Bad source route option: %s\n", argv[1]);
1637 return 0;
1638 } else {
1639 sin.sin_addr.s_addr = temp;
1640 sin.sin_family = AF_INET;
1641 }
59782978 1642 } else {
6055a9f6
PB
1643#endif
1644 temp = inet_addr(argv[1]);
1645 if (temp != (unsigned long) -1) {
1646 sin.sin_addr.s_addr = temp;
1647 sin.sin_family = AF_INET;
1648 (void) strcpy(hnamebuf, argv[1]);
1649 hostname = hnamebuf;
1650 } else {
1651 host = gethostbyname(argv[1]);
1652 if (host) {
1653 sin.sin_family = host->h_addrtype;
59782978 1654#if defined(h_addr) /* In 4.3, this is a #define */
6055a9f6 1655 memcpy((caddr_t)&sin.sin_addr,
59782978
GM
1656 host->h_addr_list[0], host->h_length);
1657#else /* defined(h_addr) */
6055a9f6 1658 memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
59782978 1659#endif /* defined(h_addr) */
6055a9f6
PB
1660 hostname = host->h_name;
1661 } else {
1662 herror(argv[1]);
1663 return 0;
1664 }
59782978 1665 }
6055a9f6 1666#if defined(SRCRT) && defined(IPPROTO_IP)
59782978 1667 }
6055a9f6 1668#endif
59782978 1669 if (argc == 3) {
6055a9f6
PB
1670 int tmp;
1671
1672 if (*argv[2] == '-') {
1673 argv[2]++;
1674 telnetport = 1;
1675 } else
1676 telnetport = 0;
59782978
GM
1677 sin.sin_port = atoi(argv[2]);
1678 if (sin.sin_port == 0) {
1679 sp = getservbyname(argv[2], "tcp");
1680 if (sp)
1681 sin.sin_port = sp->s_port;
1682 else {
1683 printf("%s: bad port number\n", argv[2]);
1684 return 0;
1685 }
1686 } else {
80a47e22
GM
1687#if !defined(htons)
1688 u_short htons();
1689#endif /* !defined(htons) */
59782978
GM
1690 sin.sin_port = htons(sin.sin_port);
1691 }
59782978
GM
1692 } else {
1693 if (sp == 0) {
1694 sp = getservbyname("telnet", "tcp");
1695 if (sp == 0) {
80a47e22 1696 fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
59782978
GM
1697 return 0;
1698 }
1699 sin.sin_port = sp->s_port;
1700 }
1701 telnetport = 1;
1702 }
445e62ba 1703 printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
59782978
GM
1704 do {
1705 net = socket(AF_INET, SOCK_STREAM, 0);
1706 if (net < 0) {
1707 perror("telnet: socket");
1708 return 0;
1709 }
6055a9f6
PB
1710#if defined(SRCRT) && defined(IPPROTO_IP)
1711 if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
1712 perror("setsockopt (IP_OPTIONS)");
1713#endif
87b60187
PB
1714#ifdef IP_TOS
1715 if ((tp = gettosbyname("telnet", "tcp")) &&
1716 (setsockopt(net, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
1717 perror("telnet: setsockopt TOS (ignored)");
1718
1719#endif /* IP_TOS */
59782978
GM
1720 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
1721 perror("setsockopt (SO_DEBUG)");
1722 }
1723
1724 if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
1725#if defined(h_addr) /* In 4.3, this is a #define */
1726 if (host && host->h_addr_list[1]) {
1727 int oerrno = errno;
1728
1729 fprintf(stderr, "telnet: connect to address %s: ",
1730 inet_ntoa(sin.sin_addr));
1731 errno = oerrno;
1732 perror((char *)0);
1733 host->h_addr_list++;
1734 memcpy((caddr_t)&sin.sin_addr,
1735 host->h_addr_list[0], host->h_length);
59782978
GM
1736 (void) NetClose(net);
1737 continue;
1738 }
1739#endif /* defined(h_addr) */
1740 perror("telnet: Unable to connect to remote host");
59782978 1741 return 0;
445e62ba 1742 }
59782978
GM
1743 connected++;
1744 } while (connected == 0);
6055a9f6 1745 cmdrc(argv[1], hostname);
80a47e22 1746 (void) call(status, "status", "notmuch", 0);
59782978
GM
1747 if (setjmp(peerdied) == 0)
1748 telnet();
80a47e22 1749 (void) NetClose(net);
115a5494 1750 ExitString("Connection closed by foreign host.\n",1);
59782978
GM
1751 /*NOTREACHED*/
1752}
1753
1754
1755#define HELPINDENT (sizeof ("connect"))
1756
1757static char
1758 openhelp[] = "connect to a site",
1759 closehelp[] = "close current connection",
1760 quithelp[] = "exit telnet",
1761 statushelp[] = "print status information",
1762 helphelp[] = "print help information",
1763 sendhelp[] = "transmit special characters ('send ?' for more)",
1764 sethelp[] = "set operating parameters ('set ?' for more)",
6055a9f6 1765 unsethelp[] = "unset operating parameters ('unset ?' for more)",
59782978 1766 togglestring[] ="toggle operating parameters ('toggle ?' for more)",
6055a9f6 1767 slchelp[] = "change state of special charaters ('slc ?' for more)",
59782978
GM
1768 displayhelp[] = "display operating parameters",
1769#if defined(TN3270) && defined(unix)
1770 transcomhelp[] = "specify Unix command for transparent mode pipe",
1771#endif /* defined(TN3270) && defined(unix) */
1772#if defined(unix)
1773 zhelp[] = "suspend telnet",
1774#endif /* defined(unix */
59782978 1775 shellhelp[] = "invoke a subshell",
6055a9f6 1776 modestring[] = "try to enter line-by-line or character-at-a-time mode";
59782978
GM
1777
1778extern int help(), shell();
1779
1780static Command cmdtab[] = {
6055a9f6
PB
1781 { "close", closehelp, bye, 1 },
1782 { "display", displayhelp, display, 0 },
1783 { "mode", modestring, modecmd, 0 },
1784 { "open", openhelp, tn, 0 },
1785 { "quit", quithelp, quit, 0 },
1786 { "send", sendhelp, sendcmd, 0 },
1787 { "set", sethelp, setcmd, 0 },
1788 { "unset", unsethelp, unsetcmd, 0 },
1789 { "status", statushelp, status, 0 },
1790 { "toggle", togglestring, toggle, 0 },
1791 { "slc", slchelp, slccmd, 0 },
59782978 1792#if defined(TN3270) && defined(unix)
6055a9f6 1793 { "transcom", transcomhelp, settranscom, 0 },
59782978
GM
1794#endif /* defined(TN3270) && defined(unix) */
1795#if defined(unix)
6055a9f6 1796 { "z", zhelp, suspend, 0 },
59782978
GM
1797#endif /* defined(unix) */
1798#if defined(TN3270)
6055a9f6
PB
1799 { "!", shellhelp, shell, 1 },
1800#else
1801 { "!", shellhelp, shell, 0 },
1802#endif
1803 { "?", helphelp, help, 0 },
59782978
GM
1804 0
1805};
1806
1807static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
1808static char escapehelp[] = "deprecated command -- use 'set escape' instead";
1809
1810static Command cmdtab2[] = {
6055a9f6
PB
1811 { "help", 0, help, 0 },
1812 { "escape", escapehelp, setescape, 0 },
1813 { "crmod", crmodhelp, togcrmod, 0 },
59782978
GM
1814 0
1815};
1816
f165dbec 1817
59782978
GM
1818/*
1819 * Call routine with argc, argv set from args (terminated by 0).
59782978 1820 */
f165dbec 1821
0ea35455 1822/*VARARGS1*/
59782978 1823static
f165dbec
GM
1824call(va_alist)
1825va_dcl
59782978 1826{
f165dbec
GM
1827 va_list ap;
1828 typedef int (*intrtn_t)();
1829 intrtn_t routine;
1830 char *args[100];
f165dbec
GM
1831 int argno = 0;
1832
1833 va_start(ap);
1834 routine = (va_arg(ap, intrtn_t));
260ef0a4 1835 while ((args[argno++] = va_arg(ap, char *)) != 0) {
f165dbec 1836 ;
260ef0a4 1837 }
f165dbec 1838 va_end(ap);
260ef0a4 1839 return (*routine)(argno-1, args);
59782978
GM
1840}
1841
f165dbec 1842
59782978
GM
1843static char **
1844getnextcmd(name)
1845char *name;
1846{
1847 Command *c = (Command *) name;
1848
1849 return (char **) (c+1);
1850}
1851
1852static Command *
1853getcmd(name)
1854char *name;
1855{
1856 Command *cm;
1857
1858 if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
1859 return cm;
1860 } else {
1861 return (Command *) genget(name, (char **) cmdtab2, getnextcmd);
1862 }
1863}
1864
1865void
6055a9f6 1866command(top, tbuf, cnt)
59782978 1867 int top;
6055a9f6
PB
1868 char *tbuf;
1869 int cnt;
59782978
GM
1870{
1871 register Command *c;
1872
1873 setcommandmode();
1874 if (!top) {
1875 putchar('\n');
59782978 1876#if defined(unix)
445e62ba 1877 } else {
59782978
GM
1878 signal(SIGINT, SIG_DFL);
1879 signal(SIGQUIT, SIG_DFL);
1880#endif /* defined(unix) */
1881 }
1882 for (;;) {
1883 printf("%s> ", prompt);
6055a9f6
PB
1884 if (tbuf) {
1885 register char *cp;
1886 cp = line;
1887 while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
1888 cnt--;
1889 tbuf = 0;
1890 if (cp == line || *--cp != '\n' || cp == line)
1891 goto getline;
1892 *cp = '\0';
1893 printf("%s\n", line);
1894 } else {
1895 getline:
1896 if (gets(line) == NULL) {
1897 if (feof(stdin) || ferror(stdin))
1898 quit();
1899 break;
1900 }
59782978
GM
1901 }
1902 if (line[0] == 0)
1903 break;
1904 makeargv();
445e62ba
GM
1905 if (margv[0] == 0) {
1906 break;
1907 }
59782978
GM
1908 c = getcmd(margv[0]);
1909 if (Ambiguous(c)) {
1910 printf("?Ambiguous command\n");
1911 continue;
1912 }
1913 if (c == 0) {
1914 printf("?Invalid command\n");
1915 continue;
1916 }
1917 if (c->needconnect && !connected) {
1918 printf("?Need to be connected first.\n");
1919 continue;
1920 }
1921 if ((*c->handler)(margc, margv)) {
1922 break;
1923 }
1924 }
1925 if (!top) {
1926 if (!connected) {
1927 longjmp(toplevel, 1);
1928 /*NOTREACHED*/
1929 }
1930#if defined(TN3270)
1931 if (shell_active == 0) {
6055a9f6 1932 setconnmode(0);
59782978
GM
1933 }
1934#else /* defined(TN3270) */
6055a9f6 1935 setconnmode(0);
59782978
GM
1936#endif /* defined(TN3270) */
1937 }
1938}
1939\f
1940/*
1941 * Help command.
1942 */
1943static
1944help(argc, argv)
1945 int argc;
1946 char *argv[];
1947{
1948 register Command *c;
1949
1950 if (argc == 1) {
1951 printf("Commands may be abbreviated. Commands are:\n\n");
1952 for (c = cmdtab; c->name; c++)
6055a9f6 1953 if (c->help) {
59782978
GM
1954 printf("%-*s\t%s\n", HELPINDENT, c->name,
1955 c->help);
1956 }
1957 return 0;
1958 }
1959 while (--argc > 0) {
1960 register char *arg;
1961 arg = *++argv;
1962 c = getcmd(arg);
1963 if (Ambiguous(c))
1964 printf("?Ambiguous help command %s\n", arg);
1965 else if (c == (Command *)0)
1966 printf("?Invalid help command %s\n", arg);
1967 else
1968 printf("%s\n", c->help);
1969 }
1970 return 0;
1971}
6055a9f6
PB
1972
1973static char *rcname = 0;
1974static char rcbuf[128];
1975
1976cmdrc(m1, m2)
1977 char *m1, *m2;
1978{
1979 register Command *c;
1980 FILE *rcfile;
1981 int gotmachine = 0;
1982 int l1 = strlen(m1);
1983 int l2 = strlen(m2);
1984 char m1save[64];
1985
1986 strcpy(m1save, m1);
1987 m1 = m1save;
1988
1989 if (rcname == 0) {
1990 rcname = getenv("HOME");
1991 if (rcname)
1992 strcpy(rcbuf, rcname);
1993 else
1994 rcbuf[0] = '\0';
1995 strcat(rcbuf, "/.telnetrc");
1996 rcname = rcbuf;
1997 }
1998
1999 if ((rcfile = fopen(rcname, "r")) == 0) {
2000 return;
2001 }
2002
2003 for (;;) {
2004 if (fgets(line, sizeof(line), rcfile) == NULL)
2005 break;
2006 if (line[0] == 0)
2007 break;
2008 if (line[0] == '#')
2009 continue;
2010 if (gotmachine == 0) {
2011 if (isspace(line[0]))
2012 continue;
2013 if (strncasecmp(line, m1, l1) == 0)
2014 strncpy(line, &line[l1], sizeof(line) - l1);
2015 else if (strncasecmp(line, m2, l2) == 0)
2016 strncpy(line, &line[l2], sizeof(line) - l2);
2017 else
2018 continue;
2019 gotmachine = 1;
2020 } else {
2021 if (!isspace(line[0])) {
2022 gotmachine = 0;
2023 continue;
2024 }
2025 }
2026 makeargv();
2027 if (margv[0] == 0)
2028 continue;
2029 c = getcmd(margv[0]);
2030 if (Ambiguous(c)) {
2031 printf("?Ambiguous command: %s\n", margv[0]);
2032 continue;
2033 }
2034 if (c == 0) {
2035 printf("?Invalid command: %s\n", margv[0]);
2036 continue;
2037 }
2038 /*
2039 * This should never happen...
2040 */
2041 if (c->needconnect && !connected) {
2042 printf("?Need to be connected first for %s.\n", margv[0]);
2043 continue;
2044 }
2045 (*c->handler)(margc, margv);
2046 }
2047 fclose(rcfile);
2048}
2049
2050#if defined(SRCRT) && defined(IPPROTO_IP)
2051
2052/*
2053 * Source route is handed in as
2054 * [!]@hop1@hop2...[@|:]dst
2055 * If the leading ! is present, it is a
2056 * strict source route, otherwise it is
2057 * assmed to be a loose source route.
2058 *
2059 * We fill in the source route option as
2060 * hop1,hop2,hop3...dest
2061 * and return a pointer to hop1, which will
2062 * be the address to connect() to.
2063 *
2064 * Arguments:
2065 * arg: pointer to route list to decipher
2066 *
2067 * cpp: If *cpp is not equal to NULL, this is a
2068 * pointer to a pointer to a character array
2069 * that should be filled in with the option.
2070 *
2071 * lenp: pointer to an integer that contains the
2072 * length of *cpp if *cpp != NULL.
2073 *
2074 * Return values:
2075 *
2076 * Returns the address of the host to connect to. If the
2077 * return value is -1, there was a syntax error in the
2078 * option, either unknown characters, or too many hosts.
2079 * If the return value is 0, one of the hostnames in the
2080 * path is unknown, and *cpp is set to point to the bad
2081 * hostname.
2082 *
2083 * *cpp: If *cpp was equal to NULL, it will be filled
2084 * in with a pointer to our static area that has
2085 * the option filled in. This will be 32bit aligned.
2086 *
2087 * *lenp: This will be filled in with how long the option
2088 * pointed to by *cpp is.
2089 *
2090 */
2091unsigned long
2092sourceroute(arg, cpp, lenp)
2093char *arg;
2094char **cpp;
2095int *lenp;
2096{
2097 static char lsr[44];
2098 char *cp, *cp2, *lsrp, *lsrep, *index();
2099 register int tmp;
2100 struct in_addr sin_addr;
2101 register struct hostent *host = 0;
2102 register char c;
2103
2104 /*
2105 * Verify the arguments, and make sure we have
2106 * at least 7 bytes for the option.
2107 */
2108 if (cpp == NULL || lenp == NULL)
2109 return((unsigned long)-1);
2110 if (*cpp != NULL && *lenp < 7)
2111 return((unsigned long)-1);
2112 /*
2113 * Decide whether we have a buffer passed to us,
2114 * or if we need to use our own static buffer.
2115 */
2116 if (*cpp) {
2117 lsrp = *cpp;
2118 lsrep = lsrp + *lenp;
2119 } else {
2120 *cpp = lsrp = lsr;
2121 lsrep = lsrp + 44;
2122 }
2123
2124 cp = arg;
2125
2126 /*
2127 * Next, decide whether we have a loose source
2128 * route or a strict source route, and fill in
2129 * the begining of the option.
2130 */
2131 if (*cp == '!') {
2132 cp++;
2133 *lsrp++ = IPOPT_SSRR;
2134 } else
2135 *lsrp++ = IPOPT_LSRR;
2136
2137 if (*cp != '@')
2138 return((unsigned long)-1);
2139
2140 lsrp++; /* skip over length, we'll fill it in later */
2141 *lsrp++ = 4;
2142
2143 cp++;
2144
2145 sin_addr.s_addr = 0;
2146
2147 for (c = 0;;) {
2148 if (c == ':')
2149 cp2 = 0;
2150 else for (cp2 = cp; c = *cp2; cp2++) {
2151 if (c == ',') {
2152 *cp2++ = '\0';
2153 if (*cp2 == '@')
2154 cp2++;
2155 } else if (c == '@') {
2156 *cp2++ = '\0';
2157 } else if (c == ':') {
2158 *cp2++ = '\0';
2159 } else
2160 continue;
2161 break;
2162 }
2163 if (!c)
2164 cp2 = 0;
2165
2166 if ((tmp = inet_addr(cp)) != -1) {
2167 sin_addr.s_addr = tmp;
2168 } else if (host = gethostbyname(cp)) {
2169#if defined(h_addr)
2170 memcpy((caddr_t)&sin_addr,
2171 host->h_addr_list[0], host->h_length);
2172#else
2173 memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
2174#endif
2175 } else {
2176 *cpp = cp;
2177 return(0);
2178 }
2179 memcpy(lsrp, (char *)&sin_addr, 4);
2180 lsrp += 4;
2181 if (cp2)
2182 cp = cp2;
2183 else
2184 break;
2185 /*
2186 * Check to make sure there is space for next address
2187 */
2188 if (lsrp + 4 > lsrep)
2189 return((unsigned long)-1);
2190 }
2191 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
2192 *cpp = 0;
2193 *lenp = 0;
2194 return((unsigned long)-1);
2195 }
2196 *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
2197 *lenp = lsrp - *cpp;
2198 return(sin_addr.s_addr);
2199}
2200#endif
2201
6570c863 2202#if defined(NOSTRNCASECMP)
6055a9f6
PB
2203strncasecmp(p1, p2, len)
2204register char *p1, *p2;
2205int len;
2206{
2207 while (len--) {
2208 if (tolower(*p1) != tolower(*p2))
2209 return(tolower(*p1) - tolower(*p2));
2210 if (*p1 == '\0')
2211 return(0);
2212 p1++, p2++;
2213 }
2214 return(0);
2215}
2216#endif