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