utility.c revision 72445
1261081Sasomers/* 2261081Sasomers * Copyright (c) 1989, 1993 3261081Sasomers * The Regents of the University of California. All rights reserved. 4261081Sasomers * 5261081Sasomers * Redistribution and use in source and binary forms, with or without 6261081Sasomers * modification, are permitted provided that the following conditions 7261081Sasomers * are met: 8261081Sasomers * 1. Redistributions of source code must retain the above copyright 9261081Sasomers * notice, this list of conditions and the following disclaimer. 10261081Sasomers * 2. Redistributions in binary form must reproduce the above copyright 11261081Sasomers * notice, this list of conditions and the following disclaimer in the 12261081Sasomers * documentation and/or other materials provided with the distribution. 13261081Sasomers * 3. All advertising materials mentioning features or use of this software 14261081Sasomers * must display the following acknowledgement: 15261081Sasomers * This product includes software developed by the University of 16261081Sasomers * California, Berkeley and its contributors. 17261081Sasomers * 4. Neither the name of the University nor the names of its contributors 18261081Sasomers * may be used to endorse or promote products derived from this software 19261081Sasomers * without specific prior written permission. 20261081Sasomers * 21261081Sasomers * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22261081Sasomers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23261081Sasomers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24261081Sasomers * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25261081Sasomers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26261081Sasomers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27261081Sasomers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28261081Sasomers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29261081Sasomers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30261081Sasomers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31261081Sasomers * SUCH DAMAGE. 32261081Sasomers */ 33261081Sasomers 34261081Sasomers#define PRINTOPTIONS 35261081Sasomers#include "telnetd.h" 36261081Sasomers 37261081SasomersRCSID("$Id: utility.c,v 1.23 2000/10/08 13:34:27 assar Exp $"); 38261081Sasomers 39261081Sasomers/* 40261081Sasomers * utility functions performing io related tasks 41261081Sasomers */ 42261081Sasomers 43261081Sasomers/* 44261081Sasomers * ttloop 45261081Sasomers * 46262894Sasomers * A small subroutine to flush the network output buffer, get some 47261081Sasomers * data from the network, and pass it through the telnet state 48261081Sasomers * machine. We also flush the pty input buffer (by dropping its data) 49261081Sasomers * if it becomes too full. 50261081Sasomers * 51261081Sasomers * return 0 if OK or 1 if interrupted by a signal. 52261081Sasomers */ 53261081Sasomers 54261081Sasomersint 55261081Sasomersttloop(void) 56261081Sasomers{ 57261081Sasomers void netflush(void); 58262894Sasomers 59261081Sasomers DIAG(TD_REPORT, { 60261081Sasomers output_data("td: ttloop\r\n"); 61261081Sasomers }); 62261081Sasomers if (nfrontp-nbackp) 63261081Sasomers netflush(); 64261081Sasomers ncc = read(net, netibuf, sizeof netibuf); 65261081Sasomers if (ncc < 0) { 66261081Sasomers if (errno == EINTR) 67261081Sasomers return 1; 68261081Sasomers syslog(LOG_INFO, "ttloop: read: %m\n"); 69261081Sasomers exit(1); 70261081Sasomers } else if (ncc == 0) { 71261081Sasomers syslog(LOG_INFO, "ttloop: peer died\n"); 72261081Sasomers exit(1); 73261081Sasomers } 74261081Sasomers DIAG(TD_REPORT, { 75261081Sasomers output_data("td: ttloop read %d chars\r\n", ncc); 76262894Sasomers }); 77261081Sasomers netip = netibuf; 78261081Sasomers telrcv(); /* state machine */ 79261081Sasomers if (ncc > 0) { 80261081Sasomers pfrontp = pbackp = ptyobuf; 81261081Sasomers telrcv(); 82261081Sasomers } 83261081Sasomers return 0; 84261081Sasomers} /* end of ttloop */ 85261081Sasomers 86261081Sasomers/* 87261081Sasomers * Check a descriptor to see if out of band data exists on it. 88261081Sasomers */ 89261081Sasomersint 90261081Sasomersstilloob(int s) 91261081Sasomers{ 92261081Sasomers static struct timeval timeout = { 0 }; 93261081Sasomers fd_set excepts; 94261081Sasomers int value; 95261081Sasomers 96261081Sasomers if (s >= FD_SETSIZE) 97261081Sasomers fatal(ourpty, "fd too large"); 98261081Sasomers 99261081Sasomers do { 100261081Sasomers FD_ZERO(&excepts); 101261081Sasomers FD_SET(s, &excepts); 102261081Sasomers value = select(s+1, 0, 0, &excepts, &timeout); 103261081Sasomers } while ((value == -1) && (errno == EINTR)); 104261081Sasomers 105261081Sasomers if (value < 0) { 106261081Sasomers fatalperror(ourpty, "select"); 107261081Sasomers } 108261081Sasomers if (FD_ISSET(s, &excepts)) { 109261081Sasomers return 1; 110261081Sasomers } else { 111261081Sasomers return 0; 112261081Sasomers } 113270228Sasomers} 114270228Sasomers 115270228Sasomersvoid 116261081Sasomersptyflush(void) 117261081Sasomers{ 118261081Sasomers int n; 119261081Sasomers 120261081Sasomers if ((n = pfrontp - pbackp) > 0) { 121262894Sasomers DIAG((TD_REPORT | TD_PTYDATA), { 122261081Sasomers output_data("td: ptyflush %d chars\r\n", n); 123261081Sasomers }); 124261081Sasomers DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); 125261081Sasomers n = write(ourpty, pbackp, n); 126261081Sasomers } 127261081Sasomers if (n < 0) { 128261081Sasomers if (errno == EWOULDBLOCK || errno == EINTR) 129262894Sasomers return; 130261081Sasomers cleanup(0); 131261081Sasomers } 132261081Sasomers pbackp += n; 133261081Sasomers if (pbackp == pfrontp) 134261081Sasomers pbackp = pfrontp = ptyobuf; 135261081Sasomers} 136262894Sasomers 137261081Sasomers/* 138262894Sasomers * nextitem() 139261081Sasomers * 140261081Sasomers * Return the address of the next "item" in the TELNET data 141262133Sasomers * stream. This will be the address of the next character if 142261081Sasomers * the current address is a user data character, or it will 143261081Sasomers * be the address of the character following the TELNET command 144261081Sasomers * if the current address is a TELNET IAC ("I Am a Command") 145261081Sasomers * character. 146261081Sasomers */ 147261081Sasomerschar * 148261081Sasomersnextitem(char *current) 149261081Sasomers{ 150262894Sasomers if ((*current&0xff) != IAC) { 151261081Sasomers return current+1; 152261081Sasomers } 153270228Sasomers switch (*(current+1)&0xff) { 154270228Sasomers case DO: 155270228Sasomers case DONT: 156261081Sasomers case WILL: 157270228Sasomers case WONT: 158261081Sasomers return current+3; 159261081Sasomers case SB:{ 160261081Sasomers /* loop forever looking for the SE */ 161261081Sasomers char *look = current+2; 162261081Sasomers 163261081Sasomers for (;;) { 164261081Sasomers if ((*look++&0xff) == IAC) { 165261081Sasomers if ((*look++&0xff) == SE) { 166261081Sasomers return look; 167262894Sasomers } 168261081Sasomers } 169261081Sasomers } 170261081Sasomers } 171262894Sasomers default: 172261081Sasomers return current+2; 173261081Sasomers } 174261081Sasomers} 175261081Sasomers 176261081Sasomers 177261081Sasomers/* 178261081Sasomers * netclear() 179261081Sasomers * 180261081Sasomers * We are about to do a TELNET SYNCH operation. Clear 181261081Sasomers * the path to the network. 182261081Sasomers * 183261081Sasomers * Things are a bit tricky since we may have sent the first 184261081Sasomers * byte or so of a previous TELNET command into the network. 185261081Sasomers * So, we have to scan the network buffer from the beginning 186261081Sasomers * until we are up to where we want to be. 187261081Sasomers * 188261081Sasomers * A side effect of what we do, just to keep things 189261081Sasomers * simple, is to clear the urgent data pointer. The principal 190261081Sasomers * caller should be setting the urgent data pointer AFTER calling 191261081Sasomers * us in any case. 192261081Sasomers */ 193261081Sasomersvoid 194261081Sasomersnetclear(void) 195261081Sasomers{ 196261081Sasomers char *thisitem, *next; 197261081Sasomers char *good; 198261081Sasomers#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 199261081Sasomers ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 200261081Sasomers 201261081Sasomers#ifdef ENCRYPTION 202261081Sasomers thisitem = nclearto > netobuf ? nclearto : netobuf; 203261081Sasomers#else 204261081Sasomers thisitem = netobuf; 205261081Sasomers#endif 206261081Sasomers 207270228Sasomers while ((next = nextitem(thisitem)) <= nbackp) { 208270228Sasomers thisitem = next; 209261081Sasomers } 210261081Sasomers 211262894Sasomers /* Now, thisitem is first before/at boundary. */ 212261081Sasomers 213261081Sasomers#ifdef ENCRYPTION 214262894Sasomers good = nclearto > netobuf ? nclearto : netobuf; 215261081Sasomers#else 216262894Sasomers good = netobuf; /* where the good bytes go */ 217261081Sasomers#endif 218261081Sasomers 219261081Sasomers while (nfrontp > thisitem) { 220261081Sasomers if (wewant(thisitem)) { 221261081Sasomers int length; 222261081Sasomers 223261081Sasomers next = thisitem; 224261081Sasomers do { 225261081Sasomers next = nextitem(next); 226261081Sasomers } while (wewant(next) && (nfrontp > next)); 227261081Sasomers length = next-thisitem; 228261081Sasomers memmove(good, thisitem, length); 229261081Sasomers good += length; 230261081Sasomers thisitem = next; 231261081Sasomers } else { 232261081Sasomers thisitem = nextitem(thisitem); 233261081Sasomers } 234261081Sasomers } 235261081Sasomers 236261081Sasomers nbackp = netobuf; 237261081Sasomers nfrontp = good; /* next byte to be sent */ 238261081Sasomers neturg = 0; 239261081Sasomers} /* end of netclear */ 240261081Sasomers 241261081Sasomers/* 242261081Sasomers * netflush 243261081Sasomers * Send as much data as possible to the network, 244261081Sasomers * handling requests for urgent data. 245261081Sasomers */ 246261081Sasomersvoid 247261081Sasomersnetflush(void) 248261081Sasomers{ 249261081Sasomers int n; 250261081Sasomers extern int not42; 251261081Sasomers 252261081Sasomers if ((n = nfrontp - nbackp) > 0) { 253261081Sasomers DIAG(TD_REPORT, 254261081Sasomers { n += output_data("td: netflush %d chars\r\n", n); 255261081Sasomers }); 256261081Sasomers#ifdef ENCRYPTION 257261081Sasomers if (encrypt_output) { 258261081Sasomers char *s = nclearto ? nclearto : nbackp; 259261081Sasomers if (nfrontp - s > 0) { 260261081Sasomers (*encrypt_output)((unsigned char *)s, nfrontp-s); 261261081Sasomers nclearto = nfrontp; 262261081Sasomers } 263261081Sasomers } 264261081Sasomers#endif 265261081Sasomers /* 266261081Sasomers * if no urgent data, or if the other side appears to be an 267261081Sasomers * old 4.2 client (and thus unable to survive TCP urgent data), 268261081Sasomers * write the entire buffer in non-OOB mode. 269261081Sasomers */ 270261081Sasomers#if 1 /* remove this to make it work between solaris 2.6 and linux */ 271261081Sasomers if ((neturg == 0) || (not42 == 0)) { 272261081Sasomers#endif 273261081Sasomers n = write(net, nbackp, n); /* normal write */ 274261081Sasomers#if 1 /* remove this to make it work between solaris 2.6 and linux */ 275261081Sasomers } else { 276261081Sasomers n = neturg - nbackp; 277261081Sasomers /* 278261081Sasomers * In 4.2 (and 4.3) systems, there is some question about 279261081Sasomers * what byte in a sendOOB operation is the "OOB" data. 280261081Sasomers * To make ourselves compatible, we only send ONE byte 281261081Sasomers * out of band, the one WE THINK should be OOB (though 282261081Sasomers * we really have more the TCP philosophy of urgent data 283261081Sasomers * rather than the Unix philosophy of OOB data). 284270228Sasomers */ 285270228Sasomers if (n > 1) { 286261081Sasomers n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 287261081Sasomers } else { 288261081Sasomers n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 289261081Sasomers } 290261081Sasomers } 291261081Sasomers#endif 292261081Sasomers } 293261081Sasomers if (n < 0) { 294261081Sasomers if (errno == EWOULDBLOCK || errno == EINTR) 295261081Sasomers return; 296261081Sasomers cleanup(0); 297261081Sasomers } 298261081Sasomers nbackp += n; 299261081Sasomers#ifdef ENCRYPTION 300261081Sasomers if (nbackp > nclearto) 301261081Sasomers nclearto = 0; 302261081Sasomers#endif 303261081Sasomers if (nbackp >= neturg) { 304261081Sasomers neturg = 0; 305261081Sasomers } 306261081Sasomers if (nbackp == nfrontp) { 307261081Sasomers nbackp = nfrontp = netobuf; 308261081Sasomers#ifdef ENCRYPTION 309261081Sasomers nclearto = 0; 310261081Sasomers#endif 311261081Sasomers } 312261081Sasomers return; 313261081Sasomers} 314261081Sasomers 315261081Sasomers 316261081Sasomers/* 317261081Sasomers * writenet 318261081Sasomers * 319261081Sasomers * Just a handy little function to write a bit of raw data to the net. 320261081Sasomers * It will force a transmit of the buffer if necessary 321261081Sasomers * 322261081Sasomers * arguments 323261081Sasomers * ptr - A pointer to a character string to write 324261081Sasomers * len - How many bytes to write 325261081Sasomers */ 326261081Sasomersvoid 327261081Sasomerswritenet(unsigned char *ptr, int len) 328261081Sasomers{ 329261081Sasomers /* flush buffer if no room for new data) */ 330261081Sasomers while ((&netobuf[BUFSIZ] - nfrontp) < len) { 331261081Sasomers /* if this fails, don't worry, buffer is a little big */ 332261081Sasomers netflush(); 333261081Sasomers } 334261081Sasomers 335261081Sasomers memmove(nfrontp, ptr, len); 336261081Sasomers nfrontp += len; 337261081Sasomers} 338261081Sasomers 339261081Sasomers 340261081Sasomers/* 341261081Sasomers * miscellaneous functions doing a variety of little jobs follow ... 342261081Sasomers */ 343262894Sasomers 344261081Sasomers 345261081Sasomersvoid fatal(int f, char *msg) 346261081Sasomers{ 347261081Sasomers char buf[BUFSIZ]; 348261081Sasomers 349261081Sasomers snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg); 350261081Sasomers#ifdef ENCRYPTION 351261081Sasomers if (encrypt_output) { 352261081Sasomers /* 353261081Sasomers * Better turn off encryption first.... 354261081Sasomers * Hope it flushes... 355261081Sasomers */ 356261081Sasomers encrypt_send_end(); 357261081Sasomers netflush(); 358261081Sasomers } 359261081Sasomers#endif 360261081Sasomers write(f, buf, (int)strlen(buf)); 361261081Sasomers sleep(1); /*XXX*/ 362261081Sasomers exit(1); 363261081Sasomers} 364261081Sasomers 365261081Sasomersvoid 366261081Sasomersfatalperror(int f, const char *msg) 367261081Sasomers{ 368261081Sasomers char buf[BUFSIZ]; 369261081Sasomers 370261081Sasomers snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno)); 371261081Sasomers fatal(f, buf); 372262867Sasomers} 373262867Sasomers 374262867Sasomerschar editedhost[32]; 375262867Sasomers 376262867Sasomersvoid edithost(char *pat, char *host) 377262867Sasomers{ 378261081Sasomers char *res = editedhost; 379261081Sasomers 380261081Sasomers if (!pat) 381261081Sasomers pat = ""; 382261081Sasomers while (*pat) { 383261081Sasomers switch (*pat) { 384270228Sasomers 385270228Sasomers case '#': 386261081Sasomers if (*host) 387261081Sasomers host++; 388261081Sasomers break; 389261081Sasomers 390261081Sasomers case '@': 391261081Sasomers if (*host) 392261081Sasomers *res++ = *host++; 393261081Sasomers break; 394261081Sasomers 395261081Sasomers default: 396261081Sasomers *res++ = *pat; 397261081Sasomers break; 398261081Sasomers } 399261081Sasomers if (res == &editedhost[sizeof editedhost - 1]) { 400261081Sasomers *res = '\0'; 401270228Sasomers return; 402261081Sasomers } 403261081Sasomers pat++; 404261081Sasomers } 405261081Sasomers if (*host) 406261081Sasomers strlcpy (res, host, 407261081Sasomers sizeof editedhost - (res - editedhost)); 408261081Sasomers else 409261081Sasomers *res = '\0'; 410261081Sasomers editedhost[sizeof editedhost - 1] = '\0'; 411261081Sasomers} 412261081Sasomers 413261081Sasomersstatic char *putlocation; 414261081Sasomers 415261081Sasomersvoid 416270228Sasomersputstr(char *s) 417270228Sasomers{ 418261081Sasomers 419261081Sasomers while (*s) 420261081Sasomers putchr(*s++); 421261081Sasomers} 422261081Sasomers 423261081Sasomersvoid 424261081Sasomersputchr(int cc) 425261081Sasomers{ 426261081Sasomers *putlocation++ = cc; 427261081Sasomers} 428261081Sasomers 429261081Sasomers/* 430261081Sasomers * This is split on two lines so that SCCS will not see the M 431270228Sasomers * between two % signs and expand it... 432261081Sasomers */ 433261081Sasomersstatic char fmtstr[] = { "%l:%M" "%P on %A, %d %B %Y" }; 434261081Sasomers 435261081Sasomersvoid putf(char *cp, char *where) 436261081Sasomers{ 437261081Sasomers#ifdef HAVE_UNAME 438261081Sasomers struct utsname name; 439261081Sasomers#endif 440261081Sasomers char *slash; 441261081Sasomers time_t t; 442261081Sasomers char db[100]; 443261081Sasomers 444261081Sasomers /* if we don't have uname, set these to sensible values */ 445261081Sasomers char *sysname = "Unix", 446261081Sasomers *machine = "", 447261081Sasomers *release = "", 448261081Sasomers *version = ""; 449261081Sasomers 450261081Sasomers#ifdef HAVE_UNAME 451261081Sasomers uname(&name); 452270228Sasomers sysname=name.sysname; 453261081Sasomers machine=name.machine; 454261081Sasomers release=name.release; 455261081Sasomers version=name.version; 456261081Sasomers#endif 457261081Sasomers 458261081Sasomers putlocation = where; 459261081Sasomers 460261081Sasomers while (*cp) { 461261081Sasomers if (*cp != '%') { 462261081Sasomers putchr(*cp++); 463261081Sasomers continue; 464261081Sasomers } 465261081Sasomers switch (*++cp) { 466261081Sasomers 467261081Sasomers case 't': 468261081Sasomers#ifdef STREAMSPTY 469261081Sasomers /* names are like /dev/pts/2 -- we want pts/2 */ 470261081Sasomers slash = strchr(line+1, '/'); 471261081Sasomers#else 472261081Sasomers slash = strrchr(line, '/'); 473261081Sasomers#endif 474261081Sasomers if (slash == (char *) 0) 475270228Sasomers putstr(line); 476261081Sasomers else 477261081Sasomers putstr(&slash[1]); 478261081Sasomers break; 479261081Sasomers 480261081Sasomers case 'h': 481261081Sasomers putstr(editedhost); 482261081Sasomers break; 483261081Sasomers 484261081Sasomers case 's': 485261081Sasomers putstr(sysname); 486261081Sasomers break; 487261081Sasomers 488261081Sasomers case 'm': 489261081Sasomers putstr(machine); 490261081Sasomers break; 491261081Sasomers 492261081Sasomers case 'r': 493261081Sasomers putstr(release); 494261081Sasomers break; 495261081Sasomers 496261081Sasomers case 'v': 497261081Sasomers putstr(version); 498261081Sasomers break; 499261081Sasomers 500261081Sasomers case 'd': 501261081Sasomers time(&t); 502261081Sasomers strftime(db, sizeof(db), fmtstr, localtime(&t)); 503261081Sasomers putstr(db); 504261081Sasomers break; 505261081Sasomers 506261081Sasomers case '%': 507270228Sasomers putchr('%'); 508270228Sasomers break; 509261081Sasomers } 510261081Sasomers cp++; 511261081Sasomers } 512261081Sasomers} 513261081Sasomers 514261081Sasomers#ifdef DIAGNOSTICS 515261081Sasomers/* 516261081Sasomers * Print telnet options and commands in plain text, if possible. 517261081Sasomers */ 518270228Sasomersvoid 519270228Sasomersprintoption(char *fmt, int option) 520261081Sasomers{ 521261081Sasomers if (TELOPT_OK(option)) 522261081Sasomers output_data("%s %s\r\n", 523261081Sasomers fmt, 524261081Sasomers TELOPT(option)); 525261081Sasomers else if (TELCMD_OK(option)) 526261081Sasomers output_data("%s %s\r\n", 527261081Sasomers fmt, 528261081Sasomers TELCMD(option)); 529261081Sasomers else 530261081Sasomers output_data("%s %d\r\n", 531261081Sasomers fmt, 532261081Sasomers option); 533261081Sasomers return; 534261081Sasomers} 535270228Sasomers 536261081Sasomersvoid 537261081Sasomersprintsub(int direction, unsigned char *pointer, int length) 538261081Sasomers /* '<' or '>' */ 539261081Sasomers /* where suboption data sits */ 540261081Sasomers /* length of suboption data */ 541261081Sasomers{ 542261081Sasomers int i = 0; 543261081Sasomers unsigned char buf[512]; 544261081Sasomers 545261081Sasomers if (!(diagnostic & TD_OPTIONS)) 546261081Sasomers return; 547261081Sasomers 548261081Sasomers if (direction) { 549261081Sasomers output_data("td: %s suboption ", 550261081Sasomers direction == '<' ? "recv" : "send"); 551261081Sasomers if (length >= 3) { 552261081Sasomers int j; 553261081Sasomers 554261081Sasomers i = pointer[length-2]; 555261081Sasomers j = pointer[length-1]; 556261081Sasomers 557261081Sasomers if (i != IAC || j != SE) { 558261081Sasomers output_data("(terminated by "); 559261081Sasomers if (TELOPT_OK(i)) 560261081Sasomers output_data("%s ", 561261081Sasomers TELOPT(i)); 562261081Sasomers else if (TELCMD_OK(i)) 563261081Sasomers output_data("%s ", 564261081Sasomers TELCMD(i)); 565261081Sasomers else 566261081Sasomers output_data("%d ", 567261081Sasomers i); 568261081Sasomers if (TELOPT_OK(j)) 569261081Sasomers output_data("%s", 570261081Sasomers TELOPT(j)); 571261081Sasomers else if (TELCMD_OK(j)) 572270228Sasomers output_data("%s", 573261081Sasomers TELCMD(j)); 574261081Sasomers else 575261081Sasomers output_data("%d", 576261081Sasomers j); 577261081Sasomers output_data(", not IAC SE!) "); 578261081Sasomers } 579261081Sasomers } 580261081Sasomers length -= 2; 581261081Sasomers } 582261081Sasomers if (length < 1) { 583261081Sasomers output_data("(Empty suboption??\?)"); 584261081Sasomers return; 585261081Sasomers } 586261081Sasomers switch (pointer[0]) { 587261081Sasomers case TELOPT_TTYPE: 588261081Sasomers output_data("TERMINAL-TYPE "); 589261081Sasomers switch (pointer[1]) { 590261081Sasomers case TELQUAL_IS: 591261081Sasomers output_data("IS \"%.*s\"", 592261081Sasomers length-2, 593261081Sasomers (char *)pointer+2); 594261081Sasomers break; 595261081Sasomers case TELQUAL_SEND: 596261081Sasomers output_data("SEND"); 597261081Sasomers break; 598261081Sasomers default: 599261081Sasomers output_data("- unknown qualifier %d (0x%x).", 600261081Sasomers pointer[1], pointer[1]); 601261081Sasomers } 602261081Sasomers break; 603261081Sasomers case TELOPT_TSPEED: 604261081Sasomers output_data("TERMINAL-SPEED"); 605261081Sasomers if (length < 2) { 606261081Sasomers output_data(" (empty suboption??\?)"); 607261081Sasomers break; 608261081Sasomers } 609261081Sasomers switch (pointer[1]) { 610261081Sasomers case TELQUAL_IS: 611261081Sasomers output_data(" IS %.*s", length-2, (char *)pointer+2); 612261081Sasomers break; 613261081Sasomers default: 614261081Sasomers if (pointer[1] == 1) 615261081Sasomers output_data(" SEND"); 616261081Sasomers else 617261081Sasomers output_data(" %d (unknown)", pointer[1]); 618261081Sasomers for (i = 2; i < length; i++) { 619261081Sasomers output_data(" ?%d?", pointer[i]); 620261081Sasomers } 621261081Sasomers break; 622261081Sasomers } 623261081Sasomers break; 624261081Sasomers 625261081Sasomers case TELOPT_LFLOW: 626261081Sasomers output_data("TOGGLE-FLOW-CONTROL"); 627261081Sasomers if (length < 2) { 628261081Sasomers output_data(" (empty suboption??\?)"); 629270228Sasomers break; 630270228Sasomers } 631261081Sasomers switch (pointer[1]) { 632261081Sasomers case LFLOW_OFF: 633261081Sasomers output_data(" OFF"); 634261081Sasomers break; 635261081Sasomers case LFLOW_ON: 636261081Sasomers output_data(" ON"); 637261081Sasomers break; 638261081Sasomers case LFLOW_RESTART_ANY: 639261081Sasomers output_data(" RESTART-ANY"); 640261081Sasomers break; 641261081Sasomers case LFLOW_RESTART_XON: 642262894Sasomers output_data(" RESTART-XON"); 643261081Sasomers break; 644261081Sasomers default: 645261081Sasomers output_data(" %d (unknown)", 646261081Sasomers pointer[1]); 647261081Sasomers } 648261081Sasomers for (i = 2; i < length; i++) { 649261081Sasomers output_data(" ?%d?", 650261081Sasomers pointer[i]); 651261081Sasomers } 652261081Sasomers break; 653261081Sasomers 654261081Sasomers case TELOPT_NAWS: 655261081Sasomers output_data("NAWS"); 656261081Sasomers if (length < 2) { 657261081Sasomers output_data(" (empty suboption??\?)"); 658261081Sasomers break; 659261081Sasomers } 660270228Sasomers if (length == 2) { 661270228Sasomers output_data(" ?%d?", 662261081Sasomers pointer[1]); 663261081Sasomers break; 664261081Sasomers } 665261081Sasomers output_data(" %u %u(%u)", 666261081Sasomers pointer[1], 667261081Sasomers pointer[2], 668261081Sasomers (((unsigned int)pointer[1])<<8) + pointer[2]); 669261081Sasomers if (length == 4) { 670261081Sasomers output_data(" ?%d?", 671261081Sasomers pointer[3]); 672261081Sasomers break; 673261081Sasomers } 674261081Sasomers output_data(" %u %u(%u)", 675261081Sasomers pointer[3], 676261081Sasomers pointer[4], 677261081Sasomers (((unsigned int)pointer[3])<<8) + pointer[4]); 678261081Sasomers for (i = 5; i < length; i++) { 679261081Sasomers output_data(" ?%d?", 680262894Sasomers pointer[i]); 681261081Sasomers } 682261081Sasomers break; 683261081Sasomers 684261081Sasomers case TELOPT_LINEMODE: 685261081Sasomers output_data("LINEMODE "); 686261081Sasomers if (length < 2) { 687261081Sasomers output_data(" (empty suboption??\?)"); 688261081Sasomers break; 689261081Sasomers } 690261081Sasomers switch (pointer[1]) { 691261081Sasomers case WILL: 692261081Sasomers output_data("WILL "); 693261081Sasomers goto common; 694261081Sasomers case WONT: 695261081Sasomers output_data("WONT "); 696261081Sasomers goto common; 697261081Sasomers case DO: 698261081Sasomers output_data("DO "); 699261081Sasomers goto common; 700261081Sasomers case DONT: 701261081Sasomers output_data("DONT "); 702261081Sasomers common: 703261081Sasomers if (length < 3) { 704261081Sasomers output_data("(no option??\?)"); 705261081Sasomers break; 706261081Sasomers } 707261081Sasomers switch (pointer[2]) { 708261081Sasomers case LM_FORWARDMASK: 709261081Sasomers output_data("Forward Mask"); 710261081Sasomers for (i = 3; i < length; i++) { 711261081Sasomers output_data(" %x", pointer[i]); 712261081Sasomers } 713261081Sasomers break; 714270228Sasomers default: 715270228Sasomers output_data("%d (unknown)", 716261081Sasomers pointer[2]); 717261081Sasomers for (i = 3; i < length; i++) { 718261081Sasomers output_data(" %d", 719261081Sasomers pointer[i]); 720261081Sasomers } 721261081Sasomers break; 722261081Sasomers } 723261081Sasomers break; 724261081Sasomers 725261081Sasomers case LM_SLC: 726261081Sasomers output_data("SLC"); 727261081Sasomers for (i = 2; i < length - 2; i += 3) { 728261081Sasomers if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 729262894Sasomers output_data(" %s", 730261081Sasomers SLC_NAME(pointer[i+SLC_FUNC])); 731261081Sasomers else 732261081Sasomers output_data(" %d", 733261081Sasomers pointer[i+SLC_FUNC]); 734261081Sasomers switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 735261081Sasomers case SLC_NOSUPPORT: 736261081Sasomers output_data(" NOSUPPORT"); 737261081Sasomers break; 738261081Sasomers case SLC_CANTCHANGE: 739261081Sasomers output_data(" CANTCHANGE"); 740261081Sasomers break; 741261081Sasomers case SLC_VARIABLE: 742261081Sasomers output_data(" VARIABLE"); 743261081Sasomers break; 744261081Sasomers case SLC_DEFAULT: 745261081Sasomers output_data(" DEFAULT"); 746270228Sasomers break; 747270228Sasomers } 748261081Sasomers output_data("%s%s%s", 749261081Sasomers pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 750261081Sasomers pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 751261081Sasomers pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 752261081Sasomers if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 753261081Sasomers SLC_FLUSHOUT| SLC_LEVELBITS)) { 754261081Sasomers output_data("(0x%x)", 755270228Sasomers pointer[i+SLC_FLAGS]); 756261081Sasomers } 757261081Sasomers output_data(" %d;", 758261081Sasomers pointer[i+SLC_VALUE]); 759270228Sasomers if ((pointer[i+SLC_VALUE] == IAC) && 760261081Sasomers (pointer[i+SLC_VALUE+1] == IAC)) 761261081Sasomers i++; 762261081Sasomers } 763261081Sasomers for (; i < length; i++) { 764261081Sasomers output_data(" ?%d?", 765270228Sasomers pointer[i]); 766261081Sasomers } 767261081Sasomers break; 768261081Sasomers 769261081Sasomers case LM_MODE: 770261081Sasomers output_data("MODE "); 771261081Sasomers if (length < 3) { 772261081Sasomers output_data("(no mode??\?)"); 773270228Sasomers break; 774261081Sasomers } 775261081Sasomers { 776261081Sasomers char tbuf[32]; 777270228Sasomers snprintf(tbuf, 778261081Sasomers sizeof(tbuf), 779261081Sasomers "%s%s%s%s%s", 780261081Sasomers pointer[2]&MODE_EDIT ? "|EDIT" : "", 781261081Sasomers pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 782270228Sasomers pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 783261081Sasomers pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 784261081Sasomers pointer[2]&MODE_ACK ? "|ACK" : ""); 785261081Sasomers output_data("%s", 786261081Sasomers tbuf[1] ? &tbuf[1] : "0"); 787261081Sasomers } 788261081Sasomers if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 789261081Sasomers output_data(" (0x%x)", 790261081Sasomers pointer[2]); 791261081Sasomers } 792261081Sasomers for (i = 3; i < length; i++) { 793262894Sasomers output_data(" ?0x%x?", 794261081Sasomers pointer[i]); 795261081Sasomers } 796261081Sasomers break; 797261081Sasomers default: 798261081Sasomers output_data("%d (unknown)", 799261081Sasomers pointer[1]); 800261081Sasomers for (i = 2; i < length; i++) { 801261081Sasomers output_data(" %d", pointer[i]); 802261081Sasomers } 803261081Sasomers } 804261081Sasomers break; 805261081Sasomers 806261081Sasomers case TELOPT_STATUS: { 807261081Sasomers char *cp; 808261081Sasomers int j, k; 809261081Sasomers 810261081Sasomers output_data("STATUS"); 811261081Sasomers 812261081Sasomers switch (pointer[1]) { 813261081Sasomers default: 814261081Sasomers if (pointer[1] == TELQUAL_SEND) 815261081Sasomers output_data(" SEND"); 816270228Sasomers else 817270228Sasomers output_data(" %d (unknown)", 818261081Sasomers pointer[1]); 819261081Sasomers for (i = 2; i < length; i++) { 820261081Sasomers output_data(" ?%d?", 821261081Sasomers pointer[i]); 822261081Sasomers } 823261081Sasomers break; 824261081Sasomers case TELQUAL_IS: 825261081Sasomers output_data(" IS\r\n"); 826261081Sasomers 827261081Sasomers for (i = 2; i < length; i++) { 828261081Sasomers switch(pointer[i]) { 829261081Sasomers case DO: cp = "DO"; goto common2; 830261081Sasomers case DONT: cp = "DONT"; goto common2; 831261081Sasomers case WILL: cp = "WILL"; goto common2; 832262894Sasomers case WONT: cp = "WONT"; goto common2; 833261081Sasomers common2: 834261081Sasomers i++; 835261081Sasomers if (TELOPT_OK(pointer[i])) 836261081Sasomers output_data(" %s %s", 837261081Sasomers cp, 838261081Sasomers TELOPT(pointer[i])); 839261081Sasomers else 840261081Sasomers output_data(" %s %d", 841261081Sasomers cp, 842261081Sasomers pointer[i]); 843261081Sasomers 844261081Sasomers output_data("\r\n"); 845270228Sasomers break; 846270228Sasomers 847261081Sasomers case SB: 848261081Sasomers output_data(" SB "); 849261081Sasomers i++; 850261081Sasomers j = k = i; 851261081Sasomers while (j < length) { 852261081Sasomers if (pointer[j] == SE) { 853261081Sasomers if (j+1 == length) 854261081Sasomers break; 855261081Sasomers if (pointer[j+1] == SE) 856261081Sasomers j++; 857261081Sasomers else 858261081Sasomers break; 859261081Sasomers } 860261081Sasomers pointer[k++] = pointer[j++]; 861262894Sasomers } 862261081Sasomers printsub(0, &pointer[i], k - i); 863261081Sasomers if (i < length) { 864261081Sasomers output_data(" SE"); 865261081Sasomers i = j; 866261081Sasomers } else 867261081Sasomers i = j - 1; 868261081Sasomers 869261081Sasomers output_data("\r\n"); 870261081Sasomers 871261081Sasomers break; 872261081Sasomers 873261081Sasomers default: 874270228Sasomers output_data(" %d", 875270228Sasomers pointer[i]); 876261081Sasomers break; 877261081Sasomers } 878261081Sasomers } 879261081Sasomers break; 880261081Sasomers } 881261081Sasomers break; 882261081Sasomers } 883261081Sasomers 884261081Sasomers case TELOPT_XDISPLOC: 885261081Sasomers output_data("X-DISPLAY-LOCATION "); 886261081Sasomers switch (pointer[1]) { 887261081Sasomers case TELQUAL_IS: 888261081Sasomers output_data("IS \"%.*s\"", 889261081Sasomers length-2, 890261081Sasomers (char *)pointer+2); 891261081Sasomers break; 892261081Sasomers case TELQUAL_SEND: 893261081Sasomers output_data("SEND"); 894261081Sasomers break; 895261081Sasomers default: 896261081Sasomers output_data("- unknown qualifier %d (0x%x).", 897261081Sasomers pointer[1], pointer[1]); 898261081Sasomers } 899261081Sasomers break; 900261081Sasomers 901261081Sasomers case TELOPT_NEW_ENVIRON: 902261081Sasomers output_data("NEW-ENVIRON "); 903261081Sasomers goto env_common1; 904261081Sasomers case TELOPT_OLD_ENVIRON: 905261081Sasomers output_data("OLD-ENVIRON"); 906261081Sasomers env_common1: 907261081Sasomers switch (pointer[1]) { 908261081Sasomers case TELQUAL_IS: 909261081Sasomers output_data("IS "); 910261081Sasomers goto env_common; 911261081Sasomers case TELQUAL_SEND: 912262894Sasomers output_data("SEND "); 913261081Sasomers goto env_common; 914264133Sjmmv case TELQUAL_INFO: 915261081Sasomers output_data("INFO "); 916261081Sasomers env_common: 917262894Sasomers { 918262894Sasomers int noquote = 2; 919261081Sasomers for (i = 2; i < length; i++ ) { 920261081Sasomers switch (pointer[i]) { 921261081Sasomers case NEW_ENV_VAR: 922261081Sasomers output_data("\" VAR " + noquote); 923261081Sasomers noquote = 2; 924261081Sasomers break; 925262894Sasomers 926262894Sasomers case NEW_ENV_VALUE: 927262894Sasomers output_data("\" VALUE " + noquote); 928262894Sasomers noquote = 2; 929261081Sasomers break; 930261081Sasomers 931261081Sasomers case ENV_ESC: 932261081Sasomers output_data("\" ESC " + noquote); 933261081Sasomers noquote = 2; 934262894Sasomers break; 935261081Sasomers 936261081Sasomers case ENV_USERVAR: 937261081Sasomers output_data("\" USERVAR " + noquote); 938261081Sasomers noquote = 2; 939261081Sasomers break; 940261081Sasomers 941261081Sasomers default: 942261081Sasomers if (isprint(pointer[i]) && pointer[i] != '"') { 943261081Sasomers if (noquote) { 944261081Sasomers output_data ("\""); 945261081Sasomers noquote = 0; 946261081Sasomers } 947261081Sasomers output_data ("%c", pointer[i]); 948261081Sasomers } else { 949261081Sasomers output_data("\" %03o " + noquote, 950261081Sasomers pointer[i]); 951261081Sasomers noquote = 2; 952261081Sasomers } 953261081Sasomers break; 954261081Sasomers } 955261081Sasomers } 956261081Sasomers if (!noquote) 957261081Sasomers output_data ("\""); 958261081Sasomers break; 959261081Sasomers } 960261081Sasomers } 961261081Sasomers break; 962261081Sasomers 963261081Sasomers#ifdef AUTHENTICATION 964261081Sasomers case TELOPT_AUTHENTICATION: 965261081Sasomers output_data("AUTHENTICATION"); 966270228Sasomers 967270228Sasomers if (length < 2) { 968261081Sasomers output_data(" (empty suboption??\?)"); 969261081Sasomers break; 970261081Sasomers } 971261081Sasomers switch (pointer[1]) { 972261081Sasomers case TELQUAL_REPLY: 973261081Sasomers case TELQUAL_IS: 974261081Sasomers output_data(" %s ", 975261081Sasomers (pointer[1] == TELQUAL_IS) ? 976261081Sasomers "IS" : "REPLY"); 977261081Sasomers if (AUTHTYPE_NAME_OK(pointer[2])) 978261081Sasomers output_data("%s ", 979261081Sasomers AUTHTYPE_NAME(pointer[2])); 980261081Sasomers else 981261081Sasomers output_data("%d ", 982261081Sasomers pointer[2]); 983261081Sasomers if (length < 3) { 984261081Sasomers output_data("(partial suboption??\?)"); 985261081Sasomers break; 986261081Sasomers } 987261081Sasomers output_data("%s|%s", 988261081Sasomers ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 989261081Sasomers "CLIENT" : "SERVER", 990261081Sasomers ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 991261081Sasomers "MUTUAL" : "ONE-WAY"); 992261081Sasomers 993261081Sasomers auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 994261081Sasomers output_data("%s", 995261081Sasomers buf); 996261081Sasomers break; 997261081Sasomers 998261081Sasomers case TELQUAL_SEND: 999261081Sasomers i = 2; 1000261081Sasomers output_data(" SEND "); 1001261081Sasomers while (i < length) { 1002261081Sasomers if (AUTHTYPE_NAME_OK(pointer[i])) 1003261081Sasomers output_data("%s ", 1004261081Sasomers AUTHTYPE_NAME(pointer[i])); 1005261081Sasomers else 1006261081Sasomers output_data("%d ", 1007261081Sasomers pointer[i]); 1008261081Sasomers if (++i >= length) { 1009261081Sasomers output_data("(partial suboption??\?)"); 1010261081Sasomers break; 1011261081Sasomers } 1012261081Sasomers output_data("%s|%s ", 1013261081Sasomers ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 1014261081Sasomers "CLIENT" : "SERVER", 1015261081Sasomers ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 1016261081Sasomers "MUTUAL" : "ONE-WAY"); 1017261081Sasomers ++i; 1018261081Sasomers } 1019261081Sasomers break; 1020261081Sasomers 1021261081Sasomers case TELQUAL_NAME: 1022261081Sasomers i = 2; 1023261081Sasomers output_data(" NAME \"%.*s\"", 1024261081Sasomers length - 2, 1025261081Sasomers pointer); 1026261081Sasomers break; 1027261081Sasomers 1028261081Sasomers default: 1029261081Sasomers for (i = 2; i < length; i++) { 1030261081Sasomers output_data(" ?%d?", 1031261081Sasomers pointer[i]); 1032261081Sasomers } 1033261081Sasomers break; 1034261081Sasomers } 1035261081Sasomers break; 1036261081Sasomers#endif 1037261081Sasomers 1038261081Sasomers#ifdef ENCRYPTION 1039261081Sasomers case TELOPT_ENCRYPT: 1040261081Sasomers output_data("ENCRYPT"); 1041261081Sasomers if (length < 2) { 1042261081Sasomers output_data(" (empty suboption?)"); 1043261081Sasomers break; 1044261081Sasomers } 1045261081Sasomers switch (pointer[1]) { 1046261081Sasomers case ENCRYPT_START: 1047261081Sasomers output_data(" START"); 1048261081Sasomers break; 1049261081Sasomers 1050261081Sasomers case ENCRYPT_END: 1051261081Sasomers output_data(" END"); 1052261081Sasomers break; 1053261081Sasomers 1054261081Sasomers case ENCRYPT_REQSTART: 1055261081Sasomers output_data(" REQUEST-START"); 1056261081Sasomers break; 1057261081Sasomers 1058261081Sasomers case ENCRYPT_REQEND: 1059261081Sasomers output_data(" REQUEST-END"); 1060261081Sasomers break; 1061261081Sasomers 1062261081Sasomers case ENCRYPT_IS: 1063261081Sasomers case ENCRYPT_REPLY: 1064261081Sasomers output_data(" %s ", 1065261081Sasomers (pointer[1] == ENCRYPT_IS) ? 1066261081Sasomers "IS" : "REPLY"); 1067261081Sasomers if (length < 3) { 1068261081Sasomers output_data(" (partial suboption?)"); 1069261081Sasomers break; 1070261081Sasomers } 1071261081Sasomers if (ENCTYPE_NAME_OK(pointer[2])) 1072261081Sasomers output_data("%s ", 1073261081Sasomers ENCTYPE_NAME(pointer[2])); 1074261081Sasomers else 1075261081Sasomers output_data(" %d (unknown)", 1076261081Sasomers pointer[2]); 1077261081Sasomers 1078261081Sasomers encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 1079261081Sasomers output_data("%s", 1080261081Sasomers buf); 1081261081Sasomers break; 1082261081Sasomers 1083261081Sasomers case ENCRYPT_SUPPORT: 1084261081Sasomers i = 2; 1085261081Sasomers output_data(" SUPPORT "); 1086261081Sasomers while (i < length) { 1087261081Sasomers if (ENCTYPE_NAME_OK(pointer[i])) 1088261081Sasomers output_data("%s ", 1089261081Sasomers ENCTYPE_NAME(pointer[i])); 1090261081Sasomers else 1091261081Sasomers output_data("%d ", 1092261081Sasomers pointer[i]); 1093261081Sasomers i++; 1094261081Sasomers } 1095261081Sasomers break; 1096261081Sasomers 1097261081Sasomers case ENCRYPT_ENC_KEYID: 1098261081Sasomers output_data(" ENC_KEYID %d", pointer[1]); 1099261081Sasomers goto encommon; 1100261081Sasomers 1101261081Sasomers case ENCRYPT_DEC_KEYID: 1102261081Sasomers output_data(" DEC_KEYID %d", pointer[1]); 1103261081Sasomers goto encommon; 1104261081Sasomers 1105261081Sasomers default: 1106261081Sasomers output_data(" %d (unknown)", pointer[1]); 1107261081Sasomers encommon: 1108261081Sasomers for (i = 2; i < length; i++) { 1109261081Sasomers output_data(" %d", pointer[i]); 1110261081Sasomers } 1111261081Sasomers break; 1112261081Sasomers } 1113261081Sasomers break; 1114261081Sasomers#endif 1115261081Sasomers 1116261081Sasomers default: 1117261081Sasomers if (TELOPT_OK(pointer[0])) 1118261081Sasomers output_data("%s (unknown)", 1119261081Sasomers TELOPT(pointer[0])); 1120261081Sasomers else 1121261081Sasomers output_data("%d (unknown)", 1122261081Sasomers pointer[i]); 1123261081Sasomers for (i = 1; i < length; i++) { 1124261081Sasomers output_data(" %d", pointer[i]); 1125261081Sasomers } 1126261081Sasomers break; 1127261081Sasomers } 1128261081Sasomers output_data("\r\n"); 1129261081Sasomers} 1130261081Sasomers 1131261081Sasomers/* 1132261081Sasomers * Dump a data buffer in hex and ascii to the output data stream. 1133261081Sasomers */ 1134261081Sasomersvoid 1135261081Sasomersprintdata(char *tag, char *ptr, int cnt) 1136261081Sasomers{ 1137261081Sasomers int i; 1138261081Sasomers char xbuf[30]; 1139261081Sasomers 1140261081Sasomers while (cnt) { 1141261081Sasomers /* flush net output buffer if no room for new data) */ 1142 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1143 netflush(); 1144 } 1145 1146 /* add a line of output */ 1147 output_data("%s: ", tag); 1148 for (i = 0; i < 20 && cnt; i++) { 1149 output_data("%02x", *ptr); 1150 if (isprint(*ptr)) { 1151 xbuf[i] = *ptr; 1152 } else { 1153 xbuf[i] = '.'; 1154 } 1155 if (i % 2) { 1156 output_data(" "); 1157 } 1158 cnt--; 1159 ptr++; 1160 } 1161 xbuf[i] = '\0'; 1162 output_data(" %s\r\n", xbuf); 1163 } 1164} 1165#endif /* DIAGNOSTICS */ 1166