130088Sminshall /* 230088Sminshall * Copyright (c) 1984, 1985, 1986 by the Regents of the 330088Sminshall * University of California and by Gregory Glenn Minshall. 430088Sminshall * 530088Sminshall * Permission to use, copy, modify, and distribute these 630088Sminshall * programs and their documentation for any purpose and 730088Sminshall * without fee is hereby granted, provided that this 830088Sminshall * copyright and permission appear on all copies and 930088Sminshall * supporting documentation, the name of the Regents of 1030088Sminshall * the University of California not be used in advertising 1130088Sminshall * or publicity pertaining to distribution of the programs 1230088Sminshall * without specific prior permission, and notice be given in 1330088Sminshall * supporting documentation that copying and distribution is 1430088Sminshall * by permission of the Regents of the University of California 1530088Sminshall * and by Gregory Glenn Minshall. Neither the Regents of the 1630088Sminshall * University of California nor Gregory Glenn Minshall make 1730088Sminshall * representations about the suitability of this software 1830088Sminshall * for any purpose. It is provided "as is" without 1930088Sminshall * express or implied warranty. 2030088Sminshall */ 2130088Sminshall 2230088Sminshall #ifndef lint 2330088Sminshall static char copyright[] = 2430088Sminshall "@(#) Copyright (c) 1984, 1985, 1986 Regents of the University of California.\n\ 2530088Sminshall All rights reserved.\n"; 2630320Sminshall #endif /* not lint */ 2730088Sminshall 2830088Sminshall #ifndef lint 2930088Sminshall static char sccsid[] = "@(#)telnet.c 3.1 10/29/86"; 3030320Sminshall #endif /* not lint */ 3130088Sminshall 3230088Sminshall /* 3330088Sminshall * User telnet program, modified for use by tn3270.c. 3430088Sminshall * 3530088Sminshall * Many of the FUNCTIONAL changes in this newest version of TELNET 3630088Sminshall * were suggested by Dave Borman of Cray Research, Inc. 3730088Sminshall * 3830088Sminshall * Other changes in the tn3270 side come from Alan Crosswell (Columbia), 3930088Sminshall * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley). 4030088Sminshall * 4130088Sminshall * This code is common between telnet(1c) and tn3270(1c). There are the 4230088Sminshall * following defines used to generate the various versions: 4330088Sminshall * 4430088Sminshall * TN3270 - This is to be linked with tn3270. 4530088Sminshall * 4630088Sminshall * DEBUG - Allow for some extra debugging operations. 4730088Sminshall * 4830088Sminshall * NOT43 - Allows the program to compile and run on 4930088Sminshall * a 4.2BSD system. 5030088Sminshall * 5130088Sminshall * PUTCHAR - Within tn3270, on a NOT43 system, 5230088Sminshall * allows the use of the 4.3 curses 5330088Sminshall * (greater speed updating the screen). 5430088Sminshall * You need the 4.3 curses for this to work. 5530088Sminshall * 5630088Sminshall * FD_SETSIZE - On whichever system, if this isn't defined, 5730088Sminshall * we patch over the FD_SET, etc., macros with 5830088Sminshall * some homebrewed ones. 5930088Sminshall * 6030088Sminshall * SO_OOBINLINE - This is a socket option which we would like 6130088Sminshall * to set to allow TCP urgent data to come 6230088Sminshall * to us "inline". This is NECESSARY for 6330088Sminshall * CORRECT operation, and desireable for 6430088Sminshall * simpler operation. 6530088Sminshall * 6630088Sminshall * LNOFLSH - Detects the presence of the LNOFLSH bit 6730088Sminshall * in the tty structure. 6830088Sminshall * 6930088Sminshall * unix - Compiles in unix specific stuff. 7030088Sminshall * 7130088Sminshall * msdos - Compiles in msdos specific stuff. 7230088Sminshall * 7330088Sminshall */ 7430088Sminshall 7530088Sminshall #if !defined(TN3270) 7630088Sminshall #define ExitString(f,s,r) { fprintf(f, s); exit(r); } 7730088Sminshall #define Exit(x) exit(x) 7830088Sminshall #define SetIn3270() 7930088Sminshall 8030088Sminshall void setcommandmode(), command(); /* forward declarations */ 8130088Sminshall #endif /* !defined(TN3270) */ 8230088Sminshall 8330088Sminshall #include <sys/types.h> 8430088Sminshall #include <sys/socket.h> 8530088Sminshall 8630088Sminshall #include <netinet/in.h> 8730088Sminshall 88*31124Sminshall #if defined(unix) 89*31124Sminshall /* By the way, we need to include curses.h before telnet.h since, 90*31124Sminshall * among other things, telnet.h #defines 'DO', which is a variable 91*31124Sminshall * declared in curses.h. 92*31124Sminshall */ 9330088Sminshall #include <curses.h> 94*31124Sminshall #endif /* defined(unix) */ 9530088Sminshall 9630088Sminshall #define TELOPTS 9730088Sminshall #include <arpa/telnet.h> 9830088Sminshall 9930088Sminshall #if !defined(NOT43) 10030088Sminshall #include <arpa/inet.h> 10130088Sminshall #else /* !defined(NOT43) */ 10230088Sminshall extern unsigned long inet_addr(); 10330088Sminshall extern char *inet_ntoa(); 10430088Sminshall #endif /* !defined(NOT43) */ 10530088Sminshall 10630088Sminshall #include <stdio.h> 10730088Sminshall #include <ctype.h> 10830088Sminshall #include <errno.h> 10930088Sminshall #include <setjmp.h> 11030088Sminshall #include <netdb.h> 111*31124Sminshall 112*31124Sminshall #if defined(unix) 11330088Sminshall #include <strings.h> 114*31124Sminshall #else /* defined(unix) */ 115*31124Sminshall #include <string.h> 116*31124Sminshall #endif /* defined(unix) */ 11730088Sminshall 11830088Sminshall #if defined(TN3270) 11930088Sminshall #include "ctlr/screen.h" 12030088Sminshall #include "system/globals.h" 12130088Sminshall #include "telnet.ext" 12230088Sminshall #include "ctlr/options.ext" 12330088Sminshall #include "ctlr/outbound.ext" 12430088Sminshall #include "keyboard/termin.ext" 12530722Sminshall #include "general.h" 12630088Sminshall #endif /* defined(TN3270) */ 12730088Sminshall 12830088Sminshall 12930088Sminshall 13030088Sminshall #ifndef FD_SETSIZE 13130088Sminshall /* 13230088Sminshall * The following is defined just in case someone should want to run 13330088Sminshall * this telnet on a 4.2 system. 13430088Sminshall * 13530088Sminshall */ 13630088Sminshall 13730088Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 13830088Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 13930088Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 14030088Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 14130088Sminshall 14230088Sminshall #endif 14330088Sminshall 14430088Sminshall #define strip(x) ((x)&0x7f) 14530088Sminshall #define min(x,y) ((x<y)? x:y) 14630088Sminshall 14730088Sminshall #if defined(TN3270) 14830326Sminshall static char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 14930088Sminshall #endif /* defined(TN3270) */ 15030088Sminshall 15130326Sminshall static char ttyobuf[2*BUFSIZ], *tfrontp, *tbackp; 15230088Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } 15330088Sminshall #define TTYLOC() (tfrontp) 15430088Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) 15530088Sminshall #define TTYMIN() (netobuf) 15630088Sminshall #define TTYBYTES() (tfrontp-tbackp) 15730088Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1) 15830088Sminshall 15930326Sminshall static char netobuf[2*BUFSIZ], *nfrontp, *nbackp; 16030088Sminshall #define NETADD(c) { *nfrontp++ = c; } 16130088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 16230088Sminshall #define NETLOC() (nfrontp) 16330088Sminshall #define NETMAX() (netobuf+sizeof netobuf-1) 16430088Sminshall #define NETBYTES() (nfrontp-nbackp) 16530088Sminshall #define NETROOM() (NETMAX()-NETLOC()+1) 16630326Sminshall static char *neturg; /* one past last byte of urgent data */ 16730088Sminshall 16830326Sminshall static char subbuffer[100], 16930326Sminshall *subpointer, *subend; /* buffer for sub-options */ 17030088Sminshall #define SB_CLEAR() subpointer = subbuffer; 17130088Sminshall #define SB_TERM() subend = subpointer; 17230088Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 17330088Sminshall *subpointer++ = (c); \ 17430088Sminshall } 17530088Sminshall 17630088Sminshall static char sb_terminal[] = { IAC, SB, 17730088Sminshall TELOPT_TTYPE, TELQUAL_IS, 17830088Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 17930088Sminshall IAC, SE }; 18030088Sminshall #define SBTERMMODEL 13 18130088Sminshall 18230088Sminshall 18330326Sminshall static char hisopts[256]; 18430326Sminshall static char myopts[256]; 18530088Sminshall 18630088Sminshall static char doopt[] = { IAC, DO, '%', 'c', 0 }; 18730088Sminshall static char dont[] = { IAC, DONT, '%', 'c', 0 }; 18830088Sminshall static char will[] = { IAC, WILL, '%', 'c', 0 }; 18930088Sminshall static char wont[] = { IAC, WONT, '%', 'c', 0 }; 19030088Sminshall 19130088Sminshall struct cmd { 19230088Sminshall char *name; /* command name */ 19330088Sminshall char *help; /* help string */ 19430088Sminshall int (*handler)(); /* routine which executes command */ 19530088Sminshall int dohelp; /* Should we give general help information? */ 19630088Sminshall int needconnect; /* Do we need to be connected to execute? */ 19730088Sminshall }; 19830088Sminshall 19930326Sminshall static char sibuf[BUFSIZ], *sbp; 20030088Sminshall static char tibuf[BUFSIZ], *tbp; 20130088Sminshall static fd_set ibits, obits, xbits; 20230088Sminshall 20330088Sminshall 20430088Sminshall static int 20530326Sminshall connected, 20630326Sminshall net, 20730326Sminshall scc, 20830326Sminshall tcc, 20930326Sminshall showoptions, 21030326Sminshall In3270, /* Are we in 3270 mode? */ 21130326Sminshall ISend, /* trying to send network data in */ 21230088Sminshall debug = 0, 21330326Sminshall crmod, 21430326Sminshall netdata, 21530722Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 21630088Sminshall telnetport = 1; 21730088Sminshall 21830326Sminshall static FILE *NetTrace = 0; /* Not in bss, since needs to stay */ 21930088Sminshall 22030088Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 22130088Sminshall 22230088Sminshall static char 22330088Sminshall *prompt = 0, 22430326Sminshall escape, 22530326Sminshall echoc; 22630088Sminshall 22730088Sminshall static int 22830326Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 22930326Sminshall flushout, /* flush output */ 23030088Sminshall autoflush = 0, /* flush output when interrupting? */ 23130326Sminshall autosynch, /* send interrupt characters with SYNCH? */ 23230326Sminshall localchars, /* we recognize interrupt/quit */ 23330326Sminshall donelclchars, /* the user has set "localchars" */ 234*31124Sminshall dontlecho, /* do we suppress local echoing right now? */ 235*31124Sminshall globalmode; 23630088Sminshall 23730088Sminshall /* The following are some tn3270 specific flags */ 23830088Sminshall #if defined(TN3270) 23930088Sminshall 24030088Sminshall static int 24130326Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 24230088Sminshall 24330722Sminshall /* 24430722Sminshall * Telnet receiver states for fsm 24530722Sminshall */ 24630722Sminshall #define TS_DATA 0 24730722Sminshall #define TS_IAC 1 24830722Sminshall #define TS_WILL 2 24930722Sminshall #define TS_WONT 3 25030722Sminshall #define TS_DO 4 25130722Sminshall #define TS_DONT 5 25230722Sminshall #define TS_CR 6 25330722Sminshall #define TS_SB 7 /* sub-option collection */ 25430722Sminshall #define TS_SE 8 /* looking for sub-option end */ 25530722Sminshall 25630722Sminshall static int telrcv_state = TS_DATA; 25730088Sminshall /* Some real, live, globals. */ 25830088Sminshall int 25930326Sminshall tout, /* Output file descriptor */ 26030326Sminshall tin; /* Input file descriptor */ 26130088Sminshall 26230088Sminshall #else /* defined(TN3270) */ 26330326Sminshall static int tin, tout; /* file descriptors */ 26430088Sminshall #endif /* defined(TN3270) */ 26530088Sminshall 26630088Sminshall static char line[200]; 26730326Sminshall static int margc; 26830088Sminshall static char *margv[20]; 26930088Sminshall 270*31124Sminshall static jmp_buf toplevel = { 0 }; 27130088Sminshall static jmp_buf peerdied; 27230088Sminshall 27330088Sminshall extern int errno; 27430088Sminshall 27530088Sminshall 27630088Sminshall static struct sockaddr_in sin; 27730088Sminshall 27830088Sminshall static struct servent *sp = 0; 27930088Sminshall 28030326Sminshall static int flushline; 28130088Sminshall 28230326Sminshall static char *hostname; 28330088Sminshall static char hnamebuf[32]; 28430088Sminshall 28530088Sminshall /* 28630088Sminshall * The following are some clocks used to decide how to interpret 28730088Sminshall * the relationship between various variables. 28830088Sminshall */ 28930088Sminshall 29030088Sminshall static struct { 29130088Sminshall int 29230088Sminshall system, /* what the current time is */ 29330088Sminshall echotoggle, /* last time user entered echo character */ 29430088Sminshall modenegotiated, /* last time operating mode negotiated */ 29530088Sminshall didnetreceive, /* last time we read data from network */ 29630088Sminshall gotDM; /* when did we last see a data mark */ 29730326Sminshall } clocks; 29830088Sminshall 29930088Sminshall #define settimer(x) clocks.x = clocks.system++ 30030088Sminshall 301*31124Sminshall /* Various modes */ 302*31124Sminshall #define MODE_LINE(m) (modelist[m].modetype & LINE) 303*31124Sminshall #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS) 304*31124Sminshall 305*31124Sminshall #define LOCAL_CHARS 0x01 /* Characters processed locally */ 306*31124Sminshall #define LINE 0x02 /* Line-by-line mode of operation */ 307*31124Sminshall 308*31124Sminshall static struct { 309*31124Sminshall char *modedescriptions; 310*31124Sminshall char modetype; 311*31124Sminshall } modelist[] = { 312*31124Sminshall { "telnet command mode", 0 }, 313*31124Sminshall { "character-at-a-time mode", 0 }, 314*31124Sminshall { "character-at-a-time mode (local echo)", LOCAL_CHARS }, 315*31124Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 316*31124Sminshall { "line-by-line mode", LINE | LOCAL_CHARS }, 317*31124Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 318*31124Sminshall { "3270 mode", 0 }, 319*31124Sminshall }; 320*31124Sminshall 321*31124Sminshall 32230088Sminshall /* 323*31124Sminshall * The following routines try to encapsulate what is system dependent 324*31124Sminshall * (at least between 4.x and dos) which is used in telnet.c. 325*31124Sminshall */ 326*31124Sminshall 327*31124Sminshall #if defined(unix) 328*31124Sminshall #include <sys/ioctl.h> 329*31124Sminshall #include <sys/time.h> 330*31124Sminshall #include <signal.h> 331*31124Sminshall 332*31124Sminshall int 333*31124Sminshall HaveInput; /* There is input available to scan */ 334*31124Sminshall 335*31124Sminshall #if defined(TN3270) 336*31124Sminshall static char tline[200]; 337*31124Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 338*31124Sminshall #endif /* defined(TN3270) */ 339*31124Sminshall 340*31124Sminshall static struct tchars otc = { 0 }, ntc = { 0 }; 341*31124Sminshall static struct ltchars oltc = { 0 }, nltc = { 0 }; 342*31124Sminshall static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 343*31124Sminshall 344*31124Sminshall 345*31124Sminshall /* 346*31124Sminshall * 347*31124Sminshall */ 348*31124Sminshall 349*31124Sminshall static int 350*31124Sminshall TerminalAutoFlush() 351*31124Sminshall { 352*31124Sminshall #if defined(LNOFLSH) 353*31124Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 354*31124Sminshall return !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 355*31124Sminshall #else /* LNOFLSH */ 356*31124Sminshall return 1; 357*31124Sminshall #endif /* LNOFLSH */ 358*31124Sminshall } 359*31124Sminshall 360*31124Sminshall /* 361*31124Sminshall * TerminalEditLine() 362*31124Sminshall * 363*31124Sminshall * Look at an input character, and decide what to do. 364*31124Sminshall * 365*31124Sminshall * Output: 366*31124Sminshall * 367*31124Sminshall * 0 Don't add this character. 368*31124Sminshall * 1 Do add this character 369*31124Sminshall */ 370*31124Sminshall 371*31124Sminshall int 372*31124Sminshall TerminalEditLine(c) /* unix */ 373*31124Sminshall int c; 374*31124Sminshall { 375*31124Sminshall void doflush(), intp(), sendbrk(); 376*31124Sminshall 377*31124Sminshall if (c == ntc.t_intrc) { 378*31124Sminshall intp(); 379*31124Sminshall return 0; 380*31124Sminshall } else if (c == ntc.t_quitc) { 381*31124Sminshall sendbrk(); 382*31124Sminshall return 0; 383*31124Sminshall } else if (c == nltc.t_flushc) { 384*31124Sminshall NET2ADD(IAC, AO); 385*31124Sminshall if (autoflush) { 386*31124Sminshall doflush(); 387*31124Sminshall } 388*31124Sminshall return 0; 389*31124Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 390*31124Sminshall if (c == nttyb.sg_kill) { 391*31124Sminshall NET2ADD(IAC, EL); 392*31124Sminshall return 0; 393*31124Sminshall } else if (c == nttyb.sg_erase) { 394*31124Sminshall NET2ADD(IAC, EC); 395*31124Sminshall return 0; 396*31124Sminshall } 397*31124Sminshall } 398*31124Sminshall return 1; 399*31124Sminshall } 400*31124Sminshall 401*31124Sminshall 402*31124Sminshall /* 403*31124Sminshall * Flush output to the terminal 404*31124Sminshall */ 405*31124Sminshall 406*31124Sminshall static void 407*31124Sminshall TerminalFlushOutput() /* unix */ 408*31124Sminshall { 409*31124Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 410*31124Sminshall } 411*31124Sminshall 412*31124Sminshall static void 413*31124Sminshall TerminalSaveState() /* unix */ 414*31124Sminshall { 415*31124Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 416*31124Sminshall ioctl(0, TIOCGETC, (char *)&otc); 417*31124Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 418*31124Sminshall 419*31124Sminshall ntc = otc; 420*31124Sminshall nltc = oltc; 421*31124Sminshall nttyb = ottyb; 422*31124Sminshall } 423*31124Sminshall 424*31124Sminshall static void 425*31124Sminshall TerminalRestoreState() /* unix */ 426*31124Sminshall { 427*31124Sminshall } 428*31124Sminshall 429*31124Sminshall /* 430*31124Sminshall * TerminalNewMode - set up terminal to a specific mode. 431*31124Sminshall */ 432*31124Sminshall 433*31124Sminshall 434*31124Sminshall static void 435*31124Sminshall TerminalNewMode(f) 436*31124Sminshall register int f; 437*31124Sminshall { 438*31124Sminshall static int prevmode = 0; 439*31124Sminshall struct tchars *tc; 440*31124Sminshall struct tchars tc3; 441*31124Sminshall struct ltchars *ltc; 442*31124Sminshall struct sgttyb sb; 443*31124Sminshall int onoff; 444*31124Sminshall int old; 445*31124Sminshall struct tchars notc2; 446*31124Sminshall struct ltchars noltc2; 447*31124Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 448*31124Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 449*31124Sminshall 450*31124Sminshall globalmode = f; 451*31124Sminshall if (prevmode == f) 452*31124Sminshall return; 453*31124Sminshall old = prevmode; 454*31124Sminshall prevmode = f; 455*31124Sminshall sb = nttyb; 456*31124Sminshall 457*31124Sminshall switch (f) { 458*31124Sminshall 459*31124Sminshall case 0: 460*31124Sminshall onoff = 0; 461*31124Sminshall tc = &otc; 462*31124Sminshall ltc = &oltc; 463*31124Sminshall break; 464*31124Sminshall 465*31124Sminshall case 1: /* remote character processing, remote echo */ 466*31124Sminshall case 2: /* remote character processing, local echo */ 467*31124Sminshall case 6: /* 3270 mode - like 1, but with xon/xoff local */ 468*31124Sminshall /* (might be nice to have "6" in telnet also...) */ 469*31124Sminshall sb.sg_flags |= CBREAK; 470*31124Sminshall if ((f == 1) || (f == 6)) { 471*31124Sminshall sb.sg_flags &= ~(ECHO|CRMOD); 472*31124Sminshall } else { 473*31124Sminshall sb.sg_flags |= ECHO|CRMOD; 474*31124Sminshall } 475*31124Sminshall sb.sg_erase = sb.sg_kill = -1; 476*31124Sminshall if (f == 6) { 477*31124Sminshall tc = &tc3; 478*31124Sminshall tc3 = notc; 479*31124Sminshall /* get XON, XOFF characters */ 480*31124Sminshall tc3.t_startc = otc.t_startc; 481*31124Sminshall tc3.t_stopc = otc.t_stopc; 482*31124Sminshall } else { 483*31124Sminshall /* 484*31124Sminshall * If user hasn't specified one way or the other, 485*31124Sminshall * then default to not trapping signals. 486*31124Sminshall */ 487*31124Sminshall if (!donelclchars) { 488*31124Sminshall localchars = 0; 489*31124Sminshall } 490*31124Sminshall if (localchars) { 491*31124Sminshall notc2 = notc; 492*31124Sminshall notc2.t_intrc = ntc.t_intrc; 493*31124Sminshall notc2.t_quitc = ntc.t_quitc; 494*31124Sminshall tc = ¬c2; 495*31124Sminshall } else { 496*31124Sminshall tc = ¬c; 497*31124Sminshall } 498*31124Sminshall } 499*31124Sminshall ltc = &noltc; 500*31124Sminshall onoff = 1; 501*31124Sminshall break; 502*31124Sminshall case 3: /* local character processing, remote echo */ 503*31124Sminshall case 4: /* local character processing, local echo */ 504*31124Sminshall case 5: /* local character processing, no echo */ 505*31124Sminshall sb.sg_flags &= ~CBREAK; 506*31124Sminshall sb.sg_flags |= CRMOD; 507*31124Sminshall if (f == 4) 508*31124Sminshall sb.sg_flags |= ECHO; 509*31124Sminshall else 510*31124Sminshall sb.sg_flags &= ~ECHO; 511*31124Sminshall notc2 = ntc; 512*31124Sminshall tc = ¬c2; 513*31124Sminshall noltc2 = oltc; 514*31124Sminshall ltc = &noltc2; 515*31124Sminshall /* 516*31124Sminshall * If user hasn't specified one way or the other, 517*31124Sminshall * then default to trapping signals. 518*31124Sminshall */ 519*31124Sminshall if (!donelclchars) { 520*31124Sminshall localchars = 1; 521*31124Sminshall } 522*31124Sminshall if (localchars) { 523*31124Sminshall notc2.t_brkc = nltc.t_flushc; 524*31124Sminshall noltc2.t_flushc = -1; 525*31124Sminshall } else { 526*31124Sminshall notc2.t_intrc = notc2.t_quitc = -1; 527*31124Sminshall } 528*31124Sminshall noltc2.t_suspc = escape; 529*31124Sminshall noltc2.t_dsuspc = -1; 530*31124Sminshall onoff = 1; 531*31124Sminshall break; 532*31124Sminshall 533*31124Sminshall default: 534*31124Sminshall return; 535*31124Sminshall } 536*31124Sminshall ioctl(tin, TIOCSLTC, (char *)ltc); 537*31124Sminshall ioctl(tin, TIOCSETC, (char *)tc); 538*31124Sminshall ioctl(tin, TIOCSETP, (char *)&sb); 539*31124Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 540*31124Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 541*31124Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 542*31124Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 543*31124Sminshall #if defined(TN3270) && !defined(DEBUG) 544*31124Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 545*31124Sminshall #endif /* defined(TN3270) && !defined(DEBUG) */ 546*31124Sminshall 547*31124Sminshall if (MODE_LINE(f)) { 548*31124Sminshall void doescape(); 549*31124Sminshall 550*31124Sminshall signal(SIGTSTP, doescape); 551*31124Sminshall } else if (MODE_LINE(old)) { 552*31124Sminshall signal(SIGTSTP, SIG_DFL); 553*31124Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 554*31124Sminshall } 555*31124Sminshall } 556*31124Sminshall 557*31124Sminshall 558*31124Sminshall static void 559*31124Sminshall NetNonblockingIO(fd, onoff) /* unix */ 560*31124Sminshall int 561*31124Sminshall fd, 562*31124Sminshall onoff; 563*31124Sminshall { 564*31124Sminshall ioctl(net, FIONBIO, (char *)&onoff); 565*31124Sminshall } 566*31124Sminshall 567*31124Sminshall static void 568*31124Sminshall NetSigIO(fd, onoff) /* unix */ 569*31124Sminshall int 570*31124Sminshall fd, 571*31124Sminshall onoff; 572*31124Sminshall { 573*31124Sminshall ioctl(net, FIOASYNC, (char *)&onoff); /* hear about input */ 574*31124Sminshall } 575*31124Sminshall 576*31124Sminshall static void 577*31124Sminshall NetSetPgrp(fd) /* unix */ 578*31124Sminshall int fd; 579*31124Sminshall { 580*31124Sminshall int myPid; 581*31124Sminshall 582*31124Sminshall myPid = getpid(); 583*31124Sminshall #if defined(NOT43) 584*31124Sminshall myPid = -myPid; 585*31124Sminshall #endif /* defined(NOT43) */ 586*31124Sminshall ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */ 587*31124Sminshall } 588*31124Sminshall 589*31124Sminshall 590*31124Sminshall #endif /* defined(unix) */ 591*31124Sminshall 592*31124Sminshall #if defined(MSDOS) 593*31124Sminshall #include <time.h> 594*31124Sminshall 595*31124Sminshall #if !defined(SO_OOBINLINE) 596*31124Sminshall #define SO_OOBINLINE 597*31124Sminshall #endif /* !defined(SO_OOBINLINE) */ 598*31124Sminshall 599*31124Sminshall 600*31124Sminshall static char 601*31124Sminshall termEraseChar, 602*31124Sminshall termFlushChar, 603*31124Sminshall termIntChar, 604*31124Sminshall termKillChar, 605*31124Sminshall termQuitChar, 606*31124Sminshall termEofChar; 607*31124Sminshall 608*31124Sminshall 609*31124Sminshall /* 610*31124Sminshall * Flush output to the terminal 611*31124Sminshall */ 612*31124Sminshall 613*31124Sminshall static void 614*31124Sminshall TerminalFlushOutput() /* MSDOS */ 615*31124Sminshall { 616*31124Sminshall } 617*31124Sminshall 618*31124Sminshall static void 619*31124Sminshall TerminalSaveState() /* MSDOS */ 620*31124Sminshall { 621*31124Sminshall } 622*31124Sminshall 623*31124Sminshall static void 624*31124Sminshall TerminalRestoreState() /* MSDOS */ 625*31124Sminshall { 626*31124Sminshall } 627*31124Sminshall 628*31124Sminshall static void 629*31124Sminshall NetNonblockingIO(fd, onoff) /* MSDOS */ 630*31124Sminshall int 631*31124Sminshall fd, 632*31124Sminshall onoff; 633*31124Sminshall { 634*31124Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) { 635*31124Sminshall perror("setsockop (SO_NONBLOCKING) "); 636*31124Sminshall XXX(); 637*31124Sminshall } 638*31124Sminshall } 639*31124Sminshall 640*31124Sminshall static void 641*31124Sminshall NetSigIO(fd) /* MSDOS */ 642*31124Sminshall int fd; 643*31124Sminshall { 644*31124Sminshall } 645*31124Sminshall 646*31124Sminshall static void 647*31124Sminshall NetSetPgrp(fd) /* MSDOS */ 648*31124Sminshall int fd; 649*31124Sminshall { 650*31124Sminshall } 651*31124Sminshall 652*31124Sminshall 653*31124Sminshall #endif /* defined(MSDOS) */ 654*31124Sminshall 655*31124Sminshall /* 65630326Sminshall * Initialize variables. 65730326Sminshall */ 65830326Sminshall 65930326Sminshall static void 66030326Sminshall tninit() 66130326Sminshall { 66230326Sminshall Ifrontp = Ibackp = Ibuf; 66330326Sminshall tfrontp = tbackp = ttyobuf; 66430326Sminshall nfrontp = nbackp = netobuf; 66530326Sminshall 66630326Sminshall /* Don't change telnetport */ 66730722Sminshall SB_CLEAR(); 66830722Sminshall ClearArray(hisopts); 66930722Sminshall ClearArray(myopts); 67030722Sminshall sbp = sibuf; 67130722Sminshall tbp = tibuf; 67230326Sminshall 67330722Sminshall connected = net = scc = tcc = In3270 = ISend = 0; 67430722Sminshall telnetport = 0; 675*31124Sminshall #if defined(unix) 676*31124Sminshall HaveInput = 0; 677*31124Sminshall #endif /* defined(unix) */ 67830722Sminshall 67930722Sminshall SYNCHing = 0; 68030722Sminshall Sent3270TerminalType = 0; 68130722Sminshall 68230722Sminshall errno = 0; 68330722Sminshall 68430722Sminshall flushline = 0; 68530722Sminshall 68630326Sminshall /* Don't change NetTrace */ 68730326Sminshall 68830326Sminshall escape = CONTROL(']'); 68930326Sminshall echoc = CONTROL('E'); 69030326Sminshall 69130326Sminshall flushline = 1; 69230326Sminshall sp = getservbyname("telnet", "tcp"); 69330326Sminshall if (sp == 0) { 69430326Sminshall ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1); 69530326Sminshall /*NOTREACHED*/ 69630326Sminshall } 69730326Sminshall 69830326Sminshall #if defined(TN3270) 69930722Sminshall init_ctlr(); /* Initialize some things */ 70030722Sminshall init_keyboard(); 70130722Sminshall init_screen(); 70230722Sminshall init_system(); 70330326Sminshall #endif /* defined(TN3270) */ 70430326Sminshall } 70530326Sminshall 70630326Sminshall /* 70730088Sminshall * Various utility routines. 70830088Sminshall */ 70930088Sminshall 71030088Sminshall static void 71130088Sminshall makeargv() 71230088Sminshall { 71330088Sminshall register char *cp; 71430088Sminshall register char **argp = margv; 71530088Sminshall 71630088Sminshall margc = 0; 71730088Sminshall for (cp = line; *cp;) { 71830088Sminshall while (isspace(*cp)) 71930088Sminshall cp++; 72030088Sminshall if (*cp == '\0') 72130088Sminshall break; 72230088Sminshall *argp++ = cp; 72330088Sminshall margc += 1; 72430088Sminshall while (*cp != '\0' && !isspace(*cp)) 72530088Sminshall cp++; 72630088Sminshall if (*cp == '\0') 72730088Sminshall break; 72830088Sminshall *cp++ = '\0'; 72930088Sminshall } 73030088Sminshall *argp++ = 0; 73130088Sminshall } 73230088Sminshall 73330088Sminshall static char *ambiguous; /* special return value */ 73430088Sminshall #define Ambiguous(t) ((t)&ambiguous) 73530088Sminshall 73630088Sminshall 73730088Sminshall static char ** 73830088Sminshall genget(name, table, next) 73930088Sminshall char *name; /* name to match */ 74030088Sminshall char **table; /* name entry in table */ 74130088Sminshall char **(*next)(); /* routine to return next entry in table */ 74230088Sminshall { 74330088Sminshall register char *p, *q; 74430088Sminshall register char **c, **found; 74530088Sminshall register int nmatches, longest; 74630088Sminshall 74730088Sminshall longest = 0; 74830088Sminshall nmatches = 0; 74930088Sminshall found = 0; 75030088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 75130088Sminshall for (q = name; 75230088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 75330088Sminshall if (*q == 0) /* exact match? */ 75430088Sminshall return (c); 75530088Sminshall if (!*q) { /* the name was a prefix */ 75630088Sminshall if (q - name > longest) { 75730088Sminshall longest = q - name; 75830088Sminshall nmatches = 1; 75930088Sminshall found = c; 76030088Sminshall } else if (q - name == longest) 76130088Sminshall nmatches++; 76230088Sminshall } 76330088Sminshall } 76430088Sminshall if (nmatches > 1) 76530088Sminshall return Ambiguous(char **); 76630088Sminshall return (found); 76730088Sminshall } 76830088Sminshall 76930088Sminshall /* 77030088Sminshall * Make a character string into a number. 77130088Sminshall * 77230088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 77330088Sminshall */ 77430088Sminshall 77530088Sminshall static 77630088Sminshall special(s) 77730088Sminshall register char *s; 77830088Sminshall { 77930088Sminshall register char c; 78030088Sminshall char b; 78130088Sminshall 78230088Sminshall switch (*s) { 78330088Sminshall case '^': 78430088Sminshall b = *++s; 78530088Sminshall if (b == '?') { 78630088Sminshall c = b | 0x40; /* DEL */ 78730088Sminshall } else { 78830088Sminshall c = b & 0x1f; 78930088Sminshall } 79030088Sminshall break; 79130088Sminshall default: 79230088Sminshall c = *s; 79330088Sminshall break; 79430088Sminshall } 79530088Sminshall return c; 79630088Sminshall } 79730088Sminshall 79830088Sminshall /* 79930088Sminshall * Construct a control character sequence 80030088Sminshall * for a special character. 80130088Sminshall */ 80230088Sminshall static char * 80330088Sminshall control(c) 80430088Sminshall register int c; 80530088Sminshall { 80630088Sminshall static char buf[3]; 80730088Sminshall 80830088Sminshall if (c == 0x7f) 80930088Sminshall return ("^?"); 81030088Sminshall if (c == '\377') { 81130088Sminshall return "off"; 81230088Sminshall } 81330088Sminshall if (c >= 0x20) { 81430088Sminshall buf[0] = c; 81530088Sminshall buf[1] = 0; 81630088Sminshall } else { 81730088Sminshall buf[0] = '^'; 81830088Sminshall buf[1] = '@'+c; 81930088Sminshall buf[2] = 0; 82030088Sminshall } 82130088Sminshall return (buf); 82230088Sminshall } 82330088Sminshall 82430088Sminshall 82530088Sminshall /* 82630088Sminshall * upcase() 82730088Sminshall * 82830088Sminshall * Upcase (in place) the argument. 82930088Sminshall */ 83030088Sminshall 83130088Sminshall static void 83230088Sminshall upcase(argument) 83330088Sminshall register char *argument; 83430088Sminshall { 83530088Sminshall register int c; 83630088Sminshall 83730088Sminshall while ((c = *argument) != 0) { 83830088Sminshall if (islower(c)) { 83930088Sminshall *argument = toupper(c); 84030088Sminshall } 84130088Sminshall argument++; 84230088Sminshall } 84330088Sminshall } 844*31124Sminshall 845*31124Sminshall /* 846*31124Sminshall * SetSockOpt() 847*31124Sminshall * 848*31124Sminshall * Compensate for differences in 4.2 and 4.3 systems. 849*31124Sminshall */ 850*31124Sminshall 851*31124Sminshall static int 852*31124Sminshall SetSockOpt(fd, level, option, yesno) 853*31124Sminshall int 854*31124Sminshall fd, 855*31124Sminshall level, 856*31124Sminshall option, 857*31124Sminshall yesno; 858*31124Sminshall { 859*31124Sminshall #ifndef NOT43 860*31124Sminshall return setsockopt(fd, level, option, 861*31124Sminshall (char *)&yesno, sizeof yesno); 862*31124Sminshall #else /* NOT43 */ 863*31124Sminshall if (yesno == 0) { /* Can't do that in 4.2! */ 864*31124Sminshall fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", 865*31124Sminshall option); 866*31124Sminshall return -1; 867*31124Sminshall } 868*31124Sminshall return setsockopt(fd, level, option, 0, 0); 869*31124Sminshall #endif /* NOT43 */ 870*31124Sminshall } 87130088Sminshall 87230088Sminshall /* 87330088Sminshall * The following are routines used to print out debugging information. 87430088Sminshall */ 87530088Sminshall 87630088Sminshall 87730088Sminshall static void 87830088Sminshall Dump(direction, buffer, length) 87930088Sminshall char direction; 88030088Sminshall char *buffer; 88130088Sminshall int length; 88230088Sminshall { 88330088Sminshall # define BYTES_PER_LINE 32 88430088Sminshall # define min(x,y) ((x<y)? x:y) 88530088Sminshall char *pThis; 88630088Sminshall int offset; 88730088Sminshall 88830088Sminshall offset = 0; 88930088Sminshall 89030088Sminshall while (length) { 89130088Sminshall /* print one line */ 89230088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 89330088Sminshall pThis = buffer; 89430088Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 89530088Sminshall while (pThis < buffer) { 89630088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 89730088Sminshall pThis++; 89830088Sminshall } 89930088Sminshall fprintf(NetTrace, "\n"); 90030088Sminshall length -= BYTES_PER_LINE; 90130088Sminshall offset += BYTES_PER_LINE; 90230088Sminshall if (length < 0) { 90330088Sminshall return; 90430088Sminshall } 90530088Sminshall /* find next unique line */ 90630088Sminshall } 90730088Sminshall } 90830088Sminshall 90930088Sminshall 91030088Sminshall /*VARARGS*/ 91130088Sminshall static void 91230088Sminshall printoption(direction, fmt, option, what) 91330088Sminshall char *direction, *fmt; 91430088Sminshall int option, what; 91530088Sminshall { 91630088Sminshall if (!showoptions) 91730088Sminshall return; 91830088Sminshall fprintf(NetTrace, "%s ", direction+1); 91930088Sminshall if (fmt == doopt) 92030088Sminshall fmt = "do"; 92130088Sminshall else if (fmt == dont) 92230088Sminshall fmt = "dont"; 92330088Sminshall else if (fmt == will) 92430088Sminshall fmt = "will"; 92530088Sminshall else if (fmt == wont) 92630088Sminshall fmt = "wont"; 92730088Sminshall else 92830088Sminshall fmt = "???"; 92930088Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 93030088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]); 93130088Sminshall else 93230088Sminshall fprintf(NetTrace, "%s %d", fmt, option); 93330088Sminshall if (*direction == '<') { 93430088Sminshall fprintf(NetTrace, "\r\n"); 93530088Sminshall return; 93630088Sminshall } 93730088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); 93830088Sminshall } 93930088Sminshall 94030088Sminshall static void 94130088Sminshall printsub(direction, pointer, length) 94230088Sminshall char *direction, /* "<" or ">" */ 94330088Sminshall *pointer; /* where suboption data sits */ 94430088Sminshall int length; /* length of suboption data */ 94530088Sminshall { 94630088Sminshall if (showoptions) { 94730088Sminshall fprintf(NetTrace, "%s suboption ", 94830088Sminshall (direction[0] == '<')? "Received":"Sent"); 94930088Sminshall switch (pointer[0]) { 95030088Sminshall case TELOPT_TTYPE: 95130088Sminshall fprintf(NetTrace, "Terminal type "); 95230088Sminshall switch (pointer[1]) { 95330088Sminshall case TELQUAL_IS: 95430088Sminshall { 95530088Sminshall char tmpbuf[sizeof subbuffer]; 95630088Sminshall int minlen = min(length, sizeof tmpbuf); 95730088Sminshall 95830088Sminshall bcopy(pointer+2, tmpbuf, minlen); 95930088Sminshall tmpbuf[minlen-1] = 0; 96030088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf); 96130088Sminshall } 96230088Sminshall break; 96330088Sminshall case TELQUAL_SEND: 96430088Sminshall fprintf(NetTrace, "- request to send.\n"); 96530088Sminshall break; 96630088Sminshall default: 96730088Sminshall fprintf(NetTrace, 96830088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]); 96930088Sminshall } 97030088Sminshall break; 97130088Sminshall default: 97230088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n", 97330088Sminshall pointer[0], pointer[0]); 97430088Sminshall } 97530088Sminshall } 97630088Sminshall } 97730088Sminshall 97830088Sminshall /* 97930088Sminshall * Check to see if any out-of-band data exists on a socket (for 98030088Sminshall * Telnet "synch" processing). 98130088Sminshall */ 98230088Sminshall 98330088Sminshall static int 98430088Sminshall stilloob(s) 98530088Sminshall int s; /* socket number */ 98630088Sminshall { 98730088Sminshall static struct timeval timeout = { 0 }; 98830088Sminshall fd_set excepts; 98930088Sminshall int value; 99030088Sminshall 99130088Sminshall do { 99230088Sminshall FD_ZERO(&excepts); 99330088Sminshall FD_SET(s, &excepts); 99430088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 99530088Sminshall } while ((value == -1) && (errno == EINTR)); 99630088Sminshall 99730088Sminshall if (value < 0) { 99830088Sminshall perror("select"); 99930088Sminshall quit(); 100030088Sminshall } 100130088Sminshall if (FD_ISSET(s, &excepts)) { 100230088Sminshall return 1; 100330088Sminshall } else { 100430088Sminshall return 0; 100530088Sminshall } 100630088Sminshall } 100730088Sminshall 100830088Sminshall 100930088Sminshall /* 101030088Sminshall * netflush 101130088Sminshall * Send as much data as possible to the network, 101230088Sminshall * handling requests for urgent data. 101330088Sminshall * 101430088Sminshall * The return value indicates whether we did any 101530088Sminshall * useful work. 101630088Sminshall */ 101730088Sminshall 101830088Sminshall 101930088Sminshall int 102030088Sminshall netflush() 102130088Sminshall { 102230088Sminshall int n; 102330088Sminshall 102430088Sminshall if ((n = nfrontp - nbackp) > 0) { 102530088Sminshall if (!neturg) { 102630088Sminshall n = write(net, nbackp, n); /* normal write */ 102730088Sminshall } else { 102830088Sminshall n = neturg - nbackp; 102930088Sminshall /* 103030088Sminshall * In 4.2 (and 4.3) systems, there is some question about 103130088Sminshall * what byte in a sendOOB operation is the "OOB" data. 103230088Sminshall * To make ourselves compatible, we only send ONE byte 103330088Sminshall * out of band, the one WE THINK should be OOB (though 103430088Sminshall * we really have more the TCP philosophy of urgent data 103530088Sminshall * rather than the Unix philosophy of OOB data). 103630088Sminshall */ 103730088Sminshall if (n > 1) { 103830088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 103930088Sminshall } else { 104030088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 104130088Sminshall } 104230088Sminshall } 104330088Sminshall } 104430088Sminshall if (n < 0) { 104530088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 104630088Sminshall setcommandmode(); 104730088Sminshall perror(hostname); 104830088Sminshall close(net); 104930088Sminshall neturg = 0; 105030088Sminshall longjmp(peerdied, -1); 105130088Sminshall /*NOTREACHED*/ 105230088Sminshall } 105330088Sminshall n = 0; 105430088Sminshall } 105530088Sminshall if (netdata && n) { 105630088Sminshall Dump('>', nbackp, n); 105730088Sminshall } 105830088Sminshall nbackp += n; 105930088Sminshall if (nbackp >= neturg) { 106030088Sminshall neturg = 0; 106130088Sminshall } 106230088Sminshall if (nbackp == nfrontp) { 106330088Sminshall nbackp = nfrontp = netobuf; 106430088Sminshall } 106530088Sminshall return n > 0; 106630088Sminshall } 106730088Sminshall 106830088Sminshall /* 106930088Sminshall * nextitem() 107030088Sminshall * 107130088Sminshall * Return the address of the next "item" in the TELNET data 107230088Sminshall * stream. This will be the address of the next character if 107330088Sminshall * the current address is a user data character, or it will 107430088Sminshall * be the address of the character following the TELNET command 107530088Sminshall * if the current address is a TELNET IAC ("I Am a Command") 107630088Sminshall * character. 107730088Sminshall */ 107830088Sminshall 107930088Sminshall static char * 108030088Sminshall nextitem(current) 108130088Sminshall char *current; 108230088Sminshall { 108330088Sminshall if ((*current&0xff) != IAC) { 108430088Sminshall return current+1; 108530088Sminshall } 108630088Sminshall switch (*(current+1)&0xff) { 108730088Sminshall case DO: 108830088Sminshall case DONT: 108930088Sminshall case WILL: 109030088Sminshall case WONT: 109130088Sminshall return current+3; 109230088Sminshall case SB: /* loop forever looking for the SE */ 109330088Sminshall { 109430088Sminshall register char *look = current+2; 109530088Sminshall 109630088Sminshall for (;;) { 109730088Sminshall if ((*look++&0xff) == IAC) { 109830088Sminshall if ((*look++&0xff) == SE) { 109930088Sminshall return look; 110030088Sminshall } 110130088Sminshall } 110230088Sminshall } 110330088Sminshall } 110430088Sminshall default: 110530088Sminshall return current+2; 110630088Sminshall } 110730088Sminshall } 110830088Sminshall /* 110930088Sminshall * netclear() 111030088Sminshall * 111130088Sminshall * We are about to do a TELNET SYNCH operation. Clear 111230088Sminshall * the path to the network. 111330088Sminshall * 111430088Sminshall * Things are a bit tricky since we may have sent the first 111530088Sminshall * byte or so of a previous TELNET command into the network. 111630088Sminshall * So, we have to scan the network buffer from the beginning 111730088Sminshall * until we are up to where we want to be. 111830088Sminshall * 111930088Sminshall * A side effect of what we do, just to keep things 112030088Sminshall * simple, is to clear the urgent data pointer. The principal 112130088Sminshall * caller should be setting the urgent data pointer AFTER calling 112230088Sminshall * us in any case. 112330088Sminshall */ 112430088Sminshall 112530088Sminshall static void 112630088Sminshall netclear() 112730088Sminshall { 112830088Sminshall register char *thisitem, *next; 112930088Sminshall char *good; 113030088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 113130088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 113230088Sminshall 113330088Sminshall thisitem = netobuf; 113430088Sminshall 113530088Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 113630088Sminshall thisitem = next; 113730088Sminshall } 113830088Sminshall 113930088Sminshall /* Now, thisitem is first before/at boundary. */ 114030088Sminshall 114130088Sminshall good = netobuf; /* where the good bytes go */ 114230088Sminshall 114330088Sminshall while (nfrontp > thisitem) { 114430088Sminshall if (wewant(thisitem)) { 114530088Sminshall int length; 114630088Sminshall 114730088Sminshall next = thisitem; 114830088Sminshall do { 114930088Sminshall next = nextitem(next); 115030088Sminshall } while (wewant(next) && (nfrontp > next)); 115130088Sminshall length = next-thisitem; 115230088Sminshall bcopy(thisitem, good, length); 115330088Sminshall good += length; 115430088Sminshall thisitem = next; 115530088Sminshall } else { 115630088Sminshall thisitem = nextitem(thisitem); 115730088Sminshall } 115830088Sminshall } 115930088Sminshall 116030088Sminshall nbackp = netobuf; 116130088Sminshall nfrontp = good; /* next byte to be sent */ 116230088Sminshall neturg = 0; 116330088Sminshall } 116430088Sminshall 116530088Sminshall /* 116630088Sminshall * These routines add various telnet commands to the data stream. 116730088Sminshall */ 116830088Sminshall 116930088Sminshall #if defined(NOT43) 117030088Sminshall static int 117130088Sminshall #else /* defined(NOT43) */ 117230088Sminshall static void 117330088Sminshall #endif /* defined(NOT43) */ 117430088Sminshall dosynch() 117530088Sminshall { 117630088Sminshall netclear(); /* clear the path to the network */ 117730088Sminshall NET2ADD(IAC, DM); 117830088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 117930088Sminshall 118030088Sminshall #if defined(NOT43) 118130088Sminshall return 0; 118230088Sminshall #endif /* defined(NOT43) */ 118330088Sminshall } 118430088Sminshall 118530088Sminshall static void 118630088Sminshall doflush() 118730088Sminshall { 118830088Sminshall NET2ADD(IAC, DO); 118930088Sminshall NETADD(TELOPT_TM); 119030088Sminshall flushline = 1; 119130088Sminshall flushout = 1; 119230088Sminshall ttyflush(); 119330088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 119430088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 119530088Sminshall } 119630088Sminshall 119730088Sminshall static void 119830088Sminshall intp() 119930088Sminshall { 120030088Sminshall NET2ADD(IAC, IP); 120130088Sminshall if (autoflush) { 120230088Sminshall doflush(); 120330088Sminshall } 120430088Sminshall if (autosynch) { 120530088Sminshall dosynch(); 120630088Sminshall } 120730088Sminshall } 120830088Sminshall 120930088Sminshall static void 121030088Sminshall sendbrk() 121130088Sminshall { 121230088Sminshall NET2ADD(IAC, BREAK); 121330088Sminshall if (autoflush) { 121430088Sminshall doflush(); 121530088Sminshall } 121630088Sminshall if (autosynch) { 121730088Sminshall dosynch(); 121830088Sminshall } 121930088Sminshall } 122030088Sminshall 122130088Sminshall /* 122230088Sminshall * Send as much data as possible to the terminal. 122330088Sminshall * 122430088Sminshall * The return value indicates whether we did any 122530088Sminshall * useful work. 122630088Sminshall */ 122730088Sminshall 122830088Sminshall 122930088Sminshall static int 123030088Sminshall ttyflush() 123130088Sminshall { 123230088Sminshall int n; 123330088Sminshall 123430088Sminshall if ((n = tfrontp - tbackp) > 0) { 123530088Sminshall if (!(SYNCHing||flushout)) { 123630088Sminshall n = write(tout, tbackp, n); 123730088Sminshall } else { 1238*31124Sminshall TerminalFlushOutput(); 123930088Sminshall /* we leave 'n' alone! */ 124030088Sminshall } 124130088Sminshall } 124230088Sminshall if (n >= 0) { 124330088Sminshall tbackp += n; 124430088Sminshall if (tbackp == tfrontp) { 124530088Sminshall tbackp = tfrontp = ttyobuf; 124630088Sminshall } 124730088Sminshall } 124830088Sminshall return n > 0; 124930088Sminshall } 125030088Sminshall 125130088Sminshall #if defined(TN3270) 125230088Sminshall 125330088Sminshall #if defined(unix) 125430088Sminshall static void 125530088Sminshall inputAvailable() 125630088Sminshall { 125730088Sminshall HaveInput = 1; 125830088Sminshall } 125930088Sminshall #endif /* defined(unix) */ 126030088Sminshall 126130088Sminshall void 126230088Sminshall outputPurge() 126330088Sminshall { 126430088Sminshall int tmp = flushout; 126530088Sminshall 126630088Sminshall flushout = 1; 126730088Sminshall 126830088Sminshall ttyflush(); 126930088Sminshall 127030088Sminshall flushout = tmp; 127130088Sminshall } 127230088Sminshall 127330088Sminshall #endif /* defined(TN3270) */ 127430088Sminshall 127530088Sminshall #if defined(unix) 127630088Sminshall /* 127730088Sminshall * Various signal handling routines. 127830088Sminshall */ 127930088Sminshall 128030088Sminshall static void 128130088Sminshall deadpeer() 128230088Sminshall { 128330088Sminshall setcommandmode(); 128430088Sminshall longjmp(peerdied, -1); 128530088Sminshall } 128630088Sminshall 128730088Sminshall static void 128830088Sminshall intr() 128930088Sminshall { 129030088Sminshall if (localchars) { 129130088Sminshall intp(); 129230088Sminshall return; 129330088Sminshall } 129430088Sminshall setcommandmode(); 129530088Sminshall longjmp(toplevel, -1); 129630088Sminshall } 129730088Sminshall 129830088Sminshall static void 129930088Sminshall intr2() 130030088Sminshall { 130130088Sminshall if (localchars) { 130230088Sminshall sendbrk(); 130330088Sminshall return; 130430088Sminshall } 130530088Sminshall } 130630088Sminshall 130730088Sminshall static void 130830088Sminshall doescape() 130930088Sminshall { 131030088Sminshall command(0); 131130088Sminshall } 131230088Sminshall #endif /* defined(unix) */ 131330088Sminshall 131430088Sminshall /* 131530088Sminshall * These routines decides on what the mode should be (based on the values 131630088Sminshall * of various global variables). 131730088Sminshall */ 131830088Sminshall 131930088Sminshall 132030088Sminshall static 132130088Sminshall getconnmode() 132230088Sminshall { 132330088Sminshall static char newmode[16] = 132430088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; 132530088Sminshall int modeindex = 0; 132630088Sminshall 132730088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 132830088Sminshall modeindex += 1; 132930088Sminshall } 133030088Sminshall if (hisopts[TELOPT_ECHO]) { 133130088Sminshall modeindex += 2; 133230088Sminshall } 133330088Sminshall if (hisopts[TELOPT_SGA]) { 133430088Sminshall modeindex += 4; 133530088Sminshall } 133630088Sminshall if (In3270) { 133730088Sminshall modeindex += 8; 133830088Sminshall } 133930088Sminshall return newmode[modeindex]; 134030088Sminshall } 134130088Sminshall 134230088Sminshall void 134330088Sminshall setconnmode() 134430088Sminshall { 1345*31124Sminshall TerminalNewMode(getconnmode()); 134630088Sminshall } 134730088Sminshall 134830088Sminshall 134930088Sminshall void 135030088Sminshall setcommandmode() 135130088Sminshall { 1352*31124Sminshall TerminalNewMode(0); 135330088Sminshall } 135430088Sminshall 135530088Sminshall static void 135630088Sminshall willoption(option, reply) 135730088Sminshall int option, reply; 135830088Sminshall { 135930088Sminshall char *fmt; 136030088Sminshall 136130088Sminshall switch (option) { 136230088Sminshall 136330368Sminshall case TELOPT_ECHO: 136430088Sminshall # if defined(TN3270) 136530368Sminshall /* 136630368Sminshall * The following is a pain in the rear-end. 136730368Sminshall * Various IBM servers (some versions of Wiscnet, 136830368Sminshall * possibly Fibronics/Spartacus, and who knows who 136930368Sminshall * else) will NOT allow us to send "DO SGA" too early 137030368Sminshall * in the setup proceedings. On the other hand, 137130368Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 137230368Sminshall * So, we are stuck. Empirically (but, based on 137330368Sminshall * a VERY small sample), the IBM servers don't send 137430368Sminshall * out anything about ECHO, so we postpone our sending 137530368Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 137630368Sminshall * DO send). 137730368Sminshall */ 137830368Sminshall { 137930368Sminshall if (askedSGA == 0) { 138030368Sminshall askedSGA = 1; 138130368Sminshall if (!hisopts[TELOPT_SGA]) { 138230368Sminshall willoption(TELOPT_SGA, 0); 138330368Sminshall } 138430368Sminshall } 138530368Sminshall } 138630368Sminshall /* Fall through */ 138730088Sminshall case TELOPT_EOR: 138830088Sminshall case TELOPT_BINARY: 138930088Sminshall #endif /* defined(TN3270) */ 139030088Sminshall case TELOPT_SGA: 139130088Sminshall settimer(modenegotiated); 139230088Sminshall hisopts[option] = 1; 139330088Sminshall fmt = doopt; 139430088Sminshall setconnmode(); /* possibly set new tty mode */ 139530088Sminshall break; 139630088Sminshall 139730088Sminshall case TELOPT_TM: 139830088Sminshall return; /* Never reply to TM will's/wont's */ 139930088Sminshall 140030088Sminshall default: 140130088Sminshall fmt = dont; 140230088Sminshall break; 140330088Sminshall } 140430088Sminshall sprintf(nfrontp, fmt, option); 140530088Sminshall nfrontp += sizeof (dont) - 2; 140630088Sminshall if (reply) 140730088Sminshall printoption(">SENT", fmt, option, reply); 140830088Sminshall else 140930088Sminshall printoption("<SENT", fmt, option, reply); 141030088Sminshall } 141130088Sminshall 141230088Sminshall static void 141330088Sminshall wontoption(option, reply) 141430088Sminshall int option, reply; 141530088Sminshall { 141630088Sminshall char *fmt; 141730088Sminshall 141830088Sminshall switch (option) { 141930088Sminshall 142030088Sminshall case TELOPT_ECHO: 142130088Sminshall case TELOPT_SGA: 142230088Sminshall settimer(modenegotiated); 142330088Sminshall hisopts[option] = 0; 142430088Sminshall fmt = dont; 142530088Sminshall setconnmode(); /* Set new tty mode */ 142630088Sminshall break; 142730088Sminshall 142830088Sminshall case TELOPT_TM: 142930088Sminshall return; /* Never reply to TM will's/wont's */ 143030088Sminshall 143130088Sminshall default: 143230088Sminshall fmt = dont; 143330088Sminshall } 143430088Sminshall sprintf(nfrontp, fmt, option); 143530088Sminshall nfrontp += sizeof (doopt) - 2; 143630088Sminshall if (reply) 143730088Sminshall printoption(">SENT", fmt, option, reply); 143830088Sminshall else 143930088Sminshall printoption("<SENT", fmt, option, reply); 144030088Sminshall } 144130088Sminshall 144230088Sminshall static void 144330088Sminshall dooption(option) 144430088Sminshall int option; 144530088Sminshall { 144630088Sminshall char *fmt; 144730088Sminshall 144830088Sminshall switch (option) { 144930088Sminshall 145030088Sminshall case TELOPT_TM: 145130088Sminshall fmt = will; 145230088Sminshall break; 145330088Sminshall 145430088Sminshall # if defined(TN3270) 145530088Sminshall case TELOPT_EOR: 145630088Sminshall case TELOPT_BINARY: 145730088Sminshall # endif /* defined(TN3270) */ 145830088Sminshall case TELOPT_TTYPE: /* terminal type option */ 145930088Sminshall case TELOPT_SGA: /* no big deal */ 146030088Sminshall fmt = will; 146130088Sminshall myopts[option] = 1; 146230088Sminshall break; 146330088Sminshall 146430088Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 146530088Sminshall default: 146630088Sminshall fmt = wont; 146730088Sminshall break; 146830088Sminshall } 146930088Sminshall sprintf(nfrontp, fmt, option); 147030088Sminshall nfrontp += sizeof (doopt) - 2; 147130088Sminshall printoption(">SENT", fmt, option, 0); 147230088Sminshall } 147330088Sminshall 147430088Sminshall /* 147530088Sminshall * suboption() 147630088Sminshall * 147730088Sminshall * Look at the sub-option buffer, and try to be helpful to the other 147830088Sminshall * side. 147930088Sminshall * 148030088Sminshall * Currently we recognize: 148130088Sminshall * 148230088Sminshall * Terminal type, send request. 148330088Sminshall */ 148430088Sminshall 148530088Sminshall static void 148630088Sminshall suboption() 148730088Sminshall { 148830088Sminshall printsub("<", subbuffer, subend-subbuffer+1); 148930088Sminshall switch (subbuffer[0]&0xff) { 149030088Sminshall case TELOPT_TTYPE: 149130088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 149230088Sminshall ; 149330088Sminshall } else { 149430088Sminshall char *name; 149530088Sminshall char namebuf[41]; 149630088Sminshall extern char *getenv(); 149730088Sminshall int len; 149830088Sminshall 149930088Sminshall #if defined(TN3270) 150030088Sminshall /* 150130326Sminshall * Try to send a 3270 type terminal name. Decide which one based 150230088Sminshall * on the format of our screen, and (in the future) color 150330088Sminshall * capaiblities. 150430088Sminshall */ 1505*31124Sminshall #if defined(unix) 150630088Sminshall if ((initscr() != ERR) && /* Initialize curses to get line size */ 150730088Sminshall (LINES >= 24) && (COLS >= 80)) { 150830088Sminshall Sent3270TerminalType = 1; 150930088Sminshall if ((LINES >= 27) && (COLS >= 132)) { 151030088Sminshall MaxNumberLines = 27; 151130088Sminshall MaxNumberColumns = 132; 151230088Sminshall sb_terminal[SBTERMMODEL] = '5'; 151330088Sminshall } else if (LINES >= 43) { 151430088Sminshall MaxNumberLines = 43; 151530088Sminshall MaxNumberColumns = 80; 151630088Sminshall sb_terminal[SBTERMMODEL] = '4'; 151730088Sminshall } else if (LINES >= 32) { 151830088Sminshall MaxNumberLines = 32; 151930088Sminshall MaxNumberColumns = 80; 152030088Sminshall sb_terminal[SBTERMMODEL] = '3'; 152130088Sminshall } else { 152230088Sminshall MaxNumberLines = 24; 152330088Sminshall MaxNumberColumns = 80; 152430088Sminshall sb_terminal[SBTERMMODEL] = '2'; 152530088Sminshall } 152630088Sminshall NumberLines = 24; /* before we start out... */ 152730088Sminshall NumberColumns = 80; 152830088Sminshall ScreenSize = NumberLines*NumberColumns; 152930088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 153030088Sminshall ExitString(stderr, 153130088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 153230088Sminshall /*NOTREACHED*/ 153330088Sminshall } 153430088Sminshall bcopy(sb_terminal, nfrontp, sizeof sb_terminal); 153530088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 153630088Sminshall nfrontp += sizeof sb_terminal; 153730088Sminshall return; 153830088Sminshall } 1539*31124Sminshall #else /* defined(unix) */ 1540*31124Sminshall XXX(); 1541*31124Sminshall #endif /* defined(unix) */ 154230088Sminshall #endif /* defined(TN3270) */ 154330088Sminshall 154430088Sminshall name = getenv("TERM"); 154530088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 154630088Sminshall name = "UNKNOWN"; 154730088Sminshall } 154830088Sminshall if ((len + 4+2) < NETROOM()) { 154930088Sminshall strcpy(namebuf, name); 155030088Sminshall upcase(namebuf); 155130088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 155230088Sminshall TELQUAL_IS, namebuf, IAC, SE); 155330088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 155430088Sminshall nfrontp += 4+strlen(namebuf)+2; 155530088Sminshall } else { 155630088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 155730088Sminshall 1); 155830088Sminshall /*NOTREACHED*/ 155930088Sminshall } 156030088Sminshall } 156130088Sminshall 156230088Sminshall default: 156330088Sminshall break; 156430088Sminshall } 156530088Sminshall } 156630088Sminshall 156730088Sminshall #if defined(TN3270) 156830088Sminshall static void 156930088Sminshall SetIn3270() 157030088Sminshall { 157130088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 157230088Sminshall && hisopts[TELOPT_BINARY]) { 157330088Sminshall if (!In3270) { 157430088Sminshall In3270 = 1; 157530326Sminshall Init3270(); /* Initialize 3270 functions */ 157630088Sminshall /* initialize terminal key mapping */ 157730326Sminshall InitTerminal(); /* Start terminal going */ 157830088Sminshall setconnmode(); 157930088Sminshall } 158030088Sminshall } else { 158130088Sminshall if (In3270) { 158230088Sminshall StopScreen(1); 158330088Sminshall In3270 = 0; 158430088Sminshall setconnmode(); 158530088Sminshall } 158630088Sminshall } 158730088Sminshall } 158830088Sminshall #endif /* defined(TN3270) */ 158930088Sminshall 159030088Sminshall 159130088Sminshall static void 159230088Sminshall telrcv() 159330088Sminshall { 159430088Sminshall register int c; 159530722Sminshall static int telrcv_state = TS_DATA; 159630088Sminshall # if defined(TN3270) 159730088Sminshall register int Scc; 159830088Sminshall register char *Sbp; 159930088Sminshall # endif /* defined(TN3270) */ 160030088Sminshall 160130088Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 160230088Sminshall c = *sbp++ & 0xff, scc--; 160330722Sminshall switch (telrcv_state) { 160430088Sminshall 160530088Sminshall case TS_CR: 160630722Sminshall telrcv_state = TS_DATA; 160730088Sminshall if (c == '\0') { 160830088Sminshall break; /* Ignore \0 after CR */ 160930088Sminshall } else if (c == '\n') { 161030088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 161130088Sminshall TTYADD(c); 161230088Sminshall } 161330088Sminshall break; 161430088Sminshall } 161530088Sminshall /* Else, fall through */ 161630088Sminshall 161730088Sminshall case TS_DATA: 161830088Sminshall if (c == IAC) { 161930722Sminshall telrcv_state = TS_IAC; 162030088Sminshall continue; 162130088Sminshall } 162230088Sminshall # if defined(TN3270) 162330088Sminshall if (In3270) { 162430088Sminshall *Ifrontp++ = c; 162530088Sminshall Sbp = sbp; 162630088Sminshall Scc = scc; 162730088Sminshall while (Scc > 0) { 162830088Sminshall c = *Sbp++ & 0377, Scc--; 162930088Sminshall if (c == IAC) { 163030722Sminshall telrcv_state = TS_IAC; 163130088Sminshall break; 163230088Sminshall } 163330088Sminshall *Ifrontp++ = c; 163430088Sminshall } 163530088Sminshall sbp = Sbp; 163630088Sminshall scc = Scc; 163730088Sminshall } else 163830088Sminshall # endif /* defined(TN3270) */ 163930088Sminshall /* 164030088Sminshall * The 'crmod' hack (see following) is needed 164130088Sminshall * since we can't * set CRMOD on output only. 164230088Sminshall * Machines like MULTICS like to send \r without 164330088Sminshall * \n; since we must turn off CRMOD to get proper 164430088Sminshall * input, the mapping is done here (sigh). 164530088Sminshall */ 164630088Sminshall if (c == '\r') { 164730088Sminshall if (scc > 0) { 164830088Sminshall c = *sbp&0xff; 164930088Sminshall if (c == 0) { 165030088Sminshall sbp++, scc--; 165130088Sminshall /* a "true" CR */ 165230088Sminshall TTYADD('\r'); 165330088Sminshall } else if (!hisopts[TELOPT_ECHO] && 165430088Sminshall (c == '\n')) { 165530088Sminshall sbp++, scc--; 165630088Sminshall TTYADD('\n'); 165730088Sminshall } else { 165830088Sminshall TTYADD('\r'); 165930088Sminshall if (crmod) { 166030088Sminshall TTYADD('\n'); 166130088Sminshall } 166230088Sminshall } 166330088Sminshall } else { 166430722Sminshall telrcv_state = TS_CR; 166530088Sminshall TTYADD('\r'); 166630088Sminshall if (crmod) { 166730088Sminshall TTYADD('\n'); 166830088Sminshall } 166930088Sminshall } 167030088Sminshall } else { 167130088Sminshall TTYADD(c); 167230088Sminshall } 167330088Sminshall continue; 167430088Sminshall 167530088Sminshall case TS_IAC: 167630088Sminshall switch (c) { 167730088Sminshall 167830088Sminshall case WILL: 167930722Sminshall telrcv_state = TS_WILL; 168030088Sminshall continue; 168130088Sminshall 168230088Sminshall case WONT: 168330722Sminshall telrcv_state = TS_WONT; 168430088Sminshall continue; 168530088Sminshall 168630088Sminshall case DO: 168730722Sminshall telrcv_state = TS_DO; 168830088Sminshall continue; 168930088Sminshall 169030088Sminshall case DONT: 169130722Sminshall telrcv_state = TS_DONT; 169230088Sminshall continue; 169330088Sminshall 169430088Sminshall case DM: 169530088Sminshall /* 169630088Sminshall * We may have missed an urgent notification, 169730088Sminshall * so make sure we flush whatever is in the 169830088Sminshall * buffer currently. 169930088Sminshall */ 170030088Sminshall SYNCHing = 1; 170130088Sminshall ttyflush(); 170230088Sminshall SYNCHing = stilloob(net); 170330088Sminshall settimer(gotDM); 170430088Sminshall break; 170530088Sminshall 170630088Sminshall case NOP: 170730088Sminshall case GA: 170830088Sminshall break; 170930088Sminshall 171030088Sminshall case SB: 171130088Sminshall SB_CLEAR(); 171230722Sminshall telrcv_state = TS_SB; 171330088Sminshall continue; 171430088Sminshall 171530088Sminshall # if defined(TN3270) 171630088Sminshall case EOR: 171730088Sminshall if (In3270) { 171830088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 171930088Sminshall if (Ibackp == Ifrontp) { 172030088Sminshall Ibackp = Ifrontp = Ibuf; 172130088Sminshall ISend = 0; /* should have been! */ 172230088Sminshall } else { 172330088Sminshall ISend = 1; 172430088Sminshall } 172530088Sminshall } 172630088Sminshall break; 172730088Sminshall # endif /* defined(TN3270) */ 172830088Sminshall 172930088Sminshall case IAC: 173030088Sminshall # if !defined(TN3270) 173130088Sminshall TTYADD(IAC); 173230088Sminshall # else /* !defined(TN3270) */ 173330088Sminshall if (In3270) { 173430088Sminshall *Ifrontp++ = IAC; 173530088Sminshall } else { 173630088Sminshall TTYADD(IAC); 173730088Sminshall } 173830088Sminshall # endif /* !defined(TN3270) */ 173930088Sminshall break; 174030088Sminshall 174130088Sminshall default: 174230088Sminshall break; 174330088Sminshall } 174430722Sminshall telrcv_state = TS_DATA; 174530088Sminshall continue; 174630088Sminshall 174730088Sminshall case TS_WILL: 174830088Sminshall printoption(">RCVD", will, c, !hisopts[c]); 174930088Sminshall if (c == TELOPT_TM) { 175030088Sminshall if (flushout) { 175130088Sminshall flushout = 0; 175230088Sminshall } 175330088Sminshall } else if (!hisopts[c]) { 175430088Sminshall willoption(c, 1); 175530088Sminshall } 175630088Sminshall SetIn3270(); 175730722Sminshall telrcv_state = TS_DATA; 175830088Sminshall continue; 175930088Sminshall 176030088Sminshall case TS_WONT: 176130088Sminshall printoption(">RCVD", wont, c, hisopts[c]); 176230088Sminshall if (c == TELOPT_TM) { 176330088Sminshall if (flushout) { 176430088Sminshall flushout = 0; 176530088Sminshall } 176630088Sminshall } else if (hisopts[c]) { 176730088Sminshall wontoption(c, 1); 176830088Sminshall } 176930088Sminshall SetIn3270(); 177030722Sminshall telrcv_state = TS_DATA; 177130088Sminshall continue; 177230088Sminshall 177330088Sminshall case TS_DO: 177430088Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 177530088Sminshall if (!myopts[c]) 177630088Sminshall dooption(c); 177730088Sminshall SetIn3270(); 177830722Sminshall telrcv_state = TS_DATA; 177930088Sminshall continue; 178030088Sminshall 178130088Sminshall case TS_DONT: 178230088Sminshall printoption(">RCVD", dont, c, myopts[c]); 178330088Sminshall if (myopts[c]) { 178430088Sminshall myopts[c] = 0; 178530088Sminshall sprintf(nfrontp, wont, c); 178630088Sminshall nfrontp += sizeof (wont) - 2; 178730088Sminshall flushline = 1; 178830088Sminshall setconnmode(); /* set new tty mode (maybe) */ 178930088Sminshall printoption(">SENT", wont, c, 0); 179030088Sminshall } 179130088Sminshall SetIn3270(); 179230722Sminshall telrcv_state = TS_DATA; 179330088Sminshall continue; 179430088Sminshall 179530088Sminshall case TS_SB: 179630088Sminshall if (c == IAC) { 179730722Sminshall telrcv_state = TS_SE; 179830088Sminshall } else { 179930088Sminshall SB_ACCUM(c); 180030088Sminshall } 180130088Sminshall continue; 180230088Sminshall 180330088Sminshall case TS_SE: 180430088Sminshall if (c != SE) { 180530088Sminshall if (c != IAC) { 180630088Sminshall SB_ACCUM(IAC); 180730088Sminshall } 180830088Sminshall SB_ACCUM(c); 180930722Sminshall telrcv_state = TS_SB; 181030088Sminshall } else { 181130088Sminshall SB_TERM(); 181230088Sminshall suboption(); /* handle sub-option */ 181330088Sminshall SetIn3270(); 181430722Sminshall telrcv_state = TS_DATA; 181530088Sminshall } 181630088Sminshall } 181730088Sminshall } 181830088Sminshall } 181930088Sminshall 182030088Sminshall #if defined(TN3270) 182130088Sminshall 182230088Sminshall /* 182330088Sminshall * The following routines are places where the various tn3270 182430088Sminshall * routines make calls into telnet.c. 182530088Sminshall */ 182630088Sminshall 182730088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 182830088Sminshall TtyChars() 182930088Sminshall { 183030088Sminshall return(tfrontp-tbackp); 183130088Sminshall } 183230088Sminshall 183330088Sminshall /* 183430088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 183530088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 183630088Sminshall * don't call us with "done" until you want that done...) 183730088Sminshall * 183830088Sminshall * We actually do send all the data to the network buffer, since our 183930088Sminshall * only client needs for us to do that. 184030088Sminshall */ 184130088Sminshall 184230088Sminshall int 184330088Sminshall DataToNetwork(buffer, count, done) 184430088Sminshall register char *buffer; /* where the data is */ 184530088Sminshall register int count; /* how much to send */ 184630088Sminshall int done; /* is this the last of a logical block */ 184730088Sminshall { 184830088Sminshall register int c; 184930088Sminshall int origCount; 185030088Sminshall fd_set o; 185130088Sminshall 185230088Sminshall origCount = count; 185330088Sminshall FD_ZERO(&o); 185430088Sminshall 185530088Sminshall while (count) { 185630088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 185730088Sminshall netflush(); 185830088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) { 185930088Sminshall FD_SET(net, &o); 186030088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 186130088Sminshall (struct timeval *) 0); 186230088Sminshall netflush(); 186330088Sminshall } 186430088Sminshall } 186530088Sminshall c = *buffer++; 186630088Sminshall count--; 186730088Sminshall if (c == IAC) { 186830088Sminshall *nfrontp++ = IAC; 186930088Sminshall *nfrontp++ = IAC; 187030088Sminshall } else { 187130088Sminshall *nfrontp++ = c; 187230088Sminshall } 187330088Sminshall } 187430088Sminshall 187530088Sminshall if (done && !count) { 187630088Sminshall *nfrontp++ = IAC; 187730088Sminshall *nfrontp++ = EOR; 187830088Sminshall netflush(); /* try to move along as quickly as ... */ 187930088Sminshall } 188030088Sminshall return(origCount - count); 188130088Sminshall } 188230088Sminshall 188330088Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 188430088Sminshall 188530088Sminshall int 188630088Sminshall DataToTerminal(buffer, count) 188730088Sminshall register char *buffer; /* where the data is */ 188830088Sminshall register int count; /* how much to send */ 188930088Sminshall { 189030088Sminshall int origCount; 189130088Sminshall fd_set o; 189230088Sminshall 189330088Sminshall origCount = count; 189430088Sminshall FD_ZERO(&o); 189530088Sminshall 189630088Sminshall while (count) { 189730088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 189830088Sminshall ttyflush(); 189930088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 190030088Sminshall FD_SET(tout, &o); 190130088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 190230088Sminshall (struct timeval *) 0); 190330088Sminshall ttyflush(); 190430088Sminshall } 190530088Sminshall } 190630088Sminshall *tfrontp++ = *buffer++; 190730088Sminshall count--; 190830088Sminshall } 190930088Sminshall return(origCount - count); 191030088Sminshall } 191130088Sminshall 191230088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 191330088Sminshall * Note that we consider the buffer to run all the 191430088Sminshall * way to the kernel (thus the select). 191530088Sminshall */ 191630088Sminshall 191730088Sminshall void 191830088Sminshall EmptyTerminal() 191930088Sminshall { 192030088Sminshall fd_set o; 192130088Sminshall 192230088Sminshall FD_ZERO(&o); 192330088Sminshall 192430088Sminshall if (tfrontp == tbackp) { 192530088Sminshall FD_SET(tout, &o); 192630088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 192730088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 192830088Sminshall } else { 192930088Sminshall while (tfrontp != tbackp) { 193030088Sminshall ttyflush(); 193130088Sminshall FD_SET(tout, &o); 193230088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 193330088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 193430088Sminshall } 193530088Sminshall } 193630088Sminshall } 193730088Sminshall 193830088Sminshall /* 193930088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 194030088Sminshall */ 194130088Sminshall 194230088Sminshall static int 194330088Sminshall Push3270() 194430088Sminshall { 194530088Sminshall int save = scc; 194630088Sminshall 194730088Sminshall if (scc) { 194830088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 194930088Sminshall if (Ibackp != Ibuf) { 195030088Sminshall bcopy(Ibackp, Ibuf, Ifrontp-Ibackp); 195130088Sminshall Ifrontp -= (Ibackp-Ibuf); 195230088Sminshall Ibackp = Ibuf; 195330088Sminshall } 195430088Sminshall } 195530088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 195630088Sminshall telrcv(); 195730088Sminshall } 195830088Sminshall } 195930088Sminshall return save != scc; 196030088Sminshall } 196130088Sminshall 196230088Sminshall 196330088Sminshall /* 196430088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 196530088Sminshall * before quitting. 196630088Sminshall */ 196730088Sminshall 196830088Sminshall static void 196930088Sminshall Finish3270() 197030088Sminshall { 197130088Sminshall while (Push3270() || !DoTerminalOutput()) { 197230088Sminshall ; 197330088Sminshall } 197430088Sminshall } 197530088Sminshall 197630088Sminshall 197730088Sminshall 197830088Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 197930088Sminshall 198030088Sminshall void 198130088Sminshall StringToTerminal(s) 198230088Sminshall char *s; 198330088Sminshall { 198430088Sminshall int count; 198530088Sminshall 198630088Sminshall count = strlen(s); 198730088Sminshall if (count) { 198830088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 198930088Sminshall } 199030088Sminshall } 199130088Sminshall 199230088Sminshall 199330088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) 199430088Sminshall /* _putchar - output a single character to the terminal. This name is so that 199530088Sminshall * curses(3x) can call us to send out data. 199630088Sminshall */ 199730088Sminshall 199830088Sminshall void 199930088Sminshall _putchar(c) 200030088Sminshall char c; 200130088Sminshall { 200230088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 200330088Sminshall (void) DataToTerminal(&c, 1); 200430088Sminshall } else { 200530088Sminshall *tfrontp++ = c; /* optimize if possible. */ 200630088Sminshall } 200730088Sminshall } 200830088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ 200930088Sminshall 201030088Sminshall static void 201130088Sminshall SetForExit() 201230088Sminshall { 201330088Sminshall setconnmode(); 201430088Sminshall if (In3270) { 201530088Sminshall Finish3270(); 201630088Sminshall } 201730088Sminshall setcommandmode(); 201830088Sminshall fflush(stdout); 201930088Sminshall fflush(stderr); 202030088Sminshall if (In3270) { 202130088Sminshall StopScreen(1); 202230088Sminshall } 202330088Sminshall setconnmode(); 202430088Sminshall setcommandmode(); 202530088Sminshall } 202630088Sminshall 202730088Sminshall static void 202830088Sminshall Exit(returnCode) 202930088Sminshall int returnCode; 203030088Sminshall { 203130088Sminshall SetForExit(); 203230088Sminshall exit(returnCode); 203330088Sminshall } 203430088Sminshall 203530088Sminshall void 203630088Sminshall ExitString(file, string, returnCode) 203730088Sminshall FILE *file; 203830088Sminshall char *string; 203930088Sminshall int returnCode; 204030088Sminshall { 204130088Sminshall SetForExit(); 204230088Sminshall fwrite(string, 1, strlen(string), file); 204330088Sminshall exit(returnCode); 204430088Sminshall } 204530088Sminshall 204630088Sminshall void 204730088Sminshall ExitPerror(string, returnCode) 204830088Sminshall char *string; 204930088Sminshall int returnCode; 205030088Sminshall { 205130088Sminshall SetForExit(); 205230088Sminshall perror(string); 205330088Sminshall exit(returnCode); 205430088Sminshall } 205530088Sminshall 205630088Sminshall #endif /* defined(TN3270) */ 205730088Sminshall 205830088Sminshall static 205930088Sminshall Scheduler(block) 206030088Sminshall int block; /* should we block in the select ? */ 206130088Sminshall { 206230088Sminshall register int c; 206330088Sminshall /* One wants to be a bit careful about setting returnValue 206430088Sminshall * to one, since a one implies we did some useful work, 206530088Sminshall * and therefore probably won't be called to block next 206630088Sminshall * time (TN3270 mode only). 206730088Sminshall */ 206830088Sminshall int returnValue = 0; 206930088Sminshall static struct timeval TimeValue = { 0 }; 207030088Sminshall 207130088Sminshall if (scc < 0 && tcc < 0) { 207230088Sminshall return -1; 207330088Sminshall } 207430088Sminshall 207530088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 207630088Sminshall FD_SET(net, &obits); 207730088Sminshall } 207830088Sminshall if (TTYBYTES()) { 207930088Sminshall FD_SET(tout, &obits); 208030088Sminshall } 208130088Sminshall if ((tcc == 0) && NETROOM()) { 208230088Sminshall FD_SET(tin, &ibits); 208330088Sminshall } 208430088Sminshall # if !defined(TN3270) 208530088Sminshall if (TTYROOM()) { 208630088Sminshall FD_SET(net, &ibits); 208730088Sminshall } 208830088Sminshall # else /* !defined(TN3270) */ 208930088Sminshall if (!ISend && TTYROOM()) { 209030088Sminshall FD_SET(net, &ibits); 209130088Sminshall } 209230088Sminshall # endif /* !defined(TN3270) */ 209330088Sminshall if (!SYNCHing) { 209430088Sminshall FD_SET(net, &xbits); 209530088Sminshall } 209630088Sminshall # if defined(TN3270) && defined(unix) 209730088Sminshall if (HaveInput) { 209830088Sminshall HaveInput = 0; 209930088Sminshall signal(SIGIO, inputAvailable); 210030088Sminshall } 210130088Sminshall #endif /* defined(TN3270) && defined(unix) */ 210230088Sminshall if ((c = select(16, &ibits, &obits, &xbits, 210330088Sminshall block? (struct timeval *)0 : &TimeValue)) < 1) { 210430088Sminshall if (c == -1) { 210530088Sminshall /* 210630088Sminshall * we can get EINTR if we are in line mode, 210730088Sminshall * and the user does an escape (TSTP), or 210830088Sminshall * some other signal generator. 210930088Sminshall */ 211030088Sminshall if (errno == EINTR) { 211130088Sminshall return 0; 211230088Sminshall } 211330088Sminshall # if defined(TN3270) 211430088Sminshall /* 211530088Sminshall * we can get EBADF if we were in transparent 211630088Sminshall * mode, and the transcom process died. 211730088Sminshall */ 211830088Sminshall if (errno == EBADF) { 211930088Sminshall /* 212030088Sminshall * zero the bits (even though kernel does it) 212130088Sminshall * to make sure we are selecting on the right 212230088Sminshall * ones. 212330088Sminshall */ 212430088Sminshall FD_ZERO(&ibits); 212530088Sminshall FD_ZERO(&obits); 212630088Sminshall FD_ZERO(&xbits); 212730088Sminshall return 0; 212830088Sminshall } 212930088Sminshall # endif /* defined(TN3270) */ 213030088Sminshall /* I don't like this, does it ever happen? */ 213130088Sminshall printf("sleep(5) from telnet, after select\r\n"); 213230088Sminshall #if defined(unix) 213330088Sminshall sleep(5); 213430088Sminshall #endif /* defined(unix) */ 213530088Sminshall } 213630088Sminshall return 0; 213730088Sminshall } 213830088Sminshall 213930088Sminshall /* 214030088Sminshall * Any urgent data? 214130088Sminshall */ 214230088Sminshall if (FD_ISSET(net, &xbits)) { 214330088Sminshall FD_CLR(net, &xbits); 214430088Sminshall SYNCHing = 1; 214530088Sminshall ttyflush(); /* flush already enqueued data */ 214630088Sminshall } 214730088Sminshall 214830088Sminshall /* 214930088Sminshall * Something to read from the network... 215030088Sminshall */ 215130088Sminshall if (FD_ISSET(net, &ibits)) { 215230088Sminshall int canread; 215330088Sminshall 215430088Sminshall FD_CLR(net, &ibits); 215530088Sminshall if (scc == 0) { 215630088Sminshall sbp = sibuf; 215730088Sminshall } 215830422Sminshall canread = sibuf + sizeof sibuf - (sbp+scc); 215930088Sminshall #if !defined(SO_OOBINLINE) 216030088Sminshall /* 216130088Sminshall * In 4.2 (and some early 4.3) systems, the 216230088Sminshall * OOB indication and data handling in the kernel 216330088Sminshall * is such that if two separate TCP Urgent requests 216430088Sminshall * come in, one byte of TCP data will be overlaid. 216530088Sminshall * This is fatal for Telnet, but we try to live 216630088Sminshall * with it. 216730088Sminshall * 216830088Sminshall * In addition, in 4.2 (and...), a special protocol 216930088Sminshall * is needed to pick up the TCP Urgent data in 217030088Sminshall * the correct sequence. 217130088Sminshall * 217230088Sminshall * What we do is: if we think we are in urgent 217330088Sminshall * mode, we look to see if we are "at the mark". 217430088Sminshall * If we are, we do an OOB receive. If we run 217530088Sminshall * this twice, we will do the OOB receive twice, 217630088Sminshall * but the second will fail, since the second 217730088Sminshall * time we were "at the mark", but there wasn't 217830088Sminshall * any data there (the kernel doesn't reset 217930088Sminshall * "at the mark" until we do a normal read). 218030088Sminshall * Once we've read the OOB data, we go ahead 218130088Sminshall * and do normal reads. 218230088Sminshall * 218330088Sminshall * There is also another problem, which is that 218430088Sminshall * since the OOB byte we read doesn't put us 218530088Sminshall * out of OOB state, and since that byte is most 218630088Sminshall * likely the TELNET DM (data mark), we would 218730088Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 218830088Sminshall * So, clocks to the rescue. If we've "just" 218930088Sminshall * received a DM, then we test for the 219030088Sminshall * presence of OOB data when the receive OOB 219130088Sminshall * fails (and AFTER we did the normal mode read 219230088Sminshall * to clear "at the mark"). 219330088Sminshall */ 219430088Sminshall if (SYNCHing) { 219530088Sminshall int atmark; 219630088Sminshall 219730088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 219830088Sminshall if (atmark) { 219930422Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 220030088Sminshall if ((c == -1) && (errno == EINVAL)) { 220130422Sminshall c = read(net, sbp+scc, canread); 220230088Sminshall if (clocks.didnetreceive < clocks.gotDM) { 220330088Sminshall SYNCHing = stilloob(net); 220430088Sminshall } 220530088Sminshall } 220630088Sminshall } else { 220730422Sminshall c = read(net, sbp+scc, canread); 220830088Sminshall } 220930088Sminshall } else { 221030422Sminshall c = read(net, sbp+scc, canread); 221130088Sminshall } 221230088Sminshall settimer(didnetreceive); 221330088Sminshall #else /* !defined(SO_OOBINLINE) */ 221430422Sminshall c = read(net, sbp+scc, canread); 221530088Sminshall #endif /* !defined(SO_OOBINLINE) */ 221630088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 221730088Sminshall c = 0; 221830088Sminshall } else if (c <= 0) { 221930088Sminshall return -1; 222030088Sminshall } 222130088Sminshall if (netdata) { 222230422Sminshall Dump('<', sbp+scc, c); 222330088Sminshall } 222430088Sminshall scc += c; 222530088Sminshall returnValue = 1; 222630088Sminshall } 222730088Sminshall 222830088Sminshall /* 222930088Sminshall * Something to read from the tty... 223030088Sminshall */ 223130088Sminshall if (FD_ISSET(tin, &ibits)) { 223230088Sminshall FD_CLR(tin, &ibits); 223330088Sminshall if (tcc == 0) { 223430088Sminshall tbp = tibuf; /* nothing left, reset */ 223530088Sminshall } 223630088Sminshall c = read(tin, tbp, tibuf+sizeof tibuf - tbp); 223730088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 223830088Sminshall c = 0; 223930088Sminshall } else { 2240*31124Sminshall #if defined(unix) 224130088Sminshall /* EOF detection for line mode!!!! */ 224230088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 224330088Sminshall /* must be an EOF... */ 224430088Sminshall *tbp = ntc.t_eofc; 224530088Sminshall c = 1; 224630088Sminshall } 2247*31124Sminshall #endif /* defined(unix) */ 224830088Sminshall if (c <= 0) { 224930088Sminshall tcc = c; 225030088Sminshall return -1; 225130088Sminshall } 225230088Sminshall } 225330088Sminshall tcc += c; 225430088Sminshall returnValue = 1; /* did something useful */ 225530088Sminshall } 225630088Sminshall 225730088Sminshall # if defined(TN3270) 225830088Sminshall if (tcc > 0) { 225930088Sminshall if (In3270) { 226030088Sminshall c = DataFromTerminal(tbp, tcc); 226130088Sminshall if (c) { 226230088Sminshall returnValue = 1; 226330088Sminshall } 226430088Sminshall tcc -= c; 226530088Sminshall tbp += c; 226630088Sminshall } else { 226730320Sminshall # endif /* defined(TN3270) */ 226830088Sminshall returnValue = 1; 226930088Sminshall while (tcc > 0) { 227030088Sminshall register int sc; 227130088Sminshall 227230088Sminshall if (NETROOM() < 2) { 227330088Sminshall flushline = 1; 227430088Sminshall break; 227530088Sminshall } 227630088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 227730088Sminshall if (sc == escape) { 227830088Sminshall command(0); 227930088Sminshall tcc = 0; 228030088Sminshall flushline = 1; 228130088Sminshall break; 228230088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 228330088Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 228430088Sminshall tbp++; 228530088Sminshall tcc--; 228630088Sminshall } else { 228730088Sminshall dontlecho = !dontlecho; 228830088Sminshall settimer(echotoggle); 228930088Sminshall setconnmode(); 229030088Sminshall tcc = 0; 229130088Sminshall flushline = 1; 229230088Sminshall break; 229330088Sminshall } 229430088Sminshall } 229530088Sminshall if (localchars) { 2296*31124Sminshall if (TerminalEditLine(sc) == 0) { 229730088Sminshall break; 229830088Sminshall } 229930088Sminshall } 230030088Sminshall switch (c) { 230130088Sminshall case '\n': 230230088Sminshall /* 230330088Sminshall * If we are in CRMOD mode (\r ==> \n) 230430088Sminshall * on our local machine, then probably 230530088Sminshall * a newline (unix) is CRLF (TELNET). 230630088Sminshall */ 230730088Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 230830088Sminshall NETADD('\r'); 230930088Sminshall } 231030088Sminshall NETADD('\n'); 231130088Sminshall flushline = 1; 231230088Sminshall break; 231330088Sminshall case '\r': 231430088Sminshall NET2ADD('\r', '\0'); 231530088Sminshall flushline = 1; 231630088Sminshall break; 231730088Sminshall case IAC: 231830088Sminshall NET2ADD(IAC, IAC); 231930088Sminshall break; 232030088Sminshall default: 232130088Sminshall NETADD(c); 232230088Sminshall break; 232330088Sminshall } 232430088Sminshall } 232530088Sminshall # if defined(TN3270) 232630088Sminshall } 232730088Sminshall } 232830088Sminshall # endif /* defined(TN3270) */ 232930088Sminshall 233030088Sminshall if ((!MODE_LINE(globalmode) || flushline) && 233130088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 233230088Sminshall FD_CLR(net, &obits); 233330088Sminshall returnValue = netflush(); 233430088Sminshall } 233530088Sminshall if (scc > 0) { 233630088Sminshall # if !defined(TN3270) 233730088Sminshall telrcv(); 233830088Sminshall returnValue = 1; 233930088Sminshall # else /* !defined(TN3270) */ 234030088Sminshall returnValue = Push3270(); 234130088Sminshall # endif /* !defined(TN3270) */ 234230088Sminshall } 234330088Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) { 234430088Sminshall FD_CLR(tout, &obits); 234530088Sminshall returnValue = ttyflush(); 234630088Sminshall } 234730088Sminshall return returnValue; 234830088Sminshall } 234930088Sminshall 235030088Sminshall /* 235130088Sminshall * Select from tty and network... 235230088Sminshall */ 235330088Sminshall static void 235430088Sminshall telnet() 235530088Sminshall { 235630088Sminshall #if defined(TN3270) && defined(unix) 235730088Sminshall int myPid; 235830088Sminshall #endif /* defined(TN3270) */ 235930088Sminshall 236030088Sminshall tout = fileno(stdout); 236130088Sminshall tin = fileno(stdin); 236230088Sminshall setconnmode(); 236330088Sminshall scc = 0; 236430088Sminshall tcc = 0; 236530088Sminshall FD_ZERO(&ibits); 236630088Sminshall FD_ZERO(&obits); 236730088Sminshall FD_ZERO(&xbits); 236830088Sminshall 2369*31124Sminshall NetNonblockingIO(net, 1); 237030088Sminshall 237130088Sminshall #if defined(TN3270) 237230088Sminshall #if !defined(DEBUG) /* DBX can't handle! */ 2373*31124Sminshall NetSigIO(net, 1); 237430088Sminshall #endif /* !defined(DEBUG) */ 237530088Sminshall 2376*31124Sminshall NetSetPgrp(net); 237730088Sminshall #endif /* defined(TN3270) */ 237830088Sminshall 237930088Sminshall 2380*31124Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 2381*31124Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 2382*31124Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 2383*31124Sminshall 238430320Sminshall # if !defined(TN3270) 238530088Sminshall if (telnetport) { 238630088Sminshall if (!hisopts[TELOPT_SGA]) { 238730088Sminshall willoption(TELOPT_SGA, 0); 238830088Sminshall } 238930088Sminshall if (!myopts[TELOPT_TTYPE]) { 239030088Sminshall dooption(TELOPT_TTYPE, 0); 239130088Sminshall } 239230088Sminshall } 239330320Sminshall # endif /* !defined(TN3270) */ 239430088Sminshall 239530088Sminshall # if !defined(TN3270) 239630088Sminshall for (;;) { 239730088Sminshall if (Scheduler(1) == -1) { 239830088Sminshall setcommandmode(); 239930088Sminshall return; 240030088Sminshall } 240130088Sminshall } 240230088Sminshall # else /* !defined(TN3270) */ 240330088Sminshall for (;;) { 240430088Sminshall int schedValue; 240530088Sminshall 240630088Sminshall while (!In3270) { 240730088Sminshall if (Scheduler(1) == -1) { 240830088Sminshall setcommandmode(); 240930088Sminshall return; 241030088Sminshall } 241130088Sminshall } 241230088Sminshall 241330088Sminshall while ((schedValue = Scheduler(0)) != 0) { 241430088Sminshall if (schedValue == -1) { 241530088Sminshall setcommandmode(); 241630088Sminshall return; 241730088Sminshall } 241830088Sminshall } 241930088Sminshall /* If there is data waiting to go out to terminal, don't 242030088Sminshall * schedule any more data for the terminal. 242130088Sminshall */ 242230088Sminshall if (tfrontp-tbackp) { 242330088Sminshall schedValue = 1; 242430088Sminshall } else { 242530088Sminshall schedValue = DoTerminalOutput(); 242630088Sminshall } 242730088Sminshall if (schedValue) { 242830088Sminshall if (Scheduler(1) == -1) { 242930088Sminshall setcommandmode(); 243030088Sminshall return; 243130088Sminshall } 243230088Sminshall } 243330088Sminshall } 243430088Sminshall # endif /* !defined(TN3270) */ 243530088Sminshall } 243630088Sminshall 243730088Sminshall /* 243830088Sminshall * The following are data structures and routines for 243930088Sminshall * the "send" command. 244030088Sminshall * 244130088Sminshall */ 244230088Sminshall 244330088Sminshall struct sendlist { 244430088Sminshall char *name; /* How user refers to it (case independent) */ 244530088Sminshall int what; /* Character to be sent (<0 ==> special) */ 244630088Sminshall char *help; /* Help information (0 ==> no help) */ 244730088Sminshall #if defined(NOT43) 244830088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 244930088Sminshall #else /* defined(NOT43) */ 245030088Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 245130088Sminshall #endif /* defined(NOT43) */ 245230088Sminshall }; 245330088Sminshall 245430088Sminshall #define SENDQUESTION -1 245530088Sminshall #define SENDESCAPE -3 245630088Sminshall 245730088Sminshall static struct sendlist Sendlist[] = { 245830088Sminshall { "ao", AO, "Send Telnet Abort output" }, 245930088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 246030088Sminshall { "brk", BREAK, "Send Telnet Break" }, 246130088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 246230088Sminshall { "el", EL, "Send Telnet Erase Line" }, 246330088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 246430088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 246530088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 246630088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 246730088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 246830088Sminshall { "?", SENDQUESTION, "Display send options" }, 246930088Sminshall { 0 } 247030088Sminshall }; 247130088Sminshall 247230088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 247330088Sminshall { "break", BREAK, 0 }, 247430088Sminshall 247530088Sminshall { "intp", IP, 0 }, 247630088Sminshall { "interrupt", IP, 0 }, 247730088Sminshall { "intr", IP, 0 }, 247830088Sminshall 247930088Sminshall { "help", SENDQUESTION, 0 }, 248030088Sminshall 248130088Sminshall { 0 } 248230088Sminshall }; 248330088Sminshall 248430088Sminshall static char ** 248530088Sminshall getnextsend(name) 248630088Sminshall char *name; 248730088Sminshall { 248830088Sminshall struct sendlist *c = (struct sendlist *) name; 248930088Sminshall 249030088Sminshall return (char **) (c+1); 249130088Sminshall } 249230088Sminshall 249330088Sminshall static struct sendlist * 249430088Sminshall getsend(name) 249530088Sminshall char *name; 249630088Sminshall { 249730088Sminshall struct sendlist *sl; 249830088Sminshall 249930088Sminshall if ((sl = (struct sendlist *) 250030088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 250130088Sminshall return sl; 250230088Sminshall } else { 250330088Sminshall return (struct sendlist *) 250430088Sminshall genget(name, (char **) Sendlist2, getnextsend); 250530088Sminshall } 250630088Sminshall } 250730088Sminshall 250830088Sminshall static 250930088Sminshall sendcmd(argc, argv) 251030088Sminshall int argc; 251130088Sminshall char **argv; 251230088Sminshall { 251330088Sminshall int what; /* what we are sending this time */ 251430088Sminshall int count; /* how many bytes we are going to need to send */ 251530088Sminshall int i; 251630088Sminshall int question = 0; /* was at least one argument a question */ 251730088Sminshall struct sendlist *s; /* pointer to current command */ 251830088Sminshall 251930088Sminshall if (argc < 2) { 252030088Sminshall printf("need at least one argument for 'send' command\n"); 252130088Sminshall printf("'send ?' for help\n"); 252230088Sminshall return 0; 252330088Sminshall } 252430088Sminshall /* 252530088Sminshall * First, validate all the send arguments. 252630088Sminshall * In addition, we see how much space we are going to need, and 252730088Sminshall * whether or not we will be doing a "SYNCH" operation (which 252830088Sminshall * flushes the network queue). 252930088Sminshall */ 253030088Sminshall count = 0; 253130088Sminshall for (i = 1; i < argc; i++) { 253230088Sminshall s = getsend(argv[i]); 253330088Sminshall if (s == 0) { 253430088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 253530088Sminshall argv[i]); 253630088Sminshall return 0; 253730088Sminshall } else if (s == Ambiguous(struct sendlist *)) { 253830088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 253930088Sminshall argv[i]); 254030088Sminshall return 0; 254130088Sminshall } 254230088Sminshall switch (s->what) { 254330088Sminshall case SENDQUESTION: 254430088Sminshall break; 254530088Sminshall case SENDESCAPE: 254630088Sminshall count += 1; 254730088Sminshall break; 254830088Sminshall case SYNCH: 254930088Sminshall count += 2; 255030088Sminshall break; 255130088Sminshall default: 255230088Sminshall count += 2; 255330088Sminshall break; 255430088Sminshall } 255530088Sminshall } 255630088Sminshall /* Now, do we have enough room? */ 255730088Sminshall if (NETROOM() < count) { 255830088Sminshall printf("There is not enough room in the buffer TO the network\n"); 255930088Sminshall printf("to process your request. Nothing will be done.\n"); 256030088Sminshall printf("('send synch' will throw away most data in the network\n"); 256130088Sminshall printf("buffer, if this might help.)\n"); 256230088Sminshall return 0; 256330088Sminshall } 256430088Sminshall /* OK, they are all OK, now go through again and actually send */ 256530088Sminshall for (i = 1; i < argc; i++) { 256630088Sminshall if ((s = getsend(argv[i])) == 0) { 256730088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 256830088Sminshall quit(); 256930088Sminshall /*NOTREACHED*/ 257030088Sminshall } 257130088Sminshall if (s->routine) { 257230088Sminshall (*s->routine)(s); 257330088Sminshall } else { 257430088Sminshall switch (what = s->what) { 257530088Sminshall case SYNCH: 257630088Sminshall dosynch(); 257730088Sminshall break; 257830088Sminshall case SENDQUESTION: 257930088Sminshall for (s = Sendlist; s->name; s++) { 258030088Sminshall if (s->help) { 258130088Sminshall printf(s->name); 258230088Sminshall if (s->help) { 258330088Sminshall printf("\t%s", s->help); 258430088Sminshall } 258530088Sminshall printf("\n"); 258630088Sminshall } 258730088Sminshall } 258830088Sminshall question = 1; 258930088Sminshall break; 259030088Sminshall case SENDESCAPE: 259130088Sminshall NETADD(escape); 259230088Sminshall break; 259330088Sminshall default: 259430088Sminshall NET2ADD(IAC, what); 259530088Sminshall break; 259630088Sminshall } 259730088Sminshall } 259830088Sminshall } 259930088Sminshall return !question; 260030088Sminshall } 260130088Sminshall 260230088Sminshall /* 260330088Sminshall * The following are the routines and data structures referred 260430088Sminshall * to by the arguments to the "toggle" command. 260530088Sminshall */ 260630088Sminshall 260730088Sminshall static 260830088Sminshall lclchars() 260930088Sminshall { 261030088Sminshall donelclchars = 1; 261130088Sminshall return 1; 261230088Sminshall } 261330088Sminshall 261430088Sminshall static 261530088Sminshall togdebug() 261630088Sminshall { 261730088Sminshall #ifndef NOT43 261830088Sminshall if (net > 0 && 2619*31124Sminshall (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 262030088Sminshall perror("setsockopt (SO_DEBUG)"); 262130088Sminshall } 262230320Sminshall #else /* NOT43 */ 262330088Sminshall if (debug) { 2624*31124Sminshall if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 262530088Sminshall perror("setsockopt (SO_DEBUG)"); 262630088Sminshall } else 262730088Sminshall printf("Cannot turn off socket debugging\n"); 262830320Sminshall #endif /* NOT43 */ 262930088Sminshall return 1; 263030088Sminshall } 263130088Sminshall 263230088Sminshall 263330088Sminshall 263430088Sminshall extern int togglehelp(); 263530088Sminshall 263630088Sminshall struct togglelist { 263730088Sminshall char *name; /* name of toggle */ 263830088Sminshall char *help; /* help message */ 263930088Sminshall int (*handler)(); /* routine to do actual setting */ 264030088Sminshall int dohelp; /* should we display help information */ 264130088Sminshall int *variable; 264230088Sminshall char *actionexplanation; 264330088Sminshall }; 264430088Sminshall 264530088Sminshall static struct togglelist Togglelist[] = { 264630088Sminshall { "autoflush", 264730088Sminshall "toggle flushing of output when sending interrupt characters", 264830088Sminshall 0, 264930088Sminshall 1, 265030088Sminshall &autoflush, 265130088Sminshall "flush output when sending interrupt characters" }, 265230088Sminshall { "autosynch", 265330088Sminshall "toggle automatic sending of interrupt characters in urgent mode", 265430088Sminshall 0, 265530088Sminshall 1, 265630088Sminshall &autosynch, 265730088Sminshall "send interrupt characters in urgent mode" }, 265830088Sminshall { "crmod", 265930088Sminshall "toggle mapping of received carriage returns", 266030088Sminshall 0, 266130088Sminshall 1, 266230088Sminshall &crmod, 266330088Sminshall "map carriage return on output" }, 266430088Sminshall { "localchars", 266530088Sminshall "toggle local recognition of certain control characters", 266630088Sminshall lclchars, 266730088Sminshall 1, 266830088Sminshall &localchars, 266930088Sminshall "recognize certain control characters" }, 267030088Sminshall { " ", "", 0, 1 }, /* empty line */ 267130088Sminshall { "debug", 267230088Sminshall "(debugging) toggle debugging", 267330088Sminshall togdebug, 267430088Sminshall 1, 267530088Sminshall &debug, 267630088Sminshall "turn on socket level debugging" }, 267730088Sminshall { "netdata", 267830088Sminshall "(debugging) toggle printing of hexadecimal network data", 267930088Sminshall 0, 268030088Sminshall 1, 268130088Sminshall &netdata, 268230088Sminshall "print hexadecimal representation of network traffic" }, 268330088Sminshall { "options", 268430088Sminshall "(debugging) toggle viewing of options processing", 268530088Sminshall 0, 268630088Sminshall 1, 268730088Sminshall &showoptions, 268830088Sminshall "show option processing" }, 268930088Sminshall { " ", "", 0, 1 }, /* empty line */ 269030088Sminshall { "?", 269130088Sminshall "display help information", 269230088Sminshall togglehelp, 269330088Sminshall 1 }, 269430088Sminshall { "help", 269530088Sminshall "display help information", 269630088Sminshall togglehelp, 269730088Sminshall 0 }, 269830088Sminshall { 0 } 269930088Sminshall }; 270030088Sminshall 270130088Sminshall static 270230088Sminshall togglehelp() 270330088Sminshall { 270430088Sminshall struct togglelist *c; 270530088Sminshall 270630088Sminshall for (c = Togglelist; c->name; c++) { 270730088Sminshall if (c->dohelp) { 270830088Sminshall printf("%s\t%s\n", c->name, c->help); 270930088Sminshall } 271030088Sminshall } 271130088Sminshall return 0; 271230088Sminshall } 271330088Sminshall 271430088Sminshall static char ** 271530088Sminshall getnexttoggle(name) 271630088Sminshall char *name; 271730088Sminshall { 271830088Sminshall struct togglelist *c = (struct togglelist *) name; 271930088Sminshall 272030088Sminshall return (char **) (c+1); 272130088Sminshall } 272230088Sminshall 272330088Sminshall static struct togglelist * 272430088Sminshall gettoggle(name) 272530088Sminshall char *name; 272630088Sminshall { 272730088Sminshall return (struct togglelist *) 272830088Sminshall genget(name, (char **) Togglelist, getnexttoggle); 272930088Sminshall } 273030088Sminshall 273130088Sminshall static 273230088Sminshall toggle(argc, argv) 273330088Sminshall int argc; 273430088Sminshall char *argv[]; 273530088Sminshall { 273630088Sminshall int retval = 1; 273730088Sminshall char *name; 273830088Sminshall struct togglelist *c; 273930088Sminshall 274030088Sminshall if (argc < 2) { 274130088Sminshall fprintf(stderr, 274230088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 274330088Sminshall return 0; 274430088Sminshall } 274530088Sminshall argc--; 274630088Sminshall argv++; 274730088Sminshall while (argc--) { 274830088Sminshall name = *argv++; 274930088Sminshall c = gettoggle(name); 275030088Sminshall if (c == Ambiguous(struct togglelist *)) { 275130088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 275230088Sminshall name); 275330088Sminshall return 0; 275430088Sminshall } else if (c == 0) { 275530088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 275630088Sminshall name); 275730088Sminshall return 0; 275830088Sminshall } else { 275930088Sminshall if (c->variable) { 276030088Sminshall *c->variable = !*c->variable; /* invert it */ 276130088Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 276230088Sminshall c->actionexplanation); 276330088Sminshall } 276430088Sminshall if (c->handler) { 276530088Sminshall retval &= (*c->handler)(c); 276630088Sminshall } 276730088Sminshall } 276830088Sminshall } 276930088Sminshall return retval; 277030088Sminshall } 277130088Sminshall 277230088Sminshall /* 277330088Sminshall * The following perform the "set" command. 277430088Sminshall */ 277530088Sminshall 277630088Sminshall struct setlist { 277730088Sminshall char *name; /* name */ 277830088Sminshall char *help; /* help information */ 277930088Sminshall char *charp; /* where it is located at */ 278030088Sminshall }; 278130088Sminshall 278230088Sminshall static struct setlist Setlist[] = { 278330088Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 278430088Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 278530088Sminshall { " ", "" }, 278630088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 2787*31124Sminshall #if defined(unix) 278830088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 278930088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 279030088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 279130088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 279230088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 279330088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 2794*31124Sminshall #endif /* defined(unix) */ 2795*31124Sminshall #if defined(MSDOS) 2796*31124Sminshall { "erase", "character to cause an Erase Character", &termEraseChar }, 2797*31124Sminshall { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 2798*31124Sminshall { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 2799*31124Sminshall { "kill", "character to cause an Erase Line", &termKillChar }, 2800*31124Sminshall { "quit", "character to cause a Break", &termQuitChar }, 2801*31124Sminshall { "eof", "character to cause an EOF ", &termEofChar }, 2802*31124Sminshall #endif /* defined(MSDOS) */ 280330088Sminshall { 0 } 280430088Sminshall }; 280530088Sminshall 280630088Sminshall static char ** 280730088Sminshall getnextset(name) 280830088Sminshall char *name; 280930088Sminshall { 281030088Sminshall struct setlist *c = (struct setlist *)name; 281130088Sminshall 281230088Sminshall return (char **) (c+1); 281330088Sminshall } 281430088Sminshall 281530088Sminshall static struct setlist * 281630088Sminshall getset(name) 281730088Sminshall char *name; 281830088Sminshall { 281930088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 282030088Sminshall } 282130088Sminshall 282230088Sminshall static 282330088Sminshall setcmd(argc, argv) 282430088Sminshall int argc; 282530088Sminshall char *argv[]; 282630088Sminshall { 282730088Sminshall int value; 282830088Sminshall struct setlist *ct; 282930088Sminshall 283030088Sminshall /* XXX back we go... sigh */ 283130088Sminshall if (argc != 3) { 283230088Sminshall if ((argc == 2) && 283330088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 283430088Sminshall for (ct = Setlist; ct->name; ct++) { 283530088Sminshall printf("%s\t%s\n", ct->name, ct->help); 283630088Sminshall } 283730088Sminshall printf("?\tdisplay help information\n"); 283830088Sminshall } else { 283930088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 284030088Sminshall } 284130088Sminshall return 0; 284230088Sminshall } 284330088Sminshall 284430088Sminshall ct = getset(argv[1]); 284530088Sminshall if (ct == 0) { 284630088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 284730088Sminshall argv[1]); 284830088Sminshall return 0; 284930088Sminshall } else if (ct == Ambiguous(struct setlist *)) { 285030088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 285130088Sminshall argv[1]); 285230088Sminshall return 0; 285330088Sminshall } else { 285430088Sminshall if (strcmp("off", argv[2])) { 285530088Sminshall value = special(argv[2]); 285630088Sminshall } else { 285730088Sminshall value = -1; 285830088Sminshall } 285930088Sminshall *(ct->charp) = value; 286030088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 286130088Sminshall } 286230088Sminshall return 1; 286330088Sminshall } 286430088Sminshall 286530088Sminshall /* 286630088Sminshall * The following are the data structures and routines for the 286730088Sminshall * 'mode' command. 286830088Sminshall */ 286930088Sminshall 287030088Sminshall static 287130088Sminshall dolinemode() 287230088Sminshall { 287330088Sminshall if (hisopts[TELOPT_SGA]) { 287430088Sminshall wontoption(TELOPT_SGA, 0); 287530088Sminshall } 287630088Sminshall if (hisopts[TELOPT_ECHO]) { 287730088Sminshall wontoption(TELOPT_ECHO, 0); 287830088Sminshall } 287930088Sminshall return 1; 288030088Sminshall } 288130088Sminshall 288230088Sminshall static 288330088Sminshall docharmode() 288430088Sminshall { 288530088Sminshall if (!hisopts[TELOPT_SGA]) { 288630088Sminshall willoption(TELOPT_SGA, 0); 288730088Sminshall } 288830088Sminshall if (!hisopts[TELOPT_ECHO]) { 288930088Sminshall willoption(TELOPT_ECHO, 0); 289030088Sminshall } 289130088Sminshall return 1; 289230088Sminshall } 289330088Sminshall 289430088Sminshall static struct cmd Modelist[] = { 289530088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 289630088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 289730088Sminshall { 0 }, 289830088Sminshall }; 289930088Sminshall 290030088Sminshall static char ** 290130088Sminshall getnextmode(name) 290230088Sminshall char *name; 290330088Sminshall { 290430088Sminshall struct cmd *c = (struct cmd *) name; 290530088Sminshall 290630088Sminshall return (char **) (c+1); 290730088Sminshall } 290830088Sminshall 290930088Sminshall static struct cmd * 291030088Sminshall getmodecmd(name) 291130088Sminshall char *name; 291230088Sminshall { 291330088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 291430088Sminshall } 291530088Sminshall 291630088Sminshall static 291730088Sminshall modecmd(argc, argv) 291830088Sminshall int argc; 291930088Sminshall char *argv[]; 292030088Sminshall { 292130088Sminshall struct cmd *mt; 292230088Sminshall 292330088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 292430088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 292530088Sminshall for (mt = Modelist; mt->name; mt++) { 292630088Sminshall printf("%s\t%s\n", mt->name, mt->help); 292730088Sminshall } 292830088Sminshall return 0; 292930088Sminshall } 293030088Sminshall mt = getmodecmd(argv[1]); 293130088Sminshall if (mt == 0) { 293230088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 293330088Sminshall return 0; 293430088Sminshall } else if (mt == Ambiguous(struct cmd *)) { 293530088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 293630088Sminshall return 0; 293730088Sminshall } else { 293830088Sminshall (*mt->handler)(); 293930088Sminshall } 294030088Sminshall return 1; 294130088Sminshall } 294230088Sminshall 294330088Sminshall /* 294430088Sminshall * The following data structures and routines implement the 294530088Sminshall * "display" command. 294630088Sminshall */ 294730088Sminshall 294830088Sminshall static 294930088Sminshall display(argc, argv) 295030088Sminshall int argc; 295130088Sminshall char *argv[]; 295230088Sminshall { 295330088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 295430088Sminshall if (*tl->variable) { \ 295530088Sminshall printf("will"); \ 295630088Sminshall } else { \ 295730088Sminshall printf("won't"); \ 295830088Sminshall } \ 295930088Sminshall printf(" %s.\n", tl->actionexplanation); \ 296030088Sminshall } 296130088Sminshall 296230088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 296330088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 296430088Sminshall } 296530088Sminshall 296630088Sminshall struct togglelist *tl; 296730088Sminshall struct setlist *sl; 296830088Sminshall 296930088Sminshall if (argc == 1) { 297030088Sminshall for (tl = Togglelist; tl->name; tl++) { 297130088Sminshall dotog(tl); 297230088Sminshall } 297330088Sminshall printf("\n"); 297430088Sminshall for (sl = Setlist; sl->name; sl++) { 297530088Sminshall doset(sl); 297630088Sminshall } 297730088Sminshall } else { 297830088Sminshall int i; 297930088Sminshall 298030088Sminshall for (i = 1; i < argc; i++) { 298130088Sminshall sl = getset(argv[i]); 298230088Sminshall tl = gettoggle(argv[i]); 298330088Sminshall if ((sl == Ambiguous(struct setlist *)) || 298430088Sminshall (tl == Ambiguous(struct togglelist *))) { 298530088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 298630088Sminshall return 0; 298730088Sminshall } else if (!sl && !tl) { 298830088Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 298930088Sminshall return 0; 299030088Sminshall } else { 299130088Sminshall if (tl) { 299230088Sminshall dotog(tl); 299330088Sminshall } 299430088Sminshall if (sl) { 299530088Sminshall doset(sl); 299630088Sminshall } 299730088Sminshall } 299830088Sminshall } 299930088Sminshall } 300030088Sminshall return 1; 300130088Sminshall #undef doset 300230088Sminshall #undef dotog 300330088Sminshall } 300430088Sminshall 300530088Sminshall /* 300630088Sminshall * The following are the data structures, and many of the routines, 300730088Sminshall * relating to command processing. 300830088Sminshall */ 300930088Sminshall 301030088Sminshall /* 301130088Sminshall * Set the escape character. 301230088Sminshall */ 301330088Sminshall static 301430088Sminshall setescape(argc, argv) 301530088Sminshall int argc; 301630088Sminshall char *argv[]; 301730088Sminshall { 301830088Sminshall register char *arg; 301930088Sminshall char buf[50]; 302030088Sminshall 302130088Sminshall printf( 302230088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 302330088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 302430088Sminshall if (argc > 2) 302530088Sminshall arg = argv[1]; 302630088Sminshall else { 302730088Sminshall printf("new escape character: "); 302830088Sminshall gets(buf); 302930088Sminshall arg = buf; 303030088Sminshall } 303130088Sminshall if (arg[0] != '\0') 303230088Sminshall escape = arg[0]; 303330088Sminshall if (!In3270) { 303430088Sminshall printf("Escape character is '%s'.\n", control(escape)); 303530088Sminshall } 303630088Sminshall fflush(stdout); 303730088Sminshall return 1; 303830088Sminshall } 303930088Sminshall 304030088Sminshall /*VARARGS*/ 304130088Sminshall static 304230088Sminshall togcrmod() 304330088Sminshall { 304430088Sminshall crmod = !crmod; 304530088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 304630088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 304730088Sminshall fflush(stdout); 304830088Sminshall return 1; 304930088Sminshall } 305030088Sminshall 305130088Sminshall /*VARARGS*/ 305230088Sminshall suspend() 305330088Sminshall { 305430088Sminshall setcommandmode(); 305530088Sminshall #if defined(unix) 305630088Sminshall kill(0, SIGTSTP); 3057*31124Sminshall /* reget parameters in case they were changed */ 3058*31124Sminshall TerminalSaveState(); 305930088Sminshall #endif /* defined(unix) */ 306030088Sminshall return 1; 306130088Sminshall } 306230088Sminshall 306330088Sminshall /*VARARGS*/ 306430088Sminshall static 306530326Sminshall bye(argc, argv) 306630326Sminshall int argc; /* Number of arguments */ 306730326Sminshall char *argv[]; /* arguments */ 306830088Sminshall { 306930088Sminshall if (connected) { 307030088Sminshall shutdown(net, 2); 307130088Sminshall printf("Connection closed.\n"); 307230088Sminshall close(net); 307330088Sminshall connected = 0; 307430088Sminshall /* reset options */ 307530326Sminshall tninit(); 307630088Sminshall #if defined(TN3270) 307730326Sminshall SetIn3270(); /* Get out of 3270 mode */ 307830088Sminshall #endif /* defined(TN3270) */ 307930088Sminshall } 308030326Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 308130326Sminshall longjmp(toplevel, 1); 308230326Sminshall /* NOTREACHED */ 308330326Sminshall } 308430326Sminshall return 1; /* Keep lint, etc., happy */ 308530088Sminshall } 308630088Sminshall 308730088Sminshall /*VARARGS*/ 308830088Sminshall quit() 308930088Sminshall { 309030326Sminshall (void) call(bye, "bye", "fromquit", 0); 309130088Sminshall Exit(0); 309230088Sminshall /*NOTREACHED*/ 309330088Sminshall return 1; /* just to keep lint happy */ 309430088Sminshall } 309530088Sminshall 309630088Sminshall /* 309730088Sminshall * Print status about the connection. 309830088Sminshall */ 309930088Sminshall static 310030088Sminshall status(argc, argv) 310130088Sminshall int argc; 310230088Sminshall char *argv[]; 310330088Sminshall { 310430088Sminshall if (connected) { 310530088Sminshall printf("Connected to %s.\n", hostname); 310630088Sminshall if (argc < 2) { 310730088Sminshall printf("Operating in %s.\n", 310830088Sminshall modelist[getconnmode()].modedescriptions); 310930088Sminshall if (localchars) { 311030088Sminshall printf("Catching signals locally.\n"); 311130088Sminshall } 311230088Sminshall } 311330088Sminshall } else { 311430088Sminshall printf("No connection.\n"); 311530088Sminshall } 311630088Sminshall # if !defined(TN3270) 311730088Sminshall printf("Escape character is '%s'.\n", control(escape)); 311830088Sminshall fflush(stdout); 311930088Sminshall # else /* !defined(TN3270) */ 312030088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 312130088Sminshall printf("Escape character is '%s'.\n", control(escape)); 312230088Sminshall } 312330088Sminshall # if defined(unix) 312430088Sminshall if (In3270 && transcom) { 312530088Sminshall printf("Transparent mode command is '%s'.\n", transcom); 312630088Sminshall } 312730088Sminshall # endif /* defined(unix) */ 312830088Sminshall fflush(stdout); 312930088Sminshall if (In3270) { 313030088Sminshall return 0; 313130088Sminshall } 313230088Sminshall # endif /* defined(TN3270) */ 313330088Sminshall return 1; 313430088Sminshall } 313530088Sminshall 313630088Sminshall #if defined(TN3270) && defined(unix) 313730088Sminshall static 313830088Sminshall settranscom(argc, argv) 313930088Sminshall int argc; 314030088Sminshall char *argv[]; 314130088Sminshall { 314230088Sminshall int i, len = 0; 314330088Sminshall char *strcpy(), *strcat(); 314430088Sminshall 314530088Sminshall if (argc == 1 && transcom) { 314630088Sminshall transcom = 0; 314730088Sminshall } 314830088Sminshall if (argc == 1) { 314930088Sminshall return; 315030088Sminshall } 315130088Sminshall for (i = 1; i < argc; ++i) { 315230088Sminshall len += 1 + strlen(argv[1]); 315330088Sminshall } 315430088Sminshall transcom = tline; 315530088Sminshall (void) strcpy(transcom, argv[1]); 315630088Sminshall for (i = 2; i < argc; ++i) { 315730088Sminshall (void) strcat(transcom, " "); 315830088Sminshall (void) strcat(transcom, argv[i]); 315930088Sminshall } 316030088Sminshall } 316130088Sminshall #endif /* defined(TN3270) && defined(unix) */ 316230088Sminshall 316330088Sminshall 316430088Sminshall static 316530088Sminshall tn(argc, argv) 316630088Sminshall int argc; 316730088Sminshall char *argv[]; 316830088Sminshall { 316930088Sminshall register struct hostent *host = 0; 317030088Sminshall #if defined(msdos) 317130088Sminshall char *cp; 317230320Sminshall #endif /* defined(msdos) */ 317330088Sminshall 317430088Sminshall if (connected) { 317530088Sminshall printf("?Already connected to %s\n", hostname); 317630088Sminshall return 0; 317730088Sminshall } 317830088Sminshall if (argc < 2) { 317930088Sminshall (void) strcpy(line, "Connect "); 318030088Sminshall printf("(to) "); 318130088Sminshall gets(&line[strlen(line)]); 318230088Sminshall makeargv(); 318330088Sminshall argc = margc; 318430088Sminshall argv = margv; 318530088Sminshall } 318630088Sminshall if (argc > 3) { 318730088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 318830088Sminshall return 0; 318930088Sminshall } 319030088Sminshall #if defined(msdos) 319130088Sminshall for (cp = argv[1]; *cp; cp++) { 319230088Sminshall if (isupper(*cp)) { 319330088Sminshall *cp = tolower(*cp); 319430088Sminshall } 319530088Sminshall } 319630088Sminshall #endif /* defined(msdos) */ 319730088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 319830088Sminshall if (sin.sin_addr.s_addr != -1) { 319930088Sminshall sin.sin_family = AF_INET; 320030088Sminshall (void) strcpy(hnamebuf, argv[1]); 320130088Sminshall hostname = hnamebuf; 320230088Sminshall } else { 320330088Sminshall host = gethostbyname(argv[1]); 320430088Sminshall if (host) { 320530088Sminshall sin.sin_family = host->h_addrtype; 320630088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 320730088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, host->h_length); 320830088Sminshall #else /* defined(h_addr) */ 320930088Sminshall bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length); 321030088Sminshall #endif /* defined(h_addr) */ 321130088Sminshall hostname = host->h_name; 321230088Sminshall } else { 321330088Sminshall printf("%s: unknown host\n", argv[1]); 321430088Sminshall return 0; 321530088Sminshall } 321630088Sminshall } 321730088Sminshall sin.sin_port = sp->s_port; 321830088Sminshall if (argc == 3) { 321930088Sminshall sin.sin_port = atoi(argv[2]); 322030088Sminshall if (sin.sin_port == 0) { 322130088Sminshall sp = getservbyname(argv[2], "tcp"); 322230088Sminshall if (sp) 322330088Sminshall sin.sin_port = sp->s_port; 322430088Sminshall else { 322530088Sminshall printf("%s: bad port number\n", argv[2]); 322630088Sminshall return 0; 322730088Sminshall } 322830088Sminshall } else { 322930088Sminshall sin.sin_port = atoi(argv[2]); 323030088Sminshall sin.sin_port = htons(sin.sin_port); 323130088Sminshall } 323230088Sminshall telnetport = 0; 323330088Sminshall } else { 323430088Sminshall telnetport = 1; 323530088Sminshall } 323630088Sminshall #if defined(unix) 323730088Sminshall signal(SIGINT, intr); 323830088Sminshall signal(SIGQUIT, intr2); 323930088Sminshall signal(SIGPIPE, deadpeer); 324030088Sminshall #endif /* defined(unix) */ 324130088Sminshall printf("Trying...\n"); 324230088Sminshall do { 324330088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 324430088Sminshall if (net < 0) { 324530088Sminshall perror("telnet: socket"); 324630088Sminshall return 0; 324730088Sminshall } 3248*31124Sminshall if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 324930088Sminshall perror("setsockopt (SO_DEBUG)"); 3250*31124Sminshall } 325130088Sminshall 325230088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 325330088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 325430088Sminshall if (host && host->h_addr_list[1]) { 325530088Sminshall int oerrno = errno; 325630088Sminshall 325730088Sminshall fprintf(stderr, "telnet: connect to address %s: ", 325830088Sminshall inet_ntoa(sin.sin_addr)); 325930088Sminshall errno = oerrno; 326030088Sminshall perror((char *)0); 326130088Sminshall host->h_addr_list++; 326230088Sminshall bcopy(host->h_addr_list[0], 326330088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 326430088Sminshall fprintf(stderr, "Trying %s...\n", 326530088Sminshall inet_ntoa(sin.sin_addr)); 326630088Sminshall (void) close(net); 326730088Sminshall continue; 326830088Sminshall } 326930088Sminshall #endif /* defined(h_addr) */ 327030088Sminshall perror("telnet: Unable to connect to remote host"); 327130088Sminshall #if defined(unix) 327230088Sminshall signal(SIGINT, SIG_DFL); 327330088Sminshall signal(SIGQUIT, SIG_DFL); 327430320Sminshall #endif /* defined(unix) */ 327530088Sminshall return 0; 327630088Sminshall } 327730088Sminshall connected++; 327830088Sminshall } while (connected == 0); 327930088Sminshall call(status, "status", "notmuch", 0); 328030088Sminshall if (setjmp(peerdied) == 0) 328130088Sminshall telnet(); 328230088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1); 328330088Sminshall /*NOTREACHED*/ 328430088Sminshall } 328530088Sminshall 328630088Sminshall 328730088Sminshall #define HELPINDENT (sizeof ("connect")) 328830088Sminshall 328930088Sminshall static char 329030088Sminshall openhelp[] = "connect to a site", 329130088Sminshall closehelp[] = "close current connection", 329230088Sminshall quithelp[] = "exit telnet", 329330088Sminshall zhelp[] = "suspend telnet", 329430088Sminshall statushelp[] = "print status information", 329530088Sminshall helphelp[] = "print help information", 329630088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 329730088Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 329830088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 329930088Sminshall displayhelp[] = "display operating parameters", 330030088Sminshall #if defined(TN3270) && defined(unix) 330130088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 330230088Sminshall #endif /* defined(TN3270) && defined(unix) */ 330330088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 330430088Sminshall 330530088Sminshall extern int help(); 330630088Sminshall 330730088Sminshall static struct cmd cmdtab[] = { 330830088Sminshall { "close", closehelp, bye, 1, 1 }, 330930088Sminshall { "display", displayhelp, display, 1, 0 }, 331030088Sminshall { "mode", modehelp, modecmd, 1, 1 }, 331130088Sminshall { "open", openhelp, tn, 1, 0 }, 331230088Sminshall { "quit", quithelp, quit, 1, 0 }, 331330088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 331430088Sminshall { "set", sethelp, setcmd, 1, 0 }, 331530088Sminshall { "status", statushelp, status, 1, 0 }, 331630088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 331730088Sminshall #if defined(TN3270) && defined(unix) 331830088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 331930088Sminshall #endif /* defined(TN3270) && defined(unix) */ 332030088Sminshall { "z", zhelp, suspend, 1, 0 }, 332130088Sminshall { "?", helphelp, help, 1, 0 }, 332230088Sminshall 0 332330088Sminshall }; 332430088Sminshall 332530088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 332630088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 332730088Sminshall 332830088Sminshall static struct cmd cmdtab2[] = { 332930088Sminshall { "help", helphelp, help, 0, 0 }, 333030088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 333130088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 333230088Sminshall 0 333330088Sminshall }; 333430088Sminshall 333530088Sminshall /* 333630088Sminshall * Call routine with argc, argv set from args (terminated by 0). 333730088Sminshall * VARARGS2 333830088Sminshall */ 333930088Sminshall static 334030088Sminshall call(routine, args) 334130088Sminshall int (*routine)(); 334230088Sminshall char *args; 334330088Sminshall { 334430088Sminshall register char **argp; 334530088Sminshall register int argc; 334630088Sminshall 334730088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 334830088Sminshall ; 334930088Sminshall return (*routine)(argc, &args); 335030088Sminshall } 335130088Sminshall 335230088Sminshall static char ** 335330088Sminshall getnextcmd(name) 335430088Sminshall char *name; 335530088Sminshall { 335630088Sminshall struct cmd *c = (struct cmd *) name; 335730088Sminshall 335830088Sminshall return (char **) (c+1); 335930088Sminshall } 336030088Sminshall 336130088Sminshall static struct cmd * 336230088Sminshall getcmd(name) 336330088Sminshall char *name; 336430088Sminshall { 336530088Sminshall struct cmd *cm; 336630088Sminshall 336730088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 336830088Sminshall return cm; 336930088Sminshall } else { 337030088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 337130088Sminshall } 337230088Sminshall } 337330088Sminshall 337430088Sminshall void 337530088Sminshall command(top) 337630088Sminshall int top; 337730088Sminshall { 337830088Sminshall register struct cmd *c; 337930088Sminshall 338030088Sminshall setcommandmode(); 338130088Sminshall if (!top) { 338230088Sminshall putchar('\n'); 338330088Sminshall } else { 338430088Sminshall #if defined(unix) 338530088Sminshall signal(SIGINT, SIG_DFL); 338630088Sminshall signal(SIGQUIT, SIG_DFL); 338730088Sminshall #endif /* defined(unix) */ 338830088Sminshall } 338930088Sminshall for (;;) { 339030088Sminshall printf("%s> ", prompt); 339130088Sminshall if (gets(line) == NULL) { 339230088Sminshall if (feof(stdin) || ferror(stdin)) 339330088Sminshall quit(); 339430088Sminshall break; 339530088Sminshall } 339630088Sminshall if (line[0] == 0) 339730088Sminshall break; 339830088Sminshall makeargv(); 339930088Sminshall c = getcmd(margv[0]); 340030088Sminshall if (c == Ambiguous(struct cmd *)) { 340130088Sminshall printf("?Ambiguous command\n"); 340230088Sminshall continue; 340330088Sminshall } 340430088Sminshall if (c == 0) { 340530088Sminshall printf("?Invalid command\n"); 340630088Sminshall continue; 340730088Sminshall } 340830088Sminshall if (c->needconnect && !connected) { 340930088Sminshall printf("?Need to be connected first.\n"); 341030088Sminshall continue; 341130088Sminshall } 341230088Sminshall if ((*c->handler)(margc, margv)) { 341330088Sminshall break; 341430088Sminshall } 341530088Sminshall } 341630088Sminshall if (!top) { 341730088Sminshall if (!connected) { 341830088Sminshall longjmp(toplevel, 1); 341930088Sminshall /*NOTREACHED*/ 342030088Sminshall } 342130088Sminshall setconnmode(); 342230088Sminshall } 342330088Sminshall } 342430088Sminshall 342530088Sminshall /* 342630088Sminshall * Help command. 342730088Sminshall */ 342830088Sminshall static 342930088Sminshall help(argc, argv) 343030088Sminshall int argc; 343130088Sminshall char *argv[]; 343230088Sminshall { 343330088Sminshall register struct cmd *c; 343430088Sminshall 343530088Sminshall if (argc == 1) { 343630088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 343730088Sminshall for (c = cmdtab; c->name; c++) 343830088Sminshall if (c->dohelp) { 343930088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 344030088Sminshall c->help); 344130088Sminshall } 344230088Sminshall return 0; 344330088Sminshall } 344430088Sminshall while (--argc > 0) { 344530088Sminshall register char *arg; 344630088Sminshall arg = *++argv; 344730088Sminshall c = getcmd(arg); 344830088Sminshall if (c == Ambiguous(struct cmd *)) 344930088Sminshall printf("?Ambiguous help command %s\n", arg); 345030088Sminshall else if (c == (struct cmd *)0) 345130088Sminshall printf("?Invalid help command %s\n", arg); 345230088Sminshall else 345330088Sminshall printf("%s\n", c->help); 345430088Sminshall } 345530088Sminshall return 0; 345630088Sminshall } 345730088Sminshall 345830088Sminshall /* 345930088Sminshall * main. Parse arguments, invoke the protocol or command parser. 346030088Sminshall */ 346130088Sminshall 346230088Sminshall 346330088Sminshall void 346430088Sminshall main(argc, argv) 346530088Sminshall int argc; 346630088Sminshall char *argv[]; 346730088Sminshall { 346830326Sminshall tninit(); /* Clear out things */ 346930326Sminshall 347030088Sminshall NetTrace = stdout; 3471*31124Sminshall TerminalSaveState(); 3472*31124Sminshall autoflush = TerminalAutoFlush(); 3473*31124Sminshall 347430088Sminshall prompt = argv[0]; 347530088Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 347630088Sminshall debug = 1; 347730088Sminshall argv++; 347830088Sminshall argc--; 347930088Sminshall } 348030088Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 348130088Sminshall argv++; 348230088Sminshall argc--; 348330088Sminshall if (argc > 1) { /* get file name */ 348430088Sminshall NetTrace = fopen(argv[1], "w"); 348530088Sminshall argv++; 348630088Sminshall argc--; 348730088Sminshall if (NetTrace == NULL) { 348830088Sminshall NetTrace = stdout; 348930088Sminshall } 349030088Sminshall } 349130088Sminshall } 349230088Sminshall #if defined(TN3270) && defined(unix) 349330088Sminshall if (argc > 1 && !strcmp(argv[1], "-t")) { 349430088Sminshall argv++; 349530088Sminshall argc--; 349630088Sminshall if (argc > 1) { /* get command name */ 349730088Sminshall transcom = tline; 349830088Sminshall (void) strcpy(transcom, argv[1]); 349930088Sminshall argv++; 350030088Sminshall argc--; 350130088Sminshall } 350230088Sminshall } 350330088Sminshall #endif /* defined(TN3270) && defined(unix) */ 350430088Sminshall if (argc != 1) { 350530088Sminshall if (setjmp(toplevel) != 0) 350630088Sminshall Exit(0); 350730088Sminshall tn(argc, argv); 350830088Sminshall } 350930088Sminshall setjmp(toplevel); 351030088Sminshall for (;;) 351130088Sminshall command(1); 351230088Sminshall } 3513