138905Sborman /* 238905Sborman * Copyright (c) 1989 Regents of the University of California. 338905Sborman * All rights reserved. 438905Sborman * 542673Sbostic * %sccs.include.redist.c% 638905Sborman */ 738905Sborman 838905Sborman #ifndef lint 9*44364Sborman static char sccsid[] = "@(#)utility.c 5.4 (Berkeley) 06/28/90"; 1038905Sborman #endif /* not lint */ 1138905Sborman 12*44364Sborman #define PRINTOPTIONS 1338905Sborman #include "telnetd.h" 1438905Sborman 1538905Sborman /* 1638905Sborman * utility functions performing io related tasks 1738905Sborman */ 1838905Sborman 1938905Sborman /* 2038905Sborman * ttloop 2138905Sborman * 2238905Sborman * A small subroutine to flush the network output buffer, get some data 2338905Sborman * from the network, and pass it through the telnet state machine. We 2438905Sborman * also flush the pty input buffer (by dropping its data) if it becomes 2538905Sborman * too full. 2638905Sborman */ 2738905Sborman 2838905Sborman void 2938905Sborman ttloop() 3038905Sborman { 3138905Sborman void netflush(); 3238905Sborman 33*44364Sborman #ifdef DIAGNOSTICS 34*44364Sborman if (diagnostic & TD_REPORT) { 35*44364Sborman sprintf(nfrontp, "td: ttloop\r\n"); 36*44364Sborman nfrontp += strlen(nfrontp); 37*44364Sborman } 38*44364Sborman #endif /* DIAGNOSTICS */ 3938905Sborman if (nfrontp-nbackp) { 4038905Sborman netflush(); 4138905Sborman } 4238905Sborman ncc = read(net, netibuf, sizeof netibuf); 4338905Sborman if (ncc < 0) { 4438905Sborman syslog(LOG_INFO, "ttloop: read: %m\n"); 4538905Sborman exit(1); 4638905Sborman } else if (ncc == 0) { 4738905Sborman syslog(LOG_INFO, "ttloop: peer died: %m\n"); 4838905Sborman exit(1); 4938905Sborman } 50*44364Sborman #ifdef DIAGNOSTICS 51*44364Sborman if (diagnostic & TD_REPORT) { 52*44364Sborman sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc); 53*44364Sborman nfrontp += strlen(nfrontp); 54*44364Sborman } 55*44364Sborman #endif /* DIAGNOSTICS */ 5638905Sborman netip = netibuf; 5738905Sborman telrcv(); /* state machine */ 5838905Sborman if (ncc > 0) { 5938905Sborman pfrontp = pbackp = ptyobuf; 6038905Sborman telrcv(); 6138905Sborman } 6238905Sborman } /* end of ttloop */ 6338905Sborman 6438905Sborman /* 6538905Sborman * Check a descriptor to see if out of band data exists on it. 6638905Sborman */ 6738905Sborman stilloob(s) 6838905Sborman int s; /* socket number */ 6938905Sborman { 7038905Sborman static struct timeval timeout = { 0 }; 7138905Sborman fd_set excepts; 7238905Sborman int value; 7338905Sborman 7438905Sborman do { 7538905Sborman FD_ZERO(&excepts); 7638905Sborman FD_SET(s, &excepts); 7738905Sborman value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 7838905Sborman } while ((value == -1) && (errno == EINTR)); 7938905Sborman 8038905Sborman if (value < 0) { 8138905Sborman fatalperror(pty, "select"); 8238905Sborman } 8338905Sborman if (FD_ISSET(s, &excepts)) { 8438905Sborman return 1; 8538905Sborman } else { 8638905Sborman return 0; 8738905Sborman } 8838905Sborman } 8938905Sborman 9038905Sborman ptyflush() 9138905Sborman { 9238905Sborman int n; 9338905Sborman 94*44364Sborman if ((n = pfrontp - pbackp) > 0) { 95*44364Sborman #ifdef DIAGNOSTICS 96*44364Sborman if (diagnostic & (TD_REPORT | TD_PTYDATA)) { 97*44364Sborman sprintf(nfrontp, "td: ptyflush %d chars\r\n", n); 98*44364Sborman nfrontp += strlen(nfrontp); 99*44364Sborman } 100*44364Sborman if (diagnostic & TD_PTYDATA) { 101*44364Sborman printdata("pd", pbackp, n); 102*44364Sborman } 103*44364Sborman #endif /* DIAGNOSTICS */ 10438905Sborman n = write(pty, pbackp, n); 105*44364Sborman } 10638905Sborman if (n < 0) 10738905Sborman return; 10838905Sborman pbackp += n; 10938905Sborman if (pbackp == pfrontp) 11038905Sborman pbackp = pfrontp = ptyobuf; 11138905Sborman } 11238905Sborman 11338905Sborman /* 11438905Sborman * nextitem() 11538905Sborman * 11638905Sborman * Return the address of the next "item" in the TELNET data 11738905Sborman * stream. This will be the address of the next character if 11838905Sborman * the current address is a user data character, or it will 11938905Sborman * be the address of the character following the TELNET command 12038905Sborman * if the current address is a TELNET IAC ("I Am a Command") 12138905Sborman * character. 12238905Sborman */ 12338905Sborman char * 12438905Sborman nextitem(current) 12538905Sborman char *current; 12638905Sborman { 12738905Sborman if ((*current&0xff) != IAC) { 12838905Sborman return current+1; 12938905Sborman } 13038905Sborman switch (*(current+1)&0xff) { 13138905Sborman case DO: 13238905Sborman case DONT: 13338905Sborman case WILL: 13438905Sborman case WONT: 13538905Sborman return current+3; 13638905Sborman case SB: /* loop forever looking for the SE */ 13738905Sborman { 13838905Sborman register char *look = current+2; 13938905Sborman 14038905Sborman for (;;) { 14138905Sborman if ((*look++&0xff) == IAC) { 14238905Sborman if ((*look++&0xff) == SE) { 14338905Sborman return look; 14438905Sborman } 14538905Sborman } 14638905Sborman } 14738905Sborman } 14838905Sborman default: 14938905Sborman return current+2; 15038905Sborman } 15138905Sborman } /* end of nextitem */ 15238905Sborman 15338905Sborman 15438905Sborman /* 15538905Sborman * netclear() 15638905Sborman * 15738905Sborman * We are about to do a TELNET SYNCH operation. Clear 15838905Sborman * the path to the network. 15938905Sborman * 16038905Sborman * Things are a bit tricky since we may have sent the first 16138905Sborman * byte or so of a previous TELNET command into the network. 16238905Sborman * So, we have to scan the network buffer from the beginning 16338905Sborman * until we are up to where we want to be. 16438905Sborman * 16538905Sborman * A side effect of what we do, just to keep things 16638905Sborman * simple, is to clear the urgent data pointer. The principal 16738905Sborman * caller should be setting the urgent data pointer AFTER calling 16838905Sborman * us in any case. 16938905Sborman */ 17038905Sborman netclear() 17138905Sborman { 17238905Sborman register char *thisitem, *next; 17338905Sborman char *good; 17438905Sborman #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 17538905Sborman ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 17638905Sborman 17738905Sborman thisitem = netobuf; 17838905Sborman 17938905Sborman while ((next = nextitem(thisitem)) <= nbackp) { 18038905Sborman thisitem = next; 18138905Sborman } 18238905Sborman 18338905Sborman /* Now, thisitem is first before/at boundary. */ 18438905Sborman 18538905Sborman good = netobuf; /* where the good bytes go */ 18638905Sborman 18738905Sborman while (nfrontp > thisitem) { 18838905Sborman if (wewant(thisitem)) { 18938905Sborman int length; 19038905Sborman 19138905Sborman next = thisitem; 19238905Sborman do { 19338905Sborman next = nextitem(next); 19438905Sborman } while (wewant(next) && (nfrontp > next)); 19538905Sborman length = next-thisitem; 19638905Sborman bcopy(thisitem, good, length); 19738905Sborman good += length; 19838905Sborman thisitem = next; 19938905Sborman } else { 20038905Sborman thisitem = nextitem(thisitem); 20138905Sborman } 20238905Sborman } 20338905Sborman 20438905Sborman nbackp = netobuf; 20538905Sborman nfrontp = good; /* next byte to be sent */ 20638905Sborman neturg = 0; 20738905Sborman } /* end of netclear */ 20838905Sborman 20938905Sborman /* 21038905Sborman * netflush 21138905Sborman * Send as much data as possible to the network, 21238905Sborman * handling requests for urgent data. 21338905Sborman */ 21438905Sborman void 21538905Sborman netflush() 21638905Sborman { 21738905Sborman int n; 21838905Sborman extern int not42; 21938905Sborman 22038905Sborman if ((n = nfrontp - nbackp) > 0) { 221*44364Sborman #ifdef DIAGNOSTICS 222*44364Sborman if (diagnostic & TD_REPORT) { 223*44364Sborman sprintf(nfrontp, "td: netflush %d chars\r\n", n); 224*44364Sborman n += strlen(nfrontp); /* get count first */ 225*44364Sborman nfrontp += strlen(nfrontp); /* then move pointer */ 226*44364Sborman } 227*44364Sborman #endif /* DIAGNOSTICS */ 22838905Sborman /* 22938905Sborman * if no urgent data, or if the other side appears to be an 23038905Sborman * old 4.2 client (and thus unable to survive TCP urgent data), 23138905Sborman * write the entire buffer in non-OOB mode. 23238905Sborman */ 23338905Sborman if ((neturg == 0) || (not42 == 0)) { 23438905Sborman n = write(net, nbackp, n); /* normal write */ 23538905Sborman } else { 23638905Sborman n = neturg - nbackp; 23738905Sborman /* 23838905Sborman * In 4.2 (and 4.3) systems, there is some question about 23938905Sborman * what byte in a sendOOB operation is the "OOB" data. 24038905Sborman * To make ourselves compatible, we only send ONE byte 24138905Sborman * out of band, the one WE THINK should be OOB (though 24238905Sborman * we really have more the TCP philosophy of urgent data 24338905Sborman * rather than the Unix philosophy of OOB data). 24438905Sborman */ 24538905Sborman if (n > 1) { 24638905Sborman n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 24738905Sborman } else { 24838905Sborman n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 24938905Sborman } 25038905Sborman } 25138905Sborman } 25238905Sborman if (n < 0) { 25338905Sborman if (errno == EWOULDBLOCK || errno == EINTR) 25438905Sborman return; 25538905Sborman cleanup(); 25638905Sborman } 25738905Sborman nbackp += n; 25838905Sborman if (nbackp >= neturg) { 25938905Sborman neturg = 0; 26038905Sborman } 26138905Sborman if (nbackp == nfrontp) { 26238905Sborman nbackp = nfrontp = netobuf; 26338905Sborman } 26438905Sborman return; 26538905Sborman } /* end of netflush */ 26638905Sborman 26738905Sborman 26838905Sborman /* 26938905Sborman * writenet 27038905Sborman * 27138905Sborman * Just a handy little function to write a bit of raw data to the net. 27238905Sborman * It will force a transmit of the buffer if necessary 27338905Sborman * 27438905Sborman * arguments 27538905Sborman * ptr - A pointer to a character string to write 27638905Sborman * len - How many bytes to write 27738905Sborman */ 27838905Sborman writenet(ptr, len) 27938905Sborman register char *ptr; 28038905Sborman register int len; 28138905Sborman { 28238905Sborman /* flush buffer if no room for new data) */ 28338905Sborman if ((&netobuf[BUFSIZ] - nfrontp) < len) { 28438905Sborman /* if this fails, don't worry, buffer is a little big */ 28538905Sborman netflush(); 28638905Sborman } 28738905Sborman 28838905Sborman bcopy(ptr, nfrontp, len); 28938905Sborman nfrontp += len; 29038905Sborman 29138905Sborman } /* end of writenet */ 29238905Sborman 29338905Sborman 29438905Sborman /* 29538905Sborman * miscellaneous functions doing a variety of little jobs follow ... 29638905Sborman */ 29738905Sborman 29838905Sborman 29938905Sborman fatal(f, msg) 30038905Sborman int f; 30138905Sborman char *msg; 30238905Sborman { 30338905Sborman char buf[BUFSIZ]; 30438905Sborman 30538905Sborman (void) sprintf(buf, "telnetd: %s.\r\n", msg); 30638905Sborman (void) write(f, buf, (int)strlen(buf)); 30738905Sborman sleep(1); /*XXX*/ 30838905Sborman exit(1); 30938905Sborman } 31038905Sborman 31138905Sborman fatalperror(f, msg) 31238905Sborman int f; 31338905Sborman char *msg; 31438905Sborman { 31542411Sbostic char buf[BUFSIZ], *strerror(); 31638905Sborman 31742411Sbostic (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno)); 31838905Sborman fatal(f, buf); 31938905Sborman } 32038905Sborman 32138905Sborman char editedhost[32]; 32238905Sborman 32338905Sborman edithost(pat, host) 32438905Sborman register char *pat; 32538905Sborman register char *host; 32638905Sborman { 32738905Sborman register char *res = editedhost; 32838905Sborman char *strncpy(); 32938905Sborman 33038905Sborman if (!pat) 33138905Sborman pat = ""; 33238905Sborman while (*pat) { 33338905Sborman switch (*pat) { 33438905Sborman 33538905Sborman case '#': 33638905Sborman if (*host) 33738905Sborman host++; 33838905Sborman break; 33938905Sborman 34038905Sborman case '@': 34138905Sborman if (*host) 34238905Sborman *res++ = *host++; 34338905Sborman break; 34438905Sborman 34538905Sborman default: 34638905Sborman *res++ = *pat; 34738905Sborman break; 34838905Sborman } 34938905Sborman if (res == &editedhost[sizeof editedhost - 1]) { 35038905Sborman *res = '\0'; 35138905Sborman return; 35238905Sborman } 35338905Sborman pat++; 35438905Sborman } 35538905Sborman if (*host) 35638905Sborman (void) strncpy(res, host, 35738905Sborman sizeof editedhost - (res - editedhost) -1); 35838905Sborman else 35938905Sborman *res = '\0'; 36038905Sborman editedhost[sizeof editedhost - 1] = '\0'; 36138905Sborman } 36238905Sborman 36338905Sborman static char *putlocation; 36438905Sborman 36538905Sborman putstr(s) 36638905Sborman register char *s; 36738905Sborman { 36838905Sborman 36938905Sborman while (*s) 37038905Sborman putchr(*s++); 37138905Sborman } 37238905Sborman 37338905Sborman putchr(cc) 37438905Sborman { 37538905Sborman *putlocation++ = cc; 37638905Sborman } 37738905Sborman 37838905Sborman putf(cp, where) 37938905Sborman register char *cp; 38038905Sborman char *where; 38138905Sborman { 38238905Sborman char *slash; 38338905Sborman #ifndef NO_GETTYTAB 38438905Sborman char datebuffer[60]; 38538905Sborman #endif /* NO_GETTYTAB */ 38638905Sborman extern char *rindex(); 38738905Sborman 38838905Sborman putlocation = where; 38938905Sborman 39038905Sborman while (*cp) { 39138905Sborman if (*cp != '%') { 39238905Sborman putchr(*cp++); 39338905Sborman continue; 39438905Sborman } 39538905Sborman switch (*++cp) { 39638905Sborman 39738905Sborman case 't': 39838905Sborman slash = rindex(line, '/'); 39938905Sborman if (slash == (char *) 0) 40038905Sborman putstr(line); 40138905Sborman else 40238905Sborman putstr(&slash[1]); 40338905Sborman break; 40438905Sborman 40538905Sborman case 'h': 40638905Sborman putstr(editedhost); 40738905Sborman break; 40838905Sborman 40938905Sborman #ifndef NO_GETTYTAB 41038905Sborman case 'd': 41138905Sborman get_date(datebuffer); 41238905Sborman putstr(datebuffer); 41338905Sborman break; 41438905Sborman #endif /* NO_GETTYTAB */ 41538905Sborman 41638905Sborman case '%': 41738905Sborman putchr('%'); 41838905Sborman break; 41938905Sborman } 42038905Sborman cp++; 42138905Sborman } 42238905Sborman } 42338905Sborman 42438905Sborman /*ARGSUSED*/ 42538905Sborman #ifdef NO_GETTYTAB 42638905Sborman getent(cp, name) 42738905Sborman char *cp, *name; 42838905Sborman { 42938905Sborman return(0); 43038905Sborman } 43138905Sborman 43238905Sborman /*ARGSUSED*/ 43338905Sborman char * 43438905Sborman getstr(cp, cpp) 43538905Sborman char *cp, **cpp; 43638905Sborman { 43738905Sborman return(0); 43838905Sborman } 43938905Sborman #endif /* NO_GETTYTAB */ 440*44364Sborman 441*44364Sborman #ifdef DIAGNOSTICS 442*44364Sborman /* 443*44364Sborman * Print telnet options and commands in plain text, if possible. 444*44364Sborman */ 445*44364Sborman void 446*44364Sborman printoption(fmt, option) 447*44364Sborman register char *fmt; 448*44364Sborman register int option; 449*44364Sborman { 450*44364Sborman if (TELOPT_OK(option)) 451*44364Sborman sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option)); 452*44364Sborman else if (TELCMD_OK(option)) 453*44364Sborman sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option)); 454*44364Sborman else 455*44364Sborman sprintf(nfrontp, "%s %d\r\n", fmt, option); 456*44364Sborman nfrontp += strlen(nfrontp); 457*44364Sborman return; 458*44364Sborman } 459*44364Sborman 460*44364Sborman char *slcnames[] = { SLC_NAMES }; 461*44364Sborman 462*44364Sborman void 463*44364Sborman printsub(dirp, pointer, length) 464*44364Sborman char *dirp; 465*44364Sborman unsigned char *pointer; /* where suboption data sits */ 466*44364Sborman int length; /* length of suboption data */ 467*44364Sborman { 468*44364Sborman register int i; 469*44364Sborman 470*44364Sborman if (dirp) { 471*44364Sborman sprintf(nfrontp, "%s suboption ", dirp); 472*44364Sborman nfrontp += strlen(nfrontp); 473*44364Sborman if (length >= 3) { 474*44364Sborman register int j; 475*44364Sborman 476*44364Sborman i = pointer[length-2]; 477*44364Sborman j = pointer[length-1]; 478*44364Sborman 479*44364Sborman if (i != IAC || j != SE) { 480*44364Sborman sprintf(nfrontp, "(terminated by "); 481*44364Sborman nfrontp += strlen(nfrontp); 482*44364Sborman if (TELOPT_OK(i)) 483*44364Sborman sprintf(nfrontp, "%s ", TELOPT(i)); 484*44364Sborman else if (TELCMD_OK(i)) 485*44364Sborman sprintf(nfrontp, "%s ", TELCMD(i)); 486*44364Sborman else 487*44364Sborman sprintf(nfrontp, "%d ", i); 488*44364Sborman nfrontp += strlen(nfrontp); 489*44364Sborman if (TELOPT_OK(j)) 490*44364Sborman sprintf(nfrontp, "%s", TELOPT(j)); 491*44364Sborman else if (TELCMD_OK(j)) 492*44364Sborman sprintf(nfrontp, "%s", TELCMD(j)); 493*44364Sborman else 494*44364Sborman sprintf(nfrontp, "%d", j); 495*44364Sborman nfrontp += strlen(nfrontp); 496*44364Sborman sprintf(nfrontp, ", not IAC SE!) "); 497*44364Sborman nfrontp += strlen(nfrontp); 498*44364Sborman } 499*44364Sborman } 500*44364Sborman length -= 2; 501*44364Sborman } 502*44364Sborman if (length < 1) { 503*44364Sborman sprintf(nfrontp, "(Empty suboption???)"); 504*44364Sborman nfrontp += strlen(nfrontp); 505*44364Sborman return; 506*44364Sborman } 507*44364Sborman switch (pointer[0]) { 508*44364Sborman case TELOPT_TTYPE: 509*44364Sborman sprintf(nfrontp, "TERMINAL-TYPE "); 510*44364Sborman nfrontp += strlen(nfrontp); 511*44364Sborman switch (pointer[1]) { 512*44364Sborman case TELQUAL_IS: 513*44364Sborman sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); 514*44364Sborman break; 515*44364Sborman case TELQUAL_SEND: 516*44364Sborman sprintf(nfrontp, "SEND"); 517*44364Sborman break; 518*44364Sborman default: 519*44364Sborman sprintf(nfrontp, 520*44364Sborman "- unknown qualifier %d (0x%x).", 521*44364Sborman pointer[1], pointer[1]); 522*44364Sborman } 523*44364Sborman nfrontp += strlen(nfrontp); 524*44364Sborman break; 525*44364Sborman case TELOPT_TSPEED: 526*44364Sborman sprintf(nfrontp, "TERMINAL-SPEED"); 527*44364Sborman nfrontp += strlen(nfrontp); 528*44364Sborman if (length < 2) { 529*44364Sborman sprintf(nfrontp, " (empty suboption???)"); 530*44364Sborman nfrontp += strlen(nfrontp); 531*44364Sborman break; 532*44364Sborman } 533*44364Sborman switch (pointer[1]) { 534*44364Sborman case TELQUAL_IS: 535*44364Sborman sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); 536*44364Sborman nfrontp += strlen(nfrontp); 537*44364Sborman break; 538*44364Sborman default: 539*44364Sborman if (pointer[1] == 1) 540*44364Sborman sprintf(nfrontp, " SEND"); 541*44364Sborman else 542*44364Sborman sprintf(nfrontp, " %d (unknown)", pointer[1]); 543*44364Sborman nfrontp += strlen(nfrontp); 544*44364Sborman for (i = 2; i < length; i++) { 545*44364Sborman sprintf(nfrontp, " ?%d?", pointer[i]); 546*44364Sborman nfrontp += strlen(nfrontp); 547*44364Sborman } 548*44364Sborman break; 549*44364Sborman } 550*44364Sborman break; 551*44364Sborman 552*44364Sborman case TELOPT_LFLOW: 553*44364Sborman sprintf(nfrontp, "TOGGLE-FLOW-CONTROL"); 554*44364Sborman nfrontp += strlen(nfrontp); 555*44364Sborman if (length < 2) { 556*44364Sborman sprintf(nfrontp, " (empty suboption???)"); 557*44364Sborman nfrontp += strlen(nfrontp); 558*44364Sborman break; 559*44364Sborman } 560*44364Sborman switch (pointer[1]) { 561*44364Sborman case 0: 562*44364Sborman sprintf(nfrontp, " OFF"); break; 563*44364Sborman case 1: 564*44364Sborman sprintf(nfrontp, " ON"); break; 565*44364Sborman default: 566*44364Sborman sprintf(nfrontp, " %d (unknown)", pointer[1]); 567*44364Sborman } 568*44364Sborman nfrontp += strlen(nfrontp); 569*44364Sborman for (i = 2; i < length; i++) { 570*44364Sborman sprintf(nfrontp, " ?%d?", pointer[i]); 571*44364Sborman nfrontp += strlen(nfrontp); 572*44364Sborman } 573*44364Sborman break; 574*44364Sborman 575*44364Sborman case TELOPT_NAWS: 576*44364Sborman sprintf(nfrontp, "NAWS"); 577*44364Sborman nfrontp += strlen(nfrontp); 578*44364Sborman if (length < 2) { 579*44364Sborman sprintf(nfrontp, " (empty suboption???)"); 580*44364Sborman nfrontp += strlen(nfrontp); 581*44364Sborman break; 582*44364Sborman } 583*44364Sborman if (length == 2) { 584*44364Sborman sprintf(nfrontp, " ?%d?", pointer[1]); 585*44364Sborman nfrontp += strlen(nfrontp); 586*44364Sborman break; 587*44364Sborman } 588*44364Sborman sprintf(nfrontp, " %d %d (%d)", 589*44364Sborman pointer[1], pointer[2], 590*44364Sborman (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); 591*44364Sborman nfrontp += strlen(nfrontp); 592*44364Sborman if (length == 4) { 593*44364Sborman sprintf(nfrontp, " ?%d?", pointer[3]); 594*44364Sborman nfrontp += strlen(nfrontp); 595*44364Sborman break; 596*44364Sborman } 597*44364Sborman sprintf(nfrontp, " %d %d (%d)", 598*44364Sborman pointer[3], pointer[4], 599*44364Sborman (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); 600*44364Sborman nfrontp += strlen(nfrontp); 601*44364Sborman for (i = 5; i < length; i++) { 602*44364Sborman sprintf(nfrontp, " ?%d?", pointer[i]); 603*44364Sborman nfrontp += strlen(nfrontp); 604*44364Sborman } 605*44364Sborman break; 606*44364Sborman 607*44364Sborman case TELOPT_LINEMODE: 608*44364Sborman sprintf(nfrontp, "LINEMODE "); 609*44364Sborman nfrontp += strlen(nfrontp); 610*44364Sborman if (length < 2) { 611*44364Sborman sprintf(nfrontp, " (empty suboption???)"); 612*44364Sborman nfrontp += strlen(nfrontp); 613*44364Sborman break; 614*44364Sborman } 615*44364Sborman switch (pointer[1]) { 616*44364Sborman case WILL: 617*44364Sborman sprintf(nfrontp, "WILL "); 618*44364Sborman goto common; 619*44364Sborman case WONT: 620*44364Sborman sprintf(nfrontp, "WONT "); 621*44364Sborman goto common; 622*44364Sborman case DO: 623*44364Sborman sprintf(nfrontp, "DO "); 624*44364Sborman goto common; 625*44364Sborman case DONT: 626*44364Sborman sprintf(nfrontp, "DONT "); 627*44364Sborman common: 628*44364Sborman nfrontp += strlen(nfrontp); 629*44364Sborman if (length < 3) { 630*44364Sborman sprintf(nfrontp, "(no option???)"); 631*44364Sborman nfrontp += strlen(nfrontp); 632*44364Sborman break; 633*44364Sborman } 634*44364Sborman switch (pointer[2]) { 635*44364Sborman case LM_FORWARDMASK: 636*44364Sborman sprintf(nfrontp, "Forward Mask"); 637*44364Sborman nfrontp += strlen(nfrontp); 638*44364Sborman for (i = 3; i < length; i++) { 639*44364Sborman sprintf(nfrontp, " %x", pointer[i]); 640*44364Sborman nfrontp += strlen(nfrontp); 641*44364Sborman } 642*44364Sborman break; 643*44364Sborman default: 644*44364Sborman sprintf(nfrontp, "%d (unknown)", pointer[2]); 645*44364Sborman nfrontp += strlen(nfrontp); 646*44364Sborman for (i = 3; i < length; i++) { 647*44364Sborman sprintf(nfrontp, " %d", pointer[i]); 648*44364Sborman nfrontp += strlen(nfrontp); 649*44364Sborman } 650*44364Sborman break; 651*44364Sborman } 652*44364Sborman break; 653*44364Sborman 654*44364Sborman case LM_SLC: 655*44364Sborman sprintf(nfrontp, "SLC"); 656*44364Sborman nfrontp += strlen(nfrontp); 657*44364Sborman for (i = 2; i < length - 2; i += 3) { 658*44364Sborman if (pointer[i+SLC_FUNC] <= NSLC) 659*44364Sborman sprintf(nfrontp, " %s", slcnames[pointer[i+SLC_FUNC]]); 660*44364Sborman else 661*44364Sborman sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]); 662*44364Sborman nfrontp += strlen(nfrontp); 663*44364Sborman switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 664*44364Sborman case SLC_NOSUPPORT: 665*44364Sborman sprintf(nfrontp, " NOSUPPORT"); break; 666*44364Sborman case SLC_CANTCHANGE: 667*44364Sborman sprintf(nfrontp, " CANTCHANGE"); break; 668*44364Sborman case SLC_VARIABLE: 669*44364Sborman sprintf(nfrontp, " VARIABLE"); break; 670*44364Sborman case SLC_DEFAULT: 671*44364Sborman sprintf(nfrontp, " DEFAULT"); break; 672*44364Sborman } 673*44364Sborman nfrontp += strlen(nfrontp); 674*44364Sborman sprintf(nfrontp, "%s%s%s", 675*44364Sborman pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 676*44364Sborman pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 677*44364Sborman pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 678*44364Sborman nfrontp += strlen(nfrontp); 679*44364Sborman if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 680*44364Sborman SLC_FLUSHOUT| SLC_LEVELBITS)) { 681*44364Sborman sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]); 682*44364Sborman nfrontp += strlen(nfrontp); 683*44364Sborman } 684*44364Sborman sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]); 685*44364Sborman nfrontp += strlen(nfrontp); 686*44364Sborman if ((pointer[i+SLC_VALUE] == IAC) && 687*44364Sborman (pointer[i+SLC_VALUE+1] == IAC)) 688*44364Sborman i++; 689*44364Sborman } 690*44364Sborman for (; i < length; i++) { 691*44364Sborman sprintf(nfrontp, " ?%d?", pointer[i]); 692*44364Sborman nfrontp += strlen(nfrontp); 693*44364Sborman } 694*44364Sborman break; 695*44364Sborman 696*44364Sborman case LM_MODE: 697*44364Sborman sprintf(nfrontp, "MODE "); 698*44364Sborman nfrontp += strlen(nfrontp); 699*44364Sborman if (length < 3) { 700*44364Sborman sprintf(nfrontp, "(no mode???)"); 701*44364Sborman nfrontp += strlen(nfrontp); 702*44364Sborman break; 703*44364Sborman } 704*44364Sborman { 705*44364Sborman char tbuf[32]; 706*44364Sborman sprintf(tbuf, "%s%s%s%s%s", 707*44364Sborman pointer[2]&MODE_EDIT ? "|EDIT" : "", 708*44364Sborman pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 709*44364Sborman pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 710*44364Sborman pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 711*44364Sborman pointer[2]&MODE_ACK ? "|ACK" : ""); 712*44364Sborman sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0"); 713*44364Sborman nfrontp += strlen(nfrontp); 714*44364Sborman } 715*44364Sborman if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 716*44364Sborman sprintf(nfrontp, " (0x%x)", pointer[2]); 717*44364Sborman nfrontp += strlen(nfrontp); 718*44364Sborman } 719*44364Sborman for (i = 3; i < length; i++) { 720*44364Sborman sprintf(nfrontp, " ?0x%x?", pointer[i]); 721*44364Sborman nfrontp += strlen(nfrontp); 722*44364Sborman } 723*44364Sborman break; 724*44364Sborman default: 725*44364Sborman sprintf(nfrontp, "%d (unknown)", pointer[1]); 726*44364Sborman nfrontp += strlen(nfrontp); 727*44364Sborman for (i = 2; i < length; i++) { 728*44364Sborman sprintf(nfrontp, " %d", pointer[i]); 729*44364Sborman nfrontp += strlen(nfrontp); 730*44364Sborman } 731*44364Sborman } 732*44364Sborman break; 733*44364Sborman 734*44364Sborman case TELOPT_STATUS: { 735*44364Sborman register char *cp; 736*44364Sborman register int j, k; 737*44364Sborman 738*44364Sborman sprintf(nfrontp, "STATUS"); 739*44364Sborman nfrontp += strlen(nfrontp); 740*44364Sborman 741*44364Sborman switch (pointer[1]) { 742*44364Sborman default: 743*44364Sborman if (pointer[1] == TELQUAL_SEND) 744*44364Sborman sprintf(nfrontp, " SEND"); 745*44364Sborman else 746*44364Sborman sprintf(nfrontp, " %d (unknown)", pointer[1]); 747*44364Sborman nfrontp += strlen(nfrontp); 748*44364Sborman for (i = 2; i < length; i++) { 749*44364Sborman sprintf(nfrontp, " ?%d?", pointer[i]); 750*44364Sborman nfrontp += strlen(nfrontp); 751*44364Sborman } 752*44364Sborman break; 753*44364Sborman case TELQUAL_IS: 754*44364Sborman sprintf(nfrontp, " IS\r\n"); 755*44364Sborman nfrontp += strlen(nfrontp); 756*44364Sborman 757*44364Sborman for (i = 2; i < length; i++) { 758*44364Sborman switch(pointer[i]) { 759*44364Sborman case DO: cp = "DO"; goto common2; 760*44364Sborman case DONT: cp = "DONT"; goto common2; 761*44364Sborman case WILL: cp = "WILL"; goto common2; 762*44364Sborman case WONT: cp = "WONT"; goto common2; 763*44364Sborman common2: 764*44364Sborman i++; 765*44364Sborman if (TELOPT_OK((int)pointer[i])) 766*44364Sborman sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i])); 767*44364Sborman else 768*44364Sborman sprintf(nfrontp, " %s %d", cp, pointer[i]); 769*44364Sborman nfrontp += strlen(nfrontp); 770*44364Sborman 771*44364Sborman sprintf(nfrontp, "\r\n"); 772*44364Sborman nfrontp += strlen(nfrontp); 773*44364Sborman break; 774*44364Sborman 775*44364Sborman case SB: 776*44364Sborman sprintf(nfrontp, " SB "); 777*44364Sborman nfrontp += strlen(nfrontp); 778*44364Sborman i++; 779*44364Sborman j = k = i; 780*44364Sborman while (j < length) { 781*44364Sborman if (pointer[j] == SE) { 782*44364Sborman if (j+1 == length) 783*44364Sborman break; 784*44364Sborman if (pointer[j+1] == SE) 785*44364Sborman j++; 786*44364Sborman else 787*44364Sborman break; 788*44364Sborman } 789*44364Sborman pointer[k++] = pointer[j++]; 790*44364Sborman } 791*44364Sborman printsub(0, &pointer[i], k - i); 792*44364Sborman if (i < length) { 793*44364Sborman sprintf(nfrontp, " SE"); 794*44364Sborman nfrontp += strlen(nfrontp); 795*44364Sborman i = j; 796*44364Sborman } else 797*44364Sborman i = j - 1; 798*44364Sborman 799*44364Sborman sprintf(nfrontp, "\r\n"); 800*44364Sborman nfrontp += strlen(nfrontp); 801*44364Sborman 802*44364Sborman break; 803*44364Sborman 804*44364Sborman default: 805*44364Sborman sprintf(nfrontp, " %d", pointer[i]); 806*44364Sborman nfrontp += strlen(nfrontp); 807*44364Sborman break; 808*44364Sborman } 809*44364Sborman } 810*44364Sborman break; 811*44364Sborman } 812*44364Sborman break; 813*44364Sborman } 814*44364Sborman 815*44364Sborman case TELOPT_XDISPLOC: 816*44364Sborman sprintf(nfrontp, "X-DISPLAY-LOCATION "); 817*44364Sborman nfrontp += strlen(nfrontp); 818*44364Sborman switch (pointer[1]) { 819*44364Sborman case TELQUAL_IS: 820*44364Sborman sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); 821*44364Sborman break; 822*44364Sborman case TELQUAL_SEND: 823*44364Sborman sprintf(nfrontp, "SEND"); 824*44364Sborman break; 825*44364Sborman default: 826*44364Sborman sprintf(nfrontp, "- unknown qualifier %d (0x%x).", 827*44364Sborman pointer[1], pointer[1]); 828*44364Sborman } 829*44364Sborman nfrontp += strlen(nfrontp); 830*44364Sborman break; 831*44364Sborman 832*44364Sborman case TELOPT_ENVIRON: 833*44364Sborman sprintf(nfrontp, "ENVIRON "); 834*44364Sborman nfrontp += strlen(nfrontp); 835*44364Sborman switch (pointer[1]) { 836*44364Sborman case TELQUAL_IS: 837*44364Sborman sprintf(nfrontp, "IS "); 838*44364Sborman goto env_common; 839*44364Sborman case TELQUAL_SEND: 840*44364Sborman sprintf(nfrontp, "SEND "); 841*44364Sborman goto env_common; 842*44364Sborman case TELQUAL_INFO: 843*44364Sborman sprintf(nfrontp, "INFO "); 844*44364Sborman env_common: 845*44364Sborman nfrontp += strlen(nfrontp); 846*44364Sborman { 847*44364Sborman register int noquote = 2; 848*44364Sborman for (i = 2; i < length; i++ ) { 849*44364Sborman switch (pointer[i]) { 850*44364Sborman case ENV_VAR: 851*44364Sborman if (pointer[1] == TELQUAL_SEND) 852*44364Sborman goto def_case; 853*44364Sborman sprintf(nfrontp, "\" VAR " + noquote); 854*44364Sborman nfrontp += strlen(nfrontp); 855*44364Sborman noquote = 2; 856*44364Sborman break; 857*44364Sborman 858*44364Sborman case ENV_VALUE: 859*44364Sborman sprintf(nfrontp, "\" VALUE " + noquote); 860*44364Sborman nfrontp += strlen(nfrontp); 861*44364Sborman noquote = 2; 862*44364Sborman break; 863*44364Sborman 864*44364Sborman case ENV_ESC: 865*44364Sborman sprintf(nfrontp, "\" ESC " + noquote); 866*44364Sborman nfrontp += strlen(nfrontp); 867*44364Sborman noquote = 2; 868*44364Sborman break; 869*44364Sborman 870*44364Sborman default: 871*44364Sborman def_case: 872*44364Sborman if (isprint(pointer[i]) && pointer[i] != '"') { 873*44364Sborman if (noquote) { 874*44364Sborman *nfrontp++ = '"'; 875*44364Sborman noquote = 0; 876*44364Sborman } 877*44364Sborman *nfrontp++ = pointer[i]; 878*44364Sborman } else { 879*44364Sborman sprintf(nfrontp, "\" %03o " + noquote, 880*44364Sborman pointer[i]); 881*44364Sborman nfrontp += strlen(nfrontp); 882*44364Sborman noquote = 2; 883*44364Sborman } 884*44364Sborman break; 885*44364Sborman } 886*44364Sborman } 887*44364Sborman if (!noquote) 888*44364Sborman *nfrontp++ = '"'; 889*44364Sborman break; 890*44364Sborman } 891*44364Sborman } 892*44364Sborman break; 893*44364Sborman 894*44364Sborman default: 895*44364Sborman sprintf(nfrontp, "Unknown option "); 896*44364Sborman nfrontp += strlen(nfrontp); 897*44364Sborman for (i = 0; i < length; i++) { 898*44364Sborman sprintf(nfrontp, " %d", pointer[i]); 899*44364Sborman nfrontp += strlen(nfrontp); 900*44364Sborman } 901*44364Sborman break; 902*44364Sborman } 903*44364Sborman sprintf(nfrontp, "\r\n"); 904*44364Sborman nfrontp += strlen(nfrontp); 905*44364Sborman } 906*44364Sborman 907*44364Sborman /* 908*44364Sborman * Dump a data buffer in hex and ascii to the output data stream. 909*44364Sborman */ 910*44364Sborman void 911*44364Sborman printdata(tag, ptr, cnt) 912*44364Sborman register char *tag; 913*44364Sborman register char *ptr; 914*44364Sborman register int cnt; 915*44364Sborman { 916*44364Sborman register int i; 917*44364Sborman char xbuf[30]; 918*44364Sborman 919*44364Sborman while (cnt) { 920*44364Sborman /* flush net output buffer if no room for new data) */ 921*44364Sborman if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 922*44364Sborman netflush(); 923*44364Sborman } 924*44364Sborman 925*44364Sborman /* add a line of output */ 926*44364Sborman sprintf(nfrontp, "%s: ", tag); 927*44364Sborman nfrontp += strlen(nfrontp); 928*44364Sborman for (i = 0; i < 20 && cnt; i++) { 929*44364Sborman sprintf(nfrontp, "%02x", *ptr); 930*44364Sborman nfrontp += strlen(nfrontp); 931*44364Sborman if (isprint(*ptr)) { 932*44364Sborman xbuf[i] = *ptr; 933*44364Sborman } else { 934*44364Sborman xbuf[i] = '.'; 935*44364Sborman } 936*44364Sborman if (i % 2) { 937*44364Sborman *nfrontp = ' '; 938*44364Sborman nfrontp++; 939*44364Sborman } 940*44364Sborman cnt--; 941*44364Sborman ptr++; 942*44364Sborman } 943*44364Sborman xbuf[i] = '\0'; 944*44364Sborman sprintf(nfrontp, " %s\r\n", xbuf ); 945*44364Sborman nfrontp += strlen(nfrontp); 946*44364Sborman } 947*44364Sborman } 948*44364Sborman 949*44364Sborman #endif /* DIAGNOSTICS */ 950*44364Sborman 951*44364Sborman #ifdef NO_STRERROR 952*44364Sborman char * 953*44364Sborman strerror(errno) 954*44364Sborman { 955*44364Sborman extern char *sys_errlist[]; 956*44364Sborman 957*44364Sborman return(sys_errlist[errno]); 958*44364Sborman } 959*44364Sborman #endif 960