xref: /csrg-svn/usr.bin/telnet/utilities.c (revision 42770)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)utilities.c	1.17 (Berkeley) 06/01/90";
10 #endif /* not lint */
11 
12 #define	TELOPTS
13 #define	TELCMDS
14 #include <arpa/telnet.h>
15 #include <sys/types.h>
16 
17 #include <ctype.h>
18 
19 #include "general.h"
20 
21 #include "fdset.h"
22 
23 #include "ring.h"
24 
25 #include "defines.h"
26 
27 #include "externs.h"
28 
29 FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
30 int	prettydump;
31 
32 /*
33  * upcase()
34  *
35  *	Upcase (in place) the argument.
36  */
37 
38 void
39 upcase(argument)
40 register char *argument;
41 {
42     register int c;
43 
44     while ((c = *argument) != 0) {
45 	if (islower(c)) {
46 	    *argument = toupper(c);
47 	}
48 	argument++;
49     }
50 }
51 
52 /*
53  * SetSockOpt()
54  *
55  * Compensate for differences in 4.2 and 4.3 systems.
56  */
57 
58 int
59 SetSockOpt(fd, level, option, yesno)
60 int
61 	fd,
62 	level,
63 	option,
64 	yesno;
65 {
66 #ifndef	NOT43
67     return setsockopt(fd, level, option,
68 				(char *)&yesno, sizeof yesno);
69 #else	/* NOT43 */
70     if (yesno == 0) {		/* Can't do that in 4.2! */
71 	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
72 				option);
73 	return -1;
74     }
75     return setsockopt(fd, level, option, 0, 0);
76 #endif	/* NOT43 */
77 }
78 
79 /*
80  * The following are routines used to print out debugging information.
81  */
82 
83 unsigned char NetTraceFile[256] = "(standard output)";
84 
85 void
86 SetNetTrace(file)
87 register char *file;
88 {
89     if (NetTrace && NetTrace != stdout)
90 	fclose(NetTrace);
91     if (file  && (strcmp(file, "-") != 0)) {
92 	NetTrace = fopen(file, "w");
93 	if (NetTrace) {
94 	    strcpy(NetTraceFile, file);
95 	    return;
96 	}
97 	fprintf(stderr, "Cannot open %s.\n", file);
98     }
99     NetTrace = stdout;
100     strcpy(NetTraceFile, "(standard output)");
101 }
102 
103 void
104 Dump(direction, buffer, length)
105 char	direction;
106 char	*buffer;
107 int	length;
108 {
109 #   define BYTES_PER_LINE	32
110 #   define min(x,y)	((x<y)? x:y)
111     char *pThis;
112     int offset;
113     extern pettydump;
114 
115     offset = 0;
116 
117     while (length) {
118 	/* print one line */
119 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
120 	pThis = buffer;
121 	if (prettydump) {
122 	    buffer = buffer + min(length, BYTES_PER_LINE/2);
123 	    while (pThis < buffer) {
124 		fprintf(NetTrace, "%c%.2x",
125 		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
126 		    (*pThis)&0xff);
127 		pThis++;
128 	    }
129 	    length -= BYTES_PER_LINE/2;
130 	    offset += BYTES_PER_LINE/2;
131 	} else {
132 	    buffer = buffer + min(length, BYTES_PER_LINE);
133 	    while (pThis < buffer) {
134 		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
135 		pThis++;
136 	    }
137 	    length -= BYTES_PER_LINE;
138 	    offset += BYTES_PER_LINE;
139 	}
140 	if (NetTrace == stdout) {
141 	    fprintf(NetTrace, "\r\n");
142 	} else {
143 	    fprintf(NetTrace, "\n");
144 	}
145 	if (length < 0) {
146 	    fflush(NetTrace);
147 	    return;
148 	}
149 	/* find next unique line */
150     }
151     fflush(NetTrace);
152 }
153 
154 
155 void
156 printoption(direction, fmt, option)
157 	char *direction, *fmt;
158 	int option;
159 {
160 	if (!showoptions)
161 		return;
162 	fprintf(NetTrace, "%s ", direction);
163 	if (TELOPT_OK(option))
164 		fprintf(NetTrace, "%s %s", fmt, TELOPT(option));
165 	else if (TELCMD_OK(option))
166 		fprintf(NetTrace, "%s %s", fmt, TELCMD(option));
167 	else
168 		fprintf(NetTrace, "%s %d", fmt, option);
169 	if (NetTrace == stdout)
170 	    fprintf(NetTrace, "\r\n");
171 	else
172 	    fprintf(NetTrace, "\n");
173 	return;
174 }
175 
176 optionstatus()
177 {
178     register int i;
179     extern char will_wont_resp[], do_dont_resp[];
180 
181     for (i = 0; i < 256; i++) {
182 	if (do_dont_resp[i]) {
183 	    if (TELOPT_OK(i))
184 		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
185 	    else if (TELCMD_OK(i))
186 		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
187 	    else
188 		printf("resp DO_DONT %d: %d\n", i,
189 				do_dont_resp[i]);
190 	    if (my_want_state_is_do(i)) {
191 		if (TELOPT_OK(i))
192 		    printf("want DO   %s\n", TELOPT(i));
193 		else if (TELCMD_OK(i))
194 		    printf("want DO   %s\n", TELCMD(i));
195 		else
196 		    printf("want DO   %d\n", i);
197 	    } else {
198 		if (TELOPT_OK(i))
199 		    printf("want DONT %s\n", TELOPT(i));
200 		else if (TELCMD_OK(i))
201 		    printf("want DONT %s\n", TELCMD(i));
202 		else
203 		    printf("want DONT %d\n", i);
204 	    }
205 	} else {
206 	    if (my_state_is_do(i)) {
207 		if (TELOPT_OK(i))
208 		    printf("     DO   %s\n", TELOPT(i));
209 		else if (TELCMD_OK(i))
210 		    printf("     DO   %s\n", TELCMD(i));
211 		else
212 		    printf("     DO   %d\n", i);
213 	    }
214 	}
215 	if (will_wont_resp[i]) {
216 	    if (TELOPT_OK(i))
217 		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
218 	    else if (TELCMD_OK(i))
219 		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
220 	    else
221 		printf("resp WILL_WONT %d: %d\n",
222 				i, will_wont_resp[i]);
223 	    if (my_want_state_is_will(i)) {
224 		if (TELOPT_OK(i))
225 		    printf("want WILL %s\n", TELOPT(i));
226 		else if (TELCMD_OK(i))
227 		    printf("want WILL %s\n", TELCMD(i));
228 		else
229 		    printf("want WILL %d\n", i);
230 	    } else {
231 		if (TELOPT_OK(i))
232 		    printf("want WONT %s\n", TELOPT(i));
233 		else if (TELCMD_OK(i))
234 		    printf("want WONT %s\n", TELCMD(i));
235 		else
236 		    printf("want WONT %d\n", i);
237 	    }
238 	} else {
239 	    if (my_state_is_will(i)) {
240 		if (TELOPT_OK(i))
241 		    printf("     WILL %s\n", TELOPT(i));
242 		else if (TELCMD_OK(i))
243 		    printf("     WILL %s\n", TELCMD(i));
244 		else
245 		    printf("     WILL %d\n", i);
246 	    }
247 	}
248     }
249 
250 }
251 
252 char *slcnames[] = { SLC_NAMES };
253 
254 void
255 printsub(direction, pointer, length)
256 char	direction;		/* '<' or '>' */
257 unsigned char	*pointer;	/* where suboption data sits */
258 int	length;			/* length of suboption data */
259 {
260     register int i;
261 
262     if (showoptions) {
263 	if (direction) {
264 	    fprintf(NetTrace, "%s suboption ",
265 				(direction == '<')? "Received":"Sent");
266 	    if (length >= 3) {
267 		register int j;
268 
269 		i = pointer[length-2];
270 		j = pointer[length-1];
271 
272 		if (i != IAC || j != SE) {
273 		    fprintf(NetTrace, "(terminated by ");
274 		    if (TELOPT_OK(i))
275 			fprintf(NetTrace, "%s ", TELOPT(i));
276 		    else if (TELCMD_OK(i))
277 			fprintf(NetTrace, "%s ", TELCMD(i));
278 		    else
279 			fprintf(NetTrace, "%d ", i);
280 		    if (TELOPT_OK(j))
281 			fprintf(NetTrace, "%s", TELOPT(j));
282 		    else if (TELCMD_OK(j))
283 			fprintf(NetTrace, "%s", TELCMD(j));
284 		    else
285 			fprintf(NetTrace, "%d", j);
286 		    fprintf(NetTrace, ", not IAC SE!) ");
287 		}
288 	    }
289 	    length -= 2;
290 	}
291 	if (length < 1) {
292 	    fprintf(NetTrace, "(Empty suboption???)");
293 	    return;
294 	}
295 	switch (pointer[0]) {
296 	case TELOPT_TTYPE:
297 	    fprintf(NetTrace, "TERMINAL-TYPE ");
298 	    switch (pointer[1]) {
299 	    case TELQUAL_IS:
300 		fprintf(NetTrace, "IS \"%.*s\"", length-2, pointer+2);
301 		break;
302 	    case TELQUAL_SEND:
303 		fprintf(NetTrace, "SEND");
304 		break;
305 	    default:
306 		fprintf(NetTrace,
307 				"- unknown qualifier %d (0x%x).",
308 				pointer[1], pointer[1]);
309 	    }
310 	    break;
311 	case TELOPT_TSPEED:
312 	    fprintf(NetTrace, "TERMINAL-SPEED");
313 	    if (length < 2) {
314 		fprintf(NetTrace, " (empty suboption???)");
315 		break;
316 	    }
317 	    switch (pointer[1]) {
318 	    case TELQUAL_IS:
319 		fprintf(NetTrace, " IS ");
320 		fprintf(NetTrace, "%.*s", length-2, pointer+2);
321 		break;
322 	    default:
323 		if (pointer[1] == 1)
324 		    fprintf(NetTrace, " SEND");
325 		else
326 		    fprintf(NetTrace, " %d (unknown)");
327 		for (i = 2; i < length; i++)
328 		    fprintf(NetTrace, " ?%d?", pointer[i]);
329 		break;
330 	    }
331 	    break;
332 
333 	case TELOPT_LFLOW:
334 	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
335 	    if (length < 2) {
336 		fprintf(NetTrace, " (empty suboption???)");
337 		break;
338 	    }
339 	    switch (pointer[1]) {
340 	    case 0:
341 		fprintf(NetTrace, " OFF"); break;
342 	    case 1:
343 		fprintf(NetTrace, " ON"); break;
344 	    default:
345 		fprintf(NetTrace, " %d (unknown)");
346 	    }
347 	    for (i = 2; i < length; i++)
348 		fprintf(NetTrace, " ?%d?", pointer[i]);
349 	    break;
350 
351 	case TELOPT_NAWS:
352 	    fprintf(NetTrace, "NAWS");
353 	    if (length < 2) {
354 		fprintf(NetTrace, " (empty suboption???)");
355 		break;
356 	    }
357 	    if (length == 2) {
358 		fprintf(NetTrace, " ?%d?", pointer[1]);
359 		break;
360 	    }
361 	    fprintf(NetTrace, " %d %d (%d)",
362 		pointer[1], pointer[2],
363 		(((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]));
364 	    if (length == 4) {
365 		fprintf(NetTrace, " ?%d?", pointer[3]);
366 		break;
367 	    }
368 	    fprintf(NetTrace, " %d %d (%d)",
369 		pointer[3], pointer[4],
370 		(((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]));
371 	    for (i = 5; i < length; i++)
372 		fprintf(NetTrace, " ?%d?", pointer[i]);
373 	    break;
374 
375 	case TELOPT_LINEMODE:
376 	    fprintf(NetTrace, "LINEMODE ");
377 	    if (length < 2) {
378 		fprintf(NetTrace, " (empty suboption???)");
379 		break;
380 	    }
381 	    switch (pointer[1]) {
382 	    case WILL:
383 		fprintf(NetTrace, "WILL ");
384 		goto common;
385 	    case WONT:
386 		fprintf(NetTrace, "WONT ");
387 		goto common;
388 	    case DO:
389 		fprintf(NetTrace, "DO ");
390 		goto common;
391 	    case DONT:
392 		fprintf(NetTrace, "DONT ");
393 	    common:
394 		if (length < 3) {
395 		    fprintf(NetTrace, "(no option???)");
396 		    break;
397 		}
398 		switch (pointer[2]) {
399 		case LM_FORWARDMASK:
400 		    fprintf(NetTrace, "Forward Mask");
401 		    for (i = 3; i < length; i++)
402 			fprintf(NetTrace, " %x", pointer[i]);
403 		    break;
404 		default:
405 		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
406 		    for (i = 3; i < length; i++)
407 			fprintf(NetTrace, " %d", pointer[i]);
408 		    break;
409 		}
410 		break;
411 
412 	    case LM_SLC:
413 		fprintf(NetTrace, "SLC");
414 		for (i = 2; i < length - 2; i += 3) {
415 		    if (pointer[i+SLC_FUNC] <= NSLC)
416 			fprintf(NetTrace, " %s", slcnames[pointer[i+SLC_FUNC]]);
417 		    else
418 			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
419 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
420 		    case SLC_NOSUPPORT:
421 			fprintf(NetTrace, " NOSUPPORT"); break;
422 		    case SLC_CANTCHANGE:
423 			fprintf(NetTrace, " CANTCHANGE"); break;
424 		    case SLC_VARIABLE:
425 			fprintf(NetTrace, " VARIABLE"); break;
426 		    case SLC_DEFAULT:
427 			fprintf(NetTrace, " DEFAULT"); break;
428 		    }
429 		    fprintf(NetTrace, "%s%s%s",
430 			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
431 			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
432 			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
433 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
434 						SLC_FLUSHOUT| SLC_LEVELBITS))
435 			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
436 		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
437 		}
438 		for (; i < length; i++)
439 		    fprintf(NetTrace, " ?%d?", pointer[i]);
440 		break;
441 
442 	    case LM_MODE:
443 		fprintf(NetTrace, "MODE ");
444 		if (length < 3) {
445 		    fprintf(NetTrace, "(no mode???)");
446 		    break;
447 		}
448 		{
449 		    char tbuf[32];
450 		    sprintf(tbuf, "%s%s%s",
451 			pointer[2]&MODE_EDIT ? "|EDIT" : "",
452 			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
453 			pointer[2]&MODE_ACK ? "|ACK" : "");
454 		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
455 		}
456 		if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
457 		    fprintf(NetTrace, " (0x%x)", pointer[2]);
458 		for (i = 3; i < length; i++)
459 		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
460 		break;
461 	    default:
462 		fprintf(NetTrace, "%d (unknown)", pointer[1]);
463 		for (i = 2; i < length; i++)
464 		    fprintf(NetTrace, " %d", pointer[i]);
465 	    }
466 	    break;
467 
468 	case TELOPT_STATUS: {
469 	    register char *cp;
470 	    register int j, k;
471 
472 	    fprintf(NetTrace, "STATUS");
473 
474 	    switch (pointer[1]) {
475 	    default:
476 		if (pointer[1] == TELQUAL_SEND)
477 		    fprintf(NetTrace, " SEND");
478 		else
479 		    fprintf(NetTrace, " %d (unknown)");
480 		for (i = 2; i < length; i++)
481 		    fprintf(NetTrace, " ?%d?", pointer[i]);
482 		break;
483 	    case TELQUAL_IS:
484 		if (NetTrace == stdout)
485 		    fprintf(NetTrace, " IS\r\n");
486 		else
487 		    fprintf(NetTrace, " IS\n");
488 
489 		for (i = 2; i < length; i++) {
490 		    switch(pointer[i]) {
491 		    case DO:	cp = "DO"; goto common2;
492 		    case DONT:	cp = "DONT"; goto common2;
493 		    case WILL:	cp = "WILL"; goto common2;
494 		    case WONT:	cp = "WONT"; goto common2;
495 		    common2:
496 			i++;
497 			if (TELOPT_OK(pointer[i]))
498 			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
499 			else
500 			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
501 
502 			if (NetTrace == stdout)
503 			    fprintf(NetTrace, "\r\n");
504 			else
505 			    fprintf(NetTrace, "\n");
506 			break;
507 
508 		    case SB:
509 			fprintf(NetTrace, " SB ");
510 			i++;
511 			j = k = i;
512 			while (j < length) {
513 			    if (pointer[j] == SE) {
514 				if (j+1 == length)
515 				    break;
516 				if (pointer[j+1] == SE)
517 				    j++;
518 				else
519 				    break;
520 			    }
521 			    pointer[k++] = pointer[j++];
522 			}
523 			printsub(0, &pointer[i], k - i);
524 			if (i < length) {
525 			    fprintf(NetTrace, " SE");
526 			    i = j;
527 			} else
528 			    i = j - 1;
529 
530 			if (NetTrace == stdout)
531 			    fprintf(NetTrace, "\r\n");
532 			else
533 			    fprintf(NetTrace, "\n");
534 
535 			break;
536 
537 		    default:
538 			fprintf(NetTrace, " %d", pointer[i]);
539 			break;
540 		    }
541 		}
542 		break;
543 	    }
544 	    break;
545 	  }
546 
547 	default:
548 	    fprintf(NetTrace, "Unknown option ");
549 	    for (i = 0; i < length; i++)
550 		fprintf(NetTrace, " %d", pointer[i]);
551 	    break;
552 	}
553 	if (direction) {
554 	    if (NetTrace == stdout)
555 		fprintf(NetTrace, "\r\n");
556 	    else
557 		fprintf(NetTrace, "\n");
558 	}
559     }
560 }
561 
562 /* EmptyTerminal - called to make sure that the terminal buffer is empty.
563  *			Note that we consider the buffer to run all the
564  *			way to the kernel (thus the select).
565  */
566 
567 void
568 EmptyTerminal()
569 {
570 #if	defined(unix)
571     fd_set	o;
572 
573     FD_ZERO(&o);
574 #endif	/* defined(unix) */
575 
576     if (TTYBYTES() == 0) {
577 #if	defined(unix)
578 	FD_SET(tout, &o);
579 	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
580 			(struct timeval *) 0);	/* wait for TTLOWAT */
581 #endif	/* defined(unix) */
582     } else {
583 	while (TTYBYTES()) {
584 	    ttyflush(0);
585 #if	defined(unix)
586 	    FD_SET(tout, &o);
587 	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
588 				(struct timeval *) 0);	/* wait for TTLOWAT */
589 #endif	/* defined(unix) */
590 	}
591     }
592 }
593 
594 void
595 SetForExit()
596 {
597     setconnmode(0);
598 #if	defined(TN3270)
599     if (In3270) {
600 	Finish3270();
601     }
602 #else	/* defined(TN3270) */
603     do {
604 	telrcv();			/* Process any incoming data */
605 	EmptyTerminal();
606     } while (ring_full_count(&netiring));	/* While there is any */
607 #endif	/* defined(TN3270) */
608     setcommandmode();
609     fflush(stdout);
610     fflush(stderr);
611 #if	defined(TN3270)
612     if (In3270) {
613 	StopScreen(1);
614     }
615 #endif	/* defined(TN3270) */
616     setconnmode(0);
617     EmptyTerminal();			/* Flush the path to the tty */
618     setcommandmode();
619 }
620 
621 void
622 Exit(returnCode)
623 int returnCode;
624 {
625     SetForExit();
626     exit(returnCode);
627 }
628 
629 void
630 ExitString(string, returnCode)
631 char *string;
632 int returnCode;
633 {
634     SetForExit();
635     fwrite(string, 1, strlen(string), stderr);
636     exit(returnCode);
637 }
638