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