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