Commit | Line | Data |
---|---|---|
ea139302 PB |
1 | /* |
2 | * Copyright (c) 1989 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
836fe169 | 5 | * %sccs.include.redist.c% |
ea139302 PB |
6 | */ |
7 | ||
8 | #ifndef lint | |
4f73d56c | 9 | static char sccsid[] = "@(#)utility.c 5.6 (Berkeley) %G%"; |
ea139302 PB |
10 | #endif /* not lint */ |
11 | ||
4a8a7128 | 12 | #define PRINTOPTIONS |
ea139302 PB |
13 | #include "telnetd.h" |
14 | ||
15 | /* | |
16 | * utility functions performing io related tasks | |
17 | */ | |
18 | ||
19 | /* | |
20 | * ttloop | |
21 | * | |
22 | * A small subroutine to flush the network output buffer, get some data | |
23 | * from the network, and pass it through the telnet state machine. We | |
24 | * also flush the pty input buffer (by dropping its data) if it becomes | |
25 | * too full. | |
26 | */ | |
27 | ||
28 | void | |
29 | ttloop() | |
30 | { | |
31 | void netflush(); | |
32 | ||
4a8a7128 PB |
33 | #ifdef DIAGNOSTICS |
34 | if (diagnostic & TD_REPORT) { | |
35 | sprintf(nfrontp, "td: ttloop\r\n"); | |
36 | nfrontp += strlen(nfrontp); | |
37 | } | |
38 | #endif /* DIAGNOSTICS */ | |
ea139302 PB |
39 | if (nfrontp-nbackp) { |
40 | netflush(); | |
41 | } | |
42 | ncc = read(net, netibuf, sizeof netibuf); | |
43 | if (ncc < 0) { | |
44 | syslog(LOG_INFO, "ttloop: read: %m\n"); | |
45 | exit(1); | |
46 | } else if (ncc == 0) { | |
47 | syslog(LOG_INFO, "ttloop: peer died: %m\n"); | |
48 | exit(1); | |
49 | } | |
4a8a7128 PB |
50 | #ifdef DIAGNOSTICS |
51 | if (diagnostic & TD_REPORT) { | |
52 | sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc); | |
53 | nfrontp += strlen(nfrontp); | |
54 | } | |
55 | #endif /* DIAGNOSTICS */ | |
ea139302 PB |
56 | netip = netibuf; |
57 | telrcv(); /* state machine */ | |
58 | if (ncc > 0) { | |
59 | pfrontp = pbackp = ptyobuf; | |
60 | telrcv(); | |
61 | } | |
62 | } /* end of ttloop */ | |
63 | ||
64 | /* | |
65 | * Check a descriptor to see if out of band data exists on it. | |
66 | */ | |
67 | stilloob(s) | |
68 | int s; /* socket number */ | |
69 | { | |
70 | static struct timeval timeout = { 0 }; | |
71 | fd_set excepts; | |
72 | int value; | |
73 | ||
74 | do { | |
75 | FD_ZERO(&excepts); | |
76 | FD_SET(s, &excepts); | |
77 | value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); | |
78 | } while ((value == -1) && (errno == EINTR)); | |
79 | ||
80 | if (value < 0) { | |
81 | fatalperror(pty, "select"); | |
82 | } | |
83 | if (FD_ISSET(s, &excepts)) { | |
84 | return 1; | |
85 | } else { | |
86 | return 0; | |
87 | } | |
88 | } | |
89 | ||
90 | ptyflush() | |
91 | { | |
92 | int n; | |
93 | ||
4a8a7128 PB |
94 | if ((n = pfrontp - pbackp) > 0) { |
95 | #ifdef DIAGNOSTICS | |
96 | if (diagnostic & (TD_REPORT | TD_PTYDATA)) { | |
97 | sprintf(nfrontp, "td: ptyflush %d chars\r\n", n); | |
98 | nfrontp += strlen(nfrontp); | |
99 | } | |
100 | if (diagnostic & TD_PTYDATA) { | |
101 | printdata("pd", pbackp, n); | |
102 | } | |
103 | #endif /* DIAGNOSTICS */ | |
ea139302 | 104 | n = write(pty, pbackp, n); |
4a8a7128 | 105 | } |
ea139302 PB |
106 | if (n < 0) |
107 | return; | |
108 | pbackp += n; | |
109 | if (pbackp == pfrontp) | |
110 | pbackp = pfrontp = ptyobuf; | |
111 | } | |
112 | ||
113 | /* | |
114 | * nextitem() | |
115 | * | |
116 | * Return the address of the next "item" in the TELNET data | |
117 | * stream. This will be the address of the next character if | |
118 | * the current address is a user data character, or it will | |
119 | * be the address of the character following the TELNET command | |
120 | * if the current address is a TELNET IAC ("I Am a Command") | |
121 | * character. | |
122 | */ | |
123 | char * | |
124 | nextitem(current) | |
125 | char *current; | |
126 | { | |
127 | if ((*current&0xff) != IAC) { | |
128 | return current+1; | |
129 | } | |
130 | switch (*(current+1)&0xff) { | |
131 | case DO: | |
132 | case DONT: | |
133 | case WILL: | |
134 | case WONT: | |
135 | return current+3; | |
136 | case SB: /* loop forever looking for the SE */ | |
137 | { | |
138 | register char *look = current+2; | |
139 | ||
140 | for (;;) { | |
141 | if ((*look++&0xff) == IAC) { | |
142 | if ((*look++&0xff) == SE) { | |
143 | return look; | |
144 | } | |
145 | } | |
146 | } | |
147 | } | |
148 | default: | |
149 | return current+2; | |
150 | } | |
151 | } /* end of nextitem */ | |
152 | ||
153 | ||
154 | /* | |
155 | * netclear() | |
156 | * | |
157 | * We are about to do a TELNET SYNCH operation. Clear | |
158 | * the path to the network. | |
159 | * | |
160 | * Things are a bit tricky since we may have sent the first | |
161 | * byte or so of a previous TELNET command into the network. | |
162 | * So, we have to scan the network buffer from the beginning | |
163 | * until we are up to where we want to be. | |
164 | * | |
165 | * A side effect of what we do, just to keep things | |
166 | * simple, is to clear the urgent data pointer. The principal | |
167 | * caller should be setting the urgent data pointer AFTER calling | |
168 | * us in any case. | |
169 | */ | |
170 | netclear() | |
171 | { | |
172 | register char *thisitem, *next; | |
173 | char *good; | |
174 | #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ | |
175 | ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) | |
176 | ||
177 | thisitem = netobuf; | |
178 | ||
179 | while ((next = nextitem(thisitem)) <= nbackp) { | |
180 | thisitem = next; | |
181 | } | |
182 | ||
183 | /* Now, thisitem is first before/at boundary. */ | |
184 | ||
185 | good = netobuf; /* where the good bytes go */ | |
186 | ||
187 | while (nfrontp > thisitem) { | |
188 | if (wewant(thisitem)) { | |
189 | int length; | |
190 | ||
191 | next = thisitem; | |
192 | do { | |
193 | next = nextitem(next); | |
194 | } while (wewant(next) && (nfrontp > next)); | |
195 | length = next-thisitem; | |
196 | bcopy(thisitem, good, length); | |
197 | good += length; | |
198 | thisitem = next; | |
199 | } else { | |
200 | thisitem = nextitem(thisitem); | |
201 | } | |
202 | } | |
203 | ||
204 | nbackp = netobuf; | |
205 | nfrontp = good; /* next byte to be sent */ | |
206 | neturg = 0; | |
207 | } /* end of netclear */ | |
208 | ||
209 | /* | |
210 | * netflush | |
211 | * Send as much data as possible to the network, | |
212 | * handling requests for urgent data. | |
213 | */ | |
214 | void | |
215 | netflush() | |
216 | { | |
217 | int n; | |
218 | extern int not42; | |
219 | ||
220 | if ((n = nfrontp - nbackp) > 0) { | |
4a8a7128 PB |
221 | #ifdef DIAGNOSTICS |
222 | if (diagnostic & TD_REPORT) { | |
223 | sprintf(nfrontp, "td: netflush %d chars\r\n", n); | |
224 | n += strlen(nfrontp); /* get count first */ | |
225 | nfrontp += strlen(nfrontp); /* then move pointer */ | |
226 | } | |
227 | #endif /* DIAGNOSTICS */ | |
ea139302 PB |
228 | /* |
229 | * if no urgent data, or if the other side appears to be an | |
230 | * old 4.2 client (and thus unable to survive TCP urgent data), | |
231 | * write the entire buffer in non-OOB mode. | |
232 | */ | |
233 | if ((neturg == 0) || (not42 == 0)) { | |
234 | n = write(net, nbackp, n); /* normal write */ | |
235 | } else { | |
236 | n = neturg - nbackp; | |
237 | /* | |
238 | * In 4.2 (and 4.3) systems, there is some question about | |
239 | * what byte in a sendOOB operation is the "OOB" data. | |
240 | * To make ourselves compatible, we only send ONE byte | |
241 | * out of band, the one WE THINK should be OOB (though | |
242 | * we really have more the TCP philosophy of urgent data | |
243 | * rather than the Unix philosophy of OOB data). | |
244 | */ | |
245 | if (n > 1) { | |
246 | n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ | |
247 | } else { | |
248 | n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ | |
249 | } | |
250 | } | |
251 | } | |
252 | if (n < 0) { | |
253 | if (errno == EWOULDBLOCK || errno == EINTR) | |
254 | return; | |
255 | cleanup(); | |
256 | } | |
257 | nbackp += n; | |
258 | if (nbackp >= neturg) { | |
259 | neturg = 0; | |
260 | } | |
261 | if (nbackp == nfrontp) { | |
262 | nbackp = nfrontp = netobuf; | |
263 | } | |
264 | return; | |
265 | } /* end of netflush */ | |
266 | ||
267 | ||
268 | /* | |
269 | * writenet | |
270 | * | |
271 | * Just a handy little function to write a bit of raw data to the net. | |
272 | * It will force a transmit of the buffer if necessary | |
273 | * | |
274 | * arguments | |
275 | * ptr - A pointer to a character string to write | |
276 | * len - How many bytes to write | |
277 | */ | |
278 | writenet(ptr, len) | |
279 | register char *ptr; | |
280 | register int len; | |
281 | { | |
282 | /* flush buffer if no room for new data) */ | |
283 | if ((&netobuf[BUFSIZ] - nfrontp) < len) { | |
284 | /* if this fails, don't worry, buffer is a little big */ | |
285 | netflush(); | |
286 | } | |
287 | ||
288 | bcopy(ptr, nfrontp, len); | |
289 | nfrontp += len; | |
290 | ||
291 | } /* end of writenet */ | |
292 | ||
293 | ||
294 | /* | |
295 | * miscellaneous functions doing a variety of little jobs follow ... | |
296 | */ | |
297 | ||
298 | ||
299 | fatal(f, msg) | |
300 | int f; | |
301 | char *msg; | |
302 | { | |
303 | char buf[BUFSIZ]; | |
304 | ||
305 | (void) sprintf(buf, "telnetd: %s.\r\n", msg); | |
306 | (void) write(f, buf, (int)strlen(buf)); | |
307 | sleep(1); /*XXX*/ | |
308 | exit(1); | |
309 | } | |
310 | ||
311 | fatalperror(f, msg) | |
312 | int f; | |
313 | char *msg; | |
314 | { | |
396aa79f | 315 | char buf[BUFSIZ], *strerror(); |
ea139302 | 316 | |
396aa79f | 317 | (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno)); |
ea139302 PB |
318 | fatal(f, buf); |
319 | } | |
320 | ||
321 | char editedhost[32]; | |
322 | ||
323 | edithost(pat, host) | |
324 | register char *pat; | |
325 | register char *host; | |
326 | { | |
327 | register char *res = editedhost; | |
328 | char *strncpy(); | |
329 | ||
330 | if (!pat) | |
331 | pat = ""; | |
332 | while (*pat) { | |
333 | switch (*pat) { | |
334 | ||
335 | case '#': | |
336 | if (*host) | |
337 | host++; | |
338 | break; | |
339 | ||
340 | case '@': | |
341 | if (*host) | |
342 | *res++ = *host++; | |
343 | break; | |
344 | ||
345 | default: | |
346 | *res++ = *pat; | |
347 | break; | |
348 | } | |
349 | if (res == &editedhost[sizeof editedhost - 1]) { | |
350 | *res = '\0'; | |
351 | return; | |
352 | } | |
353 | pat++; | |
354 | } | |
355 | if (*host) | |
356 | (void) strncpy(res, host, | |
357 | sizeof editedhost - (res - editedhost) -1); | |
358 | else | |
359 | *res = '\0'; | |
360 | editedhost[sizeof editedhost - 1] = '\0'; | |
361 | } | |
362 | ||
363 | static char *putlocation; | |
364 | ||
365 | putstr(s) | |
366 | register char *s; | |
367 | { | |
368 | ||
369 | while (*s) | |
370 | putchr(*s++); | |
371 | } | |
372 | ||
373 | putchr(cc) | |
374 | { | |
375 | *putlocation++ = cc; | |
376 | } | |
377 | ||
378 | putf(cp, where) | |
379 | register char *cp; | |
380 | char *where; | |
381 | { | |
977a0c8c KB |
382 | time_t t; |
383 | char *fmt, *slash, db[100]; | |
ea139302 PB |
384 | extern char *rindex(); |
385 | ||
386 | putlocation = where; | |
387 | ||
388 | while (*cp) { | |
389 | if (*cp != '%') { | |
390 | putchr(*cp++); | |
391 | continue; | |
392 | } | |
393 | switch (*++cp) { | |
394 | ||
395 | case 't': | |
396 | slash = rindex(line, '/'); | |
397 | if (slash == (char *) 0) | |
398 | putstr(line); | |
399 | else | |
400 | putstr(&slash[1]); | |
401 | break; | |
402 | ||
403 | case 'h': | |
404 | putstr(editedhost); | |
405 | break; | |
406 | ||
4f73d56c KB |
407 | case 'd': { |
408 | char fmt[] = "%l:% %P on %A, %d %B %Y"; | |
409 | ||
410 | fmt[4] = 'M'; /* I *hate* SCCS... */ | |
977a0c8c | 411 | (void)time(&t); |
4f73d56c | 412 | (void)strftime(db, sizeof(db), fmt, localtime(&t)); |
977a0c8c | 413 | putstr(db); |
ea139302 | 414 | break; |
4f73d56c | 415 | } |
ea139302 PB |
416 | |
417 | case '%': | |
418 | putchr('%'); | |
419 | break; | |
420 | } | |
421 | cp++; | |
422 | } | |
423 | } | |
424 | ||
425 | /*ARGSUSED*/ | |
426 | #ifdef NO_GETTYTAB | |
427 | getent(cp, name) | |
428 | char *cp, *name; | |
429 | { | |
430 | return(0); | |
431 | } | |
432 | ||
433 | /*ARGSUSED*/ | |
434 | char * | |
435 | getstr(cp, cpp) | |
436 | char *cp, **cpp; | |
437 | { | |
438 | return(0); | |
439 | } | |
440 | #endif /* NO_GETTYTAB */ | |
4a8a7128 PB |
441 | |
442 | #ifdef DIAGNOSTICS | |
443 | /* | |
444 | * Print telnet options and commands in plain text, if possible. | |
445 | */ | |
446 | void | |
447 | printoption(fmt, option) | |
448 | register char *fmt; | |
449 | register int option; | |
450 | { | |
451 | if (TELOPT_OK(option)) | |
452 | sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option)); | |
453 | else if (TELCMD_OK(option)) | |
454 | sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option)); | |
455 | else | |
456 | sprintf(nfrontp, "%s %d\r\n", fmt, option); | |
457 | nfrontp += strlen(nfrontp); | |
458 | return; | |
459 | } | |
460 | ||
461 | char *slcnames[] = { SLC_NAMES }; | |
462 | ||
463 | void | |
464 | printsub(dirp, pointer, length) | |
465 | char *dirp; | |
466 | unsigned char *pointer; /* where suboption data sits */ | |
467 | int length; /* length of suboption data */ | |
468 | { | |
469 | register int i; | |
470 | ||
471 | if (dirp) { | |
472 | sprintf(nfrontp, "%s suboption ", dirp); | |
473 | nfrontp += strlen(nfrontp); | |
474 | if (length >= 3) { | |
475 | register int j; | |
476 | ||
477 | i = pointer[length-2]; | |
478 | j = pointer[length-1]; | |
479 | ||
480 | if (i != IAC || j != SE) { | |
481 | sprintf(nfrontp, "(terminated by "); | |
482 | nfrontp += strlen(nfrontp); | |
483 | if (TELOPT_OK(i)) | |
484 | sprintf(nfrontp, "%s ", TELOPT(i)); | |
485 | else if (TELCMD_OK(i)) | |
486 | sprintf(nfrontp, "%s ", TELCMD(i)); | |
487 | else | |
488 | sprintf(nfrontp, "%d ", i); | |
489 | nfrontp += strlen(nfrontp); | |
490 | if (TELOPT_OK(j)) | |
491 | sprintf(nfrontp, "%s", TELOPT(j)); | |
492 | else if (TELCMD_OK(j)) | |
493 | sprintf(nfrontp, "%s", TELCMD(j)); | |
494 | else | |
495 | sprintf(nfrontp, "%d", j); | |
496 | nfrontp += strlen(nfrontp); | |
497 | sprintf(nfrontp, ", not IAC SE!) "); | |
498 | nfrontp += strlen(nfrontp); | |
499 | } | |
500 | } | |
501 | length -= 2; | |
502 | } | |
503 | if (length < 1) { | |
504 | sprintf(nfrontp, "(Empty suboption???)"); | |
505 | nfrontp += strlen(nfrontp); | |
506 | return; | |
507 | } | |
508 | switch (pointer[0]) { | |
509 | case TELOPT_TTYPE: | |
510 | sprintf(nfrontp, "TERMINAL-TYPE "); | |
511 | nfrontp += strlen(nfrontp); | |
512 | switch (pointer[1]) { | |
513 | case TELQUAL_IS: | |
514 | sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); | |
515 | break; | |
516 | case TELQUAL_SEND: | |
517 | sprintf(nfrontp, "SEND"); | |
518 | break; | |
519 | default: | |
520 | sprintf(nfrontp, | |
521 | "- unknown qualifier %d (0x%x).", | |
522 | pointer[1], pointer[1]); | |
523 | } | |
524 | nfrontp += strlen(nfrontp); | |
525 | break; | |
526 | case TELOPT_TSPEED: | |
527 | sprintf(nfrontp, "TERMINAL-SPEED"); | |
528 | nfrontp += strlen(nfrontp); | |
529 | if (length < 2) { | |
530 | sprintf(nfrontp, " (empty suboption???)"); | |
531 | nfrontp += strlen(nfrontp); | |
532 | break; | |
533 | } | |
534 | switch (pointer[1]) { | |
535 | case TELQUAL_IS: | |
536 | sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); | |
537 | nfrontp += strlen(nfrontp); | |
538 | break; | |
539 | default: | |
540 | if (pointer[1] == 1) | |
541 | sprintf(nfrontp, " SEND"); | |
542 | else | |
543 | sprintf(nfrontp, " %d (unknown)", pointer[1]); | |
544 | nfrontp += strlen(nfrontp); | |
545 | for (i = 2; i < length; i++) { | |
546 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
547 | nfrontp += strlen(nfrontp); | |
548 | } | |
549 | break; | |
550 | } | |
551 | break; | |
552 | ||
553 | case TELOPT_LFLOW: | |
554 | sprintf(nfrontp, "TOGGLE-FLOW-CONTROL"); | |
555 | nfrontp += strlen(nfrontp); | |
556 | if (length < 2) { | |
557 | sprintf(nfrontp, " (empty suboption???)"); | |
558 | nfrontp += strlen(nfrontp); | |
559 | break; | |
560 | } | |
561 | switch (pointer[1]) { | |
562 | case 0: | |
563 | sprintf(nfrontp, " OFF"); break; | |
564 | case 1: | |
565 | sprintf(nfrontp, " ON"); break; | |
566 | default: | |
567 | sprintf(nfrontp, " %d (unknown)", pointer[1]); | |
568 | } | |
569 | nfrontp += strlen(nfrontp); | |
570 | for (i = 2; i < length; i++) { | |
571 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
572 | nfrontp += strlen(nfrontp); | |
573 | } | |
574 | break; | |
575 | ||
576 | case TELOPT_NAWS: | |
577 | sprintf(nfrontp, "NAWS"); | |
578 | nfrontp += strlen(nfrontp); | |
579 | if (length < 2) { | |
580 | sprintf(nfrontp, " (empty suboption???)"); | |
581 | nfrontp += strlen(nfrontp); | |
582 | break; | |
583 | } | |
584 | if (length == 2) { | |
585 | sprintf(nfrontp, " ?%d?", pointer[1]); | |
586 | nfrontp += strlen(nfrontp); | |
587 | break; | |
588 | } | |
589 | sprintf(nfrontp, " %d %d (%d)", | |
590 | pointer[1], pointer[2], | |
591 | (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); | |
592 | nfrontp += strlen(nfrontp); | |
593 | if (length == 4) { | |
594 | sprintf(nfrontp, " ?%d?", pointer[3]); | |
595 | nfrontp += strlen(nfrontp); | |
596 | break; | |
597 | } | |
598 | sprintf(nfrontp, " %d %d (%d)", | |
599 | pointer[3], pointer[4], | |
600 | (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); | |
601 | nfrontp += strlen(nfrontp); | |
602 | for (i = 5; i < length; i++) { | |
603 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
604 | nfrontp += strlen(nfrontp); | |
605 | } | |
606 | break; | |
607 | ||
608 | case TELOPT_LINEMODE: | |
609 | sprintf(nfrontp, "LINEMODE "); | |
610 | nfrontp += strlen(nfrontp); | |
611 | if (length < 2) { | |
612 | sprintf(nfrontp, " (empty suboption???)"); | |
613 | nfrontp += strlen(nfrontp); | |
614 | break; | |
615 | } | |
616 | switch (pointer[1]) { | |
617 | case WILL: | |
618 | sprintf(nfrontp, "WILL "); | |
619 | goto common; | |
620 | case WONT: | |
621 | sprintf(nfrontp, "WONT "); | |
622 | goto common; | |
623 | case DO: | |
624 | sprintf(nfrontp, "DO "); | |
625 | goto common; | |
626 | case DONT: | |
627 | sprintf(nfrontp, "DONT "); | |
628 | common: | |
629 | nfrontp += strlen(nfrontp); | |
630 | if (length < 3) { | |
631 | sprintf(nfrontp, "(no option???)"); | |
632 | nfrontp += strlen(nfrontp); | |
633 | break; | |
634 | } | |
635 | switch (pointer[2]) { | |
636 | case LM_FORWARDMASK: | |
637 | sprintf(nfrontp, "Forward Mask"); | |
638 | nfrontp += strlen(nfrontp); | |
639 | for (i = 3; i < length; i++) { | |
640 | sprintf(nfrontp, " %x", pointer[i]); | |
641 | nfrontp += strlen(nfrontp); | |
642 | } | |
643 | break; | |
644 | default: | |
645 | sprintf(nfrontp, "%d (unknown)", pointer[2]); | |
646 | nfrontp += strlen(nfrontp); | |
647 | for (i = 3; i < length; i++) { | |
648 | sprintf(nfrontp, " %d", pointer[i]); | |
649 | nfrontp += strlen(nfrontp); | |
650 | } | |
651 | break; | |
652 | } | |
653 | break; | |
654 | ||
655 | case LM_SLC: | |
656 | sprintf(nfrontp, "SLC"); | |
657 | nfrontp += strlen(nfrontp); | |
658 | for (i = 2; i < length - 2; i += 3) { | |
659 | if (pointer[i+SLC_FUNC] <= NSLC) | |
660 | sprintf(nfrontp, " %s", slcnames[pointer[i+SLC_FUNC]]); | |
661 | else | |
662 | sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]); | |
663 | nfrontp += strlen(nfrontp); | |
664 | switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { | |
665 | case SLC_NOSUPPORT: | |
666 | sprintf(nfrontp, " NOSUPPORT"); break; | |
667 | case SLC_CANTCHANGE: | |
668 | sprintf(nfrontp, " CANTCHANGE"); break; | |
669 | case SLC_VARIABLE: | |
670 | sprintf(nfrontp, " VARIABLE"); break; | |
671 | case SLC_DEFAULT: | |
672 | sprintf(nfrontp, " DEFAULT"); break; | |
673 | } | |
674 | nfrontp += strlen(nfrontp); | |
675 | sprintf(nfrontp, "%s%s%s", | |
676 | pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", | |
677 | pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", | |
678 | pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); | |
679 | nfrontp += strlen(nfrontp); | |
680 | if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| | |
681 | SLC_FLUSHOUT| SLC_LEVELBITS)) { | |
682 | sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]); | |
683 | nfrontp += strlen(nfrontp); | |
684 | } | |
685 | sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]); | |
686 | nfrontp += strlen(nfrontp); | |
687 | if ((pointer[i+SLC_VALUE] == IAC) && | |
688 | (pointer[i+SLC_VALUE+1] == IAC)) | |
689 | i++; | |
690 | } | |
691 | for (; i < length; i++) { | |
692 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
693 | nfrontp += strlen(nfrontp); | |
694 | } | |
695 | break; | |
696 | ||
697 | case LM_MODE: | |
698 | sprintf(nfrontp, "MODE "); | |
699 | nfrontp += strlen(nfrontp); | |
700 | if (length < 3) { | |
701 | sprintf(nfrontp, "(no mode???)"); | |
702 | nfrontp += strlen(nfrontp); | |
703 | break; | |
704 | } | |
705 | { | |
706 | char tbuf[32]; | |
707 | sprintf(tbuf, "%s%s%s%s%s", | |
708 | pointer[2]&MODE_EDIT ? "|EDIT" : "", | |
709 | pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", | |
710 | pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", | |
711 | pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", | |
712 | pointer[2]&MODE_ACK ? "|ACK" : ""); | |
713 | sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0"); | |
714 | nfrontp += strlen(nfrontp); | |
715 | } | |
716 | if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { | |
717 | sprintf(nfrontp, " (0x%x)", pointer[2]); | |
718 | nfrontp += strlen(nfrontp); | |
719 | } | |
720 | for (i = 3; i < length; i++) { | |
721 | sprintf(nfrontp, " ?0x%x?", pointer[i]); | |
722 | nfrontp += strlen(nfrontp); | |
723 | } | |
724 | break; | |
725 | default: | |
726 | sprintf(nfrontp, "%d (unknown)", pointer[1]); | |
727 | nfrontp += strlen(nfrontp); | |
728 | for (i = 2; i < length; i++) { | |
729 | sprintf(nfrontp, " %d", pointer[i]); | |
730 | nfrontp += strlen(nfrontp); | |
731 | } | |
732 | } | |
733 | break; | |
734 | ||
735 | case TELOPT_STATUS: { | |
736 | register char *cp; | |
737 | register int j, k; | |
738 | ||
739 | sprintf(nfrontp, "STATUS"); | |
740 | nfrontp += strlen(nfrontp); | |
741 | ||
742 | switch (pointer[1]) { | |
743 | default: | |
744 | if (pointer[1] == TELQUAL_SEND) | |
745 | sprintf(nfrontp, " SEND"); | |
746 | else | |
747 | sprintf(nfrontp, " %d (unknown)", pointer[1]); | |
748 | nfrontp += strlen(nfrontp); | |
749 | for (i = 2; i < length; i++) { | |
750 | sprintf(nfrontp, " ?%d?", pointer[i]); | |
751 | nfrontp += strlen(nfrontp); | |
752 | } | |
753 | break; | |
754 | case TELQUAL_IS: | |
755 | sprintf(nfrontp, " IS\r\n"); | |
756 | nfrontp += strlen(nfrontp); | |
757 | ||
758 | for (i = 2; i < length; i++) { | |
759 | switch(pointer[i]) { | |
760 | case DO: cp = "DO"; goto common2; | |
761 | case DONT: cp = "DONT"; goto common2; | |
762 | case WILL: cp = "WILL"; goto common2; | |
763 | case WONT: cp = "WONT"; goto common2; | |
764 | common2: | |
765 | i++; | |
766 | if (TELOPT_OK((int)pointer[i])) | |
767 | sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i])); | |
768 | else | |
769 | sprintf(nfrontp, " %s %d", cp, pointer[i]); | |
770 | nfrontp += strlen(nfrontp); | |
771 | ||
772 | sprintf(nfrontp, "\r\n"); | |
773 | nfrontp += strlen(nfrontp); | |
774 | break; | |
775 | ||
776 | case SB: | |
777 | sprintf(nfrontp, " SB "); | |
778 | nfrontp += strlen(nfrontp); | |
779 | i++; | |
780 | j = k = i; | |
781 | while (j < length) { | |
782 | if (pointer[j] == SE) { | |
783 | if (j+1 == length) | |
784 | break; | |
785 | if (pointer[j+1] == SE) | |
786 | j++; | |
787 | else | |
788 | break; | |
789 | } | |
790 | pointer[k++] = pointer[j++]; | |
791 | } | |
792 | printsub(0, &pointer[i], k - i); | |
793 | if (i < length) { | |
794 | sprintf(nfrontp, " SE"); | |
795 | nfrontp += strlen(nfrontp); | |
796 | i = j; | |
797 | } else | |
798 | i = j - 1; | |
799 | ||
800 | sprintf(nfrontp, "\r\n"); | |
801 | nfrontp += strlen(nfrontp); | |
802 | ||
803 | break; | |
804 | ||
805 | default: | |
806 | sprintf(nfrontp, " %d", pointer[i]); | |
807 | nfrontp += strlen(nfrontp); | |
808 | break; | |
809 | } | |
810 | } | |
811 | break; | |
812 | } | |
813 | break; | |
814 | } | |
815 | ||
816 | case TELOPT_XDISPLOC: | |
817 | sprintf(nfrontp, "X-DISPLAY-LOCATION "); | |
818 | nfrontp += strlen(nfrontp); | |
819 | switch (pointer[1]) { | |
820 | case TELQUAL_IS: | |
821 | sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); | |
822 | break; | |
823 | case TELQUAL_SEND: | |
824 | sprintf(nfrontp, "SEND"); | |
825 | break; | |
826 | default: | |
827 | sprintf(nfrontp, "- unknown qualifier %d (0x%x).", | |
828 | pointer[1], pointer[1]); | |
829 | } | |
830 | nfrontp += strlen(nfrontp); | |
831 | break; | |
832 | ||
833 | case TELOPT_ENVIRON: | |
834 | sprintf(nfrontp, "ENVIRON "); | |
835 | nfrontp += strlen(nfrontp); | |
836 | switch (pointer[1]) { | |
837 | case TELQUAL_IS: | |
838 | sprintf(nfrontp, "IS "); | |
839 | goto env_common; | |
840 | case TELQUAL_SEND: | |
841 | sprintf(nfrontp, "SEND "); | |
842 | goto env_common; | |
843 | case TELQUAL_INFO: | |
844 | sprintf(nfrontp, "INFO "); | |
845 | env_common: | |
846 | nfrontp += strlen(nfrontp); | |
847 | { | |
848 | register int noquote = 2; | |
849 | for (i = 2; i < length; i++ ) { | |
850 | switch (pointer[i]) { | |
851 | case ENV_VAR: | |
852 | if (pointer[1] == TELQUAL_SEND) | |
853 | goto def_case; | |
854 | sprintf(nfrontp, "\" VAR " + noquote); | |
855 | nfrontp += strlen(nfrontp); | |
856 | noquote = 2; | |
857 | break; | |
858 | ||
859 | case ENV_VALUE: | |
860 | sprintf(nfrontp, "\" VALUE " + noquote); | |
861 | nfrontp += strlen(nfrontp); | |
862 | noquote = 2; | |
863 | break; | |
864 | ||
865 | case ENV_ESC: | |
866 | sprintf(nfrontp, "\" ESC " + noquote); | |
867 | nfrontp += strlen(nfrontp); | |
868 | noquote = 2; | |
869 | break; | |
870 | ||
871 | default: | |
872 | def_case: | |
873 | if (isprint(pointer[i]) && pointer[i] != '"') { | |
874 | if (noquote) { | |
875 | *nfrontp++ = '"'; | |
876 | noquote = 0; | |
877 | } | |
878 | *nfrontp++ = pointer[i]; | |
879 | } else { | |
880 | sprintf(nfrontp, "\" %03o " + noquote, | |
881 | pointer[i]); | |
882 | nfrontp += strlen(nfrontp); | |
883 | noquote = 2; | |
884 | } | |
885 | break; | |
886 | } | |
887 | } | |
888 | if (!noquote) | |
889 | *nfrontp++ = '"'; | |
890 | break; | |
891 | } | |
892 | } | |
893 | break; | |
894 | ||
895 | default: | |
896 | sprintf(nfrontp, "Unknown option "); | |
897 | nfrontp += strlen(nfrontp); | |
898 | for (i = 0; i < length; i++) { | |
899 | sprintf(nfrontp, " %d", pointer[i]); | |
900 | nfrontp += strlen(nfrontp); | |
901 | } | |
902 | break; | |
903 | } | |
904 | sprintf(nfrontp, "\r\n"); | |
905 | nfrontp += strlen(nfrontp); | |
906 | } | |
907 | ||
908 | /* | |
909 | * Dump a data buffer in hex and ascii to the output data stream. | |
910 | */ | |
911 | void | |
912 | printdata(tag, ptr, cnt) | |
913 | register char *tag; | |
914 | register char *ptr; | |
915 | register int cnt; | |
916 | { | |
917 | register int i; | |
918 | char xbuf[30]; | |
919 | ||
920 | while (cnt) { | |
921 | /* flush net output buffer if no room for new data) */ | |
922 | if ((&netobuf[BUFSIZ] - nfrontp) < 80) { | |
923 | netflush(); | |
924 | } | |
925 | ||
926 | /* add a line of output */ | |
927 | sprintf(nfrontp, "%s: ", tag); | |
928 | nfrontp += strlen(nfrontp); | |
929 | for (i = 0; i < 20 && cnt; i++) { | |
930 | sprintf(nfrontp, "%02x", *ptr); | |
931 | nfrontp += strlen(nfrontp); | |
932 | if (isprint(*ptr)) { | |
933 | xbuf[i] = *ptr; | |
934 | } else { | |
935 | xbuf[i] = '.'; | |
936 | } | |
937 | if (i % 2) { | |
938 | *nfrontp = ' '; | |
939 | nfrontp++; | |
940 | } | |
941 | cnt--; | |
942 | ptr++; | |
943 | } | |
944 | xbuf[i] = '\0'; | |
945 | sprintf(nfrontp, " %s\r\n", xbuf ); | |
946 | nfrontp += strlen(nfrontp); | |
947 | } | |
948 | } | |
949 | ||
950 | #endif /* DIAGNOSTICS */ | |
951 | ||
952 | #ifdef NO_STRERROR | |
953 | char * | |
954 | strerror(errno) | |
955 | { | |
956 | extern char *sys_errlist[]; | |
957 | ||
958 | return(sys_errlist[errno]); | |
959 | } | |
960 | #endif |