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