botched copyright
[unix-history] / usr / src / usr.bin / telnet / telnet.c
CommitLineData
22e155fc
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
f18adf63 13#ifndef lint
22e155fc
DF
14static char sccsid[] = "@(#)telnet.c 5.1 (Berkeley) %G%";
15#endif not lint
f18adf63 16
a19db822
BJ
17/*
18 * User telnet program.
19 */
de3b21e8
SL
20#include <sys/types.h>
21#include <sys/socket.h>
fb8e28da 22#include <sys/ioctl.h>
de3b21e8
SL
23
24#include <netinet/in.h>
25
9c1dab9e
SL
26#define TELOPTS
27#include <arpa/telnet.h>
28
a19db822
BJ
29#include <stdio.h>
30#include <ctype.h>
31#include <errno.h>
32#include <signal.h>
a19db822 33#include <setjmp.h>
9f005877 34#include <netdb.h>
de3b21e8 35
a19db822 36#define strip(x) ((x)&0177)
a19db822
BJ
37
38char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
a50d5753 39char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
a19db822
BJ
40
41char hisopts[256];
42char myopts[256];
43
44char doopt[] = { IAC, DO, '%', 'c', 0 };
45char dont[] = { IAC, DONT, '%', 'c', 0 };
46char will[] = { IAC, WILL, '%', 'c', 0 };
47char wont[] = { IAC, WONT, '%', 'c', 0 };
48
49int connected;
50int net;
fb8e28da 51int showoptions = 0;
19baf46e 52int options;
4971ba8c 53int debug = 0;
fb8e28da 54int crmod = 0;
a19db822 55char *prompt;
fb8e28da 56char escape = CTRL(]);
a19db822
BJ
57
58char line[200];
59int margc;
60char *margv[20];
61
62jmp_buf toplevel;
63jmp_buf peerdied;
64
65extern int errno;
66
67int tn(), quit(), suspend(), bye(), help();
de372207 68int setescape(), status(), toggle(), setoptions();
40bf00b7 69int setcrmod(), setdebug(), sendesc(), ayt(), intp();
a19db822 70
a50d5753 71#define HELPINDENT (sizeof ("connect"))
a19db822
BJ
72
73struct cmd {
f18adf63
SL
74 char *name; /* command name */
75 char *help; /* help string */
76 int (*handler)(); /* routine which executes command */
a19db822
BJ
77};
78
f18adf63
SL
79char openhelp[] = "connect to a site";
80char closehelp[] = "close current connection";
81char quithelp[] = "exit telnet";
82char zhelp[] = "suspend telnet";
83char debughelp[] = "toggle debugging";
84char escapehelp[] = "set escape character";
85char statushelp[] = "print status information";
86char helphelp[] = "print help information";
87char optionshelp[] = "toggle viewing of options processing";
88char crmodhelp[] = "toggle mapping of received carriage returns";
40bf00b7
RC
89char sendeschelp[] = "send escape character";
90char aythelp[] = "send Are You There";
91char intphelp[] = "send Interrupt Process";
a19db822
BJ
92
93struct cmd cmdtab[] = {
f18adf63
SL
94 { "open", openhelp, tn },
95 { "close", closehelp, bye },
96 { "quit", quithelp, quit },
a19db822 97 { "z", zhelp, suspend },
f18adf63
SL
98 { "escape", escapehelp, setescape },
99 { "status", statushelp, status },
100 { "options", optionshelp, setoptions },
101 { "crmod", crmodhelp, setcrmod },
102 { "debug", debughelp, setdebug },
40bf00b7
RC
103 { "ayt", aythelp, ayt },
104 { "interrupt", intphelp, intp },
105 { "passthru", sendeschelp, sendesc },
f18adf63 106 { "?", helphelp, help },
a19db822
BJ
107 0
108};
109
fb8e28da 110struct sockaddr_in sin;
a19db822
BJ
111
112int intr(), deadpeer();
113char *control();
114struct cmd *getcmd();
9f005877 115struct servent *sp;
a19db822 116
ce292c83
SL
117struct tchars otc;
118struct ltchars oltc;
119struct sgttyb ottyb;
a50d5753 120
a19db822
BJ
121main(argc, argv)
122 int argc;
123 char *argv[];
124{
9f005877
SL
125 sp = getservbyname("telnet", "tcp");
126 if (sp == 0) {
127 fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
128 exit(1);
129 }
ce292c83
SL
130 ioctl(0, TIOCGETP, (char *)&ottyb);
131 ioctl(0, TIOCGETC, (char *)&otc);
132 ioctl(0, TIOCGLTC, (char *)&oltc);
a19db822
BJ
133 setbuf(stdin, 0);
134 setbuf(stdout, 0);
135 prompt = argv[0];
87e91975
CL
136 if (argc > 1 && !strcmp(argv[1], "-d")) {
137 debug = 1;
138 argv++;
139 argc--;
140 }
a19db822
BJ
141 if (argc != 1) {
142 if (setjmp(toplevel) != 0)
143 exit(0);
144 tn(argc, argv);
145 }
146 setjmp(toplevel);
147 for (;;)
148 command(1);
149}
150
150ad7e5
SL
151char *hostname;
152char hnamebuf[32];
a19db822
BJ
153
154tn(argc, argv)
155 int argc;
156 char *argv[];
157{
158 register int c;
150ad7e5 159 register struct hostent *host;
a19db822
BJ
160
161 if (connected) {
150ad7e5 162 printf("?Already connected to %s\n", hostname);
a19db822
BJ
163 return;
164 }
165 if (argc < 2) {
166 strcpy(line, "Connect ");
167 printf("(to) ");
168 gets(&line[strlen(line)]);
169 makeargv();
170 argc = margc;
171 argv = margv;
172 }
173 if (argc > 3) {
174 printf("usage: %s host-name [port]\n", argv[0]);
175 return;
176 }
9f005877 177 host = gethostbyname(argv[1]);
150ad7e5 178 if (host) {
de3b21e8
SL
179 sin.sin_family = host->h_addrtype;
180 bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
150ad7e5
SL
181 hostname = host->h_name;
182 } else {
de3b21e8 183 sin.sin_family = AF_INET;
150ad7e5
SL
184 sin.sin_addr.s_addr = inet_addr(argv[1]);
185 if (sin.sin_addr.s_addr == -1) {
186 printf("%s: unknown host\n", argv[1]);
187 return;
188 }
189 strcpy(hnamebuf, argv[1]);
190 hostname = hnamebuf;
a19db822 191 }
9f005877 192 sin.sin_port = sp->s_port;
de372207
SL
193 if (argc == 3) {
194 sin.sin_port = atoi(argv[2]);
195 if (sin.sin_port < 0) {
196 printf("%s: bad port number\n", argv[2]);
197 return;
198 }
5eba30a3 199 sin.sin_port = htons(sin.sin_port);
de372207 200 }
40bf00b7 201 net = socket(AF_INET, SOCK_STREAM, 0);
de3b21e8
SL
202 if (net < 0) {
203 perror("telnet: socket");
a19db822
BJ
204 return;
205 }
87e91975
CL
206 if (debug &&
207 setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0)
f18adf63 208 perror("setsockopt (SO_DEBUG)");
4ca10280
SL
209 signal(SIGINT, intr);
210 signal(SIGPIPE, deadpeer);
a19db822 211 printf("Trying...\n");
40bf00b7 212 if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) {
de3b21e8 213 perror("telnet: connect");
4ca10280 214 signal(SIGINT, SIG_DFL);
a19db822
BJ
215 return;
216 }
a19db822
BJ
217 connected++;
218 call(status, "status", 0);
219 if (setjmp(peerdied) == 0)
220 telnet(net);
221 fprintf(stderr, "Connection closed by foreign host.\n");
222 exit(1);
223}
224
225/*
226 * Print status about the connection.
227 */
228/*VARARGS*/
229status()
230{
231 if (connected)
150ad7e5 232 printf("Connected to %s.\n", hostname);
a19db822
BJ
233 else
234 printf("No connection.\n");
235 printf("Escape character is '%s'.\n", control(escape));
fb8e28da 236 fflush(stdout);
a19db822
BJ
237}
238
239makeargv()
240{
241 register char *cp;
242 register char **argp = margv;
243
244 margc = 0;
245 for (cp = line; *cp;) {
246 while (isspace(*cp))
247 cp++;
248 if (*cp == '\0')
249 break;
250 *argp++ = cp;
251 margc += 1;
252 while (*cp != '\0' && !isspace(*cp))
253 cp++;
254 if (*cp == '\0')
255 break;
256 *cp++ = '\0';
257 }
258 *argp++ = 0;
259}
260
261/*VARARGS*/
262suspend()
263{
264 register int save;
265
266 save = mode(0);
a50d5753
SL
267 kill(0, SIGTSTP);
268 /* reget parameters in case they were changed */
ce292c83
SL
269 ioctl(0, TIOCGETP, (char *)&ottyb);
270 ioctl(0, TIOCGETC, (char *)&otc);
271 ioctl(0, TIOCGLTC, (char *)&oltc);
a50d5753 272 (void) mode(save);
a19db822
BJ
273}
274
275/*VARARGS*/
276bye()
277{
a50d5753 278 register char *op;
a19db822 279
a50d5753 280 (void) mode(0);
a19db822 281 if (connected) {
f18adf63 282 shutdown(net, 2);
a19db822
BJ
283 printf("Connection closed.\n");
284 close(net);
285 connected = 0;
a50d5753
SL
286 /* reset his options */
287 for (op = hisopts; op < &hisopts[256]; op++)
288 *op = 0;
a19db822
BJ
289 }
290}
291
292/*VARARGS*/
293quit()
294{
295 call(bye, "bye", 0);
296 exit(0);
297}
298
299/*
300 * Help command.
a19db822
BJ
301 */
302help(argc, argv)
303 int argc;
304 char *argv[];
305{
306 register struct cmd *c;
307
308 if (argc == 1) {
309 printf("Commands may be abbreviated. Commands are:\n\n");
310 for (c = cmdtab; c->name; c++)
311 printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
312 return;
313 }
314 while (--argc > 0) {
315 register char *arg;
316 arg = *++argv;
317 c = getcmd(arg);
318 if (c == (struct cmd *)-1)
319 printf("?Ambiguous help command %s\n", arg);
320 else if (c == (struct cmd *)0)
321 printf("?Invalid help command %s\n", arg);
322 else
323 printf("%s\n", c->help);
324 }
325}
326
327/*
328 * Call routine with argc, argv set from args (terminated by 0).
329 * VARARGS2
330 */
331call(routine, args)
332 int (*routine)();
333 int args;
334{
335 register int *argp;
336 register int argc;
337
338 for (argc = 0, argp = &args; *argp++ != 0; argc++)
339 ;
340 (*routine)(argc, &args);
341}
342
ce292c83
SL
343struct tchars notc = { -1, -1, -1, -1, -1, -1 };
344struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
fb8e28da 345
a19db822
BJ
346mode(f)
347 register int f;
348{
a50d5753 349 static int prevmode = 0;
ce292c83
SL
350 struct tchars *tc;
351 struct ltchars *ltc;
352 struct sgttyb sb;
353 int onoff, old;
a50d5753
SL
354
355 if (prevmode == f)
356 return (f);
357 old = prevmode;
358 prevmode = f;
ce292c83 359 sb = ottyb;
a19db822 360 switch (f) {
a50d5753 361
a19db822 362 case 0:
a19db822 363 onoff = 0;
fb8e28da 364 tc = &otc;
ce292c83 365 ltc = &oltc;
a19db822
BJ
366 break;
367
368 case 1:
a19db822 369 case 2:
ce292c83 370 sb.sg_flags |= CBREAK;
a50d5753 371 if (f == 1)
ce292c83 372 sb.sg_flags &= ~(ECHO|CRMOD);
a50d5753 373 else
ce292c83
SL
374 sb.sg_flags |= ECHO|CRMOD;
375 sb.sg_erase = sb.sg_kill = -1;
fb8e28da 376 tc = &notc;
ce292c83 377 ltc = &noltc;
a19db822 378 onoff = 1;
fb8e28da
SL
379 break;
380
381 default:
382 return;
a19db822 383 }
ce292c83
SL
384 ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
385 ioctl(fileno(stdin), TIOCSETC, (char *)tc);
386 ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
a19db822
BJ
387 ioctl(fileno(stdin), FIONBIO, &onoff);
388 ioctl(fileno(stdout), FIONBIO, &onoff);
389 return (old);
390}
391
392char sibuf[BUFSIZ], *sbp;
393char tibuf[BUFSIZ], *tbp;
394int scc, tcc;
395
396/*
397 * Select from tty and network...
398 */
399telnet(s)
400 int s;
401{
402 register int c;
403 int tin = fileno(stdin), tout = fileno(stdout);
404 int on = 1;
405
a50d5753 406 (void) mode(2);
a19db822 407 ioctl(s, FIONBIO, &on);
40bf00b7
RC
408 if (!hisopts[TELOPT_SGA])
409 willoption(TELOPT_SGA);
a19db822
BJ
410 for (;;) {
411 int ibits = 0, obits = 0;
412
413 if (nfrontp - nbackp)
414 obits |= (1 << s);
415 else
416 ibits |= (1 << tin);
417 if (tfrontp - tbackp)
418 obits |= (1 << tout);
419 else
420 ibits |= (1 << s);
421 if (scc < 0 && tcc < 0)
422 break;
de3b21e8 423 select(16, &ibits, &obits, 0, 0);
a19db822
BJ
424 if (ibits == 0 && obits == 0) {
425 sleep(5);
426 continue;
427 }
428
429 /*
430 * Something to read from the network...
431 */
432 if (ibits & (1 << s)) {
a50d5753 433 scc = read(s, sibuf, sizeof (sibuf));
a19db822
BJ
434 if (scc < 0 && errno == EWOULDBLOCK)
435 scc = 0;
436 else {
437 if (scc <= 0)
438 break;
439 sbp = sibuf;
440 }
441 }
442
443 /*
444 * Something to read from the tty...
445 */
446 if (ibits & (1 << tin)) {
a50d5753 447 tcc = read(tin, tibuf, sizeof (tibuf));
a19db822
BJ
448 if (tcc < 0 && errno == EWOULDBLOCK)
449 tcc = 0;
450 else {
451 if (tcc <= 0)
452 break;
453 tbp = tibuf;
454 }
455 }
456
457 while (tcc > 0) {
458 register int c;
459
460 if ((&netobuf[BUFSIZ] - nfrontp) < 2)
461 break;
462 c = *tbp++ & 0377, tcc--;
463 if (strip(c) == escape) {
464 command(0);
465 tcc = 0;
466 break;
467 }
40bf00b7
RC
468 switch (c) {
469 case '\n':
470 if (!hisopts[TELOPT_ECHO])
471 *nfrontp++ = '\r';
1698259c 472 *nfrontp++ = '\n';
40bf00b7
RC
473 break;
474 case '\r':
475 *nfrontp++ = '\r';
476 if (hisopts[TELOPT_ECHO])
477 *nfrontp++ = '\n';
478 else
479 *nfrontp++ = '\0';
480 break;
481 case IAC:
482 *nfrontp++ = IAC;
483 /* fall into ... */
484 default:
485 *nfrontp++ = c;
486 break;
487 }
a19db822
BJ
488 }
489 if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
490 netflush(s);
491 if (scc > 0)
492 telrcv();
493 if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
494 ttyflush(tout);
495 }
a50d5753 496 (void) mode(0);
a19db822
BJ
497}
498
499command(top)
500 int top;
501{
502 register struct cmd *c;
503 int oldmode, wasopen;
504
505 oldmode = mode(0);
506 if (!top)
507 putchar('\n');
508 else
4ca10280 509 signal(SIGINT, SIG_DFL);
a19db822
BJ
510 for (;;) {
511 printf("%s> ", prompt);
baba6eb5
SL
512 if (gets(line) == 0) {
513 if (feof(stdin)) {
514 clearerr(stdin);
515 putchar('\n');
516 }
a19db822 517 break;
baba6eb5 518 }
a19db822
BJ
519 if (line[0] == 0)
520 break;
521 makeargv();
522 c = getcmd(margv[0]);
523 if (c == (struct cmd *)-1) {
524 printf("?Ambiguous command\n");
525 continue;
526 }
527 if (c == 0) {
528 printf("?Invalid command\n");
529 continue;
530 }
531 (*c->handler)(margc, margv);
532 if (c->handler != help)
533 break;
534 }
535 if (!top) {
536 if (!connected)
537 longjmp(toplevel, 1);
a50d5753 538 (void) mode(oldmode);
a19db822
BJ
539 }
540}
541
542/*
543 * Telnet receiver states for fsm
544 */
545#define TS_DATA 0
546#define TS_IAC 1
547#define TS_WILL 2
548#define TS_WONT 3
549#define TS_DO 4
550#define TS_DONT 5
551
552telrcv()
553{
554 register int c;
555 static int state = TS_DATA;
556
557 while (scc > 0) {
558 c = *sbp++ & 0377, scc--;
559 switch (state) {
560
561 case TS_DATA:
fb8e28da 562 if (c == IAC) {
a19db822 563 state = TS_IAC;
fb8e28da
SL
564 continue;
565 }
566 *tfrontp++ = c;
567 /*
568 * This hack is needed since we can't set
569 * CRMOD on output only. Machines like MULTICS
570 * like to send \r without \n; since we must
571 * turn off CRMOD to get proper input, the mapping
572 * is done here (sigh).
573 */
574 if (c == '\r' && crmod)
575 *tfrontp++ = '\n';
a19db822
BJ
576 continue;
577
578 case TS_IAC:
579 switch (c) {
580
581 case WILL:
582 state = TS_WILL;
583 continue;
584
585 case WONT:
586 state = TS_WONT;
587 continue;
588
589 case DO:
590 state = TS_DO;
591 continue;
592
593 case DONT:
594 state = TS_DONT;
595 continue;
596
597 case DM:
598 ioctl(fileno(stdout), TIOCFLUSH, 0);
599 break;
600
601 case NOP:
602 case GA:
603 break;
604
605 default:
606 break;
607 }
608 state = TS_DATA;
609 continue;
610
611 case TS_WILL:
9f005877 612 printoption("RCVD", will, c, !hisopts[c]);
a19db822
BJ
613 if (!hisopts[c])
614 willoption(c);
615 state = TS_DATA;
616 continue;
617
618 case TS_WONT:
9f005877 619 printoption("RCVD", wont, c, hisopts[c]);
a19db822
BJ
620 if (hisopts[c])
621 wontoption(c);
622 state = TS_DATA;
623 continue;
624
625 case TS_DO:
9f005877 626 printoption("RCVD", doopt, c, !myopts[c]);
a19db822
BJ
627 if (!myopts[c])
628 dooption(c);
629 state = TS_DATA;
630 continue;
631
632 case TS_DONT:
9f005877 633 printoption("RCVD", dont, c, myopts[c]);
a19db822
BJ
634 if (myopts[c]) {
635 myopts[c] = 0;
636 sprintf(nfrontp, wont, c);
a50d5753 637 nfrontp += sizeof (wont) - 2;
9f005877 638 printoption("SENT", wont, c);
a19db822
BJ
639 }
640 state = TS_DATA;
641 continue;
642 }
643 }
644}
645
646willoption(option)
647 int option;
648{
649 char *fmt;
650
651 switch (option) {
652
653 case TELOPT_ECHO:
a50d5753 654 (void) mode(1);
a19db822
BJ
655
656 case TELOPT_SGA:
657 hisopts[option] = 1;
658 fmt = doopt;
659 break;
660
661 case TELOPT_TM:
662 fmt = dont;
663 break;
664
665 default:
666 fmt = dont;
667 break;
668 }
de372207 669 sprintf(nfrontp, fmt, option);
a50d5753 670 nfrontp += sizeof (dont) - 2;
9f005877 671 printoption("SENT", fmt, option);
a19db822
BJ
672}
673
674wontoption(option)
675 int option;
676{
677 char *fmt;
678
679 switch (option) {
680
681 case TELOPT_ECHO:
a50d5753 682 (void) mode(2);
a19db822
BJ
683
684 case TELOPT_SGA:
685 hisopts[option] = 0;
686 fmt = dont;
687 break;
688
689 default:
690 fmt = dont;
691 }
692 sprintf(nfrontp, fmt, option);
a50d5753 693 nfrontp += sizeof (doopt) - 2;
9f005877 694 printoption("SENT", fmt, option);
a19db822
BJ
695}
696
697dooption(option)
698 int option;
699{
700 char *fmt;
701
702 switch (option) {
703
704 case TELOPT_TM:
705 fmt = wont;
706 break;
680e328e
SL
707
708 case TELOPT_ECHO:
709 (void) mode(2);
710 fmt = will;
711 hisopts[option] = 0;
712 break;
a19db822
BJ
713
714 case TELOPT_SGA:
715 fmt = will;
716 break;
717
718 default:
719 fmt = wont;
720 break;
721 }
722 sprintf(nfrontp, fmt, option);
a50d5753 723 nfrontp += sizeof (doopt) - 2;
9f005877 724 printoption("SENT", fmt, option);
a19db822
BJ
725}
726
727/*
728 * Set the escape character.
729 */
730setescape(argc, argv)
731 int argc;
732 char *argv[];
733{
734 register char *arg;
735 char buf[50];
736
737 if (argc > 2)
738 arg = argv[1];
739 else {
740 printf("new escape character: ");
741 gets(buf);
742 arg = buf;
743 }
744 if (arg[0] != '\0')
745 escape = arg[0];
746 printf("Escape character is '%s'.\n", control(escape));
fb8e28da 747 fflush(stdout);
a19db822
BJ
748}
749
de372207
SL
750/*VARARGS*/
751setoptions()
752{
fb8e28da 753
de372207
SL
754 showoptions = !showoptions;
755 printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
fb8e28da
SL
756 fflush(stdout);
757}
758
759/*VARARGS*/
760setcrmod()
761{
762
763 crmod = !crmod;
764 printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont");
765 fflush(stdout);
de372207
SL
766}
767
4971ba8c
SL
768/*VARARGS*/
769setdebug()
770{
771
87e91975 772 debug = debug ? 0 : 1;
4971ba8c
SL
773 printf("%s turn on socket level debugging.\n",
774 debug ? "Will" : "Wont");
775 fflush(stdout);
87e91975
CL
776 if (net > 0 &&
777 setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0)
f18adf63 778 perror("setsockopt (SO_DEBUG)");
4971ba8c
SL
779}
780
40bf00b7
RC
781sendesc()
782{
783 *nfrontp++ = escape;
784}
785
786ayt()
787{
788 *nfrontp++ = IAC;
789 *nfrontp++ = AYT;
790}
791
792intp()
793{
794 *nfrontp++ = IAC;
795 *nfrontp++ = IP;
796}
797
a19db822
BJ
798/*
799 * Construct a control character sequence
800 * for a special character.
801 */
802char *
803control(c)
804 register int c;
805{
806 static char buf[3];
807
808 if (c == 0177)
809 return ("^?");
810 if (c >= 040) {
811 buf[0] = c;
812 buf[1] = 0;
813 } else {
814 buf[0] = '^';
815 buf[1] = '@'+c;
816 buf[2] = 0;
817 }
818 return (buf);
819}
820
821struct cmd *
822getcmd(name)
823 register char *name;
824{
825 register char *p, *q;
826 register struct cmd *c, *found;
827 register int nmatches, longest;
828
829 longest = 0;
830 nmatches = 0;
831 found = 0;
832 for (c = cmdtab; p = c->name; c++) {
833 for (q = name; *q == *p++; q++)
834 if (*q == 0) /* exact match? */
835 return (c);
836 if (!*q) { /* the name was a prefix */
837 if (q - name > longest) {
838 longest = q - name;
839 nmatches = 1;
840 found = c;
841 } else if (q - name == longest)
842 nmatches++;
843 }
844 }
845 if (nmatches > 1)
846 return ((struct cmd *)-1);
847 return (found);
848}
849
850deadpeer()
851{
a50d5753 852 (void) mode(0);
a19db822
BJ
853 longjmp(peerdied, -1);
854}
855
856intr()
857{
a50d5753 858 (void) mode(0);
a19db822
BJ
859 longjmp(toplevel, -1);
860}
861
862ttyflush(fd)
863{
864 int n;
865
866 if ((n = tfrontp - tbackp) > 0)
867 n = write(fd, tbackp, n);
9f005877
SL
868 if (n < 0)
869 return;
a19db822
BJ
870 tbackp += n;
871 if (tbackp == tfrontp)
872 tbackp = tfrontp = ttyobuf;
873}
874
875netflush(fd)
876{
877 int n;
878
879 if ((n = nfrontp - nbackp) > 0)
880 n = write(fd, nbackp, n);
f103d8a9
SL
881 if (n < 0) {
882 if (errno != ENOBUFS && errno != EWOULDBLOCK) {
a50d5753 883 (void) mode(0);
150ad7e5 884 perror(hostname);
f103d8a9
SL
885 close(fd);
886 longjmp(peerdied, -1);
887 /*NOTREACHED*/
888 }
a19db822 889 n = 0;
f103d8a9 890 }
a19db822
BJ
891 nbackp += n;
892 if (nbackp == nfrontp)
893 nbackp = nfrontp = netobuf;
894}
de372207 895
6cebba9f
BJ
896/*VARARGS*/
897printoption(direction, fmt, option, what)
de372207 898 char *direction, *fmt;
6cebba9f 899 int option, what;
de372207 900{
9f005877
SL
901 if (!showoptions)
902 return;
de372207
SL
903 printf("%s ", direction);
904 if (fmt == doopt)
905 fmt = "do";
906 else if (fmt == dont)
907 fmt = "dont";
908 else if (fmt == will)
909 fmt = "will";
910 else if (fmt == wont)
911 fmt = "wont";
912 else
913 fmt = "???";
914 if (option < TELOPT_SUPDUP)
6cebba9f 915 printf("%s %s", fmt, telopts[option]);
de372207 916 else
6cebba9f
BJ
917 printf("%s %d", fmt, option);
918 if (*direction == '<') {
919 printf("\r\n");
920 return;
921 }
922 printf(" (%s)\r\n", what ? "reply" : "don't reply");
de372207 923}