1*30088Sminshall /* 2*30088Sminshall * Copyright (c) 1984, 1985, 1986 by the Regents of the 3*30088Sminshall * University of California and by Gregory Glenn Minshall. 4*30088Sminshall * 5*30088Sminshall * Permission to use, copy, modify, and distribute these 6*30088Sminshall * programs and their documentation for any purpose and 7*30088Sminshall * without fee is hereby granted, provided that this 8*30088Sminshall * copyright and permission appear on all copies and 9*30088Sminshall * supporting documentation, the name of the Regents of 10*30088Sminshall * the University of California not be used in advertising 11*30088Sminshall * or publicity pertaining to distribution of the programs 12*30088Sminshall * without specific prior permission, and notice be given in 13*30088Sminshall * supporting documentation that copying and distribution is 14*30088Sminshall * by permission of the Regents of the University of California 15*30088Sminshall * and by Gregory Glenn Minshall. Neither the Regents of the 16*30088Sminshall * University of California nor Gregory Glenn Minshall make 17*30088Sminshall * representations about the suitability of this software 18*30088Sminshall * for any purpose. It is provided "as is" without 19*30088Sminshall * express or implied warranty. 20*30088Sminshall */ 21*30088Sminshall 22*30088Sminshall #ifndef lint 23*30088Sminshall static char copyright[] = 24*30088Sminshall "@(#) Copyright (c) 1984, 1985, 1986 Regents of the University of California.\n\ 25*30088Sminshall All rights reserved.\n"; 26*30088Sminshall #endif not lint 27*30088Sminshall 28*30088Sminshall #ifndef lint 29*30088Sminshall static char sccsid[] = "@(#)telnet.c 3.1 10/29/86"; 30*30088Sminshall #endif not lint 31*30088Sminshall 32*30088Sminshall /* 33*30088Sminshall * User telnet program, modified for use by tn3270.c. 34*30088Sminshall * 35*30088Sminshall * Many of the FUNCTIONAL changes in this newest version of TELNET 36*30088Sminshall * were suggested by Dave Borman of Cray Research, Inc. 37*30088Sminshall * 38*30088Sminshall * Other changes in the tn3270 side come from Alan Crosswell (Columbia), 39*30088Sminshall * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley). 40*30088Sminshall * 41*30088Sminshall * This code is common between telnet(1c) and tn3270(1c). There are the 42*30088Sminshall * following defines used to generate the various versions: 43*30088Sminshall * 44*30088Sminshall * TN3270 - This is to be linked with tn3270. 45*30088Sminshall * 46*30088Sminshall * DEBUG - Allow for some extra debugging operations. 47*30088Sminshall * 48*30088Sminshall * NOT43 - Allows the program to compile and run on 49*30088Sminshall * a 4.2BSD system. 50*30088Sminshall * 51*30088Sminshall * PUTCHAR - Within tn3270, on a NOT43 system, 52*30088Sminshall * allows the use of the 4.3 curses 53*30088Sminshall * (greater speed updating the screen). 54*30088Sminshall * You need the 4.3 curses for this to work. 55*30088Sminshall * 56*30088Sminshall * FD_SETSIZE - On whichever system, if this isn't defined, 57*30088Sminshall * we patch over the FD_SET, etc., macros with 58*30088Sminshall * some homebrewed ones. 59*30088Sminshall * 60*30088Sminshall * SO_OOBINLINE - This is a socket option which we would like 61*30088Sminshall * to set to allow TCP urgent data to come 62*30088Sminshall * to us "inline". This is NECESSARY for 63*30088Sminshall * CORRECT operation, and desireable for 64*30088Sminshall * simpler operation. 65*30088Sminshall * 66*30088Sminshall * LNOFLSH - Detects the presence of the LNOFLSH bit 67*30088Sminshall * in the tty structure. 68*30088Sminshall * 69*30088Sminshall * unix - Compiles in unix specific stuff. 70*30088Sminshall * 71*30088Sminshall * msdos - Compiles in msdos specific stuff. 72*30088Sminshall * 73*30088Sminshall */ 74*30088Sminshall 75*30088Sminshall #if !defined(TN3270) 76*30088Sminshall #define ExitString(f,s,r) { fprintf(f, s); exit(r); } 77*30088Sminshall #define Exit(x) exit(x) 78*30088Sminshall #define SetIn3270() 79*30088Sminshall 80*30088Sminshall void setcommandmode(), command(); /* forward declarations */ 81*30088Sminshall #endif /* !defined(TN3270) */ 82*30088Sminshall 83*30088Sminshall #include <sys/types.h> 84*30088Sminshall #include <sys/socket.h> 85*30088Sminshall #include <sys/ioctl.h> 86*30088Sminshall #include <sys/time.h> 87*30088Sminshall 88*30088Sminshall #include <netinet/in.h> 89*30088Sminshall 90*30088Sminshall #include <curses.h> 91*30088Sminshall 92*30088Sminshall #define TELOPTS 93*30088Sminshall #include <arpa/telnet.h> 94*30088Sminshall 95*30088Sminshall #if !defined(NOT43) 96*30088Sminshall #include <arpa/inet.h> 97*30088Sminshall #else /* !defined(NOT43) */ 98*30088Sminshall extern unsigned long inet_addr(); 99*30088Sminshall extern char *inet_ntoa(); 100*30088Sminshall #endif /* !defined(NOT43) */ 101*30088Sminshall 102*30088Sminshall #include <stdio.h> 103*30088Sminshall #include <ctype.h> 104*30088Sminshall #include <errno.h> 105*30088Sminshall #include <signal.h> 106*30088Sminshall #include <setjmp.h> 107*30088Sminshall #include <netdb.h> 108*30088Sminshall #include <strings.h> 109*30088Sminshall 110*30088Sminshall #if defined(TN3270) 111*30088Sminshall #include "ctlr/screen.h" 112*30088Sminshall #include "system/globals.h" 113*30088Sminshall #include "telnet.ext" 114*30088Sminshall #include "ctlr/options.ext" 115*30088Sminshall #include "ctlr/outbound.ext" 116*30088Sminshall #include "keyboard/termin.ext" 117*30088Sminshall #endif /* defined(TN3270) */ 118*30088Sminshall 119*30088Sminshall 120*30088Sminshall 121*30088Sminshall #ifndef FD_SETSIZE 122*30088Sminshall /* 123*30088Sminshall * The following is defined just in case someone should want to run 124*30088Sminshall * this telnet on a 4.2 system. 125*30088Sminshall * 126*30088Sminshall */ 127*30088Sminshall 128*30088Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 129*30088Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 130*30088Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 131*30088Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 132*30088Sminshall 133*30088Sminshall #endif 134*30088Sminshall 135*30088Sminshall #define strip(x) ((x)&0x7f) 136*30088Sminshall #define min(x,y) ((x<y)? x:y) 137*30088Sminshall 138*30088Sminshall #if defined(TN3270) 139*30088Sminshall static char Ibuf[8*BUFSIZ], *Ifrontp = Ibuf, *Ibackp = Ibuf; 140*30088Sminshall #endif /* defined(TN3270) */ 141*30088Sminshall 142*30088Sminshall static char ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 143*30088Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } 144*30088Sminshall #define TTYLOC() (tfrontp) 145*30088Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) 146*30088Sminshall #define TTYMIN() (netobuf) 147*30088Sminshall #define TTYBYTES() (tfrontp-tbackp) 148*30088Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1) 149*30088Sminshall 150*30088Sminshall static char netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 151*30088Sminshall #define NETADD(c) { *nfrontp++ = c; } 152*30088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 153*30088Sminshall #define NETLOC() (nfrontp) 154*30088Sminshall #define NETMAX() (netobuf+sizeof netobuf-1) 155*30088Sminshall #define NETBYTES() (nfrontp-nbackp) 156*30088Sminshall #define NETROOM() (NETMAX()-NETLOC()+1) 157*30088Sminshall static char *neturg = 0; /* one past last byte of urgent data */ 158*30088Sminshall 159*30088Sminshall static char subbuffer[100] = 0, 160*30088Sminshall *subpointer, *subend = 0; /* buffer for sub-options */ 161*30088Sminshall #define SB_CLEAR() subpointer = subbuffer; 162*30088Sminshall #define SB_TERM() subend = subpointer; 163*30088Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 164*30088Sminshall *subpointer++ = (c); \ 165*30088Sminshall } 166*30088Sminshall 167*30088Sminshall static char sb_terminal[] = { IAC, SB, 168*30088Sminshall TELOPT_TTYPE, TELQUAL_IS, 169*30088Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 170*30088Sminshall IAC, SE }; 171*30088Sminshall #define SBTERMMODEL 13 172*30088Sminshall 173*30088Sminshall 174*30088Sminshall static char hisopts[256] = 0; 175*30088Sminshall static char myopts[256] = 0; 176*30088Sminshall 177*30088Sminshall static char doopt[] = { IAC, DO, '%', 'c', 0 }; 178*30088Sminshall static char dont[] = { IAC, DONT, '%', 'c', 0 }; 179*30088Sminshall static char will[] = { IAC, WILL, '%', 'c', 0 }; 180*30088Sminshall static char wont[] = { IAC, WONT, '%', 'c', 0 }; 181*30088Sminshall 182*30088Sminshall struct cmd { 183*30088Sminshall char *name; /* command name */ 184*30088Sminshall char *help; /* help string */ 185*30088Sminshall int (*handler)(); /* routine which executes command */ 186*30088Sminshall int dohelp; /* Should we give general help information? */ 187*30088Sminshall int needconnect; /* Do we need to be connected to execute? */ 188*30088Sminshall }; 189*30088Sminshall 190*30088Sminshall static char sibuf[BUFSIZ], *sbp = 0; 191*30088Sminshall static char tibuf[BUFSIZ], *tbp; 192*30088Sminshall static fd_set ibits, obits, xbits; 193*30088Sminshall 194*30088Sminshall 195*30088Sminshall static int 196*30088Sminshall connected = 0, 197*30088Sminshall net = 0, 198*30088Sminshall scc = 0, 199*30088Sminshall tcc = 0, 200*30088Sminshall showoptions = 0, 201*30088Sminshall In3270 = 0, /* Are we in 3270 mode? */ 202*30088Sminshall ISend = 0, /* trying to send network data in */ 203*30088Sminshall debug = 0, 204*30088Sminshall crmod = 0, 205*30088Sminshall netdata = 0, 206*30088Sminshall telnetport = 1; 207*30088Sminshall 208*30088Sminshall static FILE *NetTrace = 0; 209*30088Sminshall 210*30088Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 211*30088Sminshall 212*30088Sminshall static char 213*30088Sminshall *prompt = 0, 214*30088Sminshall escape = CONTROL(']'), 215*30088Sminshall echoc = CONTROL('E'); 216*30088Sminshall 217*30088Sminshall static int 218*30088Sminshall SYNCHing = 0, /* we are in TELNET SYNCH mode */ 219*30088Sminshall flushout = 0, /* flush output */ 220*30088Sminshall autoflush = 0, /* flush output when interrupting? */ 221*30088Sminshall autosynch = 0, /* send interrupt characters with SYNCH? */ 222*30088Sminshall localchars = 0, /* we recognize interrupt/quit */ 223*30088Sminshall donelclchars = 0, /* the user has set "localchars" */ 224*30088Sminshall dontlecho = 0; /* do we suppress local echoing right now? */ 225*30088Sminshall 226*30088Sminshall /* The following are some tn3270 specific flags */ 227*30088Sminshall #if defined(TN3270) 228*30088Sminshall 229*30088Sminshall static int 230*30088Sminshall Sent3270TerminalType = 0; /* Have we said we are a 3270? */ 231*30088Sminshall 232*30088Sminshall /* Some real, live, globals. */ 233*30088Sminshall int 234*30088Sminshall #if defined(unix) 235*30088Sminshall HaveInput = 0, /* There is input available to scan */ 236*30088Sminshall #endif /* defined(unix) */ 237*30088Sminshall tout = 0, /* Output file descriptor */ 238*30088Sminshall tin = 0; /* Input file descriptor */ 239*30088Sminshall #if defined(unix) 240*30088Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 241*30088Sminshall #endif /* defined(unix) */ 242*30088Sminshall 243*30088Sminshall #else /* defined(TN3270) */ 244*30088Sminshall static int tin = 0, tout = 0; /* file descriptors */ 245*30088Sminshall #endif /* defined(TN3270) */ 246*30088Sminshall 247*30088Sminshall static char line[200]; 248*30088Sminshall #if defined(TN3270) && defined(unix) 249*30088Sminshall static char tline[200]; 250*30088Sminshall #endif /* defined(TN3270) && defined(unix) */ 251*30088Sminshall static int margc = 0; 252*30088Sminshall static char *margv[20]; 253*30088Sminshall 254*30088Sminshall static jmp_buf toplevel; 255*30088Sminshall static jmp_buf peerdied; 256*30088Sminshall 257*30088Sminshall extern int errno; 258*30088Sminshall 259*30088Sminshall 260*30088Sminshall static struct sockaddr_in sin; 261*30088Sminshall 262*30088Sminshall static struct servent *sp = 0; 263*30088Sminshall 264*30088Sminshall static struct tchars otc = { 0 }, ntc = { 0 }; 265*30088Sminshall static struct ltchars oltc = { 0 }, nltc = { 0 }; 266*30088Sminshall static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 267*30088Sminshall static int flushline = 1; 268*30088Sminshall 269*30088Sminshall static char *hostname = 0; 270*30088Sminshall static char hnamebuf[32]; 271*30088Sminshall 272*30088Sminshall /* 273*30088Sminshall * The following are some clocks used to decide how to interpret 274*30088Sminshall * the relationship between various variables. 275*30088Sminshall */ 276*30088Sminshall 277*30088Sminshall static struct { 278*30088Sminshall int 279*30088Sminshall system, /* what the current time is */ 280*30088Sminshall echotoggle, /* last time user entered echo character */ 281*30088Sminshall modenegotiated, /* last time operating mode negotiated */ 282*30088Sminshall didnetreceive, /* last time we read data from network */ 283*30088Sminshall gotDM; /* when did we last see a data mark */ 284*30088Sminshall } clocks = { 0 }; 285*30088Sminshall 286*30088Sminshall #define settimer(x) clocks.x = clocks.system++ 287*30088Sminshall 288*30088Sminshall /* 289*30088Sminshall * Various utility routines. 290*30088Sminshall */ 291*30088Sminshall 292*30088Sminshall static void 293*30088Sminshall makeargv() 294*30088Sminshall { 295*30088Sminshall register char *cp; 296*30088Sminshall register char **argp = margv; 297*30088Sminshall 298*30088Sminshall margc = 0; 299*30088Sminshall for (cp = line; *cp;) { 300*30088Sminshall while (isspace(*cp)) 301*30088Sminshall cp++; 302*30088Sminshall if (*cp == '\0') 303*30088Sminshall break; 304*30088Sminshall *argp++ = cp; 305*30088Sminshall margc += 1; 306*30088Sminshall while (*cp != '\0' && !isspace(*cp)) 307*30088Sminshall cp++; 308*30088Sminshall if (*cp == '\0') 309*30088Sminshall break; 310*30088Sminshall *cp++ = '\0'; 311*30088Sminshall } 312*30088Sminshall *argp++ = 0; 313*30088Sminshall } 314*30088Sminshall 315*30088Sminshall static char *ambiguous; /* special return value */ 316*30088Sminshall #define Ambiguous(t) ((t)&ambiguous) 317*30088Sminshall 318*30088Sminshall 319*30088Sminshall static char ** 320*30088Sminshall genget(name, table, next) 321*30088Sminshall char *name; /* name to match */ 322*30088Sminshall char **table; /* name entry in table */ 323*30088Sminshall char **(*next)(); /* routine to return next entry in table */ 324*30088Sminshall { 325*30088Sminshall register char *p, *q; 326*30088Sminshall register char **c, **found; 327*30088Sminshall register int nmatches, longest; 328*30088Sminshall 329*30088Sminshall longest = 0; 330*30088Sminshall nmatches = 0; 331*30088Sminshall found = 0; 332*30088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 333*30088Sminshall for (q = name; 334*30088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 335*30088Sminshall if (*q == 0) /* exact match? */ 336*30088Sminshall return (c); 337*30088Sminshall if (!*q) { /* the name was a prefix */ 338*30088Sminshall if (q - name > longest) { 339*30088Sminshall longest = q - name; 340*30088Sminshall nmatches = 1; 341*30088Sminshall found = c; 342*30088Sminshall } else if (q - name == longest) 343*30088Sminshall nmatches++; 344*30088Sminshall } 345*30088Sminshall } 346*30088Sminshall if (nmatches > 1) 347*30088Sminshall return Ambiguous(char **); 348*30088Sminshall return (found); 349*30088Sminshall } 350*30088Sminshall 351*30088Sminshall /* 352*30088Sminshall * Make a character string into a number. 353*30088Sminshall * 354*30088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 355*30088Sminshall */ 356*30088Sminshall 357*30088Sminshall static 358*30088Sminshall special(s) 359*30088Sminshall register char *s; 360*30088Sminshall { 361*30088Sminshall register char c; 362*30088Sminshall char b; 363*30088Sminshall 364*30088Sminshall switch (*s) { 365*30088Sminshall case '^': 366*30088Sminshall b = *++s; 367*30088Sminshall if (b == '?') { 368*30088Sminshall c = b | 0x40; /* DEL */ 369*30088Sminshall } else { 370*30088Sminshall c = b & 0x1f; 371*30088Sminshall } 372*30088Sminshall break; 373*30088Sminshall default: 374*30088Sminshall c = *s; 375*30088Sminshall break; 376*30088Sminshall } 377*30088Sminshall return c; 378*30088Sminshall } 379*30088Sminshall 380*30088Sminshall /* 381*30088Sminshall * Construct a control character sequence 382*30088Sminshall * for a special character. 383*30088Sminshall */ 384*30088Sminshall static char * 385*30088Sminshall control(c) 386*30088Sminshall register int c; 387*30088Sminshall { 388*30088Sminshall static char buf[3]; 389*30088Sminshall 390*30088Sminshall if (c == 0x7f) 391*30088Sminshall return ("^?"); 392*30088Sminshall if (c == '\377') { 393*30088Sminshall return "off"; 394*30088Sminshall } 395*30088Sminshall if (c >= 0x20) { 396*30088Sminshall buf[0] = c; 397*30088Sminshall buf[1] = 0; 398*30088Sminshall } else { 399*30088Sminshall buf[0] = '^'; 400*30088Sminshall buf[1] = '@'+c; 401*30088Sminshall buf[2] = 0; 402*30088Sminshall } 403*30088Sminshall return (buf); 404*30088Sminshall } 405*30088Sminshall 406*30088Sminshall 407*30088Sminshall /* 408*30088Sminshall * upcase() 409*30088Sminshall * 410*30088Sminshall * Upcase (in place) the argument. 411*30088Sminshall */ 412*30088Sminshall 413*30088Sminshall static void 414*30088Sminshall upcase(argument) 415*30088Sminshall register char *argument; 416*30088Sminshall { 417*30088Sminshall register int c; 418*30088Sminshall 419*30088Sminshall while ((c = *argument) != 0) { 420*30088Sminshall if (islower(c)) { 421*30088Sminshall *argument = toupper(c); 422*30088Sminshall } 423*30088Sminshall argument++; 424*30088Sminshall } 425*30088Sminshall } 426*30088Sminshall 427*30088Sminshall /* 428*30088Sminshall * The following are routines used to print out debugging information. 429*30088Sminshall */ 430*30088Sminshall 431*30088Sminshall 432*30088Sminshall static void 433*30088Sminshall Dump(direction, buffer, length) 434*30088Sminshall char direction; 435*30088Sminshall char *buffer; 436*30088Sminshall int length; 437*30088Sminshall { 438*30088Sminshall # define BYTES_PER_LINE 32 439*30088Sminshall # define min(x,y) ((x<y)? x:y) 440*30088Sminshall char *pThis; 441*30088Sminshall int offset; 442*30088Sminshall 443*30088Sminshall offset = 0; 444*30088Sminshall 445*30088Sminshall while (length) { 446*30088Sminshall /* print one line */ 447*30088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 448*30088Sminshall pThis = buffer; 449*30088Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 450*30088Sminshall while (pThis < buffer) { 451*30088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 452*30088Sminshall pThis++; 453*30088Sminshall } 454*30088Sminshall fprintf(NetTrace, "\n"); 455*30088Sminshall length -= BYTES_PER_LINE; 456*30088Sminshall offset += BYTES_PER_LINE; 457*30088Sminshall if (length < 0) { 458*30088Sminshall return; 459*30088Sminshall } 460*30088Sminshall /* find next unique line */ 461*30088Sminshall } 462*30088Sminshall } 463*30088Sminshall 464*30088Sminshall 465*30088Sminshall /*VARARGS*/ 466*30088Sminshall static void 467*30088Sminshall printoption(direction, fmt, option, what) 468*30088Sminshall char *direction, *fmt; 469*30088Sminshall int option, what; 470*30088Sminshall { 471*30088Sminshall if (!showoptions) 472*30088Sminshall return; 473*30088Sminshall fprintf(NetTrace, "%s ", direction+1); 474*30088Sminshall if (fmt == doopt) 475*30088Sminshall fmt = "do"; 476*30088Sminshall else if (fmt == dont) 477*30088Sminshall fmt = "dont"; 478*30088Sminshall else if (fmt == will) 479*30088Sminshall fmt = "will"; 480*30088Sminshall else if (fmt == wont) 481*30088Sminshall fmt = "wont"; 482*30088Sminshall else 483*30088Sminshall fmt = "???"; 484*30088Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 485*30088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]); 486*30088Sminshall else 487*30088Sminshall fprintf(NetTrace, "%s %d", fmt, option); 488*30088Sminshall if (*direction == '<') { 489*30088Sminshall fprintf(NetTrace, "\r\n"); 490*30088Sminshall return; 491*30088Sminshall } 492*30088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); 493*30088Sminshall } 494*30088Sminshall 495*30088Sminshall static void 496*30088Sminshall printsub(direction, pointer, length) 497*30088Sminshall char *direction, /* "<" or ">" */ 498*30088Sminshall *pointer; /* where suboption data sits */ 499*30088Sminshall int length; /* length of suboption data */ 500*30088Sminshall { 501*30088Sminshall if (showoptions) { 502*30088Sminshall fprintf(NetTrace, "%s suboption ", 503*30088Sminshall (direction[0] == '<')? "Received":"Sent"); 504*30088Sminshall switch (pointer[0]) { 505*30088Sminshall case TELOPT_TTYPE: 506*30088Sminshall fprintf(NetTrace, "Terminal type "); 507*30088Sminshall switch (pointer[1]) { 508*30088Sminshall case TELQUAL_IS: 509*30088Sminshall { 510*30088Sminshall char tmpbuf[sizeof subbuffer]; 511*30088Sminshall int minlen = min(length, sizeof tmpbuf); 512*30088Sminshall 513*30088Sminshall bcopy(pointer+2, tmpbuf, minlen); 514*30088Sminshall tmpbuf[minlen-1] = 0; 515*30088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf); 516*30088Sminshall } 517*30088Sminshall break; 518*30088Sminshall case TELQUAL_SEND: 519*30088Sminshall fprintf(NetTrace, "- request to send.\n"); 520*30088Sminshall break; 521*30088Sminshall default: 522*30088Sminshall fprintf(NetTrace, 523*30088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]); 524*30088Sminshall } 525*30088Sminshall break; 526*30088Sminshall default: 527*30088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n", 528*30088Sminshall pointer[0], pointer[0]); 529*30088Sminshall } 530*30088Sminshall } 531*30088Sminshall } 532*30088Sminshall 533*30088Sminshall /* 534*30088Sminshall * Check to see if any out-of-band data exists on a socket (for 535*30088Sminshall * Telnet "synch" processing). 536*30088Sminshall */ 537*30088Sminshall 538*30088Sminshall static int 539*30088Sminshall stilloob(s) 540*30088Sminshall int s; /* socket number */ 541*30088Sminshall { 542*30088Sminshall static struct timeval timeout = { 0 }; 543*30088Sminshall fd_set excepts; 544*30088Sminshall int value; 545*30088Sminshall 546*30088Sminshall do { 547*30088Sminshall FD_ZERO(&excepts); 548*30088Sminshall FD_SET(s, &excepts); 549*30088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 550*30088Sminshall } while ((value == -1) && (errno == EINTR)); 551*30088Sminshall 552*30088Sminshall if (value < 0) { 553*30088Sminshall perror("select"); 554*30088Sminshall quit(); 555*30088Sminshall } 556*30088Sminshall if (FD_ISSET(s, &excepts)) { 557*30088Sminshall return 1; 558*30088Sminshall } else { 559*30088Sminshall return 0; 560*30088Sminshall } 561*30088Sminshall } 562*30088Sminshall 563*30088Sminshall 564*30088Sminshall /* 565*30088Sminshall * netflush 566*30088Sminshall * Send as much data as possible to the network, 567*30088Sminshall * handling requests for urgent data. 568*30088Sminshall * 569*30088Sminshall * The return value indicates whether we did any 570*30088Sminshall * useful work. 571*30088Sminshall */ 572*30088Sminshall 573*30088Sminshall 574*30088Sminshall int 575*30088Sminshall netflush() 576*30088Sminshall { 577*30088Sminshall int n; 578*30088Sminshall 579*30088Sminshall if ((n = nfrontp - nbackp) > 0) { 580*30088Sminshall if (!neturg) { 581*30088Sminshall n = write(net, nbackp, n); /* normal write */ 582*30088Sminshall } else { 583*30088Sminshall n = neturg - nbackp; 584*30088Sminshall /* 585*30088Sminshall * In 4.2 (and 4.3) systems, there is some question about 586*30088Sminshall * what byte in a sendOOB operation is the "OOB" data. 587*30088Sminshall * To make ourselves compatible, we only send ONE byte 588*30088Sminshall * out of band, the one WE THINK should be OOB (though 589*30088Sminshall * we really have more the TCP philosophy of urgent data 590*30088Sminshall * rather than the Unix philosophy of OOB data). 591*30088Sminshall */ 592*30088Sminshall if (n > 1) { 593*30088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 594*30088Sminshall } else { 595*30088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 596*30088Sminshall } 597*30088Sminshall } 598*30088Sminshall } 599*30088Sminshall if (n < 0) { 600*30088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 601*30088Sminshall setcommandmode(); 602*30088Sminshall perror(hostname); 603*30088Sminshall close(net); 604*30088Sminshall neturg = 0; 605*30088Sminshall longjmp(peerdied, -1); 606*30088Sminshall /*NOTREACHED*/ 607*30088Sminshall } 608*30088Sminshall n = 0; 609*30088Sminshall } 610*30088Sminshall if (netdata && n) { 611*30088Sminshall Dump('>', nbackp, n); 612*30088Sminshall } 613*30088Sminshall nbackp += n; 614*30088Sminshall if (nbackp >= neturg) { 615*30088Sminshall neturg = 0; 616*30088Sminshall } 617*30088Sminshall if (nbackp == nfrontp) { 618*30088Sminshall nbackp = nfrontp = netobuf; 619*30088Sminshall } 620*30088Sminshall return n > 0; 621*30088Sminshall } 622*30088Sminshall 623*30088Sminshall /* 624*30088Sminshall * nextitem() 625*30088Sminshall * 626*30088Sminshall * Return the address of the next "item" in the TELNET data 627*30088Sminshall * stream. This will be the address of the next character if 628*30088Sminshall * the current address is a user data character, or it will 629*30088Sminshall * be the address of the character following the TELNET command 630*30088Sminshall * if the current address is a TELNET IAC ("I Am a Command") 631*30088Sminshall * character. 632*30088Sminshall */ 633*30088Sminshall 634*30088Sminshall static char * 635*30088Sminshall nextitem(current) 636*30088Sminshall char *current; 637*30088Sminshall { 638*30088Sminshall if ((*current&0xff) != IAC) { 639*30088Sminshall return current+1; 640*30088Sminshall } 641*30088Sminshall switch (*(current+1)&0xff) { 642*30088Sminshall case DO: 643*30088Sminshall case DONT: 644*30088Sminshall case WILL: 645*30088Sminshall case WONT: 646*30088Sminshall return current+3; 647*30088Sminshall case SB: /* loop forever looking for the SE */ 648*30088Sminshall { 649*30088Sminshall register char *look = current+2; 650*30088Sminshall 651*30088Sminshall for (;;) { 652*30088Sminshall if ((*look++&0xff) == IAC) { 653*30088Sminshall if ((*look++&0xff) == SE) { 654*30088Sminshall return look; 655*30088Sminshall } 656*30088Sminshall } 657*30088Sminshall } 658*30088Sminshall } 659*30088Sminshall default: 660*30088Sminshall return current+2; 661*30088Sminshall } 662*30088Sminshall } 663*30088Sminshall /* 664*30088Sminshall * netclear() 665*30088Sminshall * 666*30088Sminshall * We are about to do a TELNET SYNCH operation. Clear 667*30088Sminshall * the path to the network. 668*30088Sminshall * 669*30088Sminshall * Things are a bit tricky since we may have sent the first 670*30088Sminshall * byte or so of a previous TELNET command into the network. 671*30088Sminshall * So, we have to scan the network buffer from the beginning 672*30088Sminshall * until we are up to where we want to be. 673*30088Sminshall * 674*30088Sminshall * A side effect of what we do, just to keep things 675*30088Sminshall * simple, is to clear the urgent data pointer. The principal 676*30088Sminshall * caller should be setting the urgent data pointer AFTER calling 677*30088Sminshall * us in any case. 678*30088Sminshall */ 679*30088Sminshall 680*30088Sminshall static void 681*30088Sminshall netclear() 682*30088Sminshall { 683*30088Sminshall register char *thisitem, *next; 684*30088Sminshall char *good; 685*30088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 686*30088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 687*30088Sminshall 688*30088Sminshall thisitem = netobuf; 689*30088Sminshall 690*30088Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 691*30088Sminshall thisitem = next; 692*30088Sminshall } 693*30088Sminshall 694*30088Sminshall /* Now, thisitem is first before/at boundary. */ 695*30088Sminshall 696*30088Sminshall good = netobuf; /* where the good bytes go */ 697*30088Sminshall 698*30088Sminshall while (nfrontp > thisitem) { 699*30088Sminshall if (wewant(thisitem)) { 700*30088Sminshall int length; 701*30088Sminshall 702*30088Sminshall next = thisitem; 703*30088Sminshall do { 704*30088Sminshall next = nextitem(next); 705*30088Sminshall } while (wewant(next) && (nfrontp > next)); 706*30088Sminshall length = next-thisitem; 707*30088Sminshall bcopy(thisitem, good, length); 708*30088Sminshall good += length; 709*30088Sminshall thisitem = next; 710*30088Sminshall } else { 711*30088Sminshall thisitem = nextitem(thisitem); 712*30088Sminshall } 713*30088Sminshall } 714*30088Sminshall 715*30088Sminshall nbackp = netobuf; 716*30088Sminshall nfrontp = good; /* next byte to be sent */ 717*30088Sminshall neturg = 0; 718*30088Sminshall } 719*30088Sminshall 720*30088Sminshall /* 721*30088Sminshall * These routines add various telnet commands to the data stream. 722*30088Sminshall */ 723*30088Sminshall 724*30088Sminshall #if defined(NOT43) 725*30088Sminshall static int 726*30088Sminshall #else /* defined(NOT43) */ 727*30088Sminshall static void 728*30088Sminshall #endif /* defined(NOT43) */ 729*30088Sminshall dosynch() 730*30088Sminshall { 731*30088Sminshall netclear(); /* clear the path to the network */ 732*30088Sminshall NET2ADD(IAC, DM); 733*30088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 734*30088Sminshall 735*30088Sminshall #if defined(NOT43) 736*30088Sminshall return 0; 737*30088Sminshall #endif /* defined(NOT43) */ 738*30088Sminshall } 739*30088Sminshall 740*30088Sminshall static void 741*30088Sminshall doflush() 742*30088Sminshall { 743*30088Sminshall NET2ADD(IAC, DO); 744*30088Sminshall NETADD(TELOPT_TM); 745*30088Sminshall flushline = 1; 746*30088Sminshall flushout = 1; 747*30088Sminshall ttyflush(); 748*30088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 749*30088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 750*30088Sminshall } 751*30088Sminshall 752*30088Sminshall static void 753*30088Sminshall intp() 754*30088Sminshall { 755*30088Sminshall NET2ADD(IAC, IP); 756*30088Sminshall if (autoflush) { 757*30088Sminshall doflush(); 758*30088Sminshall } 759*30088Sminshall if (autosynch) { 760*30088Sminshall dosynch(); 761*30088Sminshall } 762*30088Sminshall } 763*30088Sminshall 764*30088Sminshall static void 765*30088Sminshall sendbrk() 766*30088Sminshall { 767*30088Sminshall NET2ADD(IAC, BREAK); 768*30088Sminshall if (autoflush) { 769*30088Sminshall doflush(); 770*30088Sminshall } 771*30088Sminshall if (autosynch) { 772*30088Sminshall dosynch(); 773*30088Sminshall } 774*30088Sminshall } 775*30088Sminshall 776*30088Sminshall /* 777*30088Sminshall * Send as much data as possible to the terminal. 778*30088Sminshall * 779*30088Sminshall * The return value indicates whether we did any 780*30088Sminshall * useful work. 781*30088Sminshall */ 782*30088Sminshall 783*30088Sminshall 784*30088Sminshall static int 785*30088Sminshall ttyflush() 786*30088Sminshall { 787*30088Sminshall int n; 788*30088Sminshall 789*30088Sminshall if ((n = tfrontp - tbackp) > 0) { 790*30088Sminshall if (!(SYNCHing||flushout)) { 791*30088Sminshall n = write(tout, tbackp, n); 792*30088Sminshall } else { 793*30088Sminshall ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 794*30088Sminshall /* we leave 'n' alone! */ 795*30088Sminshall } 796*30088Sminshall } 797*30088Sminshall if (n >= 0) { 798*30088Sminshall tbackp += n; 799*30088Sminshall if (tbackp == tfrontp) { 800*30088Sminshall tbackp = tfrontp = ttyobuf; 801*30088Sminshall } 802*30088Sminshall } 803*30088Sminshall return n > 0; 804*30088Sminshall } 805*30088Sminshall 806*30088Sminshall #if defined(TN3270) 807*30088Sminshall 808*30088Sminshall #if defined(unix) 809*30088Sminshall static void 810*30088Sminshall inputAvailable() 811*30088Sminshall { 812*30088Sminshall HaveInput = 1; 813*30088Sminshall } 814*30088Sminshall #endif /* defined(unix) */ 815*30088Sminshall 816*30088Sminshall void 817*30088Sminshall outputPurge() 818*30088Sminshall { 819*30088Sminshall int tmp = flushout; 820*30088Sminshall 821*30088Sminshall flushout = 1; 822*30088Sminshall 823*30088Sminshall ttyflush(); 824*30088Sminshall 825*30088Sminshall flushout = tmp; 826*30088Sminshall } 827*30088Sminshall 828*30088Sminshall #endif /* defined(TN3270) */ 829*30088Sminshall 830*30088Sminshall #if defined(unix) 831*30088Sminshall /* 832*30088Sminshall * Various signal handling routines. 833*30088Sminshall */ 834*30088Sminshall 835*30088Sminshall static void 836*30088Sminshall deadpeer() 837*30088Sminshall { 838*30088Sminshall setcommandmode(); 839*30088Sminshall longjmp(peerdied, -1); 840*30088Sminshall } 841*30088Sminshall 842*30088Sminshall static void 843*30088Sminshall intr() 844*30088Sminshall { 845*30088Sminshall if (localchars) { 846*30088Sminshall intp(); 847*30088Sminshall return; 848*30088Sminshall } 849*30088Sminshall setcommandmode(); 850*30088Sminshall longjmp(toplevel, -1); 851*30088Sminshall } 852*30088Sminshall 853*30088Sminshall static void 854*30088Sminshall intr2() 855*30088Sminshall { 856*30088Sminshall if (localchars) { 857*30088Sminshall sendbrk(); 858*30088Sminshall return; 859*30088Sminshall } 860*30088Sminshall } 861*30088Sminshall 862*30088Sminshall static void 863*30088Sminshall doescape() 864*30088Sminshall { 865*30088Sminshall command(0); 866*30088Sminshall } 867*30088Sminshall #endif /* defined(unix) */ 868*30088Sminshall 869*30088Sminshall static int globalmode = 0; 870*30088Sminshall /* Various modes */ 871*30088Sminshall #define MODE_LINE(m) (modelist[m].modetype & LINE) 872*30088Sminshall #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS) 873*30088Sminshall 874*30088Sminshall #define LOCAL_CHARS 0x01 /* Characters processed locally */ 875*30088Sminshall #define LINE 0x02 /* Line-by-line mode of operation */ 876*30088Sminshall 877*30088Sminshall static struct { 878*30088Sminshall char *modedescriptions; 879*30088Sminshall char modetype; 880*30088Sminshall } modelist[] = { 881*30088Sminshall { "telnet command mode", 0 }, 882*30088Sminshall { "character-at-a-time mode", 0 }, 883*30088Sminshall { "character-at-a-time mode (local echo)", LOCAL_CHARS }, 884*30088Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 885*30088Sminshall { "line-by-line mode", LINE | LOCAL_CHARS }, 886*30088Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 887*30088Sminshall { "3270 mode", 0 }, 888*30088Sminshall }; 889*30088Sminshall /* 890*30088Sminshall * Mode - set up terminal to a specific mode. 891*30088Sminshall */ 892*30088Sminshall 893*30088Sminshall 894*30088Sminshall static void 895*30088Sminshall mode(f) 896*30088Sminshall register int f; 897*30088Sminshall { 898*30088Sminshall static int prevmode = 0; 899*30088Sminshall struct tchars *tc; 900*30088Sminshall struct tchars tc3; 901*30088Sminshall struct ltchars *ltc; 902*30088Sminshall struct sgttyb sb; 903*30088Sminshall int onoff; 904*30088Sminshall #if defined(unix) 905*30088Sminshall int old; 906*30088Sminshall #endif /* defined(unix) */ 907*30088Sminshall struct tchars notc2; 908*30088Sminshall struct ltchars noltc2; 909*30088Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 910*30088Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 911*30088Sminshall 912*30088Sminshall globalmode = f; 913*30088Sminshall if (prevmode == f) 914*30088Sminshall return; 915*30088Sminshall #if defined(unix) 916*30088Sminshall old = prevmode; 917*30088Sminshall #endif /* defined(unix) */ 918*30088Sminshall prevmode = f; 919*30088Sminshall sb = nttyb; 920*30088Sminshall 921*30088Sminshall switch (f) { 922*30088Sminshall 923*30088Sminshall case 0: 924*30088Sminshall onoff = 0; 925*30088Sminshall tc = &otc; 926*30088Sminshall ltc = &oltc; 927*30088Sminshall break; 928*30088Sminshall 929*30088Sminshall case 1: /* remote character processing, remote echo */ 930*30088Sminshall case 2: /* remote character processing, local echo */ 931*30088Sminshall case 6: /* 3270 mode - like 1, but with xon/xoff local */ 932*30088Sminshall /* (might be nice to have "6" in telnet also...) */ 933*30088Sminshall sb.sg_flags |= CBREAK; 934*30088Sminshall if ((f == 1) || (f == 6)) { 935*30088Sminshall sb.sg_flags &= ~(ECHO|CRMOD); 936*30088Sminshall } else { 937*30088Sminshall sb.sg_flags |= ECHO|CRMOD; 938*30088Sminshall } 939*30088Sminshall sb.sg_erase = sb.sg_kill = -1; 940*30088Sminshall if (f == 6) { 941*30088Sminshall tc = &tc3; 942*30088Sminshall tc3 = notc; 943*30088Sminshall /* get XON, XOFF characters */ 944*30088Sminshall tc3.t_startc = otc.t_startc; 945*30088Sminshall tc3.t_stopc = otc.t_stopc; 946*30088Sminshall } else { 947*30088Sminshall /* 948*30088Sminshall * If user hasn't specified one way or the other, 949*30088Sminshall * then default to not trapping signals. 950*30088Sminshall */ 951*30088Sminshall if (!donelclchars) { 952*30088Sminshall localchars = 0; 953*30088Sminshall } 954*30088Sminshall if (localchars) { 955*30088Sminshall notc2 = notc; 956*30088Sminshall notc2.t_intrc = ntc.t_intrc; 957*30088Sminshall notc2.t_quitc = ntc.t_quitc; 958*30088Sminshall tc = ¬c2; 959*30088Sminshall } else { 960*30088Sminshall tc = ¬c; 961*30088Sminshall } 962*30088Sminshall } 963*30088Sminshall ltc = &noltc; 964*30088Sminshall onoff = 1; 965*30088Sminshall break; 966*30088Sminshall case 3: /* local character processing, remote echo */ 967*30088Sminshall case 4: /* local character processing, local echo */ 968*30088Sminshall case 5: /* local character processing, no echo */ 969*30088Sminshall sb.sg_flags &= ~CBREAK; 970*30088Sminshall sb.sg_flags |= CRMOD; 971*30088Sminshall if (f == 4) 972*30088Sminshall sb.sg_flags |= ECHO; 973*30088Sminshall else 974*30088Sminshall sb.sg_flags &= ~ECHO; 975*30088Sminshall notc2 = ntc; 976*30088Sminshall tc = ¬c2; 977*30088Sminshall noltc2 = oltc; 978*30088Sminshall ltc = &noltc2; 979*30088Sminshall /* 980*30088Sminshall * If user hasn't specified one way or the other, 981*30088Sminshall * then default to trapping signals. 982*30088Sminshall */ 983*30088Sminshall if (!donelclchars) { 984*30088Sminshall localchars = 1; 985*30088Sminshall } 986*30088Sminshall if (localchars) { 987*30088Sminshall notc2.t_brkc = nltc.t_flushc; 988*30088Sminshall noltc2.t_flushc = -1; 989*30088Sminshall } else { 990*30088Sminshall notc2.t_intrc = notc2.t_quitc = -1; 991*30088Sminshall } 992*30088Sminshall noltc2.t_suspc = escape; 993*30088Sminshall noltc2.t_dsuspc = -1; 994*30088Sminshall onoff = 1; 995*30088Sminshall break; 996*30088Sminshall 997*30088Sminshall default: 998*30088Sminshall return; 999*30088Sminshall } 1000*30088Sminshall ioctl(tin, TIOCSLTC, (char *)ltc); 1001*30088Sminshall ioctl(tin, TIOCSETC, (char *)tc); 1002*30088Sminshall ioctl(tin, TIOCSETP, (char *)&sb); 1003*30088Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 1004*30088Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 1005*30088Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 1006*30088Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 1007*30088Sminshall #if defined(TN3270) && !defined(DEBUG) 1008*30088Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 1009*30088Sminshall #endif /* defined(TN3270) && !defined(DEBUG) */ 1010*30088Sminshall 1011*30088Sminshall #if defined(unix) 1012*30088Sminshall if (MODE_LINE(f)) { 1013*30088Sminshall signal(SIGTSTP, doescape); 1014*30088Sminshall } else if (MODE_LINE(old)) { 1015*30088Sminshall signal(SIGTSTP, SIG_DFL); 1016*30088Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 1017*30088Sminshall } 1018*30088Sminshall #endif /* defined(unix) */ 1019*30088Sminshall } 1020*30088Sminshall 1021*30088Sminshall /* 1022*30088Sminshall * These routines decides on what the mode should be (based on the values 1023*30088Sminshall * of various global variables). 1024*30088Sminshall */ 1025*30088Sminshall 1026*30088Sminshall 1027*30088Sminshall static 1028*30088Sminshall getconnmode() 1029*30088Sminshall { 1030*30088Sminshall static char newmode[16] = 1031*30088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; 1032*30088Sminshall int modeindex = 0; 1033*30088Sminshall 1034*30088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 1035*30088Sminshall modeindex += 1; 1036*30088Sminshall } 1037*30088Sminshall if (hisopts[TELOPT_ECHO]) { 1038*30088Sminshall modeindex += 2; 1039*30088Sminshall } 1040*30088Sminshall if (hisopts[TELOPT_SGA]) { 1041*30088Sminshall modeindex += 4; 1042*30088Sminshall } 1043*30088Sminshall if (In3270) { 1044*30088Sminshall modeindex += 8; 1045*30088Sminshall } 1046*30088Sminshall return newmode[modeindex]; 1047*30088Sminshall } 1048*30088Sminshall 1049*30088Sminshall void 1050*30088Sminshall setconnmode() 1051*30088Sminshall { 1052*30088Sminshall mode(getconnmode()); 1053*30088Sminshall } 1054*30088Sminshall 1055*30088Sminshall 1056*30088Sminshall void 1057*30088Sminshall setcommandmode() 1058*30088Sminshall { 1059*30088Sminshall mode(0); 1060*30088Sminshall } 1061*30088Sminshall 1062*30088Sminshall static void 1063*30088Sminshall willoption(option, reply) 1064*30088Sminshall int option, reply; 1065*30088Sminshall { 1066*30088Sminshall char *fmt; 1067*30088Sminshall 1068*30088Sminshall switch (option) { 1069*30088Sminshall 1070*30088Sminshall # if defined(TN3270) 1071*30088Sminshall case TELOPT_EOR: 1072*30088Sminshall case TELOPT_BINARY: 1073*30088Sminshall #endif /* defined(TN3270) */ 1074*30088Sminshall case TELOPT_ECHO: 1075*30088Sminshall case TELOPT_SGA: 1076*30088Sminshall settimer(modenegotiated); 1077*30088Sminshall hisopts[option] = 1; 1078*30088Sminshall fmt = doopt; 1079*30088Sminshall setconnmode(); /* possibly set new tty mode */ 1080*30088Sminshall break; 1081*30088Sminshall 1082*30088Sminshall case TELOPT_TM: 1083*30088Sminshall return; /* Never reply to TM will's/wont's */ 1084*30088Sminshall 1085*30088Sminshall default: 1086*30088Sminshall fmt = dont; 1087*30088Sminshall break; 1088*30088Sminshall } 1089*30088Sminshall sprintf(nfrontp, fmt, option); 1090*30088Sminshall nfrontp += sizeof (dont) - 2; 1091*30088Sminshall if (reply) 1092*30088Sminshall printoption(">SENT", fmt, option, reply); 1093*30088Sminshall else 1094*30088Sminshall printoption("<SENT", fmt, option, reply); 1095*30088Sminshall } 1096*30088Sminshall 1097*30088Sminshall static void 1098*30088Sminshall wontoption(option, reply) 1099*30088Sminshall int option, reply; 1100*30088Sminshall { 1101*30088Sminshall char *fmt; 1102*30088Sminshall 1103*30088Sminshall switch (option) { 1104*30088Sminshall 1105*30088Sminshall case TELOPT_ECHO: 1106*30088Sminshall case TELOPT_SGA: 1107*30088Sminshall settimer(modenegotiated); 1108*30088Sminshall hisopts[option] = 0; 1109*30088Sminshall fmt = dont; 1110*30088Sminshall setconnmode(); /* Set new tty mode */ 1111*30088Sminshall break; 1112*30088Sminshall 1113*30088Sminshall case TELOPT_TM: 1114*30088Sminshall return; /* Never reply to TM will's/wont's */ 1115*30088Sminshall 1116*30088Sminshall default: 1117*30088Sminshall fmt = dont; 1118*30088Sminshall } 1119*30088Sminshall sprintf(nfrontp, fmt, option); 1120*30088Sminshall nfrontp += sizeof (doopt) - 2; 1121*30088Sminshall if (reply) 1122*30088Sminshall printoption(">SENT", fmt, option, reply); 1123*30088Sminshall else 1124*30088Sminshall printoption("<SENT", fmt, option, reply); 1125*30088Sminshall } 1126*30088Sminshall 1127*30088Sminshall static void 1128*30088Sminshall dooption(option) 1129*30088Sminshall int option; 1130*30088Sminshall { 1131*30088Sminshall char *fmt; 1132*30088Sminshall 1133*30088Sminshall switch (option) { 1134*30088Sminshall 1135*30088Sminshall case TELOPT_TM: 1136*30088Sminshall fmt = will; 1137*30088Sminshall break; 1138*30088Sminshall 1139*30088Sminshall # if defined(TN3270) 1140*30088Sminshall case TELOPT_EOR: 1141*30088Sminshall case TELOPT_BINARY: 1142*30088Sminshall # endif /* defined(TN3270) */ 1143*30088Sminshall case TELOPT_TTYPE: /* terminal type option */ 1144*30088Sminshall case TELOPT_SGA: /* no big deal */ 1145*30088Sminshall fmt = will; 1146*30088Sminshall myopts[option] = 1; 1147*30088Sminshall break; 1148*30088Sminshall 1149*30088Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 1150*30088Sminshall default: 1151*30088Sminshall fmt = wont; 1152*30088Sminshall break; 1153*30088Sminshall } 1154*30088Sminshall sprintf(nfrontp, fmt, option); 1155*30088Sminshall nfrontp += sizeof (doopt) - 2; 1156*30088Sminshall printoption(">SENT", fmt, option, 0); 1157*30088Sminshall } 1158*30088Sminshall 1159*30088Sminshall /* 1160*30088Sminshall * suboption() 1161*30088Sminshall * 1162*30088Sminshall * Look at the sub-option buffer, and try to be helpful to the other 1163*30088Sminshall * side. 1164*30088Sminshall * 1165*30088Sminshall * Currently we recognize: 1166*30088Sminshall * 1167*30088Sminshall * Terminal type, send request. 1168*30088Sminshall */ 1169*30088Sminshall 1170*30088Sminshall static void 1171*30088Sminshall suboption() 1172*30088Sminshall { 1173*30088Sminshall printsub("<", subbuffer, subend-subbuffer+1); 1174*30088Sminshall switch (subbuffer[0]&0xff) { 1175*30088Sminshall case TELOPT_TTYPE: 1176*30088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 1177*30088Sminshall ; 1178*30088Sminshall } else { 1179*30088Sminshall char *name; 1180*30088Sminshall char namebuf[41]; 1181*30088Sminshall extern char *getenv(); 1182*30088Sminshall int len; 1183*30088Sminshall 1184*30088Sminshall #if defined(TN3270) 1185*30088Sminshall /* 1186*30088Sminshall * Try to send a 3270 type terminal name. Decide which one base 1187*30088Sminshall * on the format of our screen, and (in the future) color 1188*30088Sminshall * capaiblities. 1189*30088Sminshall */ 1190*30088Sminshall if ((initscr() != ERR) && /* Initialize curses to get line size */ 1191*30088Sminshall (LINES >= 24) && (COLS >= 80)) { 1192*30088Sminshall Sent3270TerminalType = 1; 1193*30088Sminshall if ((LINES >= 27) && (COLS >= 132)) { 1194*30088Sminshall MaxNumberLines = 27; 1195*30088Sminshall MaxNumberColumns = 132; 1196*30088Sminshall sb_terminal[SBTERMMODEL] = '5'; 1197*30088Sminshall } else if (LINES >= 43) { 1198*30088Sminshall MaxNumberLines = 43; 1199*30088Sminshall MaxNumberColumns = 80; 1200*30088Sminshall sb_terminal[SBTERMMODEL] = '4'; 1201*30088Sminshall } else if (LINES >= 32) { 1202*30088Sminshall MaxNumberLines = 32; 1203*30088Sminshall MaxNumberColumns = 80; 1204*30088Sminshall sb_terminal[SBTERMMODEL] = '3'; 1205*30088Sminshall } else { 1206*30088Sminshall MaxNumberLines = 24; 1207*30088Sminshall MaxNumberColumns = 80; 1208*30088Sminshall sb_terminal[SBTERMMODEL] = '2'; 1209*30088Sminshall } 1210*30088Sminshall NumberLines = 24; /* before we start out... */ 1211*30088Sminshall NumberColumns = 80; 1212*30088Sminshall ScreenSize = NumberLines*NumberColumns; 1213*30088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 1214*30088Sminshall ExitString(stderr, 1215*30088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 1216*30088Sminshall /*NOTREACHED*/ 1217*30088Sminshall } 1218*30088Sminshall bcopy(sb_terminal, nfrontp, sizeof sb_terminal); 1219*30088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 1220*30088Sminshall nfrontp += sizeof sb_terminal; 1221*30088Sminshall return; 1222*30088Sminshall } 1223*30088Sminshall #endif /* defined(TN3270) */ 1224*30088Sminshall 1225*30088Sminshall name = getenv("TERM"); 1226*30088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 1227*30088Sminshall name = "UNKNOWN"; 1228*30088Sminshall } 1229*30088Sminshall if ((len + 4+2) < NETROOM()) { 1230*30088Sminshall strcpy(namebuf, name); 1231*30088Sminshall upcase(namebuf); 1232*30088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 1233*30088Sminshall TELQUAL_IS, namebuf, IAC, SE); 1234*30088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 1235*30088Sminshall nfrontp += 4+strlen(namebuf)+2; 1236*30088Sminshall } else { 1237*30088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 1238*30088Sminshall 1); 1239*30088Sminshall /*NOTREACHED*/ 1240*30088Sminshall } 1241*30088Sminshall } 1242*30088Sminshall 1243*30088Sminshall default: 1244*30088Sminshall break; 1245*30088Sminshall } 1246*30088Sminshall } 1247*30088Sminshall 1248*30088Sminshall #if defined(TN3270) 1249*30088Sminshall static void 1250*30088Sminshall SetIn3270() 1251*30088Sminshall { 1252*30088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 1253*30088Sminshall && hisopts[TELOPT_BINARY]) { 1254*30088Sminshall if (!In3270) { 1255*30088Sminshall In3270 = 1; 1256*30088Sminshall OptInit(); /* initialize mappings */ 1257*30088Sminshall /* initialize terminal key mapping */ 1258*30088Sminshall (void) DataFromTerminal(ttyobuf, 0); 1259*30088Sminshall StartScreen(); /* Start terminal going */ 1260*30088Sminshall setconnmode(); 1261*30088Sminshall } 1262*30088Sminshall } else { 1263*30088Sminshall if (In3270) { 1264*30088Sminshall StopScreen(1); 1265*30088Sminshall In3270 = 0; 1266*30088Sminshall setconnmode(); 1267*30088Sminshall } 1268*30088Sminshall } 1269*30088Sminshall } 1270*30088Sminshall #endif /* defined(TN3270) */ 1271*30088Sminshall 1272*30088Sminshall /* 1273*30088Sminshall * Telnet receiver states for fsm 1274*30088Sminshall */ 1275*30088Sminshall #define TS_DATA 0 1276*30088Sminshall #define TS_IAC 1 1277*30088Sminshall #define TS_WILL 2 1278*30088Sminshall #define TS_WONT 3 1279*30088Sminshall #define TS_DO 4 1280*30088Sminshall #define TS_DONT 5 1281*30088Sminshall #define TS_CR 6 1282*30088Sminshall #define TS_SB 7 /* sub-option collection */ 1283*30088Sminshall #define TS_SE 8 /* looking for sub-option end */ 1284*30088Sminshall 1285*30088Sminshall static void 1286*30088Sminshall telrcv() 1287*30088Sminshall { 1288*30088Sminshall register int c; 1289*30088Sminshall static int state = TS_DATA; 1290*30088Sminshall # if defined(TN3270) 1291*30088Sminshall register int Scc; 1292*30088Sminshall register char *Sbp; 1293*30088Sminshall # endif /* defined(TN3270) */ 1294*30088Sminshall 1295*30088Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 1296*30088Sminshall c = *sbp++ & 0xff, scc--; 1297*30088Sminshall switch (state) { 1298*30088Sminshall 1299*30088Sminshall case TS_CR: 1300*30088Sminshall state = TS_DATA; 1301*30088Sminshall if (c == '\0') { 1302*30088Sminshall break; /* Ignore \0 after CR */ 1303*30088Sminshall } else if (c == '\n') { 1304*30088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 1305*30088Sminshall TTYADD(c); 1306*30088Sminshall } 1307*30088Sminshall break; 1308*30088Sminshall } 1309*30088Sminshall /* Else, fall through */ 1310*30088Sminshall 1311*30088Sminshall case TS_DATA: 1312*30088Sminshall if (c == IAC) { 1313*30088Sminshall state = TS_IAC; 1314*30088Sminshall continue; 1315*30088Sminshall } 1316*30088Sminshall # if defined(TN3270) 1317*30088Sminshall if (In3270) { 1318*30088Sminshall *Ifrontp++ = c; 1319*30088Sminshall Sbp = sbp; 1320*30088Sminshall Scc = scc; 1321*30088Sminshall while (Scc > 0) { 1322*30088Sminshall c = *Sbp++ & 0377, Scc--; 1323*30088Sminshall if (c == IAC) { 1324*30088Sminshall state = TS_IAC; 1325*30088Sminshall break; 1326*30088Sminshall } 1327*30088Sminshall *Ifrontp++ = c; 1328*30088Sminshall } 1329*30088Sminshall sbp = Sbp; 1330*30088Sminshall scc = Scc; 1331*30088Sminshall } else 1332*30088Sminshall # endif /* defined(TN3270) */ 1333*30088Sminshall /* 1334*30088Sminshall * The 'crmod' hack (see following) is needed 1335*30088Sminshall * since we can't * set CRMOD on output only. 1336*30088Sminshall * Machines like MULTICS like to send \r without 1337*30088Sminshall * \n; since we must turn off CRMOD to get proper 1338*30088Sminshall * input, the mapping is done here (sigh). 1339*30088Sminshall */ 1340*30088Sminshall if (c == '\r') { 1341*30088Sminshall if (scc > 0) { 1342*30088Sminshall c = *sbp&0xff; 1343*30088Sminshall if (c == 0) { 1344*30088Sminshall sbp++, scc--; 1345*30088Sminshall /* a "true" CR */ 1346*30088Sminshall TTYADD('\r'); 1347*30088Sminshall } else if (!hisopts[TELOPT_ECHO] && 1348*30088Sminshall (c == '\n')) { 1349*30088Sminshall sbp++, scc--; 1350*30088Sminshall TTYADD('\n'); 1351*30088Sminshall } else { 1352*30088Sminshall TTYADD('\r'); 1353*30088Sminshall if (crmod) { 1354*30088Sminshall TTYADD('\n'); 1355*30088Sminshall } 1356*30088Sminshall } 1357*30088Sminshall } else { 1358*30088Sminshall state = TS_CR; 1359*30088Sminshall TTYADD('\r'); 1360*30088Sminshall if (crmod) { 1361*30088Sminshall TTYADD('\n'); 1362*30088Sminshall } 1363*30088Sminshall } 1364*30088Sminshall } else { 1365*30088Sminshall TTYADD(c); 1366*30088Sminshall } 1367*30088Sminshall continue; 1368*30088Sminshall 1369*30088Sminshall case TS_IAC: 1370*30088Sminshall switch (c) { 1371*30088Sminshall 1372*30088Sminshall case WILL: 1373*30088Sminshall state = TS_WILL; 1374*30088Sminshall continue; 1375*30088Sminshall 1376*30088Sminshall case WONT: 1377*30088Sminshall state = TS_WONT; 1378*30088Sminshall continue; 1379*30088Sminshall 1380*30088Sminshall case DO: 1381*30088Sminshall state = TS_DO; 1382*30088Sminshall continue; 1383*30088Sminshall 1384*30088Sminshall case DONT: 1385*30088Sminshall state = TS_DONT; 1386*30088Sminshall continue; 1387*30088Sminshall 1388*30088Sminshall case DM: 1389*30088Sminshall /* 1390*30088Sminshall * We may have missed an urgent notification, 1391*30088Sminshall * so make sure we flush whatever is in the 1392*30088Sminshall * buffer currently. 1393*30088Sminshall */ 1394*30088Sminshall SYNCHing = 1; 1395*30088Sminshall ttyflush(); 1396*30088Sminshall SYNCHing = stilloob(net); 1397*30088Sminshall settimer(gotDM); 1398*30088Sminshall break; 1399*30088Sminshall 1400*30088Sminshall case NOP: 1401*30088Sminshall case GA: 1402*30088Sminshall break; 1403*30088Sminshall 1404*30088Sminshall case SB: 1405*30088Sminshall SB_CLEAR(); 1406*30088Sminshall state = TS_SB; 1407*30088Sminshall continue; 1408*30088Sminshall 1409*30088Sminshall # if defined(TN3270) 1410*30088Sminshall case EOR: 1411*30088Sminshall if (In3270) { 1412*30088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 1413*30088Sminshall if (Ibackp == Ifrontp) { 1414*30088Sminshall Ibackp = Ifrontp = Ibuf; 1415*30088Sminshall ISend = 0; /* should have been! */ 1416*30088Sminshall } else { 1417*30088Sminshall ISend = 1; 1418*30088Sminshall } 1419*30088Sminshall } 1420*30088Sminshall break; 1421*30088Sminshall # endif /* defined(TN3270) */ 1422*30088Sminshall 1423*30088Sminshall case IAC: 1424*30088Sminshall # if !defined(TN3270) 1425*30088Sminshall TTYADD(IAC); 1426*30088Sminshall # else /* !defined(TN3270) */ 1427*30088Sminshall if (In3270) { 1428*30088Sminshall *Ifrontp++ = IAC; 1429*30088Sminshall } else { 1430*30088Sminshall TTYADD(IAC); 1431*30088Sminshall } 1432*30088Sminshall # endif /* !defined(TN3270) */ 1433*30088Sminshall break; 1434*30088Sminshall 1435*30088Sminshall default: 1436*30088Sminshall break; 1437*30088Sminshall } 1438*30088Sminshall state = TS_DATA; 1439*30088Sminshall continue; 1440*30088Sminshall 1441*30088Sminshall case TS_WILL: 1442*30088Sminshall printoption(">RCVD", will, c, !hisopts[c]); 1443*30088Sminshall if (c == TELOPT_TM) { 1444*30088Sminshall if (flushout) { 1445*30088Sminshall flushout = 0; 1446*30088Sminshall } 1447*30088Sminshall } else if (!hisopts[c]) { 1448*30088Sminshall willoption(c, 1); 1449*30088Sminshall } 1450*30088Sminshall SetIn3270(); 1451*30088Sminshall state = TS_DATA; 1452*30088Sminshall continue; 1453*30088Sminshall 1454*30088Sminshall case TS_WONT: 1455*30088Sminshall printoption(">RCVD", wont, c, hisopts[c]); 1456*30088Sminshall if (c == TELOPT_TM) { 1457*30088Sminshall if (flushout) { 1458*30088Sminshall flushout = 0; 1459*30088Sminshall } 1460*30088Sminshall } else if (hisopts[c]) { 1461*30088Sminshall wontoption(c, 1); 1462*30088Sminshall } 1463*30088Sminshall SetIn3270(); 1464*30088Sminshall state = TS_DATA; 1465*30088Sminshall continue; 1466*30088Sminshall 1467*30088Sminshall case TS_DO: 1468*30088Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 1469*30088Sminshall if (!myopts[c]) 1470*30088Sminshall dooption(c); 1471*30088Sminshall SetIn3270(); 1472*30088Sminshall state = TS_DATA; 1473*30088Sminshall continue; 1474*30088Sminshall 1475*30088Sminshall case TS_DONT: 1476*30088Sminshall printoption(">RCVD", dont, c, myopts[c]); 1477*30088Sminshall if (myopts[c]) { 1478*30088Sminshall myopts[c] = 0; 1479*30088Sminshall sprintf(nfrontp, wont, c); 1480*30088Sminshall nfrontp += sizeof (wont) - 2; 1481*30088Sminshall flushline = 1; 1482*30088Sminshall setconnmode(); /* set new tty mode (maybe) */ 1483*30088Sminshall printoption(">SENT", wont, c, 0); 1484*30088Sminshall } 1485*30088Sminshall SetIn3270(); 1486*30088Sminshall state = TS_DATA; 1487*30088Sminshall continue; 1488*30088Sminshall 1489*30088Sminshall case TS_SB: 1490*30088Sminshall if (c == IAC) { 1491*30088Sminshall state = TS_SE; 1492*30088Sminshall } else { 1493*30088Sminshall SB_ACCUM(c); 1494*30088Sminshall } 1495*30088Sminshall continue; 1496*30088Sminshall 1497*30088Sminshall case TS_SE: 1498*30088Sminshall if (c != SE) { 1499*30088Sminshall if (c != IAC) { 1500*30088Sminshall SB_ACCUM(IAC); 1501*30088Sminshall } 1502*30088Sminshall SB_ACCUM(c); 1503*30088Sminshall state = TS_SB; 1504*30088Sminshall } else { 1505*30088Sminshall SB_TERM(); 1506*30088Sminshall suboption(); /* handle sub-option */ 1507*30088Sminshall SetIn3270(); 1508*30088Sminshall state = TS_DATA; 1509*30088Sminshall } 1510*30088Sminshall } 1511*30088Sminshall } 1512*30088Sminshall } 1513*30088Sminshall 1514*30088Sminshall #if defined(TN3270) 1515*30088Sminshall 1516*30088Sminshall /* 1517*30088Sminshall * The following routines are places where the various tn3270 1518*30088Sminshall * routines make calls into telnet.c. 1519*30088Sminshall */ 1520*30088Sminshall 1521*30088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 1522*30088Sminshall TtyChars() 1523*30088Sminshall { 1524*30088Sminshall return(tfrontp-tbackp); 1525*30088Sminshall } 1526*30088Sminshall 1527*30088Sminshall /* 1528*30088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 1529*30088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 1530*30088Sminshall * don't call us with "done" until you want that done...) 1531*30088Sminshall * 1532*30088Sminshall * We actually do send all the data to the network buffer, since our 1533*30088Sminshall * only client needs for us to do that. 1534*30088Sminshall */ 1535*30088Sminshall 1536*30088Sminshall int 1537*30088Sminshall DataToNetwork(buffer, count, done) 1538*30088Sminshall register char *buffer; /* where the data is */ 1539*30088Sminshall register int count; /* how much to send */ 1540*30088Sminshall int done; /* is this the last of a logical block */ 1541*30088Sminshall { 1542*30088Sminshall register int c; 1543*30088Sminshall int origCount; 1544*30088Sminshall fd_set o; 1545*30088Sminshall 1546*30088Sminshall origCount = count; 1547*30088Sminshall FD_ZERO(&o); 1548*30088Sminshall 1549*30088Sminshall while (count) { 1550*30088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 1551*30088Sminshall netflush(); 1552*30088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) { 1553*30088Sminshall FD_SET(net, &o); 1554*30088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 1555*30088Sminshall (struct timeval *) 0); 1556*30088Sminshall netflush(); 1557*30088Sminshall } 1558*30088Sminshall } 1559*30088Sminshall c = *buffer++; 1560*30088Sminshall count--; 1561*30088Sminshall if (c == IAC) { 1562*30088Sminshall *nfrontp++ = IAC; 1563*30088Sminshall *nfrontp++ = IAC; 1564*30088Sminshall } else { 1565*30088Sminshall *nfrontp++ = c; 1566*30088Sminshall } 1567*30088Sminshall } 1568*30088Sminshall 1569*30088Sminshall if (done && !count) { 1570*30088Sminshall *nfrontp++ = IAC; 1571*30088Sminshall *nfrontp++ = EOR; 1572*30088Sminshall netflush(); /* try to move along as quickly as ... */ 1573*30088Sminshall } 1574*30088Sminshall return(origCount - count); 1575*30088Sminshall } 1576*30088Sminshall 1577*30088Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 1578*30088Sminshall 1579*30088Sminshall int 1580*30088Sminshall DataToTerminal(buffer, count) 1581*30088Sminshall register char *buffer; /* where the data is */ 1582*30088Sminshall register int count; /* how much to send */ 1583*30088Sminshall { 1584*30088Sminshall int origCount; 1585*30088Sminshall fd_set o; 1586*30088Sminshall 1587*30088Sminshall origCount = count; 1588*30088Sminshall FD_ZERO(&o); 1589*30088Sminshall 1590*30088Sminshall while (count) { 1591*30088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 1592*30088Sminshall ttyflush(); 1593*30088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 1594*30088Sminshall FD_SET(tout, &o); 1595*30088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 1596*30088Sminshall (struct timeval *) 0); 1597*30088Sminshall ttyflush(); 1598*30088Sminshall } 1599*30088Sminshall } 1600*30088Sminshall *tfrontp++ = *buffer++; 1601*30088Sminshall count--; 1602*30088Sminshall } 1603*30088Sminshall return(origCount - count); 1604*30088Sminshall } 1605*30088Sminshall 1606*30088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 1607*30088Sminshall * Note that we consider the buffer to run all the 1608*30088Sminshall * way to the kernel (thus the select). 1609*30088Sminshall */ 1610*30088Sminshall 1611*30088Sminshall void 1612*30088Sminshall EmptyTerminal() 1613*30088Sminshall { 1614*30088Sminshall fd_set o; 1615*30088Sminshall 1616*30088Sminshall FD_ZERO(&o); 1617*30088Sminshall 1618*30088Sminshall if (tfrontp == tbackp) { 1619*30088Sminshall FD_SET(tout, &o); 1620*30088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 1621*30088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 1622*30088Sminshall } else { 1623*30088Sminshall while (tfrontp != tbackp) { 1624*30088Sminshall ttyflush(); 1625*30088Sminshall FD_SET(tout, &o); 1626*30088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 1627*30088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 1628*30088Sminshall } 1629*30088Sminshall } 1630*30088Sminshall } 1631*30088Sminshall 1632*30088Sminshall /* 1633*30088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 1634*30088Sminshall */ 1635*30088Sminshall 1636*30088Sminshall static int 1637*30088Sminshall Push3270() 1638*30088Sminshall { 1639*30088Sminshall int save = scc; 1640*30088Sminshall 1641*30088Sminshall if (scc) { 1642*30088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 1643*30088Sminshall if (Ibackp != Ibuf) { 1644*30088Sminshall bcopy(Ibackp, Ibuf, Ifrontp-Ibackp); 1645*30088Sminshall Ifrontp -= (Ibackp-Ibuf); 1646*30088Sminshall Ibackp = Ibuf; 1647*30088Sminshall } 1648*30088Sminshall } 1649*30088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 1650*30088Sminshall telrcv(); 1651*30088Sminshall } 1652*30088Sminshall } 1653*30088Sminshall return save != scc; 1654*30088Sminshall } 1655*30088Sminshall 1656*30088Sminshall 1657*30088Sminshall /* 1658*30088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 1659*30088Sminshall * before quitting. 1660*30088Sminshall */ 1661*30088Sminshall 1662*30088Sminshall static void 1663*30088Sminshall Finish3270() 1664*30088Sminshall { 1665*30088Sminshall while (Push3270() || !DoTerminalOutput()) { 1666*30088Sminshall ; 1667*30088Sminshall } 1668*30088Sminshall } 1669*30088Sminshall 1670*30088Sminshall 1671*30088Sminshall 1672*30088Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 1673*30088Sminshall 1674*30088Sminshall void 1675*30088Sminshall StringToTerminal(s) 1676*30088Sminshall char *s; 1677*30088Sminshall { 1678*30088Sminshall int count; 1679*30088Sminshall 1680*30088Sminshall count = strlen(s); 1681*30088Sminshall if (count) { 1682*30088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 1683*30088Sminshall } 1684*30088Sminshall } 1685*30088Sminshall 1686*30088Sminshall 1687*30088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) 1688*30088Sminshall /* _putchar - output a single character to the terminal. This name is so that 1689*30088Sminshall * curses(3x) can call us to send out data. 1690*30088Sminshall */ 1691*30088Sminshall 1692*30088Sminshall void 1693*30088Sminshall _putchar(c) 1694*30088Sminshall char c; 1695*30088Sminshall { 1696*30088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 1697*30088Sminshall (void) DataToTerminal(&c, 1); 1698*30088Sminshall } else { 1699*30088Sminshall *tfrontp++ = c; /* optimize if possible. */ 1700*30088Sminshall } 1701*30088Sminshall } 1702*30088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ 1703*30088Sminshall 1704*30088Sminshall static void 1705*30088Sminshall SetForExit() 1706*30088Sminshall { 1707*30088Sminshall setconnmode(); 1708*30088Sminshall if (In3270) { 1709*30088Sminshall Finish3270(); 1710*30088Sminshall } 1711*30088Sminshall setcommandmode(); 1712*30088Sminshall fflush(stdout); 1713*30088Sminshall fflush(stderr); 1714*30088Sminshall if (In3270) { 1715*30088Sminshall StopScreen(1); 1716*30088Sminshall } 1717*30088Sminshall setconnmode(); 1718*30088Sminshall setcommandmode(); 1719*30088Sminshall } 1720*30088Sminshall 1721*30088Sminshall static void 1722*30088Sminshall Exit(returnCode) 1723*30088Sminshall int returnCode; 1724*30088Sminshall { 1725*30088Sminshall SetForExit(); 1726*30088Sminshall exit(returnCode); 1727*30088Sminshall } 1728*30088Sminshall 1729*30088Sminshall void 1730*30088Sminshall ExitString(file, string, returnCode) 1731*30088Sminshall FILE *file; 1732*30088Sminshall char *string; 1733*30088Sminshall int returnCode; 1734*30088Sminshall { 1735*30088Sminshall SetForExit(); 1736*30088Sminshall fwrite(string, 1, strlen(string), file); 1737*30088Sminshall exit(returnCode); 1738*30088Sminshall } 1739*30088Sminshall 1740*30088Sminshall void 1741*30088Sminshall ExitPerror(string, returnCode) 1742*30088Sminshall char *string; 1743*30088Sminshall int returnCode; 1744*30088Sminshall { 1745*30088Sminshall SetForExit(); 1746*30088Sminshall perror(string); 1747*30088Sminshall exit(returnCode); 1748*30088Sminshall } 1749*30088Sminshall 1750*30088Sminshall #endif /* defined(TN3270) */ 1751*30088Sminshall 1752*30088Sminshall static 1753*30088Sminshall Scheduler(block) 1754*30088Sminshall int block; /* should we block in the select ? */ 1755*30088Sminshall { 1756*30088Sminshall register int c; 1757*30088Sminshall /* One wants to be a bit careful about setting returnValue 1758*30088Sminshall * to one, since a one implies we did some useful work, 1759*30088Sminshall * and therefore probably won't be called to block next 1760*30088Sminshall * time (TN3270 mode only). 1761*30088Sminshall */ 1762*30088Sminshall int returnValue = 0; 1763*30088Sminshall static struct timeval TimeValue = { 0 }; 1764*30088Sminshall 1765*30088Sminshall if (scc < 0 && tcc < 0) { 1766*30088Sminshall return -1; 1767*30088Sminshall } 1768*30088Sminshall 1769*30088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 1770*30088Sminshall FD_SET(net, &obits); 1771*30088Sminshall } 1772*30088Sminshall if (TTYBYTES()) { 1773*30088Sminshall FD_SET(tout, &obits); 1774*30088Sminshall } 1775*30088Sminshall if ((tcc == 0) && NETROOM()) { 1776*30088Sminshall FD_SET(tin, &ibits); 1777*30088Sminshall } 1778*30088Sminshall # if !defined(TN3270) 1779*30088Sminshall if (TTYROOM()) { 1780*30088Sminshall FD_SET(net, &ibits); 1781*30088Sminshall } 1782*30088Sminshall # else /* !defined(TN3270) */ 1783*30088Sminshall if (!ISend && TTYROOM()) { 1784*30088Sminshall FD_SET(net, &ibits); 1785*30088Sminshall } 1786*30088Sminshall # endif /* !defined(TN3270) */ 1787*30088Sminshall if (!SYNCHing) { 1788*30088Sminshall FD_SET(net, &xbits); 1789*30088Sminshall } 1790*30088Sminshall # if defined(TN3270) && defined(unix) 1791*30088Sminshall if (HaveInput) { 1792*30088Sminshall HaveInput = 0; 1793*30088Sminshall signal(SIGIO, inputAvailable); 1794*30088Sminshall } 1795*30088Sminshall #endif /* defined(TN3270) && defined(unix) */ 1796*30088Sminshall if ((c = select(16, &ibits, &obits, &xbits, 1797*30088Sminshall block? (struct timeval *)0 : &TimeValue)) < 1) { 1798*30088Sminshall if (c == -1) { 1799*30088Sminshall /* 1800*30088Sminshall * we can get EINTR if we are in line mode, 1801*30088Sminshall * and the user does an escape (TSTP), or 1802*30088Sminshall * some other signal generator. 1803*30088Sminshall */ 1804*30088Sminshall if (errno == EINTR) { 1805*30088Sminshall return 0; 1806*30088Sminshall } 1807*30088Sminshall # if defined(TN3270) 1808*30088Sminshall /* 1809*30088Sminshall * we can get EBADF if we were in transparent 1810*30088Sminshall * mode, and the transcom process died. 1811*30088Sminshall */ 1812*30088Sminshall if (errno == EBADF) { 1813*30088Sminshall /* 1814*30088Sminshall * zero the bits (even though kernel does it) 1815*30088Sminshall * to make sure we are selecting on the right 1816*30088Sminshall * ones. 1817*30088Sminshall */ 1818*30088Sminshall FD_ZERO(&ibits); 1819*30088Sminshall FD_ZERO(&obits); 1820*30088Sminshall FD_ZERO(&xbits); 1821*30088Sminshall return 0; 1822*30088Sminshall } 1823*30088Sminshall # endif /* defined(TN3270) */ 1824*30088Sminshall /* I don't like this, does it ever happen? */ 1825*30088Sminshall printf("sleep(5) from telnet, after select\r\n"); 1826*30088Sminshall #if defined(unix) 1827*30088Sminshall sleep(5); 1828*30088Sminshall #endif /* defined(unix) */ 1829*30088Sminshall } 1830*30088Sminshall return 0; 1831*30088Sminshall } 1832*30088Sminshall 1833*30088Sminshall /* 1834*30088Sminshall * Any urgent data? 1835*30088Sminshall */ 1836*30088Sminshall if (FD_ISSET(net, &xbits)) { 1837*30088Sminshall FD_CLR(net, &xbits); 1838*30088Sminshall SYNCHing = 1; 1839*30088Sminshall ttyflush(); /* flush already enqueued data */ 1840*30088Sminshall } 1841*30088Sminshall 1842*30088Sminshall /* 1843*30088Sminshall * Something to read from the network... 1844*30088Sminshall */ 1845*30088Sminshall if (FD_ISSET(net, &ibits)) { 1846*30088Sminshall int canread; 1847*30088Sminshall 1848*30088Sminshall FD_CLR(net, &ibits); 1849*30088Sminshall if (scc == 0) { 1850*30088Sminshall sbp = sibuf; 1851*30088Sminshall } 1852*30088Sminshall canread = sibuf + sizeof sibuf - sbp; 1853*30088Sminshall #if !defined(SO_OOBINLINE) 1854*30088Sminshall /* 1855*30088Sminshall * In 4.2 (and some early 4.3) systems, the 1856*30088Sminshall * OOB indication and data handling in the kernel 1857*30088Sminshall * is such that if two separate TCP Urgent requests 1858*30088Sminshall * come in, one byte of TCP data will be overlaid. 1859*30088Sminshall * This is fatal for Telnet, but we try to live 1860*30088Sminshall * with it. 1861*30088Sminshall * 1862*30088Sminshall * In addition, in 4.2 (and...), a special protocol 1863*30088Sminshall * is needed to pick up the TCP Urgent data in 1864*30088Sminshall * the correct sequence. 1865*30088Sminshall * 1866*30088Sminshall * What we do is: if we think we are in urgent 1867*30088Sminshall * mode, we look to see if we are "at the mark". 1868*30088Sminshall * If we are, we do an OOB receive. If we run 1869*30088Sminshall * this twice, we will do the OOB receive twice, 1870*30088Sminshall * but the second will fail, since the second 1871*30088Sminshall * time we were "at the mark", but there wasn't 1872*30088Sminshall * any data there (the kernel doesn't reset 1873*30088Sminshall * "at the mark" until we do a normal read). 1874*30088Sminshall * Once we've read the OOB data, we go ahead 1875*30088Sminshall * and do normal reads. 1876*30088Sminshall * 1877*30088Sminshall * There is also another problem, which is that 1878*30088Sminshall * since the OOB byte we read doesn't put us 1879*30088Sminshall * out of OOB state, and since that byte is most 1880*30088Sminshall * likely the TELNET DM (data mark), we would 1881*30088Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 1882*30088Sminshall * So, clocks to the rescue. If we've "just" 1883*30088Sminshall * received a DM, then we test for the 1884*30088Sminshall * presence of OOB data when the receive OOB 1885*30088Sminshall * fails (and AFTER we did the normal mode read 1886*30088Sminshall * to clear "at the mark"). 1887*30088Sminshall */ 1888*30088Sminshall if (SYNCHing) { 1889*30088Sminshall int atmark; 1890*30088Sminshall 1891*30088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 1892*30088Sminshall if (atmark) { 1893*30088Sminshall c = recv(net, sibuf, canread, MSG_OOB); 1894*30088Sminshall if ((c == -1) && (errno == EINVAL)) { 1895*30088Sminshall c = read(net, sibuf, canread); 1896*30088Sminshall if (clocks.didnetreceive < clocks.gotDM) { 1897*30088Sminshall SYNCHing = stilloob(net); 1898*30088Sminshall } 1899*30088Sminshall } 1900*30088Sminshall } else { 1901*30088Sminshall c = read(net, sibuf, canread); 1902*30088Sminshall } 1903*30088Sminshall } else { 1904*30088Sminshall c = read(net, sibuf, canread); 1905*30088Sminshall } 1906*30088Sminshall settimer(didnetreceive); 1907*30088Sminshall #else /* !defined(SO_OOBINLINE) */ 1908*30088Sminshall c = read(net, sbp, canread); 1909*30088Sminshall #endif /* !defined(SO_OOBINLINE) */ 1910*30088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 1911*30088Sminshall c = 0; 1912*30088Sminshall } else if (c <= 0) { 1913*30088Sminshall return -1; 1914*30088Sminshall } 1915*30088Sminshall if (netdata) { 1916*30088Sminshall Dump('<', sbp, c); 1917*30088Sminshall } 1918*30088Sminshall scc += c; 1919*30088Sminshall returnValue = 1; 1920*30088Sminshall } 1921*30088Sminshall 1922*30088Sminshall /* 1923*30088Sminshall * Something to read from the tty... 1924*30088Sminshall */ 1925*30088Sminshall if (FD_ISSET(tin, &ibits)) { 1926*30088Sminshall FD_CLR(tin, &ibits); 1927*30088Sminshall if (tcc == 0) { 1928*30088Sminshall tbp = tibuf; /* nothing left, reset */ 1929*30088Sminshall } 1930*30088Sminshall c = read(tin, tbp, tibuf+sizeof tibuf - tbp); 1931*30088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 1932*30088Sminshall c = 0; 1933*30088Sminshall } else { 1934*30088Sminshall /* EOF detection for line mode!!!! */ 1935*30088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 1936*30088Sminshall /* must be an EOF... */ 1937*30088Sminshall *tbp = ntc.t_eofc; 1938*30088Sminshall c = 1; 1939*30088Sminshall } 1940*30088Sminshall if (c <= 0) { 1941*30088Sminshall tcc = c; 1942*30088Sminshall return -1; 1943*30088Sminshall } 1944*30088Sminshall } 1945*30088Sminshall tcc += c; 1946*30088Sminshall returnValue = 1; /* did something useful */ 1947*30088Sminshall } 1948*30088Sminshall 1949*30088Sminshall # if defined(TN3270) 1950*30088Sminshall if (tcc > 0) { 1951*30088Sminshall if (In3270) { 1952*30088Sminshall c = DataFromTerminal(tbp, tcc); 1953*30088Sminshall if (c) { 1954*30088Sminshall returnValue = 1; 1955*30088Sminshall } 1956*30088Sminshall tcc -= c; 1957*30088Sminshall tbp += c; 1958*30088Sminshall } else { 1959*30088Sminshall # endif defined(TN3270) 1960*30088Sminshall returnValue = 1; 1961*30088Sminshall while (tcc > 0) { 1962*30088Sminshall register int sc; 1963*30088Sminshall 1964*30088Sminshall if (NETROOM() < 2) { 1965*30088Sminshall flushline = 1; 1966*30088Sminshall break; 1967*30088Sminshall } 1968*30088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 1969*30088Sminshall if (sc == escape) { 1970*30088Sminshall command(0); 1971*30088Sminshall tcc = 0; 1972*30088Sminshall flushline = 1; 1973*30088Sminshall break; 1974*30088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 1975*30088Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 1976*30088Sminshall tbp++; 1977*30088Sminshall tcc--; 1978*30088Sminshall } else { 1979*30088Sminshall dontlecho = !dontlecho; 1980*30088Sminshall settimer(echotoggle); 1981*30088Sminshall setconnmode(); 1982*30088Sminshall tcc = 0; 1983*30088Sminshall flushline = 1; 1984*30088Sminshall break; 1985*30088Sminshall } 1986*30088Sminshall } 1987*30088Sminshall if (localchars) { 1988*30088Sminshall if (sc == ntc.t_intrc) { 1989*30088Sminshall intp(); 1990*30088Sminshall break; 1991*30088Sminshall } else if (sc == ntc.t_quitc) { 1992*30088Sminshall sendbrk(); 1993*30088Sminshall break; 1994*30088Sminshall } else if (sc == nltc.t_flushc) { 1995*30088Sminshall NET2ADD(IAC, AO); 1996*30088Sminshall if (autoflush) { 1997*30088Sminshall doflush(); 1998*30088Sminshall } 1999*30088Sminshall break; 2000*30088Sminshall } else if (MODE_LOCAL_CHARS(globalmode)) { 2001*30088Sminshall ; 2002*30088Sminshall } else if (sc == nttyb.sg_kill) { 2003*30088Sminshall NET2ADD(IAC, EL); 2004*30088Sminshall break; 2005*30088Sminshall } else if (sc == nttyb.sg_erase) { 2006*30088Sminshall NET2ADD(IAC, EC); 2007*30088Sminshall break; 2008*30088Sminshall } 2009*30088Sminshall } 2010*30088Sminshall switch (c) { 2011*30088Sminshall case '\n': 2012*30088Sminshall /* 2013*30088Sminshall * If we are in CRMOD mode (\r ==> \n) 2014*30088Sminshall * on our local machine, then probably 2015*30088Sminshall * a newline (unix) is CRLF (TELNET). 2016*30088Sminshall */ 2017*30088Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 2018*30088Sminshall NETADD('\r'); 2019*30088Sminshall } 2020*30088Sminshall NETADD('\n'); 2021*30088Sminshall flushline = 1; 2022*30088Sminshall break; 2023*30088Sminshall case '\r': 2024*30088Sminshall NET2ADD('\r', '\0'); 2025*30088Sminshall flushline = 1; 2026*30088Sminshall break; 2027*30088Sminshall case IAC: 2028*30088Sminshall NET2ADD(IAC, IAC); 2029*30088Sminshall break; 2030*30088Sminshall default: 2031*30088Sminshall NETADD(c); 2032*30088Sminshall break; 2033*30088Sminshall } 2034*30088Sminshall } 2035*30088Sminshall # if defined(TN3270) 2036*30088Sminshall } 2037*30088Sminshall } 2038*30088Sminshall # endif /* defined(TN3270) */ 2039*30088Sminshall 2040*30088Sminshall if ((!MODE_LINE(globalmode) || flushline) && 2041*30088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 2042*30088Sminshall FD_CLR(net, &obits); 2043*30088Sminshall returnValue = netflush(); 2044*30088Sminshall } 2045*30088Sminshall if (scc > 0) { 2046*30088Sminshall # if !defined(TN3270) 2047*30088Sminshall telrcv(); 2048*30088Sminshall returnValue = 1; 2049*30088Sminshall # else /* !defined(TN3270) */ 2050*30088Sminshall returnValue = Push3270(); 2051*30088Sminshall # endif /* !defined(TN3270) */ 2052*30088Sminshall } 2053*30088Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) { 2054*30088Sminshall FD_CLR(tout, &obits); 2055*30088Sminshall returnValue = ttyflush(); 2056*30088Sminshall } 2057*30088Sminshall return returnValue; 2058*30088Sminshall } 2059*30088Sminshall 2060*30088Sminshall /* 2061*30088Sminshall * Select from tty and network... 2062*30088Sminshall */ 2063*30088Sminshall static void 2064*30088Sminshall telnet() 2065*30088Sminshall { 2066*30088Sminshall int on = 1; 2067*30088Sminshall #if defined(TN3270) && defined(unix) 2068*30088Sminshall int myPid; 2069*30088Sminshall #endif /* defined(TN3270) */ 2070*30088Sminshall 2071*30088Sminshall tout = fileno(stdout); 2072*30088Sminshall tin = fileno(stdin); 2073*30088Sminshall setconnmode(); 2074*30088Sminshall scc = 0; 2075*30088Sminshall tcc = 0; 2076*30088Sminshall FD_ZERO(&ibits); 2077*30088Sminshall FD_ZERO(&obits); 2078*30088Sminshall FD_ZERO(&xbits); 2079*30088Sminshall 2080*30088Sminshall ioctl(net, FIONBIO, (char *)&on); 2081*30088Sminshall 2082*30088Sminshall #if defined(TN3270) 2083*30088Sminshall #if !defined(DEBUG) /* DBX can't handle! */ 2084*30088Sminshall ioctl(net, FIOASYNC, (char *)&on); /* hear about input */ 2085*30088Sminshall #endif /* !defined(DEBUG) */ 2086*30088Sminshall 2087*30088Sminshall #if defined(unix) 2088*30088Sminshall myPid = getpid(); 2089*30088Sminshall #if defined(NOT43) 2090*30088Sminshall myPid = -myPid; 2091*30088Sminshall #endif /* defined(NOT43) */ 2092*30088Sminshall ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */ 2093*30088Sminshall #endif /* defined(unix) */ 2094*30088Sminshall 2095*30088Sminshall #endif /* defined(TN3270) */ 2096*30088Sminshall 2097*30088Sminshall #if defined(SO_OOBINLINE) 2098*30088Sminshall setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); 2099*30088Sminshall #endif /* defined(SO_OOBINLINE) */ 2100*30088Sminshall 2101*30088Sminshall if (telnetport) { 2102*30088Sminshall if (!hisopts[TELOPT_SGA]) { 2103*30088Sminshall willoption(TELOPT_SGA, 0); 2104*30088Sminshall } 2105*30088Sminshall # if !defined(TN3270) 2106*30088Sminshall if (!myopts[TELOPT_TTYPE]) { 2107*30088Sminshall dooption(TELOPT_TTYPE, 0); 2108*30088Sminshall } 2109*30088Sminshall # endif !defined(TN3270) 2110*30088Sminshall } 2111*30088Sminshall 2112*30088Sminshall # if !defined(TN3270) 2113*30088Sminshall for (;;) { 2114*30088Sminshall if (Scheduler(1) == -1) { 2115*30088Sminshall setcommandmode(); 2116*30088Sminshall return; 2117*30088Sminshall } 2118*30088Sminshall } 2119*30088Sminshall # else /* !defined(TN3270) */ 2120*30088Sminshall for (;;) { 2121*30088Sminshall int schedValue; 2122*30088Sminshall 2123*30088Sminshall while (!In3270) { 2124*30088Sminshall if (Scheduler(1) == -1) { 2125*30088Sminshall setcommandmode(); 2126*30088Sminshall return; 2127*30088Sminshall } 2128*30088Sminshall } 2129*30088Sminshall 2130*30088Sminshall while ((schedValue = Scheduler(0)) != 0) { 2131*30088Sminshall if (schedValue == -1) { 2132*30088Sminshall setcommandmode(); 2133*30088Sminshall return; 2134*30088Sminshall } 2135*30088Sminshall } 2136*30088Sminshall /* If there is data waiting to go out to terminal, don't 2137*30088Sminshall * schedule any more data for the terminal. 2138*30088Sminshall */ 2139*30088Sminshall if (tfrontp-tbackp) { 2140*30088Sminshall schedValue = 1; 2141*30088Sminshall } else { 2142*30088Sminshall schedValue = DoTerminalOutput(); 2143*30088Sminshall } 2144*30088Sminshall if (schedValue) { 2145*30088Sminshall if (Scheduler(1) == -1) { 2146*30088Sminshall setcommandmode(); 2147*30088Sminshall return; 2148*30088Sminshall } 2149*30088Sminshall } 2150*30088Sminshall } 2151*30088Sminshall # endif /* !defined(TN3270) */ 2152*30088Sminshall } 2153*30088Sminshall 2154*30088Sminshall /* 2155*30088Sminshall * The following are data structures and routines for 2156*30088Sminshall * the "send" command. 2157*30088Sminshall * 2158*30088Sminshall */ 2159*30088Sminshall 2160*30088Sminshall struct sendlist { 2161*30088Sminshall char *name; /* How user refers to it (case independent) */ 2162*30088Sminshall int what; /* Character to be sent (<0 ==> special) */ 2163*30088Sminshall char *help; /* Help information (0 ==> no help) */ 2164*30088Sminshall #if defined(NOT43) 2165*30088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 2166*30088Sminshall #else /* defined(NOT43) */ 2167*30088Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 2168*30088Sminshall #endif /* defined(NOT43) */ 2169*30088Sminshall }; 2170*30088Sminshall 2171*30088Sminshall #define SENDQUESTION -1 2172*30088Sminshall #define SENDESCAPE -3 2173*30088Sminshall 2174*30088Sminshall static struct sendlist Sendlist[] = { 2175*30088Sminshall { "ao", AO, "Send Telnet Abort output" }, 2176*30088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 2177*30088Sminshall { "brk", BREAK, "Send Telnet Break" }, 2178*30088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 2179*30088Sminshall { "el", EL, "Send Telnet Erase Line" }, 2180*30088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 2181*30088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 2182*30088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 2183*30088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 2184*30088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 2185*30088Sminshall { "?", SENDQUESTION, "Display send options" }, 2186*30088Sminshall { 0 } 2187*30088Sminshall }; 2188*30088Sminshall 2189*30088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 2190*30088Sminshall { "break", BREAK, 0 }, 2191*30088Sminshall 2192*30088Sminshall { "intp", IP, 0 }, 2193*30088Sminshall { "interrupt", IP, 0 }, 2194*30088Sminshall { "intr", IP, 0 }, 2195*30088Sminshall 2196*30088Sminshall { "help", SENDQUESTION, 0 }, 2197*30088Sminshall 2198*30088Sminshall { 0 } 2199*30088Sminshall }; 2200*30088Sminshall 2201*30088Sminshall static char ** 2202*30088Sminshall getnextsend(name) 2203*30088Sminshall char *name; 2204*30088Sminshall { 2205*30088Sminshall struct sendlist *c = (struct sendlist *) name; 2206*30088Sminshall 2207*30088Sminshall return (char **) (c+1); 2208*30088Sminshall } 2209*30088Sminshall 2210*30088Sminshall static struct sendlist * 2211*30088Sminshall getsend(name) 2212*30088Sminshall char *name; 2213*30088Sminshall { 2214*30088Sminshall struct sendlist *sl; 2215*30088Sminshall 2216*30088Sminshall if ((sl = (struct sendlist *) 2217*30088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 2218*30088Sminshall return sl; 2219*30088Sminshall } else { 2220*30088Sminshall return (struct sendlist *) 2221*30088Sminshall genget(name, (char **) Sendlist2, getnextsend); 2222*30088Sminshall } 2223*30088Sminshall } 2224*30088Sminshall 2225*30088Sminshall static 2226*30088Sminshall sendcmd(argc, argv) 2227*30088Sminshall int argc; 2228*30088Sminshall char **argv; 2229*30088Sminshall { 2230*30088Sminshall int what; /* what we are sending this time */ 2231*30088Sminshall int count; /* how many bytes we are going to need to send */ 2232*30088Sminshall int i; 2233*30088Sminshall int question = 0; /* was at least one argument a question */ 2234*30088Sminshall struct sendlist *s; /* pointer to current command */ 2235*30088Sminshall 2236*30088Sminshall if (argc < 2) { 2237*30088Sminshall printf("need at least one argument for 'send' command\n"); 2238*30088Sminshall printf("'send ?' for help\n"); 2239*30088Sminshall return 0; 2240*30088Sminshall } 2241*30088Sminshall /* 2242*30088Sminshall * First, validate all the send arguments. 2243*30088Sminshall * In addition, we see how much space we are going to need, and 2244*30088Sminshall * whether or not we will be doing a "SYNCH" operation (which 2245*30088Sminshall * flushes the network queue). 2246*30088Sminshall */ 2247*30088Sminshall count = 0; 2248*30088Sminshall for (i = 1; i < argc; i++) { 2249*30088Sminshall s = getsend(argv[i]); 2250*30088Sminshall if (s == 0) { 2251*30088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 2252*30088Sminshall argv[i]); 2253*30088Sminshall return 0; 2254*30088Sminshall } else if (s == Ambiguous(struct sendlist *)) { 2255*30088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 2256*30088Sminshall argv[i]); 2257*30088Sminshall return 0; 2258*30088Sminshall } 2259*30088Sminshall switch (s->what) { 2260*30088Sminshall case SENDQUESTION: 2261*30088Sminshall break; 2262*30088Sminshall case SENDESCAPE: 2263*30088Sminshall count += 1; 2264*30088Sminshall break; 2265*30088Sminshall case SYNCH: 2266*30088Sminshall count += 2; 2267*30088Sminshall break; 2268*30088Sminshall default: 2269*30088Sminshall count += 2; 2270*30088Sminshall break; 2271*30088Sminshall } 2272*30088Sminshall } 2273*30088Sminshall /* Now, do we have enough room? */ 2274*30088Sminshall if (NETROOM() < count) { 2275*30088Sminshall printf("There is not enough room in the buffer TO the network\n"); 2276*30088Sminshall printf("to process your request. Nothing will be done.\n"); 2277*30088Sminshall printf("('send synch' will throw away most data in the network\n"); 2278*30088Sminshall printf("buffer, if this might help.)\n"); 2279*30088Sminshall return 0; 2280*30088Sminshall } 2281*30088Sminshall /* OK, they are all OK, now go through again and actually send */ 2282*30088Sminshall for (i = 1; i < argc; i++) { 2283*30088Sminshall if ((s = getsend(argv[i])) == 0) { 2284*30088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 2285*30088Sminshall quit(); 2286*30088Sminshall /*NOTREACHED*/ 2287*30088Sminshall } 2288*30088Sminshall if (s->routine) { 2289*30088Sminshall (*s->routine)(s); 2290*30088Sminshall } else { 2291*30088Sminshall switch (what = s->what) { 2292*30088Sminshall case SYNCH: 2293*30088Sminshall dosynch(); 2294*30088Sminshall break; 2295*30088Sminshall case SENDQUESTION: 2296*30088Sminshall for (s = Sendlist; s->name; s++) { 2297*30088Sminshall if (s->help) { 2298*30088Sminshall printf(s->name); 2299*30088Sminshall if (s->help) { 2300*30088Sminshall printf("\t%s", s->help); 2301*30088Sminshall } 2302*30088Sminshall printf("\n"); 2303*30088Sminshall } 2304*30088Sminshall } 2305*30088Sminshall question = 1; 2306*30088Sminshall break; 2307*30088Sminshall case SENDESCAPE: 2308*30088Sminshall NETADD(escape); 2309*30088Sminshall break; 2310*30088Sminshall default: 2311*30088Sminshall NET2ADD(IAC, what); 2312*30088Sminshall break; 2313*30088Sminshall } 2314*30088Sminshall } 2315*30088Sminshall } 2316*30088Sminshall return !question; 2317*30088Sminshall } 2318*30088Sminshall 2319*30088Sminshall /* 2320*30088Sminshall * The following are the routines and data structures referred 2321*30088Sminshall * to by the arguments to the "toggle" command. 2322*30088Sminshall */ 2323*30088Sminshall 2324*30088Sminshall static 2325*30088Sminshall lclchars() 2326*30088Sminshall { 2327*30088Sminshall donelclchars = 1; 2328*30088Sminshall return 1; 2329*30088Sminshall } 2330*30088Sminshall 2331*30088Sminshall static 2332*30088Sminshall togdebug() 2333*30088Sminshall { 2334*30088Sminshall #ifndef NOT43 2335*30088Sminshall if (net > 0 && 2336*30088Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug)) 2337*30088Sminshall < 0) { 2338*30088Sminshall perror("setsockopt (SO_DEBUG)"); 2339*30088Sminshall } 2340*30088Sminshall #else NOT43 2341*30088Sminshall if (debug) { 2342*30088Sminshall if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 2343*30088Sminshall perror("setsockopt (SO_DEBUG)"); 2344*30088Sminshall } else 2345*30088Sminshall printf("Cannot turn off socket debugging\n"); 2346*30088Sminshall #endif NOT43 2347*30088Sminshall return 1; 2348*30088Sminshall } 2349*30088Sminshall 2350*30088Sminshall 2351*30088Sminshall 2352*30088Sminshall extern int togglehelp(); 2353*30088Sminshall 2354*30088Sminshall struct togglelist { 2355*30088Sminshall char *name; /* name of toggle */ 2356*30088Sminshall char *help; /* help message */ 2357*30088Sminshall int (*handler)(); /* routine to do actual setting */ 2358*30088Sminshall int dohelp; /* should we display help information */ 2359*30088Sminshall int *variable; 2360*30088Sminshall char *actionexplanation; 2361*30088Sminshall }; 2362*30088Sminshall 2363*30088Sminshall static struct togglelist Togglelist[] = { 2364*30088Sminshall { "autoflush", 2365*30088Sminshall "toggle flushing of output when sending interrupt characters", 2366*30088Sminshall 0, 2367*30088Sminshall 1, 2368*30088Sminshall &autoflush, 2369*30088Sminshall "flush output when sending interrupt characters" }, 2370*30088Sminshall { "autosynch", 2371*30088Sminshall "toggle automatic sending of interrupt characters in urgent mode", 2372*30088Sminshall 0, 2373*30088Sminshall 1, 2374*30088Sminshall &autosynch, 2375*30088Sminshall "send interrupt characters in urgent mode" }, 2376*30088Sminshall { "crmod", 2377*30088Sminshall "toggle mapping of received carriage returns", 2378*30088Sminshall 0, 2379*30088Sminshall 1, 2380*30088Sminshall &crmod, 2381*30088Sminshall "map carriage return on output" }, 2382*30088Sminshall { "localchars", 2383*30088Sminshall "toggle local recognition of certain control characters", 2384*30088Sminshall lclchars, 2385*30088Sminshall 1, 2386*30088Sminshall &localchars, 2387*30088Sminshall "recognize certain control characters" }, 2388*30088Sminshall { " ", "", 0, 1 }, /* empty line */ 2389*30088Sminshall { "debug", 2390*30088Sminshall "(debugging) toggle debugging", 2391*30088Sminshall togdebug, 2392*30088Sminshall 1, 2393*30088Sminshall &debug, 2394*30088Sminshall "turn on socket level debugging" }, 2395*30088Sminshall { "netdata", 2396*30088Sminshall "(debugging) toggle printing of hexadecimal network data", 2397*30088Sminshall 0, 2398*30088Sminshall 1, 2399*30088Sminshall &netdata, 2400*30088Sminshall "print hexadecimal representation of network traffic" }, 2401*30088Sminshall { "options", 2402*30088Sminshall "(debugging) toggle viewing of options processing", 2403*30088Sminshall 0, 2404*30088Sminshall 1, 2405*30088Sminshall &showoptions, 2406*30088Sminshall "show option processing" }, 2407*30088Sminshall { " ", "", 0, 1 }, /* empty line */ 2408*30088Sminshall { "?", 2409*30088Sminshall "display help information", 2410*30088Sminshall togglehelp, 2411*30088Sminshall 1 }, 2412*30088Sminshall { "help", 2413*30088Sminshall "display help information", 2414*30088Sminshall togglehelp, 2415*30088Sminshall 0 }, 2416*30088Sminshall { 0 } 2417*30088Sminshall }; 2418*30088Sminshall 2419*30088Sminshall static 2420*30088Sminshall togglehelp() 2421*30088Sminshall { 2422*30088Sminshall struct togglelist *c; 2423*30088Sminshall 2424*30088Sminshall for (c = Togglelist; c->name; c++) { 2425*30088Sminshall if (c->dohelp) { 2426*30088Sminshall printf("%s\t%s\n", c->name, c->help); 2427*30088Sminshall } 2428*30088Sminshall } 2429*30088Sminshall return 0; 2430*30088Sminshall } 2431*30088Sminshall 2432*30088Sminshall static char ** 2433*30088Sminshall getnexttoggle(name) 2434*30088Sminshall char *name; 2435*30088Sminshall { 2436*30088Sminshall struct togglelist *c = (struct togglelist *) name; 2437*30088Sminshall 2438*30088Sminshall return (char **) (c+1); 2439*30088Sminshall } 2440*30088Sminshall 2441*30088Sminshall static struct togglelist * 2442*30088Sminshall gettoggle(name) 2443*30088Sminshall char *name; 2444*30088Sminshall { 2445*30088Sminshall return (struct togglelist *) 2446*30088Sminshall genget(name, (char **) Togglelist, getnexttoggle); 2447*30088Sminshall } 2448*30088Sminshall 2449*30088Sminshall static 2450*30088Sminshall toggle(argc, argv) 2451*30088Sminshall int argc; 2452*30088Sminshall char *argv[]; 2453*30088Sminshall { 2454*30088Sminshall int retval = 1; 2455*30088Sminshall char *name; 2456*30088Sminshall struct togglelist *c; 2457*30088Sminshall 2458*30088Sminshall if (argc < 2) { 2459*30088Sminshall fprintf(stderr, 2460*30088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 2461*30088Sminshall return 0; 2462*30088Sminshall } 2463*30088Sminshall argc--; 2464*30088Sminshall argv++; 2465*30088Sminshall while (argc--) { 2466*30088Sminshall name = *argv++; 2467*30088Sminshall c = gettoggle(name); 2468*30088Sminshall if (c == Ambiguous(struct togglelist *)) { 2469*30088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 2470*30088Sminshall name); 2471*30088Sminshall return 0; 2472*30088Sminshall } else if (c == 0) { 2473*30088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 2474*30088Sminshall name); 2475*30088Sminshall return 0; 2476*30088Sminshall } else { 2477*30088Sminshall if (c->variable) { 2478*30088Sminshall *c->variable = !*c->variable; /* invert it */ 2479*30088Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 2480*30088Sminshall c->actionexplanation); 2481*30088Sminshall } 2482*30088Sminshall if (c->handler) { 2483*30088Sminshall retval &= (*c->handler)(c); 2484*30088Sminshall } 2485*30088Sminshall } 2486*30088Sminshall } 2487*30088Sminshall return retval; 2488*30088Sminshall } 2489*30088Sminshall 2490*30088Sminshall /* 2491*30088Sminshall * The following perform the "set" command. 2492*30088Sminshall */ 2493*30088Sminshall 2494*30088Sminshall struct setlist { 2495*30088Sminshall char *name; /* name */ 2496*30088Sminshall char *help; /* help information */ 2497*30088Sminshall char *charp; /* where it is located at */ 2498*30088Sminshall }; 2499*30088Sminshall 2500*30088Sminshall static struct setlist Setlist[] = { 2501*30088Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 2502*30088Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 2503*30088Sminshall { " ", "" }, 2504*30088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 2505*30088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 2506*30088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 2507*30088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 2508*30088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 2509*30088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 2510*30088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 2511*30088Sminshall { 0 } 2512*30088Sminshall }; 2513*30088Sminshall 2514*30088Sminshall static char ** 2515*30088Sminshall getnextset(name) 2516*30088Sminshall char *name; 2517*30088Sminshall { 2518*30088Sminshall struct setlist *c = (struct setlist *)name; 2519*30088Sminshall 2520*30088Sminshall return (char **) (c+1); 2521*30088Sminshall } 2522*30088Sminshall 2523*30088Sminshall static struct setlist * 2524*30088Sminshall getset(name) 2525*30088Sminshall char *name; 2526*30088Sminshall { 2527*30088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 2528*30088Sminshall } 2529*30088Sminshall 2530*30088Sminshall static 2531*30088Sminshall setcmd(argc, argv) 2532*30088Sminshall int argc; 2533*30088Sminshall char *argv[]; 2534*30088Sminshall { 2535*30088Sminshall int value; 2536*30088Sminshall struct setlist *ct; 2537*30088Sminshall 2538*30088Sminshall /* XXX back we go... sigh */ 2539*30088Sminshall if (argc != 3) { 2540*30088Sminshall if ((argc == 2) && 2541*30088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 2542*30088Sminshall for (ct = Setlist; ct->name; ct++) { 2543*30088Sminshall printf("%s\t%s\n", ct->name, ct->help); 2544*30088Sminshall } 2545*30088Sminshall printf("?\tdisplay help information\n"); 2546*30088Sminshall } else { 2547*30088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 2548*30088Sminshall } 2549*30088Sminshall return 0; 2550*30088Sminshall } 2551*30088Sminshall 2552*30088Sminshall ct = getset(argv[1]); 2553*30088Sminshall if (ct == 0) { 2554*30088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 2555*30088Sminshall argv[1]); 2556*30088Sminshall return 0; 2557*30088Sminshall } else if (ct == Ambiguous(struct setlist *)) { 2558*30088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 2559*30088Sminshall argv[1]); 2560*30088Sminshall return 0; 2561*30088Sminshall } else { 2562*30088Sminshall if (strcmp("off", argv[2])) { 2563*30088Sminshall value = special(argv[2]); 2564*30088Sminshall } else { 2565*30088Sminshall value = -1; 2566*30088Sminshall } 2567*30088Sminshall *(ct->charp) = value; 2568*30088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 2569*30088Sminshall } 2570*30088Sminshall return 1; 2571*30088Sminshall } 2572*30088Sminshall 2573*30088Sminshall /* 2574*30088Sminshall * The following are the data structures and routines for the 2575*30088Sminshall * 'mode' command. 2576*30088Sminshall */ 2577*30088Sminshall 2578*30088Sminshall static 2579*30088Sminshall dolinemode() 2580*30088Sminshall { 2581*30088Sminshall if (hisopts[TELOPT_SGA]) { 2582*30088Sminshall wontoption(TELOPT_SGA, 0); 2583*30088Sminshall } 2584*30088Sminshall if (hisopts[TELOPT_ECHO]) { 2585*30088Sminshall wontoption(TELOPT_ECHO, 0); 2586*30088Sminshall } 2587*30088Sminshall return 1; 2588*30088Sminshall } 2589*30088Sminshall 2590*30088Sminshall static 2591*30088Sminshall docharmode() 2592*30088Sminshall { 2593*30088Sminshall if (!hisopts[TELOPT_SGA]) { 2594*30088Sminshall willoption(TELOPT_SGA, 0); 2595*30088Sminshall } 2596*30088Sminshall if (!hisopts[TELOPT_ECHO]) { 2597*30088Sminshall willoption(TELOPT_ECHO, 0); 2598*30088Sminshall } 2599*30088Sminshall return 1; 2600*30088Sminshall } 2601*30088Sminshall 2602*30088Sminshall static struct cmd Modelist[] = { 2603*30088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 2604*30088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 2605*30088Sminshall { 0 }, 2606*30088Sminshall }; 2607*30088Sminshall 2608*30088Sminshall static char ** 2609*30088Sminshall getnextmode(name) 2610*30088Sminshall char *name; 2611*30088Sminshall { 2612*30088Sminshall struct cmd *c = (struct cmd *) name; 2613*30088Sminshall 2614*30088Sminshall return (char **) (c+1); 2615*30088Sminshall } 2616*30088Sminshall 2617*30088Sminshall static struct cmd * 2618*30088Sminshall getmodecmd(name) 2619*30088Sminshall char *name; 2620*30088Sminshall { 2621*30088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 2622*30088Sminshall } 2623*30088Sminshall 2624*30088Sminshall static 2625*30088Sminshall modecmd(argc, argv) 2626*30088Sminshall int argc; 2627*30088Sminshall char *argv[]; 2628*30088Sminshall { 2629*30088Sminshall struct cmd *mt; 2630*30088Sminshall 2631*30088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 2632*30088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 2633*30088Sminshall for (mt = Modelist; mt->name; mt++) { 2634*30088Sminshall printf("%s\t%s\n", mt->name, mt->help); 2635*30088Sminshall } 2636*30088Sminshall return 0; 2637*30088Sminshall } 2638*30088Sminshall mt = getmodecmd(argv[1]); 2639*30088Sminshall if (mt == 0) { 2640*30088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 2641*30088Sminshall return 0; 2642*30088Sminshall } else if (mt == Ambiguous(struct cmd *)) { 2643*30088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 2644*30088Sminshall return 0; 2645*30088Sminshall } else { 2646*30088Sminshall (*mt->handler)(); 2647*30088Sminshall } 2648*30088Sminshall return 1; 2649*30088Sminshall } 2650*30088Sminshall 2651*30088Sminshall /* 2652*30088Sminshall * The following data structures and routines implement the 2653*30088Sminshall * "display" command. 2654*30088Sminshall */ 2655*30088Sminshall 2656*30088Sminshall static 2657*30088Sminshall display(argc, argv) 2658*30088Sminshall int argc; 2659*30088Sminshall char *argv[]; 2660*30088Sminshall { 2661*30088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 2662*30088Sminshall if (*tl->variable) { \ 2663*30088Sminshall printf("will"); \ 2664*30088Sminshall } else { \ 2665*30088Sminshall printf("won't"); \ 2666*30088Sminshall } \ 2667*30088Sminshall printf(" %s.\n", tl->actionexplanation); \ 2668*30088Sminshall } 2669*30088Sminshall 2670*30088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 2671*30088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 2672*30088Sminshall } 2673*30088Sminshall 2674*30088Sminshall struct togglelist *tl; 2675*30088Sminshall struct setlist *sl; 2676*30088Sminshall 2677*30088Sminshall if (argc == 1) { 2678*30088Sminshall for (tl = Togglelist; tl->name; tl++) { 2679*30088Sminshall dotog(tl); 2680*30088Sminshall } 2681*30088Sminshall printf("\n"); 2682*30088Sminshall for (sl = Setlist; sl->name; sl++) { 2683*30088Sminshall doset(sl); 2684*30088Sminshall } 2685*30088Sminshall } else { 2686*30088Sminshall int i; 2687*30088Sminshall 2688*30088Sminshall for (i = 1; i < argc; i++) { 2689*30088Sminshall sl = getset(argv[i]); 2690*30088Sminshall tl = gettoggle(argv[i]); 2691*30088Sminshall if ((sl == Ambiguous(struct setlist *)) || 2692*30088Sminshall (tl == Ambiguous(struct togglelist *))) { 2693*30088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 2694*30088Sminshall return 0; 2695*30088Sminshall } else if (!sl && !tl) { 2696*30088Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 2697*30088Sminshall return 0; 2698*30088Sminshall } else { 2699*30088Sminshall if (tl) { 2700*30088Sminshall dotog(tl); 2701*30088Sminshall } 2702*30088Sminshall if (sl) { 2703*30088Sminshall doset(sl); 2704*30088Sminshall } 2705*30088Sminshall } 2706*30088Sminshall } 2707*30088Sminshall } 2708*30088Sminshall return 1; 2709*30088Sminshall #undef doset 2710*30088Sminshall #undef dotog 2711*30088Sminshall } 2712*30088Sminshall 2713*30088Sminshall /* 2714*30088Sminshall * The following are the data structures, and many of the routines, 2715*30088Sminshall * relating to command processing. 2716*30088Sminshall */ 2717*30088Sminshall 2718*30088Sminshall /* 2719*30088Sminshall * Set the escape character. 2720*30088Sminshall */ 2721*30088Sminshall static 2722*30088Sminshall setescape(argc, argv) 2723*30088Sminshall int argc; 2724*30088Sminshall char *argv[]; 2725*30088Sminshall { 2726*30088Sminshall register char *arg; 2727*30088Sminshall char buf[50]; 2728*30088Sminshall 2729*30088Sminshall printf( 2730*30088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 2731*30088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 2732*30088Sminshall if (argc > 2) 2733*30088Sminshall arg = argv[1]; 2734*30088Sminshall else { 2735*30088Sminshall printf("new escape character: "); 2736*30088Sminshall gets(buf); 2737*30088Sminshall arg = buf; 2738*30088Sminshall } 2739*30088Sminshall if (arg[0] != '\0') 2740*30088Sminshall escape = arg[0]; 2741*30088Sminshall if (!In3270) { 2742*30088Sminshall printf("Escape character is '%s'.\n", control(escape)); 2743*30088Sminshall } 2744*30088Sminshall fflush(stdout); 2745*30088Sminshall return 1; 2746*30088Sminshall } 2747*30088Sminshall 2748*30088Sminshall /*VARARGS*/ 2749*30088Sminshall static 2750*30088Sminshall togcrmod() 2751*30088Sminshall { 2752*30088Sminshall crmod = !crmod; 2753*30088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 2754*30088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 2755*30088Sminshall fflush(stdout); 2756*30088Sminshall return 1; 2757*30088Sminshall } 2758*30088Sminshall 2759*30088Sminshall /*VARARGS*/ 2760*30088Sminshall suspend() 2761*30088Sminshall { 2762*30088Sminshall setcommandmode(); 2763*30088Sminshall #if defined(unix) 2764*30088Sminshall kill(0, SIGTSTP); 2765*30088Sminshall #endif /* defined(unix) */ 2766*30088Sminshall /* reget parameters in case they were changed */ 2767*30088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 2768*30088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 2769*30088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 2770*30088Sminshall return 1; 2771*30088Sminshall } 2772*30088Sminshall 2773*30088Sminshall /*VARARGS*/ 2774*30088Sminshall static 2775*30088Sminshall bye() 2776*30088Sminshall { 2777*30088Sminshall if (connected) { 2778*30088Sminshall shutdown(net, 2); 2779*30088Sminshall printf("Connection closed.\n"); 2780*30088Sminshall close(net); 2781*30088Sminshall connected = 0; 2782*30088Sminshall /* reset options */ 2783*30088Sminshall bzero((char *)hisopts, sizeof hisopts); 2784*30088Sminshall bzero((char *)myopts, sizeof myopts); 2785*30088Sminshall SYNCHing = flushout = 0; 2786*30088Sminshall flushline = 1; 2787*30088Sminshall #if defined(TN3270) 2788*30088Sminshall /* 2789*30088Sminshall * The problem is that we were called from command() which 2790*30088Sminshall * was called from DataFrom3270() which was called from 2791*30088Sminshall * DataFromTerminal() which was called from... 2792*30088Sminshall * 2793*30088Sminshall * So, just quit. 2794*30088Sminshall */ 2795*30088Sminshall if (In3270) { 2796*30088Sminshall Exit(0); 2797*30088Sminshall } 2798*30088Sminshall #endif /* defined(TN3270) */ 2799*30088Sminshall } 2800*30088Sminshall return 1; 2801*30088Sminshall } 2802*30088Sminshall 2803*30088Sminshall /*VARARGS*/ 2804*30088Sminshall quit() 2805*30088Sminshall { 2806*30088Sminshall (void) call(bye, "bye", 0); 2807*30088Sminshall Exit(0); 2808*30088Sminshall /*NOTREACHED*/ 2809*30088Sminshall return 1; /* just to keep lint happy */ 2810*30088Sminshall } 2811*30088Sminshall 2812*30088Sminshall /* 2813*30088Sminshall * Print status about the connection. 2814*30088Sminshall */ 2815*30088Sminshall static 2816*30088Sminshall status(argc, argv) 2817*30088Sminshall int argc; 2818*30088Sminshall char *argv[]; 2819*30088Sminshall { 2820*30088Sminshall if (connected) { 2821*30088Sminshall printf("Connected to %s.\n", hostname); 2822*30088Sminshall if (argc < 2) { 2823*30088Sminshall printf("Operating in %s.\n", 2824*30088Sminshall modelist[getconnmode()].modedescriptions); 2825*30088Sminshall if (localchars) { 2826*30088Sminshall printf("Catching signals locally.\n"); 2827*30088Sminshall } 2828*30088Sminshall } 2829*30088Sminshall } else { 2830*30088Sminshall printf("No connection.\n"); 2831*30088Sminshall } 2832*30088Sminshall # if !defined(TN3270) 2833*30088Sminshall printf("Escape character is '%s'.\n", control(escape)); 2834*30088Sminshall fflush(stdout); 2835*30088Sminshall # else /* !defined(TN3270) */ 2836*30088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 2837*30088Sminshall printf("Escape character is '%s'.\n", control(escape)); 2838*30088Sminshall } 2839*30088Sminshall # if defined(unix) 2840*30088Sminshall if (In3270 && transcom) { 2841*30088Sminshall printf("Transparent mode command is '%s'.\n", transcom); 2842*30088Sminshall } 2843*30088Sminshall # endif /* defined(unix) */ 2844*30088Sminshall fflush(stdout); 2845*30088Sminshall if (In3270) { 2846*30088Sminshall return 0; 2847*30088Sminshall } 2848*30088Sminshall # endif /* defined(TN3270) */ 2849*30088Sminshall return 1; 2850*30088Sminshall } 2851*30088Sminshall 2852*30088Sminshall #if defined(TN3270) && defined(unix) 2853*30088Sminshall static 2854*30088Sminshall settranscom(argc, argv) 2855*30088Sminshall int argc; 2856*30088Sminshall char *argv[]; 2857*30088Sminshall { 2858*30088Sminshall int i, len = 0; 2859*30088Sminshall char *strcpy(), *strcat(); 2860*30088Sminshall 2861*30088Sminshall if (argc == 1 && transcom) { 2862*30088Sminshall transcom = 0; 2863*30088Sminshall } 2864*30088Sminshall if (argc == 1) { 2865*30088Sminshall return; 2866*30088Sminshall } 2867*30088Sminshall for (i = 1; i < argc; ++i) { 2868*30088Sminshall len += 1 + strlen(argv[1]); 2869*30088Sminshall } 2870*30088Sminshall transcom = tline; 2871*30088Sminshall (void) strcpy(transcom, argv[1]); 2872*30088Sminshall for (i = 2; i < argc; ++i) { 2873*30088Sminshall (void) strcat(transcom, " "); 2874*30088Sminshall (void) strcat(transcom, argv[i]); 2875*30088Sminshall } 2876*30088Sminshall } 2877*30088Sminshall #endif /* defined(TN3270) && defined(unix) */ 2878*30088Sminshall 2879*30088Sminshall 2880*30088Sminshall static 2881*30088Sminshall tn(argc, argv) 2882*30088Sminshall int argc; 2883*30088Sminshall char *argv[]; 2884*30088Sminshall { 2885*30088Sminshall register struct hostent *host = 0; 2886*30088Sminshall #if defined(msdos) 2887*30088Sminshall char *cp; 2888*30088Sminshall #endif /* defined(msdos) */ 2889*30088Sminshall 2890*30088Sminshall if (connected) { 2891*30088Sminshall printf("?Already connected to %s\n", hostname); 2892*30088Sminshall return 0; 2893*30088Sminshall } 2894*30088Sminshall if (argc < 2) { 2895*30088Sminshall (void) strcpy(line, "Connect "); 2896*30088Sminshall printf("(to) "); 2897*30088Sminshall gets(&line[strlen(line)]); 2898*30088Sminshall makeargv(); 2899*30088Sminshall argc = margc; 2900*30088Sminshall argv = margv; 2901*30088Sminshall } 2902*30088Sminshall if (argc > 3) { 2903*30088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 2904*30088Sminshall return 0; 2905*30088Sminshall } 2906*30088Sminshall #if defined(msdos) 2907*30088Sminshall for (cp = argv[1]; *cp; cp++) { 2908*30088Sminshall if (isupper(*cp)) { 2909*30088Sminshall *cp = tolower(*cp); 2910*30088Sminshall } 2911*30088Sminshall } 2912*30088Sminshall #endif /* defined(msdos) */ 2913*30088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 2914*30088Sminshall if (sin.sin_addr.s_addr != -1) { 2915*30088Sminshall sin.sin_family = AF_INET; 2916*30088Sminshall (void) strcpy(hnamebuf, argv[1]); 2917*30088Sminshall hostname = hnamebuf; 2918*30088Sminshall } else { 2919*30088Sminshall host = gethostbyname(argv[1]); 2920*30088Sminshall if (host) { 2921*30088Sminshall sin.sin_family = host->h_addrtype; 2922*30088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 2923*30088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, host->h_length); 2924*30088Sminshall #else /* defined(h_addr) */ 2925*30088Sminshall bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length); 2926*30088Sminshall #endif /* defined(h_addr) */ 2927*30088Sminshall hostname = host->h_name; 2928*30088Sminshall } else { 2929*30088Sminshall printf("%s: unknown host\n", argv[1]); 2930*30088Sminshall return 0; 2931*30088Sminshall } 2932*30088Sminshall } 2933*30088Sminshall sin.sin_port = sp->s_port; 2934*30088Sminshall if (argc == 3) { 2935*30088Sminshall sin.sin_port = atoi(argv[2]); 2936*30088Sminshall if (sin.sin_port == 0) { 2937*30088Sminshall sp = getservbyname(argv[2], "tcp"); 2938*30088Sminshall if (sp) 2939*30088Sminshall sin.sin_port = sp->s_port; 2940*30088Sminshall else { 2941*30088Sminshall printf("%s: bad port number\n", argv[2]); 2942*30088Sminshall return 0; 2943*30088Sminshall } 2944*30088Sminshall } else { 2945*30088Sminshall sin.sin_port = atoi(argv[2]); 2946*30088Sminshall sin.sin_port = htons(sin.sin_port); 2947*30088Sminshall } 2948*30088Sminshall telnetport = 0; 2949*30088Sminshall } else { 2950*30088Sminshall telnetport = 1; 2951*30088Sminshall } 2952*30088Sminshall #if defined(unix) 2953*30088Sminshall signal(SIGINT, intr); 2954*30088Sminshall signal(SIGQUIT, intr2); 2955*30088Sminshall signal(SIGPIPE, deadpeer); 2956*30088Sminshall #endif /* defined(unix) */ 2957*30088Sminshall printf("Trying...\n"); 2958*30088Sminshall do { 2959*30088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 2960*30088Sminshall if (net < 0) { 2961*30088Sminshall perror("telnet: socket"); 2962*30088Sminshall return 0; 2963*30088Sminshall } 2964*30088Sminshall #ifndef NOT43 2965*30088Sminshall if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 2966*30088Sminshall (char *)&debug, sizeof(debug)) < 0) 2967*30088Sminshall #else NOT43 2968*30088Sminshall if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 2969*30088Sminshall #endif NOT43 2970*30088Sminshall perror("setsockopt (SO_DEBUG)"); 2971*30088Sminshall 2972*30088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 2973*30088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 2974*30088Sminshall if (host && host->h_addr_list[1]) { 2975*30088Sminshall int oerrno = errno; 2976*30088Sminshall 2977*30088Sminshall fprintf(stderr, "telnet: connect to address %s: ", 2978*30088Sminshall inet_ntoa(sin.sin_addr)); 2979*30088Sminshall errno = oerrno; 2980*30088Sminshall perror((char *)0); 2981*30088Sminshall host->h_addr_list++; 2982*30088Sminshall bcopy(host->h_addr_list[0], 2983*30088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 2984*30088Sminshall fprintf(stderr, "Trying %s...\n", 2985*30088Sminshall inet_ntoa(sin.sin_addr)); 2986*30088Sminshall (void) close(net); 2987*30088Sminshall continue; 2988*30088Sminshall } 2989*30088Sminshall #endif /* defined(h_addr) */ 2990*30088Sminshall perror("telnet: Unable to connect to remote host"); 2991*30088Sminshall #if defined(unix) 2992*30088Sminshall signal(SIGINT, SIG_DFL); 2993*30088Sminshall signal(SIGQUIT, SIG_DFL); 2994*30088Sminshall #endif /* defined(unix) */ 2995*30088Sminshall return 0; 2996*30088Sminshall } 2997*30088Sminshall connected++; 2998*30088Sminshall } while (connected == 0); 2999*30088Sminshall call(status, "status", "notmuch", 0); 3000*30088Sminshall if (setjmp(peerdied) == 0) 3001*30088Sminshall telnet(); 3002*30088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1); 3003*30088Sminshall /*NOTREACHED*/ 3004*30088Sminshall } 3005*30088Sminshall 3006*30088Sminshall 3007*30088Sminshall #define HELPINDENT (sizeof ("connect")) 3008*30088Sminshall 3009*30088Sminshall static char 3010*30088Sminshall openhelp[] = "connect to a site", 3011*30088Sminshall closehelp[] = "close current connection", 3012*30088Sminshall quithelp[] = "exit telnet", 3013*30088Sminshall zhelp[] = "suspend telnet", 3014*30088Sminshall statushelp[] = "print status information", 3015*30088Sminshall helphelp[] = "print help information", 3016*30088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 3017*30088Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 3018*30088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 3019*30088Sminshall displayhelp[] = "display operating parameters", 3020*30088Sminshall #if defined(TN3270) && defined(unix) 3021*30088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 3022*30088Sminshall #endif /* defined(TN3270) && defined(unix) */ 3023*30088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 3024*30088Sminshall 3025*30088Sminshall extern int help(); 3026*30088Sminshall 3027*30088Sminshall static struct cmd cmdtab[] = { 3028*30088Sminshall { "close", closehelp, bye, 1, 1 }, 3029*30088Sminshall { "display", displayhelp, display, 1, 0 }, 3030*30088Sminshall { "mode", modehelp, modecmd, 1, 1 }, 3031*30088Sminshall { "open", openhelp, tn, 1, 0 }, 3032*30088Sminshall { "quit", quithelp, quit, 1, 0 }, 3033*30088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 3034*30088Sminshall { "set", sethelp, setcmd, 1, 0 }, 3035*30088Sminshall { "status", statushelp, status, 1, 0 }, 3036*30088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 3037*30088Sminshall #if defined(TN3270) && defined(unix) 3038*30088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 3039*30088Sminshall #endif /* defined(TN3270) && defined(unix) */ 3040*30088Sminshall { "z", zhelp, suspend, 1, 0 }, 3041*30088Sminshall { "?", helphelp, help, 1, 0 }, 3042*30088Sminshall 0 3043*30088Sminshall }; 3044*30088Sminshall 3045*30088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 3046*30088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 3047*30088Sminshall 3048*30088Sminshall static struct cmd cmdtab2[] = { 3049*30088Sminshall { "help", helphelp, help, 0, 0 }, 3050*30088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 3051*30088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 3052*30088Sminshall 0 3053*30088Sminshall }; 3054*30088Sminshall 3055*30088Sminshall /* 3056*30088Sminshall * Call routine with argc, argv set from args (terminated by 0). 3057*30088Sminshall * VARARGS2 3058*30088Sminshall */ 3059*30088Sminshall static 3060*30088Sminshall call(routine, args) 3061*30088Sminshall int (*routine)(); 3062*30088Sminshall char *args; 3063*30088Sminshall { 3064*30088Sminshall register char **argp; 3065*30088Sminshall register int argc; 3066*30088Sminshall 3067*30088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 3068*30088Sminshall ; 3069*30088Sminshall return (*routine)(argc, &args); 3070*30088Sminshall } 3071*30088Sminshall 3072*30088Sminshall static char ** 3073*30088Sminshall getnextcmd(name) 3074*30088Sminshall char *name; 3075*30088Sminshall { 3076*30088Sminshall struct cmd *c = (struct cmd *) name; 3077*30088Sminshall 3078*30088Sminshall return (char **) (c+1); 3079*30088Sminshall } 3080*30088Sminshall 3081*30088Sminshall static struct cmd * 3082*30088Sminshall getcmd(name) 3083*30088Sminshall char *name; 3084*30088Sminshall { 3085*30088Sminshall struct cmd *cm; 3086*30088Sminshall 3087*30088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 3088*30088Sminshall return cm; 3089*30088Sminshall } else { 3090*30088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 3091*30088Sminshall } 3092*30088Sminshall } 3093*30088Sminshall 3094*30088Sminshall void 3095*30088Sminshall command(top) 3096*30088Sminshall int top; 3097*30088Sminshall { 3098*30088Sminshall register struct cmd *c; 3099*30088Sminshall 3100*30088Sminshall setcommandmode(); 3101*30088Sminshall if (!top) { 3102*30088Sminshall putchar('\n'); 3103*30088Sminshall } else { 3104*30088Sminshall #if defined(unix) 3105*30088Sminshall signal(SIGINT, SIG_DFL); 3106*30088Sminshall signal(SIGQUIT, SIG_DFL); 3107*30088Sminshall #endif /* defined(unix) */ 3108*30088Sminshall } 3109*30088Sminshall for (;;) { 3110*30088Sminshall printf("%s> ", prompt); 3111*30088Sminshall if (gets(line) == NULL) { 3112*30088Sminshall if (feof(stdin) || ferror(stdin)) 3113*30088Sminshall quit(); 3114*30088Sminshall break; 3115*30088Sminshall } 3116*30088Sminshall if (line[0] == 0) 3117*30088Sminshall break; 3118*30088Sminshall makeargv(); 3119*30088Sminshall c = getcmd(margv[0]); 3120*30088Sminshall if (c == Ambiguous(struct cmd *)) { 3121*30088Sminshall printf("?Ambiguous command\n"); 3122*30088Sminshall continue; 3123*30088Sminshall } 3124*30088Sminshall if (c == 0) { 3125*30088Sminshall printf("?Invalid command\n"); 3126*30088Sminshall continue; 3127*30088Sminshall } 3128*30088Sminshall if (c->needconnect && !connected) { 3129*30088Sminshall printf("?Need to be connected first.\n"); 3130*30088Sminshall continue; 3131*30088Sminshall } 3132*30088Sminshall if ((*c->handler)(margc, margv)) { 3133*30088Sminshall break; 3134*30088Sminshall } 3135*30088Sminshall } 3136*30088Sminshall if (!top) { 3137*30088Sminshall if (!connected) { 3138*30088Sminshall longjmp(toplevel, 1); 3139*30088Sminshall /*NOTREACHED*/ 3140*30088Sminshall } 3141*30088Sminshall setconnmode(); 3142*30088Sminshall } 3143*30088Sminshall } 3144*30088Sminshall 3145*30088Sminshall /* 3146*30088Sminshall * Help command. 3147*30088Sminshall */ 3148*30088Sminshall static 3149*30088Sminshall help(argc, argv) 3150*30088Sminshall int argc; 3151*30088Sminshall char *argv[]; 3152*30088Sminshall { 3153*30088Sminshall register struct cmd *c; 3154*30088Sminshall 3155*30088Sminshall if (argc == 1) { 3156*30088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 3157*30088Sminshall for (c = cmdtab; c->name; c++) 3158*30088Sminshall if (c->dohelp) { 3159*30088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 3160*30088Sminshall c->help); 3161*30088Sminshall } 3162*30088Sminshall return 0; 3163*30088Sminshall } 3164*30088Sminshall while (--argc > 0) { 3165*30088Sminshall register char *arg; 3166*30088Sminshall arg = *++argv; 3167*30088Sminshall c = getcmd(arg); 3168*30088Sminshall if (c == Ambiguous(struct cmd *)) 3169*30088Sminshall printf("?Ambiguous help command %s\n", arg); 3170*30088Sminshall else if (c == (struct cmd *)0) 3171*30088Sminshall printf("?Invalid help command %s\n", arg); 3172*30088Sminshall else 3173*30088Sminshall printf("%s\n", c->help); 3174*30088Sminshall } 3175*30088Sminshall return 0; 3176*30088Sminshall } 3177*30088Sminshall 3178*30088Sminshall /* 3179*30088Sminshall * main. Parse arguments, invoke the protocol or command parser. 3180*30088Sminshall */ 3181*30088Sminshall 3182*30088Sminshall 3183*30088Sminshall void 3184*30088Sminshall main(argc, argv) 3185*30088Sminshall int argc; 3186*30088Sminshall char *argv[]; 3187*30088Sminshall { 3188*30088Sminshall sp = getservbyname("telnet", "tcp"); 3189*30088Sminshall if (sp == 0) { 3190*30088Sminshall ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1); 3191*30088Sminshall /*NOTREACHED*/ 3192*30088Sminshall } 3193*30088Sminshall NetTrace = stdout; 3194*30088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 3195*30088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 3196*30088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 3197*30088Sminshall #if defined(LNOFLSH) 3198*30088Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 3199*30088Sminshall autoflush = !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 3200*30088Sminshall #else /* LNOFLSH */ 3201*30088Sminshall autoflush = 1; 3202*30088Sminshall #endif /* LNOFLSH */ 3203*30088Sminshall ntc = otc; 3204*30088Sminshall nltc = oltc; 3205*30088Sminshall nttyb = ottyb; 3206*30088Sminshall setbuf(stdin, (char *)0); 3207*30088Sminshall setbuf(stdout, (char *)0); 3208*30088Sminshall prompt = argv[0]; 3209*30088Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 3210*30088Sminshall debug = 1; 3211*30088Sminshall argv++; 3212*30088Sminshall argc--; 3213*30088Sminshall } 3214*30088Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 3215*30088Sminshall argv++; 3216*30088Sminshall argc--; 3217*30088Sminshall if (argc > 1) { /* get file name */ 3218*30088Sminshall NetTrace = fopen(argv[1], "w"); 3219*30088Sminshall argv++; 3220*30088Sminshall argc--; 3221*30088Sminshall if (NetTrace == NULL) { 3222*30088Sminshall NetTrace = stdout; 3223*30088Sminshall } 3224*30088Sminshall } 3225*30088Sminshall } 3226*30088Sminshall #if defined(TN3270) && defined(unix) 3227*30088Sminshall if (argc > 1 && !strcmp(argv[1], "-t")) { 3228*30088Sminshall argv++; 3229*30088Sminshall argc--; 3230*30088Sminshall if (argc > 1) { /* get command name */ 3231*30088Sminshall transcom = tline; 3232*30088Sminshall (void) strcpy(transcom, argv[1]); 3233*30088Sminshall argv++; 3234*30088Sminshall argc--; 3235*30088Sminshall } 3236*30088Sminshall } 3237*30088Sminshall #endif /* defined(TN3270) && defined(unix) */ 3238*30088Sminshall if (argc != 1) { 3239*30088Sminshall if (setjmp(toplevel) != 0) 3240*30088Sminshall Exit(0); 3241*30088Sminshall tn(argc, argv); 3242*30088Sminshall } 3243*30088Sminshall setjmp(toplevel); 3244*30088Sminshall for (;;) 3245*30088Sminshall command(1); 3246*30088Sminshall } 3247