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