botched sccsid
[unix-history] / usr / src / usr.bin / telnet / telnet.c
CommitLineData
f18adf63 1#ifndef lint
87e91975 2static char sccsid[] = "@(#)telnet.c 4.25 (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
BJ
450 *nfrontp++ = c;
451 }
452 if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
453 netflush(s);
454 if (scc > 0)
455 telrcv();
456 if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
457 ttyflush(tout);
458 }
a50d5753 459 (void) mode(0);
a19db822
BJ
460}
461
462command(top)
463 int top;
464{
465 register struct cmd *c;
466 int oldmode, wasopen;
467
468 oldmode = mode(0);
469 if (!top)
470 putchar('\n');
471 else
4ca10280 472 signal(SIGINT, SIG_DFL);
a19db822
BJ
473 for (;;) {
474 printf("%s> ", prompt);
baba6eb5
SL
475 if (gets(line) == 0) {
476 if (feof(stdin)) {
477 clearerr(stdin);
478 putchar('\n');
479 }
a19db822 480 break;
baba6eb5 481 }
a19db822
BJ
482 if (line[0] == 0)
483 break;
484 makeargv();
485 c = getcmd(margv[0]);
486 if (c == (struct cmd *)-1) {
487 printf("?Ambiguous command\n");
488 continue;
489 }
490 if (c == 0) {
491 printf("?Invalid command\n");
492 continue;
493 }
494 (*c->handler)(margc, margv);
495 if (c->handler != help)
496 break;
497 }
498 if (!top) {
499 if (!connected)
500 longjmp(toplevel, 1);
a50d5753 501 (void) mode(oldmode);
a19db822
BJ
502 }
503}
504
505/*
506 * Telnet receiver states for fsm
507 */
508#define TS_DATA 0
509#define TS_IAC 1
510#define TS_WILL 2
511#define TS_WONT 3
512#define TS_DO 4
513#define TS_DONT 5
514
515telrcv()
516{
517 register int c;
518 static int state = TS_DATA;
519
520 while (scc > 0) {
521 c = *sbp++ & 0377, scc--;
522 switch (state) {
523
524 case TS_DATA:
fb8e28da 525 if (c == IAC) {
a19db822 526 state = TS_IAC;
fb8e28da
SL
527 continue;
528 }
529 *tfrontp++ = c;
530 /*
531 * This hack is needed since we can't set
532 * CRMOD on output only. Machines like MULTICS
533 * like to send \r without \n; since we must
534 * turn off CRMOD to get proper input, the mapping
535 * is done here (sigh).
536 */
537 if (c == '\r' && crmod)
538 *tfrontp++ = '\n';
a19db822
BJ
539 continue;
540
541 case TS_IAC:
542 switch (c) {
543
544 case WILL:
545 state = TS_WILL;
546 continue;
547
548 case WONT:
549 state = TS_WONT;
550 continue;
551
552 case DO:
553 state = TS_DO;
554 continue;
555
556 case DONT:
557 state = TS_DONT;
558 continue;
559
560 case DM:
561 ioctl(fileno(stdout), TIOCFLUSH, 0);
562 break;
563
564 case NOP:
565 case GA:
566 break;
567
568 default:
569 break;
570 }
571 state = TS_DATA;
572 continue;
573
574 case TS_WILL:
9f005877 575 printoption("RCVD", will, c, !hisopts[c]);
a19db822
BJ
576 if (!hisopts[c])
577 willoption(c);
578 state = TS_DATA;
579 continue;
580
581 case TS_WONT:
9f005877 582 printoption("RCVD", wont, c, hisopts[c]);
a19db822
BJ
583 if (hisopts[c])
584 wontoption(c);
585 state = TS_DATA;
586 continue;
587
588 case TS_DO:
9f005877 589 printoption("RCVD", doopt, c, !myopts[c]);
a19db822
BJ
590 if (!myopts[c])
591 dooption(c);
592 state = TS_DATA;
593 continue;
594
595 case TS_DONT:
9f005877 596 printoption("RCVD", dont, c, myopts[c]);
a19db822
BJ
597 if (myopts[c]) {
598 myopts[c] = 0;
599 sprintf(nfrontp, wont, c);
a50d5753 600 nfrontp += sizeof (wont) - 2;
9f005877 601 printoption("SENT", wont, c);
a19db822
BJ
602 }
603 state = TS_DATA;
604 continue;
605 }
606 }
607}
608
609willoption(option)
610 int option;
611{
612 char *fmt;
613
614 switch (option) {
615
616 case TELOPT_ECHO:
a50d5753 617 (void) mode(1);
a19db822
BJ
618
619 case TELOPT_SGA:
620 hisopts[option] = 1;
621 fmt = doopt;
622 break;
623
624 case TELOPT_TM:
625 fmt = dont;
626 break;
627
628 default:
629 fmt = dont;
630 break;
631 }
de372207 632 sprintf(nfrontp, fmt, option);
a50d5753 633 nfrontp += sizeof (dont) - 2;
9f005877 634 printoption("SENT", fmt, option);
a19db822
BJ
635}
636
637wontoption(option)
638 int option;
639{
640 char *fmt;
641
642 switch (option) {
643
644 case TELOPT_ECHO:
a50d5753 645 (void) mode(2);
a19db822
BJ
646
647 case TELOPT_SGA:
648 hisopts[option] = 0;
649 fmt = dont;
650 break;
651
652 default:
653 fmt = dont;
654 }
655 sprintf(nfrontp, fmt, option);
a50d5753 656 nfrontp += sizeof (doopt) - 2;
9f005877 657 printoption("SENT", fmt, option);
a19db822
BJ
658}
659
660dooption(option)
661 int option;
662{
663 char *fmt;
664
665 switch (option) {
666
667 case TELOPT_TM:
668 fmt = wont;
669 break;
680e328e
SL
670
671 case TELOPT_ECHO:
672 (void) mode(2);
673 fmt = will;
674 hisopts[option] = 0;
675 break;
a19db822
BJ
676
677 case TELOPT_SGA:
678 fmt = will;
679 break;
680
681 default:
682 fmt = wont;
683 break;
684 }
685 sprintf(nfrontp, fmt, option);
a50d5753 686 nfrontp += sizeof (doopt) - 2;
9f005877 687 printoption("SENT", fmt, option);
a19db822
BJ
688}
689
690/*
691 * Set the escape character.
692 */
693setescape(argc, argv)
694 int argc;
695 char *argv[];
696{
697 register char *arg;
698 char buf[50];
699
700 if (argc > 2)
701 arg = argv[1];
702 else {
703 printf("new escape character: ");
704 gets(buf);
705 arg = buf;
706 }
707 if (arg[0] != '\0')
708 escape = arg[0];
709 printf("Escape character is '%s'.\n", control(escape));
fb8e28da 710 fflush(stdout);
a19db822
BJ
711}
712
de372207
SL
713/*VARARGS*/
714setoptions()
715{
fb8e28da 716
de372207
SL
717 showoptions = !showoptions;
718 printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
fb8e28da
SL
719 fflush(stdout);
720}
721
722/*VARARGS*/
723setcrmod()
724{
725
726 crmod = !crmod;
727 printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont");
728 fflush(stdout);
de372207
SL
729}
730
4971ba8c
SL
731/*VARARGS*/
732setdebug()
733{
734
87e91975 735 debug = debug ? 0 : 1;
4971ba8c
SL
736 printf("%s turn on socket level debugging.\n",
737 debug ? "Will" : "Wont");
738 fflush(stdout);
87e91975
CL
739 if (net > 0 &&
740 setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0)
f18adf63 741 perror("setsockopt (SO_DEBUG)");
4971ba8c
SL
742}
743
a19db822
BJ
744/*
745 * Construct a control character sequence
746 * for a special character.
747 */
748char *
749control(c)
750 register int c;
751{
752 static char buf[3];
753
754 if (c == 0177)
755 return ("^?");
756 if (c >= 040) {
757 buf[0] = c;
758 buf[1] = 0;
759 } else {
760 buf[0] = '^';
761 buf[1] = '@'+c;
762 buf[2] = 0;
763 }
764 return (buf);
765}
766
767struct cmd *
768getcmd(name)
769 register char *name;
770{
771 register char *p, *q;
772 register struct cmd *c, *found;
773 register int nmatches, longest;
774
775 longest = 0;
776 nmatches = 0;
777 found = 0;
778 for (c = cmdtab; p = c->name; c++) {
779 for (q = name; *q == *p++; q++)
780 if (*q == 0) /* exact match? */
781 return (c);
782 if (!*q) { /* the name was a prefix */
783 if (q - name > longest) {
784 longest = q - name;
785 nmatches = 1;
786 found = c;
787 } else if (q - name == longest)
788 nmatches++;
789 }
790 }
791 if (nmatches > 1)
792 return ((struct cmd *)-1);
793 return (found);
794}
795
796deadpeer()
797{
a50d5753 798 (void) mode(0);
a19db822
BJ
799 longjmp(peerdied, -1);
800}
801
802intr()
803{
a50d5753 804 (void) mode(0);
a19db822
BJ
805 longjmp(toplevel, -1);
806}
807
808ttyflush(fd)
809{
810 int n;
811
812 if ((n = tfrontp - tbackp) > 0)
813 n = write(fd, tbackp, n);
9f005877
SL
814 if (n < 0)
815 return;
a19db822
BJ
816 tbackp += n;
817 if (tbackp == tfrontp)
818 tbackp = tfrontp = ttyobuf;
819}
820
821netflush(fd)
822{
823 int n;
824
825 if ((n = nfrontp - nbackp) > 0)
826 n = write(fd, nbackp, n);
f103d8a9
SL
827 if (n < 0) {
828 if (errno != ENOBUFS && errno != EWOULDBLOCK) {
a50d5753 829 (void) mode(0);
150ad7e5 830 perror(hostname);
f103d8a9
SL
831 close(fd);
832 longjmp(peerdied, -1);
833 /*NOTREACHED*/
834 }
a19db822 835 n = 0;
f103d8a9 836 }
a19db822
BJ
837 nbackp += n;
838 if (nbackp == nfrontp)
839 nbackp = nfrontp = netobuf;
840}
de372207 841
6cebba9f
BJ
842/*VARARGS*/
843printoption(direction, fmt, option, what)
de372207 844 char *direction, *fmt;
6cebba9f 845 int option, what;
de372207 846{
9f005877
SL
847 if (!showoptions)
848 return;
de372207
SL
849 printf("%s ", direction);
850 if (fmt == doopt)
851 fmt = "do";
852 else if (fmt == dont)
853 fmt = "dont";
854 else if (fmt == will)
855 fmt = "will";
856 else if (fmt == wont)
857 fmt = "wont";
858 else
859 fmt = "???";
860 if (option < TELOPT_SUPDUP)
6cebba9f 861 printf("%s %s", fmt, telopts[option]);
de372207 862 else
6cebba9f
BJ
863 printf("%s %d", fmt, option);
864 if (*direction == '<') {
865 printf("\r\n");
866 return;
867 }
868 printf(" (%s)\r\n", what ? "reply" : "don't reply");
de372207 869}