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