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