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 #include <sys/ioctl.h> 8630088Sminshall #include <sys/time.h> 8730088Sminshall 8830088Sminshall #include <netinet/in.h> 8930088Sminshall 9030088Sminshall #include <curses.h> 9130088Sminshall 9230088Sminshall #define TELOPTS 9330088Sminshall #include <arpa/telnet.h> 9430088Sminshall 9530088Sminshall #if !defined(NOT43) 9630088Sminshall #include <arpa/inet.h> 9730088Sminshall #else /* !defined(NOT43) */ 9830088Sminshall extern unsigned long inet_addr(); 9930088Sminshall extern char *inet_ntoa(); 10030088Sminshall #endif /* !defined(NOT43) */ 10130088Sminshall 10230088Sminshall #include <stdio.h> 10330088Sminshall #include <ctype.h> 10430088Sminshall #include <errno.h> 10530088Sminshall #include <signal.h> 10630088Sminshall #include <setjmp.h> 10730088Sminshall #include <netdb.h> 10830088Sminshall #include <strings.h> 10930088Sminshall 11030088Sminshall #if defined(TN3270) 11130088Sminshall #include "ctlr/screen.h" 11230088Sminshall #include "system/globals.h" 11330088Sminshall #include "telnet.ext" 11430088Sminshall #include "ctlr/options.ext" 11530088Sminshall #include "ctlr/outbound.ext" 11630088Sminshall #include "keyboard/termin.ext" 117*30722Sminshall #include "general.h" 11830088Sminshall #endif /* defined(TN3270) */ 11930088Sminshall 12030088Sminshall 12130088Sminshall 12230088Sminshall #ifndef FD_SETSIZE 12330088Sminshall /* 12430088Sminshall * The following is defined just in case someone should want to run 12530088Sminshall * this telnet on a 4.2 system. 12630088Sminshall * 12730088Sminshall */ 12830088Sminshall 12930088Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 13030088Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 13130088Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 13230088Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 13330088Sminshall 13430088Sminshall #endif 13530088Sminshall 13630088Sminshall #define strip(x) ((x)&0x7f) 13730088Sminshall #define min(x,y) ((x<y)? x:y) 13830088Sminshall 13930088Sminshall #if defined(TN3270) 14030326Sminshall static char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 14130088Sminshall #endif /* defined(TN3270) */ 14230088Sminshall 14330326Sminshall static char ttyobuf[2*BUFSIZ], *tfrontp, *tbackp; 14430088Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } 14530088Sminshall #define TTYLOC() (tfrontp) 14630088Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) 14730088Sminshall #define TTYMIN() (netobuf) 14830088Sminshall #define TTYBYTES() (tfrontp-tbackp) 14930088Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1) 15030088Sminshall 15130326Sminshall static char netobuf[2*BUFSIZ], *nfrontp, *nbackp; 15230088Sminshall #define NETADD(c) { *nfrontp++ = c; } 15330088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 15430088Sminshall #define NETLOC() (nfrontp) 15530088Sminshall #define NETMAX() (netobuf+sizeof netobuf-1) 15630088Sminshall #define NETBYTES() (nfrontp-nbackp) 15730088Sminshall #define NETROOM() (NETMAX()-NETLOC()+1) 15830326Sminshall static char *neturg; /* one past last byte of urgent data */ 15930088Sminshall 16030326Sminshall static char subbuffer[100], 16130326Sminshall *subpointer, *subend; /* buffer for sub-options */ 16230088Sminshall #define SB_CLEAR() subpointer = subbuffer; 16330088Sminshall #define SB_TERM() subend = subpointer; 16430088Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 16530088Sminshall *subpointer++ = (c); \ 16630088Sminshall } 16730088Sminshall 16830088Sminshall static char sb_terminal[] = { IAC, SB, 16930088Sminshall TELOPT_TTYPE, TELQUAL_IS, 17030088Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 17130088Sminshall IAC, SE }; 17230088Sminshall #define SBTERMMODEL 13 17330088Sminshall 17430088Sminshall 17530326Sminshall static char hisopts[256]; 17630326Sminshall static char myopts[256]; 17730088Sminshall 17830088Sminshall static char doopt[] = { IAC, DO, '%', 'c', 0 }; 17930088Sminshall static char dont[] = { IAC, DONT, '%', 'c', 0 }; 18030088Sminshall static char will[] = { IAC, WILL, '%', 'c', 0 }; 18130088Sminshall static char wont[] = { IAC, WONT, '%', 'c', 0 }; 18230088Sminshall 18330088Sminshall struct cmd { 18430088Sminshall char *name; /* command name */ 18530088Sminshall char *help; /* help string */ 18630088Sminshall int (*handler)(); /* routine which executes command */ 18730088Sminshall int dohelp; /* Should we give general help information? */ 18830088Sminshall int needconnect; /* Do we need to be connected to execute? */ 18930088Sminshall }; 19030088Sminshall 19130326Sminshall static char sibuf[BUFSIZ], *sbp; 19230088Sminshall static char tibuf[BUFSIZ], *tbp; 19330088Sminshall static fd_set ibits, obits, xbits; 19430088Sminshall 19530088Sminshall 19630088Sminshall static int 19730326Sminshall connected, 19830326Sminshall net, 19930326Sminshall scc, 20030326Sminshall tcc, 20130326Sminshall showoptions, 20230326Sminshall In3270, /* Are we in 3270 mode? */ 20330326Sminshall ISend, /* trying to send network data in */ 20430088Sminshall debug = 0, 20530326Sminshall crmod, 20630326Sminshall netdata, 207*30722Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 20830088Sminshall telnetport = 1; 20930088Sminshall 21030326Sminshall static FILE *NetTrace = 0; /* Not in bss, since needs to stay */ 21130088Sminshall 21230088Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 21330088Sminshall 21430088Sminshall static char 21530088Sminshall *prompt = 0, 21630326Sminshall escape, 21730326Sminshall echoc; 21830088Sminshall 21930088Sminshall static int 22030326Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 22130326Sminshall flushout, /* flush output */ 22230088Sminshall autoflush = 0, /* flush output when interrupting? */ 22330326Sminshall autosynch, /* send interrupt characters with SYNCH? */ 22430326Sminshall localchars, /* we recognize interrupt/quit */ 22530326Sminshall donelclchars, /* the user has set "localchars" */ 22630326Sminshall dontlecho; /* do we suppress local echoing right now? */ 22730088Sminshall 22830088Sminshall /* The following are some tn3270 specific flags */ 22930088Sminshall #if defined(TN3270) 23030088Sminshall 23130088Sminshall static int 23230326Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 23330088Sminshall 234*30722Sminshall /* 235*30722Sminshall * Telnet receiver states for fsm 236*30722Sminshall */ 237*30722Sminshall #define TS_DATA 0 238*30722Sminshall #define TS_IAC 1 239*30722Sminshall #define TS_WILL 2 240*30722Sminshall #define TS_WONT 3 241*30722Sminshall #define TS_DO 4 242*30722Sminshall #define TS_DONT 5 243*30722Sminshall #define TS_CR 6 244*30722Sminshall #define TS_SB 7 /* sub-option collection */ 245*30722Sminshall #define TS_SE 8 /* looking for sub-option end */ 246*30722Sminshall 247*30722Sminshall static int telrcv_state = TS_DATA; 24830088Sminshall /* Some real, live, globals. */ 24930088Sminshall int 25030088Sminshall #if defined(unix) 25130326Sminshall HaveInput, /* There is input available to scan */ 25230088Sminshall #endif /* defined(unix) */ 25330326Sminshall tout, /* Output file descriptor */ 25430326Sminshall tin; /* Input file descriptor */ 25530088Sminshall #if defined(unix) 25630088Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 25730088Sminshall #endif /* defined(unix) */ 25830088Sminshall 25930088Sminshall #else /* defined(TN3270) */ 26030326Sminshall static int tin, tout; /* file descriptors */ 26130088Sminshall #endif /* defined(TN3270) */ 26230088Sminshall 26330088Sminshall static char line[200]; 26430088Sminshall #if defined(TN3270) && defined(unix) 26530088Sminshall static char tline[200]; 26630088Sminshall #endif /* defined(TN3270) && defined(unix) */ 26730326Sminshall static int margc; 26830088Sminshall static char *margv[20]; 26930088Sminshall 27030326Sminshall 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 28030088Sminshall static struct tchars otc = { 0 }, ntc = { 0 }; 28130088Sminshall static struct ltchars oltc = { 0 }, nltc = { 0 }; 28230088Sminshall static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 28330326Sminshall static int flushline; 28430088Sminshall 28530326Sminshall static char *hostname; 28630088Sminshall static char hnamebuf[32]; 28730088Sminshall 28830088Sminshall /* 28930088Sminshall * The following are some clocks used to decide how to interpret 29030088Sminshall * the relationship between various variables. 29130088Sminshall */ 29230088Sminshall 29330088Sminshall static struct { 29430088Sminshall int 29530088Sminshall system, /* what the current time is */ 29630088Sminshall echotoggle, /* last time user entered echo character */ 29730088Sminshall modenegotiated, /* last time operating mode negotiated */ 29830088Sminshall didnetreceive, /* last time we read data from network */ 29930088Sminshall gotDM; /* when did we last see a data mark */ 30030326Sminshall } clocks; 30130088Sminshall 30230088Sminshall #define settimer(x) clocks.x = clocks.system++ 30330088Sminshall 30430088Sminshall /* 30530326Sminshall * Initialize variables. 30630326Sminshall */ 30730326Sminshall 30830326Sminshall static void 30930326Sminshall tninit() 31030326Sminshall { 31130326Sminshall Ifrontp = Ibackp = Ibuf; 31230326Sminshall tfrontp = tbackp = ttyobuf; 31330326Sminshall nfrontp = nbackp = netobuf; 31430326Sminshall 31530326Sminshall /* Don't change telnetport */ 316*30722Sminshall SB_CLEAR(); 317*30722Sminshall ClearArray(hisopts); 318*30722Sminshall ClearArray(myopts); 319*30722Sminshall sbp = sibuf; 320*30722Sminshall tbp = tibuf; 32130326Sminshall 322*30722Sminshall connected = net = scc = tcc = In3270 = ISend = 0; 323*30722Sminshall telnetport = 0; 324*30722Sminshall 325*30722Sminshall SYNCHing = 0; 326*30722Sminshall Sent3270TerminalType = 0; 327*30722Sminshall 328*30722Sminshall #if defined(unix) 329*30722Sminshall HaveInput = 0; 330*30722Sminshall #endif /* defined(unix) */ 331*30722Sminshall errno = 0; 332*30722Sminshall 333*30722Sminshall flushline = 0; 334*30722Sminshall 33530326Sminshall /* Don't change NetTrace */ 33630326Sminshall 33730326Sminshall escape = CONTROL(']'); 33830326Sminshall echoc = CONTROL('E'); 33930326Sminshall 34030326Sminshall flushline = 1; 34130326Sminshall sp = getservbyname("telnet", "tcp"); 34230326Sminshall if (sp == 0) { 34330326Sminshall ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1); 34430326Sminshall /*NOTREACHED*/ 34530326Sminshall } 34630326Sminshall 34730326Sminshall #if defined(TN3270) 348*30722Sminshall init_ctlr(); /* Initialize some things */ 349*30722Sminshall init_keyboard(); 350*30722Sminshall init_screen(); 351*30722Sminshall init_system(); 35230326Sminshall #endif /* defined(TN3270) */ 35330326Sminshall } 35430326Sminshall 35530326Sminshall /* 35630088Sminshall * Various utility routines. 35730088Sminshall */ 35830088Sminshall 35930088Sminshall static void 36030088Sminshall makeargv() 36130088Sminshall { 36230088Sminshall register char *cp; 36330088Sminshall register char **argp = margv; 36430088Sminshall 36530088Sminshall margc = 0; 36630088Sminshall for (cp = line; *cp;) { 36730088Sminshall while (isspace(*cp)) 36830088Sminshall cp++; 36930088Sminshall if (*cp == '\0') 37030088Sminshall break; 37130088Sminshall *argp++ = cp; 37230088Sminshall margc += 1; 37330088Sminshall while (*cp != '\0' && !isspace(*cp)) 37430088Sminshall cp++; 37530088Sminshall if (*cp == '\0') 37630088Sminshall break; 37730088Sminshall *cp++ = '\0'; 37830088Sminshall } 37930088Sminshall *argp++ = 0; 38030088Sminshall } 38130088Sminshall 38230088Sminshall static char *ambiguous; /* special return value */ 38330088Sminshall #define Ambiguous(t) ((t)&ambiguous) 38430088Sminshall 38530088Sminshall 38630088Sminshall static char ** 38730088Sminshall genget(name, table, next) 38830088Sminshall char *name; /* name to match */ 38930088Sminshall char **table; /* name entry in table */ 39030088Sminshall char **(*next)(); /* routine to return next entry in table */ 39130088Sminshall { 39230088Sminshall register char *p, *q; 39330088Sminshall register char **c, **found; 39430088Sminshall register int nmatches, longest; 39530088Sminshall 39630088Sminshall longest = 0; 39730088Sminshall nmatches = 0; 39830088Sminshall found = 0; 39930088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 40030088Sminshall for (q = name; 40130088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 40230088Sminshall if (*q == 0) /* exact match? */ 40330088Sminshall return (c); 40430088Sminshall if (!*q) { /* the name was a prefix */ 40530088Sminshall if (q - name > longest) { 40630088Sminshall longest = q - name; 40730088Sminshall nmatches = 1; 40830088Sminshall found = c; 40930088Sminshall } else if (q - name == longest) 41030088Sminshall nmatches++; 41130088Sminshall } 41230088Sminshall } 41330088Sminshall if (nmatches > 1) 41430088Sminshall return Ambiguous(char **); 41530088Sminshall return (found); 41630088Sminshall } 41730088Sminshall 41830088Sminshall /* 41930088Sminshall * Make a character string into a number. 42030088Sminshall * 42130088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 42230088Sminshall */ 42330088Sminshall 42430088Sminshall static 42530088Sminshall special(s) 42630088Sminshall register char *s; 42730088Sminshall { 42830088Sminshall register char c; 42930088Sminshall char b; 43030088Sminshall 43130088Sminshall switch (*s) { 43230088Sminshall case '^': 43330088Sminshall b = *++s; 43430088Sminshall if (b == '?') { 43530088Sminshall c = b | 0x40; /* DEL */ 43630088Sminshall } else { 43730088Sminshall c = b & 0x1f; 43830088Sminshall } 43930088Sminshall break; 44030088Sminshall default: 44130088Sminshall c = *s; 44230088Sminshall break; 44330088Sminshall } 44430088Sminshall return c; 44530088Sminshall } 44630088Sminshall 44730088Sminshall /* 44830088Sminshall * Construct a control character sequence 44930088Sminshall * for a special character. 45030088Sminshall */ 45130088Sminshall static char * 45230088Sminshall control(c) 45330088Sminshall register int c; 45430088Sminshall { 45530088Sminshall static char buf[3]; 45630088Sminshall 45730088Sminshall if (c == 0x7f) 45830088Sminshall return ("^?"); 45930088Sminshall if (c == '\377') { 46030088Sminshall return "off"; 46130088Sminshall } 46230088Sminshall if (c >= 0x20) { 46330088Sminshall buf[0] = c; 46430088Sminshall buf[1] = 0; 46530088Sminshall } else { 46630088Sminshall buf[0] = '^'; 46730088Sminshall buf[1] = '@'+c; 46830088Sminshall buf[2] = 0; 46930088Sminshall } 47030088Sminshall return (buf); 47130088Sminshall } 47230088Sminshall 47330088Sminshall 47430088Sminshall /* 47530088Sminshall * upcase() 47630088Sminshall * 47730088Sminshall * Upcase (in place) the argument. 47830088Sminshall */ 47930088Sminshall 48030088Sminshall static void 48130088Sminshall upcase(argument) 48230088Sminshall register char *argument; 48330088Sminshall { 48430088Sminshall register int c; 48530088Sminshall 48630088Sminshall while ((c = *argument) != 0) { 48730088Sminshall if (islower(c)) { 48830088Sminshall *argument = toupper(c); 48930088Sminshall } 49030088Sminshall argument++; 49130088Sminshall } 49230088Sminshall } 49330088Sminshall 49430088Sminshall /* 49530088Sminshall * The following are routines used to print out debugging information. 49630088Sminshall */ 49730088Sminshall 49830088Sminshall 49930088Sminshall static void 50030088Sminshall Dump(direction, buffer, length) 50130088Sminshall char direction; 50230088Sminshall char *buffer; 50330088Sminshall int length; 50430088Sminshall { 50530088Sminshall # define BYTES_PER_LINE 32 50630088Sminshall # define min(x,y) ((x<y)? x:y) 50730088Sminshall char *pThis; 50830088Sminshall int offset; 50930088Sminshall 51030088Sminshall offset = 0; 51130088Sminshall 51230088Sminshall while (length) { 51330088Sminshall /* print one line */ 51430088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 51530088Sminshall pThis = buffer; 51630088Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 51730088Sminshall while (pThis < buffer) { 51830088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 51930088Sminshall pThis++; 52030088Sminshall } 52130088Sminshall fprintf(NetTrace, "\n"); 52230088Sminshall length -= BYTES_PER_LINE; 52330088Sminshall offset += BYTES_PER_LINE; 52430088Sminshall if (length < 0) { 52530088Sminshall return; 52630088Sminshall } 52730088Sminshall /* find next unique line */ 52830088Sminshall } 52930088Sminshall } 53030088Sminshall 53130088Sminshall 53230088Sminshall /*VARARGS*/ 53330088Sminshall static void 53430088Sminshall printoption(direction, fmt, option, what) 53530088Sminshall char *direction, *fmt; 53630088Sminshall int option, what; 53730088Sminshall { 53830088Sminshall if (!showoptions) 53930088Sminshall return; 54030088Sminshall fprintf(NetTrace, "%s ", direction+1); 54130088Sminshall if (fmt == doopt) 54230088Sminshall fmt = "do"; 54330088Sminshall else if (fmt == dont) 54430088Sminshall fmt = "dont"; 54530088Sminshall else if (fmt == will) 54630088Sminshall fmt = "will"; 54730088Sminshall else if (fmt == wont) 54830088Sminshall fmt = "wont"; 54930088Sminshall else 55030088Sminshall fmt = "???"; 55130088Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 55230088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]); 55330088Sminshall else 55430088Sminshall fprintf(NetTrace, "%s %d", fmt, option); 55530088Sminshall if (*direction == '<') { 55630088Sminshall fprintf(NetTrace, "\r\n"); 55730088Sminshall return; 55830088Sminshall } 55930088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); 56030088Sminshall } 56130088Sminshall 56230088Sminshall static void 56330088Sminshall printsub(direction, pointer, length) 56430088Sminshall char *direction, /* "<" or ">" */ 56530088Sminshall *pointer; /* where suboption data sits */ 56630088Sminshall int length; /* length of suboption data */ 56730088Sminshall { 56830088Sminshall if (showoptions) { 56930088Sminshall fprintf(NetTrace, "%s suboption ", 57030088Sminshall (direction[0] == '<')? "Received":"Sent"); 57130088Sminshall switch (pointer[0]) { 57230088Sminshall case TELOPT_TTYPE: 57330088Sminshall fprintf(NetTrace, "Terminal type "); 57430088Sminshall switch (pointer[1]) { 57530088Sminshall case TELQUAL_IS: 57630088Sminshall { 57730088Sminshall char tmpbuf[sizeof subbuffer]; 57830088Sminshall int minlen = min(length, sizeof tmpbuf); 57930088Sminshall 58030088Sminshall bcopy(pointer+2, tmpbuf, minlen); 58130088Sminshall tmpbuf[minlen-1] = 0; 58230088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf); 58330088Sminshall } 58430088Sminshall break; 58530088Sminshall case TELQUAL_SEND: 58630088Sminshall fprintf(NetTrace, "- request to send.\n"); 58730088Sminshall break; 58830088Sminshall default: 58930088Sminshall fprintf(NetTrace, 59030088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]); 59130088Sminshall } 59230088Sminshall break; 59330088Sminshall default: 59430088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n", 59530088Sminshall pointer[0], pointer[0]); 59630088Sminshall } 59730088Sminshall } 59830088Sminshall } 59930088Sminshall 60030088Sminshall /* 60130088Sminshall * Check to see if any out-of-band data exists on a socket (for 60230088Sminshall * Telnet "synch" processing). 60330088Sminshall */ 60430088Sminshall 60530088Sminshall static int 60630088Sminshall stilloob(s) 60730088Sminshall int s; /* socket number */ 60830088Sminshall { 60930088Sminshall static struct timeval timeout = { 0 }; 61030088Sminshall fd_set excepts; 61130088Sminshall int value; 61230088Sminshall 61330088Sminshall do { 61430088Sminshall FD_ZERO(&excepts); 61530088Sminshall FD_SET(s, &excepts); 61630088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 61730088Sminshall } while ((value == -1) && (errno == EINTR)); 61830088Sminshall 61930088Sminshall if (value < 0) { 62030088Sminshall perror("select"); 62130088Sminshall quit(); 62230088Sminshall } 62330088Sminshall if (FD_ISSET(s, &excepts)) { 62430088Sminshall return 1; 62530088Sminshall } else { 62630088Sminshall return 0; 62730088Sminshall } 62830088Sminshall } 62930088Sminshall 63030088Sminshall 63130088Sminshall /* 63230088Sminshall * netflush 63330088Sminshall * Send as much data as possible to the network, 63430088Sminshall * handling requests for urgent data. 63530088Sminshall * 63630088Sminshall * The return value indicates whether we did any 63730088Sminshall * useful work. 63830088Sminshall */ 63930088Sminshall 64030088Sminshall 64130088Sminshall int 64230088Sminshall netflush() 64330088Sminshall { 64430088Sminshall int n; 64530088Sminshall 64630088Sminshall if ((n = nfrontp - nbackp) > 0) { 64730088Sminshall if (!neturg) { 64830088Sminshall n = write(net, nbackp, n); /* normal write */ 64930088Sminshall } else { 65030088Sminshall n = neturg - nbackp; 65130088Sminshall /* 65230088Sminshall * In 4.2 (and 4.3) systems, there is some question about 65330088Sminshall * what byte in a sendOOB operation is the "OOB" data. 65430088Sminshall * To make ourselves compatible, we only send ONE byte 65530088Sminshall * out of band, the one WE THINK should be OOB (though 65630088Sminshall * we really have more the TCP philosophy of urgent data 65730088Sminshall * rather than the Unix philosophy of OOB data). 65830088Sminshall */ 65930088Sminshall if (n > 1) { 66030088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 66130088Sminshall } else { 66230088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 66330088Sminshall } 66430088Sminshall } 66530088Sminshall } 66630088Sminshall if (n < 0) { 66730088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 66830088Sminshall setcommandmode(); 66930088Sminshall perror(hostname); 67030088Sminshall close(net); 67130088Sminshall neturg = 0; 67230088Sminshall longjmp(peerdied, -1); 67330088Sminshall /*NOTREACHED*/ 67430088Sminshall } 67530088Sminshall n = 0; 67630088Sminshall } 67730088Sminshall if (netdata && n) { 67830088Sminshall Dump('>', nbackp, n); 67930088Sminshall } 68030088Sminshall nbackp += n; 68130088Sminshall if (nbackp >= neturg) { 68230088Sminshall neturg = 0; 68330088Sminshall } 68430088Sminshall if (nbackp == nfrontp) { 68530088Sminshall nbackp = nfrontp = netobuf; 68630088Sminshall } 68730088Sminshall return n > 0; 68830088Sminshall } 68930088Sminshall 69030088Sminshall /* 69130088Sminshall * nextitem() 69230088Sminshall * 69330088Sminshall * Return the address of the next "item" in the TELNET data 69430088Sminshall * stream. This will be the address of the next character if 69530088Sminshall * the current address is a user data character, or it will 69630088Sminshall * be the address of the character following the TELNET command 69730088Sminshall * if the current address is a TELNET IAC ("I Am a Command") 69830088Sminshall * character. 69930088Sminshall */ 70030088Sminshall 70130088Sminshall static char * 70230088Sminshall nextitem(current) 70330088Sminshall char *current; 70430088Sminshall { 70530088Sminshall if ((*current&0xff) != IAC) { 70630088Sminshall return current+1; 70730088Sminshall } 70830088Sminshall switch (*(current+1)&0xff) { 70930088Sminshall case DO: 71030088Sminshall case DONT: 71130088Sminshall case WILL: 71230088Sminshall case WONT: 71330088Sminshall return current+3; 71430088Sminshall case SB: /* loop forever looking for the SE */ 71530088Sminshall { 71630088Sminshall register char *look = current+2; 71730088Sminshall 71830088Sminshall for (;;) { 71930088Sminshall if ((*look++&0xff) == IAC) { 72030088Sminshall if ((*look++&0xff) == SE) { 72130088Sminshall return look; 72230088Sminshall } 72330088Sminshall } 72430088Sminshall } 72530088Sminshall } 72630088Sminshall default: 72730088Sminshall return current+2; 72830088Sminshall } 72930088Sminshall } 73030088Sminshall /* 73130088Sminshall * netclear() 73230088Sminshall * 73330088Sminshall * We are about to do a TELNET SYNCH operation. Clear 73430088Sminshall * the path to the network. 73530088Sminshall * 73630088Sminshall * Things are a bit tricky since we may have sent the first 73730088Sminshall * byte or so of a previous TELNET command into the network. 73830088Sminshall * So, we have to scan the network buffer from the beginning 73930088Sminshall * until we are up to where we want to be. 74030088Sminshall * 74130088Sminshall * A side effect of what we do, just to keep things 74230088Sminshall * simple, is to clear the urgent data pointer. The principal 74330088Sminshall * caller should be setting the urgent data pointer AFTER calling 74430088Sminshall * us in any case. 74530088Sminshall */ 74630088Sminshall 74730088Sminshall static void 74830088Sminshall netclear() 74930088Sminshall { 75030088Sminshall register char *thisitem, *next; 75130088Sminshall char *good; 75230088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 75330088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 75430088Sminshall 75530088Sminshall thisitem = netobuf; 75630088Sminshall 75730088Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 75830088Sminshall thisitem = next; 75930088Sminshall } 76030088Sminshall 76130088Sminshall /* Now, thisitem is first before/at boundary. */ 76230088Sminshall 76330088Sminshall good = netobuf; /* where the good bytes go */ 76430088Sminshall 76530088Sminshall while (nfrontp > thisitem) { 76630088Sminshall if (wewant(thisitem)) { 76730088Sminshall int length; 76830088Sminshall 76930088Sminshall next = thisitem; 77030088Sminshall do { 77130088Sminshall next = nextitem(next); 77230088Sminshall } while (wewant(next) && (nfrontp > next)); 77330088Sminshall length = next-thisitem; 77430088Sminshall bcopy(thisitem, good, length); 77530088Sminshall good += length; 77630088Sminshall thisitem = next; 77730088Sminshall } else { 77830088Sminshall thisitem = nextitem(thisitem); 77930088Sminshall } 78030088Sminshall } 78130088Sminshall 78230088Sminshall nbackp = netobuf; 78330088Sminshall nfrontp = good; /* next byte to be sent */ 78430088Sminshall neturg = 0; 78530088Sminshall } 78630088Sminshall 78730088Sminshall /* 78830088Sminshall * These routines add various telnet commands to the data stream. 78930088Sminshall */ 79030088Sminshall 79130088Sminshall #if defined(NOT43) 79230088Sminshall static int 79330088Sminshall #else /* defined(NOT43) */ 79430088Sminshall static void 79530088Sminshall #endif /* defined(NOT43) */ 79630088Sminshall dosynch() 79730088Sminshall { 79830088Sminshall netclear(); /* clear the path to the network */ 79930088Sminshall NET2ADD(IAC, DM); 80030088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 80130088Sminshall 80230088Sminshall #if defined(NOT43) 80330088Sminshall return 0; 80430088Sminshall #endif /* defined(NOT43) */ 80530088Sminshall } 80630088Sminshall 80730088Sminshall static void 80830088Sminshall doflush() 80930088Sminshall { 81030088Sminshall NET2ADD(IAC, DO); 81130088Sminshall NETADD(TELOPT_TM); 81230088Sminshall flushline = 1; 81330088Sminshall flushout = 1; 81430088Sminshall ttyflush(); 81530088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 81630088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 81730088Sminshall } 81830088Sminshall 81930088Sminshall static void 82030088Sminshall intp() 82130088Sminshall { 82230088Sminshall NET2ADD(IAC, IP); 82330088Sminshall if (autoflush) { 82430088Sminshall doflush(); 82530088Sminshall } 82630088Sminshall if (autosynch) { 82730088Sminshall dosynch(); 82830088Sminshall } 82930088Sminshall } 83030088Sminshall 83130088Sminshall static void 83230088Sminshall sendbrk() 83330088Sminshall { 83430088Sminshall NET2ADD(IAC, BREAK); 83530088Sminshall if (autoflush) { 83630088Sminshall doflush(); 83730088Sminshall } 83830088Sminshall if (autosynch) { 83930088Sminshall dosynch(); 84030088Sminshall } 84130088Sminshall } 84230088Sminshall 84330088Sminshall /* 84430088Sminshall * Send as much data as possible to the terminal. 84530088Sminshall * 84630088Sminshall * The return value indicates whether we did any 84730088Sminshall * useful work. 84830088Sminshall */ 84930088Sminshall 85030088Sminshall 85130088Sminshall static int 85230088Sminshall ttyflush() 85330088Sminshall { 85430088Sminshall int n; 85530088Sminshall 85630088Sminshall if ((n = tfrontp - tbackp) > 0) { 85730088Sminshall if (!(SYNCHing||flushout)) { 85830088Sminshall n = write(tout, tbackp, n); 85930088Sminshall } else { 86030088Sminshall ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 86130088Sminshall /* we leave 'n' alone! */ 86230088Sminshall } 86330088Sminshall } 86430088Sminshall if (n >= 0) { 86530088Sminshall tbackp += n; 86630088Sminshall if (tbackp == tfrontp) { 86730088Sminshall tbackp = tfrontp = ttyobuf; 86830088Sminshall } 86930088Sminshall } 87030088Sminshall return n > 0; 87130088Sminshall } 87230088Sminshall 87330088Sminshall #if defined(TN3270) 87430088Sminshall 87530088Sminshall #if defined(unix) 87630088Sminshall static void 87730088Sminshall inputAvailable() 87830088Sminshall { 87930088Sminshall HaveInput = 1; 88030088Sminshall } 88130088Sminshall #endif /* defined(unix) */ 88230088Sminshall 88330088Sminshall void 88430088Sminshall outputPurge() 88530088Sminshall { 88630088Sminshall int tmp = flushout; 88730088Sminshall 88830088Sminshall flushout = 1; 88930088Sminshall 89030088Sminshall ttyflush(); 89130088Sminshall 89230088Sminshall flushout = tmp; 89330088Sminshall } 89430088Sminshall 89530088Sminshall #endif /* defined(TN3270) */ 89630088Sminshall 89730088Sminshall #if defined(unix) 89830088Sminshall /* 89930088Sminshall * Various signal handling routines. 90030088Sminshall */ 90130088Sminshall 90230088Sminshall static void 90330088Sminshall deadpeer() 90430088Sminshall { 90530088Sminshall setcommandmode(); 90630088Sminshall longjmp(peerdied, -1); 90730088Sminshall } 90830088Sminshall 90930088Sminshall static void 91030088Sminshall intr() 91130088Sminshall { 91230088Sminshall if (localchars) { 91330088Sminshall intp(); 91430088Sminshall return; 91530088Sminshall } 91630088Sminshall setcommandmode(); 91730088Sminshall longjmp(toplevel, -1); 91830088Sminshall } 91930088Sminshall 92030088Sminshall static void 92130088Sminshall intr2() 92230088Sminshall { 92330088Sminshall if (localchars) { 92430088Sminshall sendbrk(); 92530088Sminshall return; 92630088Sminshall } 92730088Sminshall } 92830088Sminshall 92930088Sminshall static void 93030088Sminshall doescape() 93130088Sminshall { 93230088Sminshall command(0); 93330088Sminshall } 93430088Sminshall #endif /* defined(unix) */ 93530088Sminshall 93630088Sminshall static int globalmode = 0; 93730088Sminshall /* Various modes */ 93830088Sminshall #define MODE_LINE(m) (modelist[m].modetype & LINE) 93930088Sminshall #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS) 94030088Sminshall 94130088Sminshall #define LOCAL_CHARS 0x01 /* Characters processed locally */ 94230088Sminshall #define LINE 0x02 /* Line-by-line mode of operation */ 94330088Sminshall 94430088Sminshall static struct { 94530088Sminshall char *modedescriptions; 94630088Sminshall char modetype; 94730088Sminshall } modelist[] = { 94830088Sminshall { "telnet command mode", 0 }, 94930088Sminshall { "character-at-a-time mode", 0 }, 95030088Sminshall { "character-at-a-time mode (local echo)", LOCAL_CHARS }, 95130088Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 95230088Sminshall { "line-by-line mode", LINE | LOCAL_CHARS }, 95330088Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 95430088Sminshall { "3270 mode", 0 }, 95530088Sminshall }; 95630088Sminshall /* 95730088Sminshall * Mode - set up terminal to a specific mode. 95830088Sminshall */ 95930088Sminshall 96030088Sminshall 96130088Sminshall static void 96230088Sminshall mode(f) 96330088Sminshall register int f; 96430088Sminshall { 96530088Sminshall static int prevmode = 0; 96630088Sminshall struct tchars *tc; 96730088Sminshall struct tchars tc3; 96830088Sminshall struct ltchars *ltc; 96930088Sminshall struct sgttyb sb; 97030088Sminshall int onoff; 97130088Sminshall #if defined(unix) 97230088Sminshall int old; 97330088Sminshall #endif /* defined(unix) */ 97430088Sminshall struct tchars notc2; 97530088Sminshall struct ltchars noltc2; 97630088Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 97730088Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 97830088Sminshall 97930088Sminshall globalmode = f; 98030088Sminshall if (prevmode == f) 98130088Sminshall return; 98230088Sminshall #if defined(unix) 98330088Sminshall old = prevmode; 98430088Sminshall #endif /* defined(unix) */ 98530088Sminshall prevmode = f; 98630088Sminshall sb = nttyb; 98730088Sminshall 98830088Sminshall switch (f) { 98930088Sminshall 99030088Sminshall case 0: 99130088Sminshall onoff = 0; 99230088Sminshall tc = &otc; 99330088Sminshall ltc = &oltc; 99430088Sminshall break; 99530088Sminshall 99630088Sminshall case 1: /* remote character processing, remote echo */ 99730088Sminshall case 2: /* remote character processing, local echo */ 99830088Sminshall case 6: /* 3270 mode - like 1, but with xon/xoff local */ 99930088Sminshall /* (might be nice to have "6" in telnet also...) */ 100030088Sminshall sb.sg_flags |= CBREAK; 100130088Sminshall if ((f == 1) || (f == 6)) { 100230088Sminshall sb.sg_flags &= ~(ECHO|CRMOD); 100330088Sminshall } else { 100430088Sminshall sb.sg_flags |= ECHO|CRMOD; 100530088Sminshall } 100630088Sminshall sb.sg_erase = sb.sg_kill = -1; 100730088Sminshall if (f == 6) { 100830088Sminshall tc = &tc3; 100930088Sminshall tc3 = notc; 101030088Sminshall /* get XON, XOFF characters */ 101130088Sminshall tc3.t_startc = otc.t_startc; 101230088Sminshall tc3.t_stopc = otc.t_stopc; 101330088Sminshall } else { 101430088Sminshall /* 101530088Sminshall * If user hasn't specified one way or the other, 101630088Sminshall * then default to not trapping signals. 101730088Sminshall */ 101830088Sminshall if (!donelclchars) { 101930088Sminshall localchars = 0; 102030088Sminshall } 102130088Sminshall if (localchars) { 102230088Sminshall notc2 = notc; 102330088Sminshall notc2.t_intrc = ntc.t_intrc; 102430088Sminshall notc2.t_quitc = ntc.t_quitc; 102530088Sminshall tc = ¬c2; 102630088Sminshall } else { 102730088Sminshall tc = ¬c; 102830088Sminshall } 102930088Sminshall } 103030088Sminshall ltc = &noltc; 103130088Sminshall onoff = 1; 103230088Sminshall break; 103330088Sminshall case 3: /* local character processing, remote echo */ 103430088Sminshall case 4: /* local character processing, local echo */ 103530088Sminshall case 5: /* local character processing, no echo */ 103630088Sminshall sb.sg_flags &= ~CBREAK; 103730088Sminshall sb.sg_flags |= CRMOD; 103830088Sminshall if (f == 4) 103930088Sminshall sb.sg_flags |= ECHO; 104030088Sminshall else 104130088Sminshall sb.sg_flags &= ~ECHO; 104230088Sminshall notc2 = ntc; 104330088Sminshall tc = ¬c2; 104430088Sminshall noltc2 = oltc; 104530088Sminshall ltc = &noltc2; 104630368Sminshall #if defined(unix) 104730088Sminshall /* 104830088Sminshall * If user hasn't specified one way or the other, 104930088Sminshall * then default to trapping signals. 105030088Sminshall */ 105130088Sminshall if (!donelclchars) { 105230088Sminshall localchars = 1; 105330088Sminshall } 105430088Sminshall if (localchars) { 105530088Sminshall notc2.t_brkc = nltc.t_flushc; 105630088Sminshall noltc2.t_flushc = -1; 105730088Sminshall } else { 105830088Sminshall notc2.t_intrc = notc2.t_quitc = -1; 105930088Sminshall } 106030368Sminshall #else /* defined(unix) */ 106130368Sminshall notc2.t_intrc = -1; 106230368Sminshall #endif /* defined(unix) */ 106330088Sminshall noltc2.t_suspc = escape; 106430088Sminshall noltc2.t_dsuspc = -1; 106530088Sminshall onoff = 1; 106630088Sminshall break; 106730088Sminshall 106830088Sminshall default: 106930088Sminshall return; 107030088Sminshall } 107130088Sminshall ioctl(tin, TIOCSLTC, (char *)ltc); 107230088Sminshall ioctl(tin, TIOCSETC, (char *)tc); 107330088Sminshall ioctl(tin, TIOCSETP, (char *)&sb); 107430088Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 107530088Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 107630088Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 107730088Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 107830088Sminshall #if defined(TN3270) && !defined(DEBUG) 107930088Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 108030088Sminshall #endif /* defined(TN3270) && !defined(DEBUG) */ 108130088Sminshall 108230088Sminshall #if defined(unix) 108330088Sminshall if (MODE_LINE(f)) { 108430088Sminshall signal(SIGTSTP, doescape); 108530088Sminshall } else if (MODE_LINE(old)) { 108630088Sminshall signal(SIGTSTP, SIG_DFL); 108730088Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 108830088Sminshall } 108930088Sminshall #endif /* defined(unix) */ 109030088Sminshall } 109130088Sminshall 109230088Sminshall /* 109330088Sminshall * These routines decides on what the mode should be (based on the values 109430088Sminshall * of various global variables). 109530088Sminshall */ 109630088Sminshall 109730088Sminshall 109830088Sminshall static 109930088Sminshall getconnmode() 110030088Sminshall { 110130088Sminshall static char newmode[16] = 110230088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; 110330088Sminshall int modeindex = 0; 110430088Sminshall 110530088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 110630088Sminshall modeindex += 1; 110730088Sminshall } 110830088Sminshall if (hisopts[TELOPT_ECHO]) { 110930088Sminshall modeindex += 2; 111030088Sminshall } 111130088Sminshall if (hisopts[TELOPT_SGA]) { 111230088Sminshall modeindex += 4; 111330088Sminshall } 111430088Sminshall if (In3270) { 111530088Sminshall modeindex += 8; 111630088Sminshall } 111730088Sminshall return newmode[modeindex]; 111830088Sminshall } 111930088Sminshall 112030088Sminshall void 112130088Sminshall setconnmode() 112230088Sminshall { 112330088Sminshall mode(getconnmode()); 112430088Sminshall } 112530088Sminshall 112630088Sminshall 112730088Sminshall void 112830088Sminshall setcommandmode() 112930088Sminshall { 113030088Sminshall mode(0); 113130088Sminshall } 113230088Sminshall 113330088Sminshall static void 113430088Sminshall willoption(option, reply) 113530088Sminshall int option, reply; 113630088Sminshall { 113730088Sminshall char *fmt; 113830088Sminshall 113930088Sminshall switch (option) { 114030088Sminshall 114130368Sminshall case TELOPT_ECHO: 114230088Sminshall # if defined(TN3270) 114330368Sminshall /* 114430368Sminshall * The following is a pain in the rear-end. 114530368Sminshall * Various IBM servers (some versions of Wiscnet, 114630368Sminshall * possibly Fibronics/Spartacus, and who knows who 114730368Sminshall * else) will NOT allow us to send "DO SGA" too early 114830368Sminshall * in the setup proceedings. On the other hand, 114930368Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 115030368Sminshall * So, we are stuck. Empirically (but, based on 115130368Sminshall * a VERY small sample), the IBM servers don't send 115230368Sminshall * out anything about ECHO, so we postpone our sending 115330368Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 115430368Sminshall * DO send). 115530368Sminshall */ 115630368Sminshall { 115730368Sminshall if (askedSGA == 0) { 115830368Sminshall askedSGA = 1; 115930368Sminshall if (!hisopts[TELOPT_SGA]) { 116030368Sminshall willoption(TELOPT_SGA, 0); 116130368Sminshall } 116230368Sminshall } 116330368Sminshall } 116430368Sminshall /* Fall through */ 116530088Sminshall case TELOPT_EOR: 116630088Sminshall case TELOPT_BINARY: 116730088Sminshall #endif /* defined(TN3270) */ 116830088Sminshall case TELOPT_SGA: 116930088Sminshall settimer(modenegotiated); 117030088Sminshall hisopts[option] = 1; 117130088Sminshall fmt = doopt; 117230088Sminshall setconnmode(); /* possibly set new tty mode */ 117330088Sminshall break; 117430088Sminshall 117530088Sminshall case TELOPT_TM: 117630088Sminshall return; /* Never reply to TM will's/wont's */ 117730088Sminshall 117830088Sminshall default: 117930088Sminshall fmt = dont; 118030088Sminshall break; 118130088Sminshall } 118230088Sminshall sprintf(nfrontp, fmt, option); 118330088Sminshall nfrontp += sizeof (dont) - 2; 118430088Sminshall if (reply) 118530088Sminshall printoption(">SENT", fmt, option, reply); 118630088Sminshall else 118730088Sminshall printoption("<SENT", fmt, option, reply); 118830088Sminshall } 118930088Sminshall 119030088Sminshall static void 119130088Sminshall wontoption(option, reply) 119230088Sminshall int option, reply; 119330088Sminshall { 119430088Sminshall char *fmt; 119530088Sminshall 119630088Sminshall switch (option) { 119730088Sminshall 119830088Sminshall case TELOPT_ECHO: 119930088Sminshall case TELOPT_SGA: 120030088Sminshall settimer(modenegotiated); 120130088Sminshall hisopts[option] = 0; 120230088Sminshall fmt = dont; 120330088Sminshall setconnmode(); /* Set new tty mode */ 120430088Sminshall break; 120530088Sminshall 120630088Sminshall case TELOPT_TM: 120730088Sminshall return; /* Never reply to TM will's/wont's */ 120830088Sminshall 120930088Sminshall default: 121030088Sminshall fmt = dont; 121130088Sminshall } 121230088Sminshall sprintf(nfrontp, fmt, option); 121330088Sminshall nfrontp += sizeof (doopt) - 2; 121430088Sminshall if (reply) 121530088Sminshall printoption(">SENT", fmt, option, reply); 121630088Sminshall else 121730088Sminshall printoption("<SENT", fmt, option, reply); 121830088Sminshall } 121930088Sminshall 122030088Sminshall static void 122130088Sminshall dooption(option) 122230088Sminshall int option; 122330088Sminshall { 122430088Sminshall char *fmt; 122530088Sminshall 122630088Sminshall switch (option) { 122730088Sminshall 122830088Sminshall case TELOPT_TM: 122930088Sminshall fmt = will; 123030088Sminshall break; 123130088Sminshall 123230088Sminshall # if defined(TN3270) 123330088Sminshall case TELOPT_EOR: 123430088Sminshall case TELOPT_BINARY: 123530088Sminshall # endif /* defined(TN3270) */ 123630088Sminshall case TELOPT_TTYPE: /* terminal type option */ 123730088Sminshall case TELOPT_SGA: /* no big deal */ 123830088Sminshall fmt = will; 123930088Sminshall myopts[option] = 1; 124030088Sminshall break; 124130088Sminshall 124230088Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 124330088Sminshall default: 124430088Sminshall fmt = wont; 124530088Sminshall break; 124630088Sminshall } 124730088Sminshall sprintf(nfrontp, fmt, option); 124830088Sminshall nfrontp += sizeof (doopt) - 2; 124930088Sminshall printoption(">SENT", fmt, option, 0); 125030088Sminshall } 125130088Sminshall 125230088Sminshall /* 125330088Sminshall * suboption() 125430088Sminshall * 125530088Sminshall * Look at the sub-option buffer, and try to be helpful to the other 125630088Sminshall * side. 125730088Sminshall * 125830088Sminshall * Currently we recognize: 125930088Sminshall * 126030088Sminshall * Terminal type, send request. 126130088Sminshall */ 126230088Sminshall 126330088Sminshall static void 126430088Sminshall suboption() 126530088Sminshall { 126630088Sminshall printsub("<", subbuffer, subend-subbuffer+1); 126730088Sminshall switch (subbuffer[0]&0xff) { 126830088Sminshall case TELOPT_TTYPE: 126930088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 127030088Sminshall ; 127130088Sminshall } else { 127230088Sminshall char *name; 127330088Sminshall char namebuf[41]; 127430088Sminshall extern char *getenv(); 127530088Sminshall int len; 127630088Sminshall 127730088Sminshall #if defined(TN3270) 127830088Sminshall /* 127930326Sminshall * Try to send a 3270 type terminal name. Decide which one based 128030088Sminshall * on the format of our screen, and (in the future) color 128130088Sminshall * capaiblities. 128230088Sminshall */ 128330088Sminshall if ((initscr() != ERR) && /* Initialize curses to get line size */ 128430088Sminshall (LINES >= 24) && (COLS >= 80)) { 128530088Sminshall Sent3270TerminalType = 1; 128630088Sminshall if ((LINES >= 27) && (COLS >= 132)) { 128730088Sminshall MaxNumberLines = 27; 128830088Sminshall MaxNumberColumns = 132; 128930088Sminshall sb_terminal[SBTERMMODEL] = '5'; 129030088Sminshall } else if (LINES >= 43) { 129130088Sminshall MaxNumberLines = 43; 129230088Sminshall MaxNumberColumns = 80; 129330088Sminshall sb_terminal[SBTERMMODEL] = '4'; 129430088Sminshall } else if (LINES >= 32) { 129530088Sminshall MaxNumberLines = 32; 129630088Sminshall MaxNumberColumns = 80; 129730088Sminshall sb_terminal[SBTERMMODEL] = '3'; 129830088Sminshall } else { 129930088Sminshall MaxNumberLines = 24; 130030088Sminshall MaxNumberColumns = 80; 130130088Sminshall sb_terminal[SBTERMMODEL] = '2'; 130230088Sminshall } 130330088Sminshall NumberLines = 24; /* before we start out... */ 130430088Sminshall NumberColumns = 80; 130530088Sminshall ScreenSize = NumberLines*NumberColumns; 130630088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 130730088Sminshall ExitString(stderr, 130830088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 130930088Sminshall /*NOTREACHED*/ 131030088Sminshall } 131130088Sminshall bcopy(sb_terminal, nfrontp, sizeof sb_terminal); 131230088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 131330088Sminshall nfrontp += sizeof sb_terminal; 131430088Sminshall return; 131530088Sminshall } 131630088Sminshall #endif /* defined(TN3270) */ 131730088Sminshall 131830088Sminshall name = getenv("TERM"); 131930088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 132030088Sminshall name = "UNKNOWN"; 132130088Sminshall } 132230088Sminshall if ((len + 4+2) < NETROOM()) { 132330088Sminshall strcpy(namebuf, name); 132430088Sminshall upcase(namebuf); 132530088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 132630088Sminshall TELQUAL_IS, namebuf, IAC, SE); 132730088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 132830088Sminshall nfrontp += 4+strlen(namebuf)+2; 132930088Sminshall } else { 133030088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 133130088Sminshall 1); 133230088Sminshall /*NOTREACHED*/ 133330088Sminshall } 133430088Sminshall } 133530088Sminshall 133630088Sminshall default: 133730088Sminshall break; 133830088Sminshall } 133930088Sminshall } 134030088Sminshall 134130088Sminshall #if defined(TN3270) 134230088Sminshall static void 134330088Sminshall SetIn3270() 134430088Sminshall { 134530088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 134630088Sminshall && hisopts[TELOPT_BINARY]) { 134730088Sminshall if (!In3270) { 134830088Sminshall In3270 = 1; 134930326Sminshall Init3270(); /* Initialize 3270 functions */ 135030088Sminshall /* initialize terminal key mapping */ 135130326Sminshall InitTerminal(); /* Start terminal going */ 135230088Sminshall setconnmode(); 135330088Sminshall } 135430088Sminshall } else { 135530088Sminshall if (In3270) { 135630088Sminshall StopScreen(1); 135730088Sminshall In3270 = 0; 135830088Sminshall setconnmode(); 135930088Sminshall } 136030088Sminshall } 136130088Sminshall } 136230088Sminshall #endif /* defined(TN3270) */ 136330088Sminshall 136430088Sminshall 136530088Sminshall static void 136630088Sminshall telrcv() 136730088Sminshall { 136830088Sminshall register int c; 1369*30722Sminshall static int telrcv_state = TS_DATA; 137030088Sminshall # if defined(TN3270) 137130088Sminshall register int Scc; 137230088Sminshall register char *Sbp; 137330088Sminshall # endif /* defined(TN3270) */ 137430088Sminshall 137530088Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 137630088Sminshall c = *sbp++ & 0xff, scc--; 1377*30722Sminshall switch (telrcv_state) { 137830088Sminshall 137930088Sminshall case TS_CR: 1380*30722Sminshall telrcv_state = TS_DATA; 138130088Sminshall if (c == '\0') { 138230088Sminshall break; /* Ignore \0 after CR */ 138330088Sminshall } else if (c == '\n') { 138430088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 138530088Sminshall TTYADD(c); 138630088Sminshall } 138730088Sminshall break; 138830088Sminshall } 138930088Sminshall /* Else, fall through */ 139030088Sminshall 139130088Sminshall case TS_DATA: 139230088Sminshall if (c == IAC) { 1393*30722Sminshall telrcv_state = TS_IAC; 139430088Sminshall continue; 139530088Sminshall } 139630088Sminshall # if defined(TN3270) 139730088Sminshall if (In3270) { 139830088Sminshall *Ifrontp++ = c; 139930088Sminshall Sbp = sbp; 140030088Sminshall Scc = scc; 140130088Sminshall while (Scc > 0) { 140230088Sminshall c = *Sbp++ & 0377, Scc--; 140330088Sminshall if (c == IAC) { 1404*30722Sminshall telrcv_state = TS_IAC; 140530088Sminshall break; 140630088Sminshall } 140730088Sminshall *Ifrontp++ = c; 140830088Sminshall } 140930088Sminshall sbp = Sbp; 141030088Sminshall scc = Scc; 141130088Sminshall } else 141230088Sminshall # endif /* defined(TN3270) */ 141330088Sminshall /* 141430088Sminshall * The 'crmod' hack (see following) is needed 141530088Sminshall * since we can't * set CRMOD on output only. 141630088Sminshall * Machines like MULTICS like to send \r without 141730088Sminshall * \n; since we must turn off CRMOD to get proper 141830088Sminshall * input, the mapping is done here (sigh). 141930088Sminshall */ 142030088Sminshall if (c == '\r') { 142130088Sminshall if (scc > 0) { 142230088Sminshall c = *sbp&0xff; 142330088Sminshall if (c == 0) { 142430088Sminshall sbp++, scc--; 142530088Sminshall /* a "true" CR */ 142630088Sminshall TTYADD('\r'); 142730088Sminshall } else if (!hisopts[TELOPT_ECHO] && 142830088Sminshall (c == '\n')) { 142930088Sminshall sbp++, scc--; 143030088Sminshall TTYADD('\n'); 143130088Sminshall } else { 143230088Sminshall TTYADD('\r'); 143330088Sminshall if (crmod) { 143430088Sminshall TTYADD('\n'); 143530088Sminshall } 143630088Sminshall } 143730088Sminshall } else { 1438*30722Sminshall telrcv_state = TS_CR; 143930088Sminshall TTYADD('\r'); 144030088Sminshall if (crmod) { 144130088Sminshall TTYADD('\n'); 144230088Sminshall } 144330088Sminshall } 144430088Sminshall } else { 144530088Sminshall TTYADD(c); 144630088Sminshall } 144730088Sminshall continue; 144830088Sminshall 144930088Sminshall case TS_IAC: 145030088Sminshall switch (c) { 145130088Sminshall 145230088Sminshall case WILL: 1453*30722Sminshall telrcv_state = TS_WILL; 145430088Sminshall continue; 145530088Sminshall 145630088Sminshall case WONT: 1457*30722Sminshall telrcv_state = TS_WONT; 145830088Sminshall continue; 145930088Sminshall 146030088Sminshall case DO: 1461*30722Sminshall telrcv_state = TS_DO; 146230088Sminshall continue; 146330088Sminshall 146430088Sminshall case DONT: 1465*30722Sminshall telrcv_state = TS_DONT; 146630088Sminshall continue; 146730088Sminshall 146830088Sminshall case DM: 146930088Sminshall /* 147030088Sminshall * We may have missed an urgent notification, 147130088Sminshall * so make sure we flush whatever is in the 147230088Sminshall * buffer currently. 147330088Sminshall */ 147430088Sminshall SYNCHing = 1; 147530088Sminshall ttyflush(); 147630088Sminshall SYNCHing = stilloob(net); 147730088Sminshall settimer(gotDM); 147830088Sminshall break; 147930088Sminshall 148030088Sminshall case NOP: 148130088Sminshall case GA: 148230088Sminshall break; 148330088Sminshall 148430088Sminshall case SB: 148530088Sminshall SB_CLEAR(); 1486*30722Sminshall telrcv_state = TS_SB; 148730088Sminshall continue; 148830088Sminshall 148930088Sminshall # if defined(TN3270) 149030088Sminshall case EOR: 149130088Sminshall if (In3270) { 149230088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 149330088Sminshall if (Ibackp == Ifrontp) { 149430088Sminshall Ibackp = Ifrontp = Ibuf; 149530088Sminshall ISend = 0; /* should have been! */ 149630088Sminshall } else { 149730088Sminshall ISend = 1; 149830088Sminshall } 149930088Sminshall } 150030088Sminshall break; 150130088Sminshall # endif /* defined(TN3270) */ 150230088Sminshall 150330088Sminshall case IAC: 150430088Sminshall # if !defined(TN3270) 150530088Sminshall TTYADD(IAC); 150630088Sminshall # else /* !defined(TN3270) */ 150730088Sminshall if (In3270) { 150830088Sminshall *Ifrontp++ = IAC; 150930088Sminshall } else { 151030088Sminshall TTYADD(IAC); 151130088Sminshall } 151230088Sminshall # endif /* !defined(TN3270) */ 151330088Sminshall break; 151430088Sminshall 151530088Sminshall default: 151630088Sminshall break; 151730088Sminshall } 1518*30722Sminshall telrcv_state = TS_DATA; 151930088Sminshall continue; 152030088Sminshall 152130088Sminshall case TS_WILL: 152230088Sminshall printoption(">RCVD", will, c, !hisopts[c]); 152330088Sminshall if (c == TELOPT_TM) { 152430088Sminshall if (flushout) { 152530088Sminshall flushout = 0; 152630088Sminshall } 152730088Sminshall } else if (!hisopts[c]) { 152830088Sminshall willoption(c, 1); 152930088Sminshall } 153030088Sminshall SetIn3270(); 1531*30722Sminshall telrcv_state = TS_DATA; 153230088Sminshall continue; 153330088Sminshall 153430088Sminshall case TS_WONT: 153530088Sminshall printoption(">RCVD", wont, c, hisopts[c]); 153630088Sminshall if (c == TELOPT_TM) { 153730088Sminshall if (flushout) { 153830088Sminshall flushout = 0; 153930088Sminshall } 154030088Sminshall } else if (hisopts[c]) { 154130088Sminshall wontoption(c, 1); 154230088Sminshall } 154330088Sminshall SetIn3270(); 1544*30722Sminshall telrcv_state = TS_DATA; 154530088Sminshall continue; 154630088Sminshall 154730088Sminshall case TS_DO: 154830088Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 154930088Sminshall if (!myopts[c]) 155030088Sminshall dooption(c); 155130088Sminshall SetIn3270(); 1552*30722Sminshall telrcv_state = TS_DATA; 155330088Sminshall continue; 155430088Sminshall 155530088Sminshall case TS_DONT: 155630088Sminshall printoption(">RCVD", dont, c, myopts[c]); 155730088Sminshall if (myopts[c]) { 155830088Sminshall myopts[c] = 0; 155930088Sminshall sprintf(nfrontp, wont, c); 156030088Sminshall nfrontp += sizeof (wont) - 2; 156130088Sminshall flushline = 1; 156230088Sminshall setconnmode(); /* set new tty mode (maybe) */ 156330088Sminshall printoption(">SENT", wont, c, 0); 156430088Sminshall } 156530088Sminshall SetIn3270(); 1566*30722Sminshall telrcv_state = TS_DATA; 156730088Sminshall continue; 156830088Sminshall 156930088Sminshall case TS_SB: 157030088Sminshall if (c == IAC) { 1571*30722Sminshall telrcv_state = TS_SE; 157230088Sminshall } else { 157330088Sminshall SB_ACCUM(c); 157430088Sminshall } 157530088Sminshall continue; 157630088Sminshall 157730088Sminshall case TS_SE: 157830088Sminshall if (c != SE) { 157930088Sminshall if (c != IAC) { 158030088Sminshall SB_ACCUM(IAC); 158130088Sminshall } 158230088Sminshall SB_ACCUM(c); 1583*30722Sminshall telrcv_state = TS_SB; 158430088Sminshall } else { 158530088Sminshall SB_TERM(); 158630088Sminshall suboption(); /* handle sub-option */ 158730088Sminshall SetIn3270(); 1588*30722Sminshall telrcv_state = TS_DATA; 158930088Sminshall } 159030088Sminshall } 159130088Sminshall } 159230088Sminshall } 159330088Sminshall 159430088Sminshall #if defined(TN3270) 159530088Sminshall 159630088Sminshall /* 159730088Sminshall * The following routines are places where the various tn3270 159830088Sminshall * routines make calls into telnet.c. 159930088Sminshall */ 160030088Sminshall 160130088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 160230088Sminshall TtyChars() 160330088Sminshall { 160430088Sminshall return(tfrontp-tbackp); 160530088Sminshall } 160630088Sminshall 160730088Sminshall /* 160830088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 160930088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 161030088Sminshall * don't call us with "done" until you want that done...) 161130088Sminshall * 161230088Sminshall * We actually do send all the data to the network buffer, since our 161330088Sminshall * only client needs for us to do that. 161430088Sminshall */ 161530088Sminshall 161630088Sminshall int 161730088Sminshall DataToNetwork(buffer, count, done) 161830088Sminshall register char *buffer; /* where the data is */ 161930088Sminshall register int count; /* how much to send */ 162030088Sminshall int done; /* is this the last of a logical block */ 162130088Sminshall { 162230088Sminshall register int c; 162330088Sminshall int origCount; 162430088Sminshall fd_set o; 162530088Sminshall 162630088Sminshall origCount = count; 162730088Sminshall FD_ZERO(&o); 162830088Sminshall 162930088Sminshall while (count) { 163030088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 163130088Sminshall netflush(); 163230088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) { 163330088Sminshall FD_SET(net, &o); 163430088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 163530088Sminshall (struct timeval *) 0); 163630088Sminshall netflush(); 163730088Sminshall } 163830088Sminshall } 163930088Sminshall c = *buffer++; 164030088Sminshall count--; 164130088Sminshall if (c == IAC) { 164230088Sminshall *nfrontp++ = IAC; 164330088Sminshall *nfrontp++ = IAC; 164430088Sminshall } else { 164530088Sminshall *nfrontp++ = c; 164630088Sminshall } 164730088Sminshall } 164830088Sminshall 164930088Sminshall if (done && !count) { 165030088Sminshall *nfrontp++ = IAC; 165130088Sminshall *nfrontp++ = EOR; 165230088Sminshall netflush(); /* try to move along as quickly as ... */ 165330088Sminshall } 165430088Sminshall return(origCount - count); 165530088Sminshall } 165630088Sminshall 165730088Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 165830088Sminshall 165930088Sminshall int 166030088Sminshall DataToTerminal(buffer, count) 166130088Sminshall register char *buffer; /* where the data is */ 166230088Sminshall register int count; /* how much to send */ 166330088Sminshall { 166430088Sminshall int origCount; 166530088Sminshall fd_set o; 166630088Sminshall 166730088Sminshall origCount = count; 166830088Sminshall FD_ZERO(&o); 166930088Sminshall 167030088Sminshall while (count) { 167130088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 167230088Sminshall ttyflush(); 167330088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 167430088Sminshall FD_SET(tout, &o); 167530088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 167630088Sminshall (struct timeval *) 0); 167730088Sminshall ttyflush(); 167830088Sminshall } 167930088Sminshall } 168030088Sminshall *tfrontp++ = *buffer++; 168130088Sminshall count--; 168230088Sminshall } 168330088Sminshall return(origCount - count); 168430088Sminshall } 168530088Sminshall 168630088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 168730088Sminshall * Note that we consider the buffer to run all the 168830088Sminshall * way to the kernel (thus the select). 168930088Sminshall */ 169030088Sminshall 169130088Sminshall void 169230088Sminshall EmptyTerminal() 169330088Sminshall { 169430088Sminshall fd_set o; 169530088Sminshall 169630088Sminshall FD_ZERO(&o); 169730088Sminshall 169830088Sminshall if (tfrontp == tbackp) { 169930088Sminshall FD_SET(tout, &o); 170030088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 170130088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 170230088Sminshall } else { 170330088Sminshall while (tfrontp != tbackp) { 170430088Sminshall ttyflush(); 170530088Sminshall FD_SET(tout, &o); 170630088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 170730088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 170830088Sminshall } 170930088Sminshall } 171030088Sminshall } 171130088Sminshall 171230088Sminshall /* 171330088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 171430088Sminshall */ 171530088Sminshall 171630088Sminshall static int 171730088Sminshall Push3270() 171830088Sminshall { 171930088Sminshall int save = scc; 172030088Sminshall 172130088Sminshall if (scc) { 172230088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 172330088Sminshall if (Ibackp != Ibuf) { 172430088Sminshall bcopy(Ibackp, Ibuf, Ifrontp-Ibackp); 172530088Sminshall Ifrontp -= (Ibackp-Ibuf); 172630088Sminshall Ibackp = Ibuf; 172730088Sminshall } 172830088Sminshall } 172930088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 173030088Sminshall telrcv(); 173130088Sminshall } 173230088Sminshall } 173330088Sminshall return save != scc; 173430088Sminshall } 173530088Sminshall 173630088Sminshall 173730088Sminshall /* 173830088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 173930088Sminshall * before quitting. 174030088Sminshall */ 174130088Sminshall 174230088Sminshall static void 174330088Sminshall Finish3270() 174430088Sminshall { 174530088Sminshall while (Push3270() || !DoTerminalOutput()) { 174630088Sminshall ; 174730088Sminshall } 174830088Sminshall } 174930088Sminshall 175030088Sminshall 175130088Sminshall 175230088Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 175330088Sminshall 175430088Sminshall void 175530088Sminshall StringToTerminal(s) 175630088Sminshall char *s; 175730088Sminshall { 175830088Sminshall int count; 175930088Sminshall 176030088Sminshall count = strlen(s); 176130088Sminshall if (count) { 176230088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 176330088Sminshall } 176430088Sminshall } 176530088Sminshall 176630088Sminshall 176730088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) 176830088Sminshall /* _putchar - output a single character to the terminal. This name is so that 176930088Sminshall * curses(3x) can call us to send out data. 177030088Sminshall */ 177130088Sminshall 177230088Sminshall void 177330088Sminshall _putchar(c) 177430088Sminshall char c; 177530088Sminshall { 177630088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 177730088Sminshall (void) DataToTerminal(&c, 1); 177830088Sminshall } else { 177930088Sminshall *tfrontp++ = c; /* optimize if possible. */ 178030088Sminshall } 178130088Sminshall } 178230088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ 178330088Sminshall 178430088Sminshall static void 178530088Sminshall SetForExit() 178630088Sminshall { 178730088Sminshall setconnmode(); 178830088Sminshall if (In3270) { 178930088Sminshall Finish3270(); 179030088Sminshall } 179130088Sminshall setcommandmode(); 179230088Sminshall fflush(stdout); 179330088Sminshall fflush(stderr); 179430088Sminshall if (In3270) { 179530088Sminshall StopScreen(1); 179630088Sminshall } 179730088Sminshall setconnmode(); 179830088Sminshall setcommandmode(); 179930088Sminshall } 180030088Sminshall 180130088Sminshall static void 180230088Sminshall Exit(returnCode) 180330088Sminshall int returnCode; 180430088Sminshall { 180530088Sminshall SetForExit(); 180630088Sminshall exit(returnCode); 180730088Sminshall } 180830088Sminshall 180930088Sminshall void 181030088Sminshall ExitString(file, string, returnCode) 181130088Sminshall FILE *file; 181230088Sminshall char *string; 181330088Sminshall int returnCode; 181430088Sminshall { 181530088Sminshall SetForExit(); 181630088Sminshall fwrite(string, 1, strlen(string), file); 181730088Sminshall exit(returnCode); 181830088Sminshall } 181930088Sminshall 182030088Sminshall void 182130088Sminshall ExitPerror(string, returnCode) 182230088Sminshall char *string; 182330088Sminshall int returnCode; 182430088Sminshall { 182530088Sminshall SetForExit(); 182630088Sminshall perror(string); 182730088Sminshall exit(returnCode); 182830088Sminshall } 182930088Sminshall 183030088Sminshall #endif /* defined(TN3270) */ 183130088Sminshall 183230088Sminshall static 183330088Sminshall Scheduler(block) 183430088Sminshall int block; /* should we block in the select ? */ 183530088Sminshall { 183630088Sminshall register int c; 183730088Sminshall /* One wants to be a bit careful about setting returnValue 183830088Sminshall * to one, since a one implies we did some useful work, 183930088Sminshall * and therefore probably won't be called to block next 184030088Sminshall * time (TN3270 mode only). 184130088Sminshall */ 184230088Sminshall int returnValue = 0; 184330088Sminshall static struct timeval TimeValue = { 0 }; 184430088Sminshall 184530088Sminshall if (scc < 0 && tcc < 0) { 184630088Sminshall return -1; 184730088Sminshall } 184830088Sminshall 184930088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 185030088Sminshall FD_SET(net, &obits); 185130088Sminshall } 185230088Sminshall if (TTYBYTES()) { 185330088Sminshall FD_SET(tout, &obits); 185430088Sminshall } 185530088Sminshall if ((tcc == 0) && NETROOM()) { 185630088Sminshall FD_SET(tin, &ibits); 185730088Sminshall } 185830088Sminshall # if !defined(TN3270) 185930088Sminshall if (TTYROOM()) { 186030088Sminshall FD_SET(net, &ibits); 186130088Sminshall } 186230088Sminshall # else /* !defined(TN3270) */ 186330088Sminshall if (!ISend && TTYROOM()) { 186430088Sminshall FD_SET(net, &ibits); 186530088Sminshall } 186630088Sminshall # endif /* !defined(TN3270) */ 186730088Sminshall if (!SYNCHing) { 186830088Sminshall FD_SET(net, &xbits); 186930088Sminshall } 187030088Sminshall # if defined(TN3270) && defined(unix) 187130088Sminshall if (HaveInput) { 187230088Sminshall HaveInput = 0; 187330088Sminshall signal(SIGIO, inputAvailable); 187430088Sminshall } 187530088Sminshall #endif /* defined(TN3270) && defined(unix) */ 187630088Sminshall if ((c = select(16, &ibits, &obits, &xbits, 187730088Sminshall block? (struct timeval *)0 : &TimeValue)) < 1) { 187830088Sminshall if (c == -1) { 187930088Sminshall /* 188030088Sminshall * we can get EINTR if we are in line mode, 188130088Sminshall * and the user does an escape (TSTP), or 188230088Sminshall * some other signal generator. 188330088Sminshall */ 188430088Sminshall if (errno == EINTR) { 188530088Sminshall return 0; 188630088Sminshall } 188730088Sminshall # if defined(TN3270) 188830088Sminshall /* 188930088Sminshall * we can get EBADF if we were in transparent 189030088Sminshall * mode, and the transcom process died. 189130088Sminshall */ 189230088Sminshall if (errno == EBADF) { 189330088Sminshall /* 189430088Sminshall * zero the bits (even though kernel does it) 189530088Sminshall * to make sure we are selecting on the right 189630088Sminshall * ones. 189730088Sminshall */ 189830088Sminshall FD_ZERO(&ibits); 189930088Sminshall FD_ZERO(&obits); 190030088Sminshall FD_ZERO(&xbits); 190130088Sminshall return 0; 190230088Sminshall } 190330088Sminshall # endif /* defined(TN3270) */ 190430088Sminshall /* I don't like this, does it ever happen? */ 190530088Sminshall printf("sleep(5) from telnet, after select\r\n"); 190630088Sminshall #if defined(unix) 190730088Sminshall sleep(5); 190830088Sminshall #endif /* defined(unix) */ 190930088Sminshall } 191030088Sminshall return 0; 191130088Sminshall } 191230088Sminshall 191330088Sminshall /* 191430088Sminshall * Any urgent data? 191530088Sminshall */ 191630088Sminshall if (FD_ISSET(net, &xbits)) { 191730088Sminshall FD_CLR(net, &xbits); 191830088Sminshall SYNCHing = 1; 191930088Sminshall ttyflush(); /* flush already enqueued data */ 192030088Sminshall } 192130088Sminshall 192230088Sminshall /* 192330088Sminshall * Something to read from the network... 192430088Sminshall */ 192530088Sminshall if (FD_ISSET(net, &ibits)) { 192630088Sminshall int canread; 192730088Sminshall 192830088Sminshall FD_CLR(net, &ibits); 192930088Sminshall if (scc == 0) { 193030088Sminshall sbp = sibuf; 193130088Sminshall } 193230422Sminshall canread = sibuf + sizeof sibuf - (sbp+scc); 193330088Sminshall #if !defined(SO_OOBINLINE) 193430088Sminshall /* 193530088Sminshall * In 4.2 (and some early 4.3) systems, the 193630088Sminshall * OOB indication and data handling in the kernel 193730088Sminshall * is such that if two separate TCP Urgent requests 193830088Sminshall * come in, one byte of TCP data will be overlaid. 193930088Sminshall * This is fatal for Telnet, but we try to live 194030088Sminshall * with it. 194130088Sminshall * 194230088Sminshall * In addition, in 4.2 (and...), a special protocol 194330088Sminshall * is needed to pick up the TCP Urgent data in 194430088Sminshall * the correct sequence. 194530088Sminshall * 194630088Sminshall * What we do is: if we think we are in urgent 194730088Sminshall * mode, we look to see if we are "at the mark". 194830088Sminshall * If we are, we do an OOB receive. If we run 194930088Sminshall * this twice, we will do the OOB receive twice, 195030088Sminshall * but the second will fail, since the second 195130088Sminshall * time we were "at the mark", but there wasn't 195230088Sminshall * any data there (the kernel doesn't reset 195330088Sminshall * "at the mark" until we do a normal read). 195430088Sminshall * Once we've read the OOB data, we go ahead 195530088Sminshall * and do normal reads. 195630088Sminshall * 195730088Sminshall * There is also another problem, which is that 195830088Sminshall * since the OOB byte we read doesn't put us 195930088Sminshall * out of OOB state, and since that byte is most 196030088Sminshall * likely the TELNET DM (data mark), we would 196130088Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 196230088Sminshall * So, clocks to the rescue. If we've "just" 196330088Sminshall * received a DM, then we test for the 196430088Sminshall * presence of OOB data when the receive OOB 196530088Sminshall * fails (and AFTER we did the normal mode read 196630088Sminshall * to clear "at the mark"). 196730088Sminshall */ 196830088Sminshall if (SYNCHing) { 196930088Sminshall int atmark; 197030088Sminshall 197130088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 197230088Sminshall if (atmark) { 197330422Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 197430088Sminshall if ((c == -1) && (errno == EINVAL)) { 197530422Sminshall c = read(net, sbp+scc, canread); 197630088Sminshall if (clocks.didnetreceive < clocks.gotDM) { 197730088Sminshall SYNCHing = stilloob(net); 197830088Sminshall } 197930088Sminshall } 198030088Sminshall } else { 198130422Sminshall c = read(net, sbp+scc, canread); 198230088Sminshall } 198330088Sminshall } else { 198430422Sminshall c = read(net, sbp+scc, canread); 198530088Sminshall } 198630088Sminshall settimer(didnetreceive); 198730088Sminshall #else /* !defined(SO_OOBINLINE) */ 198830422Sminshall c = read(net, sbp+scc, canread); 198930088Sminshall #endif /* !defined(SO_OOBINLINE) */ 199030088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 199130088Sminshall c = 0; 199230088Sminshall } else if (c <= 0) { 199330088Sminshall return -1; 199430088Sminshall } 199530088Sminshall if (netdata) { 199630422Sminshall Dump('<', sbp+scc, c); 199730088Sminshall } 199830088Sminshall scc += c; 199930088Sminshall returnValue = 1; 200030088Sminshall } 200130088Sminshall 200230088Sminshall /* 200330088Sminshall * Something to read from the tty... 200430088Sminshall */ 200530088Sminshall if (FD_ISSET(tin, &ibits)) { 200630088Sminshall FD_CLR(tin, &ibits); 200730088Sminshall if (tcc == 0) { 200830088Sminshall tbp = tibuf; /* nothing left, reset */ 200930088Sminshall } 201030088Sminshall c = read(tin, tbp, tibuf+sizeof tibuf - tbp); 201130088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 201230088Sminshall c = 0; 201330088Sminshall } else { 201430088Sminshall /* EOF detection for line mode!!!! */ 201530088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 201630088Sminshall /* must be an EOF... */ 201730088Sminshall *tbp = ntc.t_eofc; 201830088Sminshall c = 1; 201930088Sminshall } 202030088Sminshall if (c <= 0) { 202130088Sminshall tcc = c; 202230088Sminshall return -1; 202330088Sminshall } 202430088Sminshall } 202530088Sminshall tcc += c; 202630088Sminshall returnValue = 1; /* did something useful */ 202730088Sminshall } 202830088Sminshall 202930088Sminshall # if defined(TN3270) 203030088Sminshall if (tcc > 0) { 203130088Sminshall if (In3270) { 203230088Sminshall c = DataFromTerminal(tbp, tcc); 203330088Sminshall if (c) { 203430088Sminshall returnValue = 1; 203530088Sminshall } 203630088Sminshall tcc -= c; 203730088Sminshall tbp += c; 203830088Sminshall } else { 203930320Sminshall # endif /* defined(TN3270) */ 204030088Sminshall returnValue = 1; 204130088Sminshall while (tcc > 0) { 204230088Sminshall register int sc; 204330088Sminshall 204430088Sminshall if (NETROOM() < 2) { 204530088Sminshall flushline = 1; 204630088Sminshall break; 204730088Sminshall } 204830088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 204930088Sminshall if (sc == escape) { 205030088Sminshall command(0); 205130088Sminshall tcc = 0; 205230088Sminshall flushline = 1; 205330088Sminshall break; 205430088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 205530088Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 205630088Sminshall tbp++; 205730088Sminshall tcc--; 205830088Sminshall } else { 205930088Sminshall dontlecho = !dontlecho; 206030088Sminshall settimer(echotoggle); 206130088Sminshall setconnmode(); 206230088Sminshall tcc = 0; 206330088Sminshall flushline = 1; 206430088Sminshall break; 206530088Sminshall } 206630088Sminshall } 206730088Sminshall if (localchars) { 206830088Sminshall if (sc == ntc.t_intrc) { 206930088Sminshall intp(); 207030088Sminshall break; 207130088Sminshall } else if (sc == ntc.t_quitc) { 207230088Sminshall sendbrk(); 207330088Sminshall break; 207430088Sminshall } else if (sc == nltc.t_flushc) { 207530088Sminshall NET2ADD(IAC, AO); 207630088Sminshall if (autoflush) { 207730088Sminshall doflush(); 207830088Sminshall } 207930088Sminshall break; 208030088Sminshall } else if (MODE_LOCAL_CHARS(globalmode)) { 208130088Sminshall ; 208230088Sminshall } else if (sc == nttyb.sg_kill) { 208330088Sminshall NET2ADD(IAC, EL); 208430088Sminshall break; 208530088Sminshall } else if (sc == nttyb.sg_erase) { 208630088Sminshall NET2ADD(IAC, EC); 208730088Sminshall break; 208830088Sminshall } 208930088Sminshall } 209030088Sminshall switch (c) { 209130088Sminshall case '\n': 209230088Sminshall /* 209330088Sminshall * If we are in CRMOD mode (\r ==> \n) 209430088Sminshall * on our local machine, then probably 209530088Sminshall * a newline (unix) is CRLF (TELNET). 209630088Sminshall */ 209730088Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 209830088Sminshall NETADD('\r'); 209930088Sminshall } 210030088Sminshall NETADD('\n'); 210130088Sminshall flushline = 1; 210230088Sminshall break; 210330088Sminshall case '\r': 210430088Sminshall NET2ADD('\r', '\0'); 210530088Sminshall flushline = 1; 210630088Sminshall break; 210730088Sminshall case IAC: 210830088Sminshall NET2ADD(IAC, IAC); 210930088Sminshall break; 211030088Sminshall default: 211130088Sminshall NETADD(c); 211230088Sminshall break; 211330088Sminshall } 211430088Sminshall } 211530088Sminshall # if defined(TN3270) 211630088Sminshall } 211730088Sminshall } 211830088Sminshall # endif /* defined(TN3270) */ 211930088Sminshall 212030088Sminshall if ((!MODE_LINE(globalmode) || flushline) && 212130088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 212230088Sminshall FD_CLR(net, &obits); 212330088Sminshall returnValue = netflush(); 212430088Sminshall } 212530088Sminshall if (scc > 0) { 212630088Sminshall # if !defined(TN3270) 212730088Sminshall telrcv(); 212830088Sminshall returnValue = 1; 212930088Sminshall # else /* !defined(TN3270) */ 213030088Sminshall returnValue = Push3270(); 213130088Sminshall # endif /* !defined(TN3270) */ 213230088Sminshall } 213330088Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) { 213430088Sminshall FD_CLR(tout, &obits); 213530088Sminshall returnValue = ttyflush(); 213630088Sminshall } 213730088Sminshall return returnValue; 213830088Sminshall } 213930088Sminshall 214030088Sminshall /* 214130088Sminshall * Select from tty and network... 214230088Sminshall */ 214330088Sminshall static void 214430088Sminshall telnet() 214530088Sminshall { 214630088Sminshall int on = 1; 214730088Sminshall #if defined(TN3270) && defined(unix) 214830088Sminshall int myPid; 214930088Sminshall #endif /* defined(TN3270) */ 215030088Sminshall 215130088Sminshall tout = fileno(stdout); 215230088Sminshall tin = fileno(stdin); 215330088Sminshall setconnmode(); 215430088Sminshall scc = 0; 215530088Sminshall tcc = 0; 215630088Sminshall FD_ZERO(&ibits); 215730088Sminshall FD_ZERO(&obits); 215830088Sminshall FD_ZERO(&xbits); 215930088Sminshall 216030088Sminshall ioctl(net, FIONBIO, (char *)&on); 216130088Sminshall 216230088Sminshall #if defined(TN3270) 216330088Sminshall #if !defined(DEBUG) /* DBX can't handle! */ 216430088Sminshall ioctl(net, FIOASYNC, (char *)&on); /* hear about input */ 216530088Sminshall #endif /* !defined(DEBUG) */ 216630088Sminshall 216730088Sminshall #if defined(unix) 216830088Sminshall myPid = getpid(); 216930088Sminshall #if defined(NOT43) 217030088Sminshall myPid = -myPid; 217130088Sminshall #endif /* defined(NOT43) */ 217230088Sminshall ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */ 217330088Sminshall #endif /* defined(unix) */ 217430088Sminshall 217530088Sminshall #endif /* defined(TN3270) */ 217630088Sminshall 217730088Sminshall #if defined(SO_OOBINLINE) 217830088Sminshall setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); 217930088Sminshall #endif /* defined(SO_OOBINLINE) */ 218030088Sminshall 218130320Sminshall # if !defined(TN3270) 218230088Sminshall if (telnetport) { 218330088Sminshall if (!hisopts[TELOPT_SGA]) { 218430088Sminshall willoption(TELOPT_SGA, 0); 218530088Sminshall } 218630088Sminshall if (!myopts[TELOPT_TTYPE]) { 218730088Sminshall dooption(TELOPT_TTYPE, 0); 218830088Sminshall } 218930088Sminshall } 219030320Sminshall # endif /* !defined(TN3270) */ 219130088Sminshall 219230088Sminshall # if !defined(TN3270) 219330088Sminshall for (;;) { 219430088Sminshall if (Scheduler(1) == -1) { 219530088Sminshall setcommandmode(); 219630088Sminshall return; 219730088Sminshall } 219830088Sminshall } 219930088Sminshall # else /* !defined(TN3270) */ 220030088Sminshall for (;;) { 220130088Sminshall int schedValue; 220230088Sminshall 220330088Sminshall while (!In3270) { 220430088Sminshall if (Scheduler(1) == -1) { 220530088Sminshall setcommandmode(); 220630088Sminshall return; 220730088Sminshall } 220830088Sminshall } 220930088Sminshall 221030088Sminshall while ((schedValue = Scheduler(0)) != 0) { 221130088Sminshall if (schedValue == -1) { 221230088Sminshall setcommandmode(); 221330088Sminshall return; 221430088Sminshall } 221530088Sminshall } 221630088Sminshall /* If there is data waiting to go out to terminal, don't 221730088Sminshall * schedule any more data for the terminal. 221830088Sminshall */ 221930088Sminshall if (tfrontp-tbackp) { 222030088Sminshall schedValue = 1; 222130088Sminshall } else { 222230088Sminshall schedValue = DoTerminalOutput(); 222330088Sminshall } 222430088Sminshall if (schedValue) { 222530088Sminshall if (Scheduler(1) == -1) { 222630088Sminshall setcommandmode(); 222730088Sminshall return; 222830088Sminshall } 222930088Sminshall } 223030088Sminshall } 223130088Sminshall # endif /* !defined(TN3270) */ 223230088Sminshall } 223330088Sminshall 223430088Sminshall /* 223530088Sminshall * The following are data structures and routines for 223630088Sminshall * the "send" command. 223730088Sminshall * 223830088Sminshall */ 223930088Sminshall 224030088Sminshall struct sendlist { 224130088Sminshall char *name; /* How user refers to it (case independent) */ 224230088Sminshall int what; /* Character to be sent (<0 ==> special) */ 224330088Sminshall char *help; /* Help information (0 ==> no help) */ 224430088Sminshall #if defined(NOT43) 224530088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 224630088Sminshall #else /* defined(NOT43) */ 224730088Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 224830088Sminshall #endif /* defined(NOT43) */ 224930088Sminshall }; 225030088Sminshall 225130088Sminshall #define SENDQUESTION -1 225230088Sminshall #define SENDESCAPE -3 225330088Sminshall 225430088Sminshall static struct sendlist Sendlist[] = { 225530088Sminshall { "ao", AO, "Send Telnet Abort output" }, 225630088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 225730088Sminshall { "brk", BREAK, "Send Telnet Break" }, 225830088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 225930088Sminshall { "el", EL, "Send Telnet Erase Line" }, 226030088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 226130088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 226230088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 226330088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 226430088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 226530088Sminshall { "?", SENDQUESTION, "Display send options" }, 226630088Sminshall { 0 } 226730088Sminshall }; 226830088Sminshall 226930088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 227030088Sminshall { "break", BREAK, 0 }, 227130088Sminshall 227230088Sminshall { "intp", IP, 0 }, 227330088Sminshall { "interrupt", IP, 0 }, 227430088Sminshall { "intr", IP, 0 }, 227530088Sminshall 227630088Sminshall { "help", SENDQUESTION, 0 }, 227730088Sminshall 227830088Sminshall { 0 } 227930088Sminshall }; 228030088Sminshall 228130088Sminshall static char ** 228230088Sminshall getnextsend(name) 228330088Sminshall char *name; 228430088Sminshall { 228530088Sminshall struct sendlist *c = (struct sendlist *) name; 228630088Sminshall 228730088Sminshall return (char **) (c+1); 228830088Sminshall } 228930088Sminshall 229030088Sminshall static struct sendlist * 229130088Sminshall getsend(name) 229230088Sminshall char *name; 229330088Sminshall { 229430088Sminshall struct sendlist *sl; 229530088Sminshall 229630088Sminshall if ((sl = (struct sendlist *) 229730088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 229830088Sminshall return sl; 229930088Sminshall } else { 230030088Sminshall return (struct sendlist *) 230130088Sminshall genget(name, (char **) Sendlist2, getnextsend); 230230088Sminshall } 230330088Sminshall } 230430088Sminshall 230530088Sminshall static 230630088Sminshall sendcmd(argc, argv) 230730088Sminshall int argc; 230830088Sminshall char **argv; 230930088Sminshall { 231030088Sminshall int what; /* what we are sending this time */ 231130088Sminshall int count; /* how many bytes we are going to need to send */ 231230088Sminshall int i; 231330088Sminshall int question = 0; /* was at least one argument a question */ 231430088Sminshall struct sendlist *s; /* pointer to current command */ 231530088Sminshall 231630088Sminshall if (argc < 2) { 231730088Sminshall printf("need at least one argument for 'send' command\n"); 231830088Sminshall printf("'send ?' for help\n"); 231930088Sminshall return 0; 232030088Sminshall } 232130088Sminshall /* 232230088Sminshall * First, validate all the send arguments. 232330088Sminshall * In addition, we see how much space we are going to need, and 232430088Sminshall * whether or not we will be doing a "SYNCH" operation (which 232530088Sminshall * flushes the network queue). 232630088Sminshall */ 232730088Sminshall count = 0; 232830088Sminshall for (i = 1; i < argc; i++) { 232930088Sminshall s = getsend(argv[i]); 233030088Sminshall if (s == 0) { 233130088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 233230088Sminshall argv[i]); 233330088Sminshall return 0; 233430088Sminshall } else if (s == Ambiguous(struct sendlist *)) { 233530088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 233630088Sminshall argv[i]); 233730088Sminshall return 0; 233830088Sminshall } 233930088Sminshall switch (s->what) { 234030088Sminshall case SENDQUESTION: 234130088Sminshall break; 234230088Sminshall case SENDESCAPE: 234330088Sminshall count += 1; 234430088Sminshall break; 234530088Sminshall case SYNCH: 234630088Sminshall count += 2; 234730088Sminshall break; 234830088Sminshall default: 234930088Sminshall count += 2; 235030088Sminshall break; 235130088Sminshall } 235230088Sminshall } 235330088Sminshall /* Now, do we have enough room? */ 235430088Sminshall if (NETROOM() < count) { 235530088Sminshall printf("There is not enough room in the buffer TO the network\n"); 235630088Sminshall printf("to process your request. Nothing will be done.\n"); 235730088Sminshall printf("('send synch' will throw away most data in the network\n"); 235830088Sminshall printf("buffer, if this might help.)\n"); 235930088Sminshall return 0; 236030088Sminshall } 236130088Sminshall /* OK, they are all OK, now go through again and actually send */ 236230088Sminshall for (i = 1; i < argc; i++) { 236330088Sminshall if ((s = getsend(argv[i])) == 0) { 236430088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 236530088Sminshall quit(); 236630088Sminshall /*NOTREACHED*/ 236730088Sminshall } 236830088Sminshall if (s->routine) { 236930088Sminshall (*s->routine)(s); 237030088Sminshall } else { 237130088Sminshall switch (what = s->what) { 237230088Sminshall case SYNCH: 237330088Sminshall dosynch(); 237430088Sminshall break; 237530088Sminshall case SENDQUESTION: 237630088Sminshall for (s = Sendlist; s->name; s++) { 237730088Sminshall if (s->help) { 237830088Sminshall printf(s->name); 237930088Sminshall if (s->help) { 238030088Sminshall printf("\t%s", s->help); 238130088Sminshall } 238230088Sminshall printf("\n"); 238330088Sminshall } 238430088Sminshall } 238530088Sminshall question = 1; 238630088Sminshall break; 238730088Sminshall case SENDESCAPE: 238830088Sminshall NETADD(escape); 238930088Sminshall break; 239030088Sminshall default: 239130088Sminshall NET2ADD(IAC, what); 239230088Sminshall break; 239330088Sminshall } 239430088Sminshall } 239530088Sminshall } 239630088Sminshall return !question; 239730088Sminshall } 239830088Sminshall 239930088Sminshall /* 240030088Sminshall * The following are the routines and data structures referred 240130088Sminshall * to by the arguments to the "toggle" command. 240230088Sminshall */ 240330088Sminshall 240430088Sminshall static 240530088Sminshall lclchars() 240630088Sminshall { 240730088Sminshall donelclchars = 1; 240830088Sminshall return 1; 240930088Sminshall } 241030088Sminshall 241130088Sminshall static 241230088Sminshall togdebug() 241330088Sminshall { 241430088Sminshall #ifndef NOT43 241530088Sminshall if (net > 0 && 241630088Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug)) 241730088Sminshall < 0) { 241830088Sminshall perror("setsockopt (SO_DEBUG)"); 241930088Sminshall } 242030320Sminshall #else /* NOT43 */ 242130088Sminshall if (debug) { 242230088Sminshall if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 242330088Sminshall perror("setsockopt (SO_DEBUG)"); 242430088Sminshall } else 242530088Sminshall printf("Cannot turn off socket debugging\n"); 242630320Sminshall #endif /* NOT43 */ 242730088Sminshall return 1; 242830088Sminshall } 242930088Sminshall 243030088Sminshall 243130088Sminshall 243230088Sminshall extern int togglehelp(); 243330088Sminshall 243430088Sminshall struct togglelist { 243530088Sminshall char *name; /* name of toggle */ 243630088Sminshall char *help; /* help message */ 243730088Sminshall int (*handler)(); /* routine to do actual setting */ 243830088Sminshall int dohelp; /* should we display help information */ 243930088Sminshall int *variable; 244030088Sminshall char *actionexplanation; 244130088Sminshall }; 244230088Sminshall 244330088Sminshall static struct togglelist Togglelist[] = { 244430088Sminshall { "autoflush", 244530088Sminshall "toggle flushing of output when sending interrupt characters", 244630088Sminshall 0, 244730088Sminshall 1, 244830088Sminshall &autoflush, 244930088Sminshall "flush output when sending interrupt characters" }, 245030088Sminshall { "autosynch", 245130088Sminshall "toggle automatic sending of interrupt characters in urgent mode", 245230088Sminshall 0, 245330088Sminshall 1, 245430088Sminshall &autosynch, 245530088Sminshall "send interrupt characters in urgent mode" }, 245630088Sminshall { "crmod", 245730088Sminshall "toggle mapping of received carriage returns", 245830088Sminshall 0, 245930088Sminshall 1, 246030088Sminshall &crmod, 246130088Sminshall "map carriage return on output" }, 246230088Sminshall { "localchars", 246330088Sminshall "toggle local recognition of certain control characters", 246430088Sminshall lclchars, 246530088Sminshall 1, 246630088Sminshall &localchars, 246730088Sminshall "recognize certain control characters" }, 246830088Sminshall { " ", "", 0, 1 }, /* empty line */ 246930088Sminshall { "debug", 247030088Sminshall "(debugging) toggle debugging", 247130088Sminshall togdebug, 247230088Sminshall 1, 247330088Sminshall &debug, 247430088Sminshall "turn on socket level debugging" }, 247530088Sminshall { "netdata", 247630088Sminshall "(debugging) toggle printing of hexadecimal network data", 247730088Sminshall 0, 247830088Sminshall 1, 247930088Sminshall &netdata, 248030088Sminshall "print hexadecimal representation of network traffic" }, 248130088Sminshall { "options", 248230088Sminshall "(debugging) toggle viewing of options processing", 248330088Sminshall 0, 248430088Sminshall 1, 248530088Sminshall &showoptions, 248630088Sminshall "show option processing" }, 248730088Sminshall { " ", "", 0, 1 }, /* empty line */ 248830088Sminshall { "?", 248930088Sminshall "display help information", 249030088Sminshall togglehelp, 249130088Sminshall 1 }, 249230088Sminshall { "help", 249330088Sminshall "display help information", 249430088Sminshall togglehelp, 249530088Sminshall 0 }, 249630088Sminshall { 0 } 249730088Sminshall }; 249830088Sminshall 249930088Sminshall static 250030088Sminshall togglehelp() 250130088Sminshall { 250230088Sminshall struct togglelist *c; 250330088Sminshall 250430088Sminshall for (c = Togglelist; c->name; c++) { 250530088Sminshall if (c->dohelp) { 250630088Sminshall printf("%s\t%s\n", c->name, c->help); 250730088Sminshall } 250830088Sminshall } 250930088Sminshall return 0; 251030088Sminshall } 251130088Sminshall 251230088Sminshall static char ** 251330088Sminshall getnexttoggle(name) 251430088Sminshall char *name; 251530088Sminshall { 251630088Sminshall struct togglelist *c = (struct togglelist *) name; 251730088Sminshall 251830088Sminshall return (char **) (c+1); 251930088Sminshall } 252030088Sminshall 252130088Sminshall static struct togglelist * 252230088Sminshall gettoggle(name) 252330088Sminshall char *name; 252430088Sminshall { 252530088Sminshall return (struct togglelist *) 252630088Sminshall genget(name, (char **) Togglelist, getnexttoggle); 252730088Sminshall } 252830088Sminshall 252930088Sminshall static 253030088Sminshall toggle(argc, argv) 253130088Sminshall int argc; 253230088Sminshall char *argv[]; 253330088Sminshall { 253430088Sminshall int retval = 1; 253530088Sminshall char *name; 253630088Sminshall struct togglelist *c; 253730088Sminshall 253830088Sminshall if (argc < 2) { 253930088Sminshall fprintf(stderr, 254030088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 254130088Sminshall return 0; 254230088Sminshall } 254330088Sminshall argc--; 254430088Sminshall argv++; 254530088Sminshall while (argc--) { 254630088Sminshall name = *argv++; 254730088Sminshall c = gettoggle(name); 254830088Sminshall if (c == Ambiguous(struct togglelist *)) { 254930088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 255030088Sminshall name); 255130088Sminshall return 0; 255230088Sminshall } else if (c == 0) { 255330088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 255430088Sminshall name); 255530088Sminshall return 0; 255630088Sminshall } else { 255730088Sminshall if (c->variable) { 255830088Sminshall *c->variable = !*c->variable; /* invert it */ 255930088Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 256030088Sminshall c->actionexplanation); 256130088Sminshall } 256230088Sminshall if (c->handler) { 256330088Sminshall retval &= (*c->handler)(c); 256430088Sminshall } 256530088Sminshall } 256630088Sminshall } 256730088Sminshall return retval; 256830088Sminshall } 256930088Sminshall 257030088Sminshall /* 257130088Sminshall * The following perform the "set" command. 257230088Sminshall */ 257330088Sminshall 257430088Sminshall struct setlist { 257530088Sminshall char *name; /* name */ 257630088Sminshall char *help; /* help information */ 257730088Sminshall char *charp; /* where it is located at */ 257830088Sminshall }; 257930088Sminshall 258030088Sminshall static struct setlist Setlist[] = { 258130088Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 258230088Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 258330088Sminshall { " ", "" }, 258430088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 258530088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 258630088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 258730088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 258830088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 258930088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 259030088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 259130088Sminshall { 0 } 259230088Sminshall }; 259330088Sminshall 259430088Sminshall static char ** 259530088Sminshall getnextset(name) 259630088Sminshall char *name; 259730088Sminshall { 259830088Sminshall struct setlist *c = (struct setlist *)name; 259930088Sminshall 260030088Sminshall return (char **) (c+1); 260130088Sminshall } 260230088Sminshall 260330088Sminshall static struct setlist * 260430088Sminshall getset(name) 260530088Sminshall char *name; 260630088Sminshall { 260730088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 260830088Sminshall } 260930088Sminshall 261030088Sminshall static 261130088Sminshall setcmd(argc, argv) 261230088Sminshall int argc; 261330088Sminshall char *argv[]; 261430088Sminshall { 261530088Sminshall int value; 261630088Sminshall struct setlist *ct; 261730088Sminshall 261830088Sminshall /* XXX back we go... sigh */ 261930088Sminshall if (argc != 3) { 262030088Sminshall if ((argc == 2) && 262130088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 262230088Sminshall for (ct = Setlist; ct->name; ct++) { 262330088Sminshall printf("%s\t%s\n", ct->name, ct->help); 262430088Sminshall } 262530088Sminshall printf("?\tdisplay help information\n"); 262630088Sminshall } else { 262730088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 262830088Sminshall } 262930088Sminshall return 0; 263030088Sminshall } 263130088Sminshall 263230088Sminshall ct = getset(argv[1]); 263330088Sminshall if (ct == 0) { 263430088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 263530088Sminshall argv[1]); 263630088Sminshall return 0; 263730088Sminshall } else if (ct == Ambiguous(struct setlist *)) { 263830088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 263930088Sminshall argv[1]); 264030088Sminshall return 0; 264130088Sminshall } else { 264230088Sminshall if (strcmp("off", argv[2])) { 264330088Sminshall value = special(argv[2]); 264430088Sminshall } else { 264530088Sminshall value = -1; 264630088Sminshall } 264730088Sminshall *(ct->charp) = value; 264830088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 264930088Sminshall } 265030088Sminshall return 1; 265130088Sminshall } 265230088Sminshall 265330088Sminshall /* 265430088Sminshall * The following are the data structures and routines for the 265530088Sminshall * 'mode' command. 265630088Sminshall */ 265730088Sminshall 265830088Sminshall static 265930088Sminshall dolinemode() 266030088Sminshall { 266130088Sminshall if (hisopts[TELOPT_SGA]) { 266230088Sminshall wontoption(TELOPT_SGA, 0); 266330088Sminshall } 266430088Sminshall if (hisopts[TELOPT_ECHO]) { 266530088Sminshall wontoption(TELOPT_ECHO, 0); 266630088Sminshall } 266730088Sminshall return 1; 266830088Sminshall } 266930088Sminshall 267030088Sminshall static 267130088Sminshall docharmode() 267230088Sminshall { 267330088Sminshall if (!hisopts[TELOPT_SGA]) { 267430088Sminshall willoption(TELOPT_SGA, 0); 267530088Sminshall } 267630088Sminshall if (!hisopts[TELOPT_ECHO]) { 267730088Sminshall willoption(TELOPT_ECHO, 0); 267830088Sminshall } 267930088Sminshall return 1; 268030088Sminshall } 268130088Sminshall 268230088Sminshall static struct cmd Modelist[] = { 268330088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 268430088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 268530088Sminshall { 0 }, 268630088Sminshall }; 268730088Sminshall 268830088Sminshall static char ** 268930088Sminshall getnextmode(name) 269030088Sminshall char *name; 269130088Sminshall { 269230088Sminshall struct cmd *c = (struct cmd *) name; 269330088Sminshall 269430088Sminshall return (char **) (c+1); 269530088Sminshall } 269630088Sminshall 269730088Sminshall static struct cmd * 269830088Sminshall getmodecmd(name) 269930088Sminshall char *name; 270030088Sminshall { 270130088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 270230088Sminshall } 270330088Sminshall 270430088Sminshall static 270530088Sminshall modecmd(argc, argv) 270630088Sminshall int argc; 270730088Sminshall char *argv[]; 270830088Sminshall { 270930088Sminshall struct cmd *mt; 271030088Sminshall 271130088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 271230088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 271330088Sminshall for (mt = Modelist; mt->name; mt++) { 271430088Sminshall printf("%s\t%s\n", mt->name, mt->help); 271530088Sminshall } 271630088Sminshall return 0; 271730088Sminshall } 271830088Sminshall mt = getmodecmd(argv[1]); 271930088Sminshall if (mt == 0) { 272030088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 272130088Sminshall return 0; 272230088Sminshall } else if (mt == Ambiguous(struct cmd *)) { 272330088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 272430088Sminshall return 0; 272530088Sminshall } else { 272630088Sminshall (*mt->handler)(); 272730088Sminshall } 272830088Sminshall return 1; 272930088Sminshall } 273030088Sminshall 273130088Sminshall /* 273230088Sminshall * The following data structures and routines implement the 273330088Sminshall * "display" command. 273430088Sminshall */ 273530088Sminshall 273630088Sminshall static 273730088Sminshall display(argc, argv) 273830088Sminshall int argc; 273930088Sminshall char *argv[]; 274030088Sminshall { 274130088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 274230088Sminshall if (*tl->variable) { \ 274330088Sminshall printf("will"); \ 274430088Sminshall } else { \ 274530088Sminshall printf("won't"); \ 274630088Sminshall } \ 274730088Sminshall printf(" %s.\n", tl->actionexplanation); \ 274830088Sminshall } 274930088Sminshall 275030088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 275130088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 275230088Sminshall } 275330088Sminshall 275430088Sminshall struct togglelist *tl; 275530088Sminshall struct setlist *sl; 275630088Sminshall 275730088Sminshall if (argc == 1) { 275830088Sminshall for (tl = Togglelist; tl->name; tl++) { 275930088Sminshall dotog(tl); 276030088Sminshall } 276130088Sminshall printf("\n"); 276230088Sminshall for (sl = Setlist; sl->name; sl++) { 276330088Sminshall doset(sl); 276430088Sminshall } 276530088Sminshall } else { 276630088Sminshall int i; 276730088Sminshall 276830088Sminshall for (i = 1; i < argc; i++) { 276930088Sminshall sl = getset(argv[i]); 277030088Sminshall tl = gettoggle(argv[i]); 277130088Sminshall if ((sl == Ambiguous(struct setlist *)) || 277230088Sminshall (tl == Ambiguous(struct togglelist *))) { 277330088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 277430088Sminshall return 0; 277530088Sminshall } else if (!sl && !tl) { 277630088Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 277730088Sminshall return 0; 277830088Sminshall } else { 277930088Sminshall if (tl) { 278030088Sminshall dotog(tl); 278130088Sminshall } 278230088Sminshall if (sl) { 278330088Sminshall doset(sl); 278430088Sminshall } 278530088Sminshall } 278630088Sminshall } 278730088Sminshall } 278830088Sminshall return 1; 278930088Sminshall #undef doset 279030088Sminshall #undef dotog 279130088Sminshall } 279230088Sminshall 279330088Sminshall /* 279430088Sminshall * The following are the data structures, and many of the routines, 279530088Sminshall * relating to command processing. 279630088Sminshall */ 279730088Sminshall 279830088Sminshall /* 279930088Sminshall * Set the escape character. 280030088Sminshall */ 280130088Sminshall static 280230088Sminshall setescape(argc, argv) 280330088Sminshall int argc; 280430088Sminshall char *argv[]; 280530088Sminshall { 280630088Sminshall register char *arg; 280730088Sminshall char buf[50]; 280830088Sminshall 280930088Sminshall printf( 281030088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 281130088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 281230088Sminshall if (argc > 2) 281330088Sminshall arg = argv[1]; 281430088Sminshall else { 281530088Sminshall printf("new escape character: "); 281630088Sminshall gets(buf); 281730088Sminshall arg = buf; 281830088Sminshall } 281930088Sminshall if (arg[0] != '\0') 282030088Sminshall escape = arg[0]; 282130088Sminshall if (!In3270) { 282230088Sminshall printf("Escape character is '%s'.\n", control(escape)); 282330088Sminshall } 282430088Sminshall fflush(stdout); 282530088Sminshall return 1; 282630088Sminshall } 282730088Sminshall 282830088Sminshall /*VARARGS*/ 282930088Sminshall static 283030088Sminshall togcrmod() 283130088Sminshall { 283230088Sminshall crmod = !crmod; 283330088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 283430088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 283530088Sminshall fflush(stdout); 283630088Sminshall return 1; 283730088Sminshall } 283830088Sminshall 283930088Sminshall /*VARARGS*/ 284030088Sminshall suspend() 284130088Sminshall { 284230088Sminshall setcommandmode(); 284330088Sminshall #if defined(unix) 284430088Sminshall kill(0, SIGTSTP); 284530088Sminshall #endif /* defined(unix) */ 284630088Sminshall /* reget parameters in case they were changed */ 284730088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 284830088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 284930088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 285030088Sminshall return 1; 285130088Sminshall } 285230088Sminshall 285330088Sminshall /*VARARGS*/ 285430088Sminshall static 285530326Sminshall bye(argc, argv) 285630326Sminshall int argc; /* Number of arguments */ 285730326Sminshall char *argv[]; /* arguments */ 285830088Sminshall { 285930088Sminshall if (connected) { 286030088Sminshall shutdown(net, 2); 286130088Sminshall printf("Connection closed.\n"); 286230088Sminshall close(net); 286330088Sminshall connected = 0; 286430088Sminshall /* reset options */ 286530326Sminshall tninit(); 286630088Sminshall #if defined(TN3270) 286730326Sminshall SetIn3270(); /* Get out of 3270 mode */ 286830088Sminshall #endif /* defined(TN3270) */ 286930088Sminshall } 287030326Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 287130326Sminshall longjmp(toplevel, 1); 287230326Sminshall /* NOTREACHED */ 287330326Sminshall } 287430326Sminshall return 1; /* Keep lint, etc., happy */ 287530088Sminshall } 287630088Sminshall 287730088Sminshall /*VARARGS*/ 287830088Sminshall quit() 287930088Sminshall { 288030326Sminshall (void) call(bye, "bye", "fromquit", 0); 288130088Sminshall Exit(0); 288230088Sminshall /*NOTREACHED*/ 288330088Sminshall return 1; /* just to keep lint happy */ 288430088Sminshall } 288530088Sminshall 288630088Sminshall /* 288730088Sminshall * Print status about the connection. 288830088Sminshall */ 288930088Sminshall static 289030088Sminshall status(argc, argv) 289130088Sminshall int argc; 289230088Sminshall char *argv[]; 289330088Sminshall { 289430088Sminshall if (connected) { 289530088Sminshall printf("Connected to %s.\n", hostname); 289630088Sminshall if (argc < 2) { 289730088Sminshall printf("Operating in %s.\n", 289830088Sminshall modelist[getconnmode()].modedescriptions); 289930088Sminshall if (localchars) { 290030088Sminshall printf("Catching signals locally.\n"); 290130088Sminshall } 290230088Sminshall } 290330088Sminshall } else { 290430088Sminshall printf("No connection.\n"); 290530088Sminshall } 290630088Sminshall # if !defined(TN3270) 290730088Sminshall printf("Escape character is '%s'.\n", control(escape)); 290830088Sminshall fflush(stdout); 290930088Sminshall # else /* !defined(TN3270) */ 291030088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 291130088Sminshall printf("Escape character is '%s'.\n", control(escape)); 291230088Sminshall } 291330088Sminshall # if defined(unix) 291430088Sminshall if (In3270 && transcom) { 291530088Sminshall printf("Transparent mode command is '%s'.\n", transcom); 291630088Sminshall } 291730088Sminshall # endif /* defined(unix) */ 291830088Sminshall fflush(stdout); 291930088Sminshall if (In3270) { 292030088Sminshall return 0; 292130088Sminshall } 292230088Sminshall # endif /* defined(TN3270) */ 292330088Sminshall return 1; 292430088Sminshall } 292530088Sminshall 292630088Sminshall #if defined(TN3270) && defined(unix) 292730088Sminshall static 292830088Sminshall settranscom(argc, argv) 292930088Sminshall int argc; 293030088Sminshall char *argv[]; 293130088Sminshall { 293230088Sminshall int i, len = 0; 293330088Sminshall char *strcpy(), *strcat(); 293430088Sminshall 293530088Sminshall if (argc == 1 && transcom) { 293630088Sminshall transcom = 0; 293730088Sminshall } 293830088Sminshall if (argc == 1) { 293930088Sminshall return; 294030088Sminshall } 294130088Sminshall for (i = 1; i < argc; ++i) { 294230088Sminshall len += 1 + strlen(argv[1]); 294330088Sminshall } 294430088Sminshall transcom = tline; 294530088Sminshall (void) strcpy(transcom, argv[1]); 294630088Sminshall for (i = 2; i < argc; ++i) { 294730088Sminshall (void) strcat(transcom, " "); 294830088Sminshall (void) strcat(transcom, argv[i]); 294930088Sminshall } 295030088Sminshall } 295130088Sminshall #endif /* defined(TN3270) && defined(unix) */ 295230088Sminshall 295330088Sminshall 295430088Sminshall static 295530088Sminshall tn(argc, argv) 295630088Sminshall int argc; 295730088Sminshall char *argv[]; 295830088Sminshall { 295930088Sminshall register struct hostent *host = 0; 296030088Sminshall #if defined(msdos) 296130088Sminshall char *cp; 296230320Sminshall #endif /* defined(msdos) */ 296330088Sminshall 296430088Sminshall if (connected) { 296530088Sminshall printf("?Already connected to %s\n", hostname); 296630088Sminshall return 0; 296730088Sminshall } 296830088Sminshall if (argc < 2) { 296930088Sminshall (void) strcpy(line, "Connect "); 297030088Sminshall printf("(to) "); 297130088Sminshall gets(&line[strlen(line)]); 297230088Sminshall makeargv(); 297330088Sminshall argc = margc; 297430088Sminshall argv = margv; 297530088Sminshall } 297630088Sminshall if (argc > 3) { 297730088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 297830088Sminshall return 0; 297930088Sminshall } 298030088Sminshall #if defined(msdos) 298130088Sminshall for (cp = argv[1]; *cp; cp++) { 298230088Sminshall if (isupper(*cp)) { 298330088Sminshall *cp = tolower(*cp); 298430088Sminshall } 298530088Sminshall } 298630088Sminshall #endif /* defined(msdos) */ 298730088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 298830088Sminshall if (sin.sin_addr.s_addr != -1) { 298930088Sminshall sin.sin_family = AF_INET; 299030088Sminshall (void) strcpy(hnamebuf, argv[1]); 299130088Sminshall hostname = hnamebuf; 299230088Sminshall } else { 299330088Sminshall host = gethostbyname(argv[1]); 299430088Sminshall if (host) { 299530088Sminshall sin.sin_family = host->h_addrtype; 299630088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 299730088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, host->h_length); 299830088Sminshall #else /* defined(h_addr) */ 299930088Sminshall bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length); 300030088Sminshall #endif /* defined(h_addr) */ 300130088Sminshall hostname = host->h_name; 300230088Sminshall } else { 300330088Sminshall printf("%s: unknown host\n", argv[1]); 300430088Sminshall return 0; 300530088Sminshall } 300630088Sminshall } 300730088Sminshall sin.sin_port = sp->s_port; 300830088Sminshall if (argc == 3) { 300930088Sminshall sin.sin_port = atoi(argv[2]); 301030088Sminshall if (sin.sin_port == 0) { 301130088Sminshall sp = getservbyname(argv[2], "tcp"); 301230088Sminshall if (sp) 301330088Sminshall sin.sin_port = sp->s_port; 301430088Sminshall else { 301530088Sminshall printf("%s: bad port number\n", argv[2]); 301630088Sminshall return 0; 301730088Sminshall } 301830088Sminshall } else { 301930088Sminshall sin.sin_port = atoi(argv[2]); 302030088Sminshall sin.sin_port = htons(sin.sin_port); 302130088Sminshall } 302230088Sminshall telnetport = 0; 302330088Sminshall } else { 302430088Sminshall telnetport = 1; 302530088Sminshall } 302630088Sminshall #if defined(unix) 302730088Sminshall signal(SIGINT, intr); 302830088Sminshall signal(SIGQUIT, intr2); 302930088Sminshall signal(SIGPIPE, deadpeer); 303030088Sminshall #endif /* defined(unix) */ 303130088Sminshall printf("Trying...\n"); 303230088Sminshall do { 303330088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 303430088Sminshall if (net < 0) { 303530088Sminshall perror("telnet: socket"); 303630088Sminshall return 0; 303730088Sminshall } 303830088Sminshall #ifndef NOT43 303930088Sminshall if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 304030088Sminshall (char *)&debug, sizeof(debug)) < 0) 304130320Sminshall #else /* NOT43 */ 304230088Sminshall if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 304330320Sminshall #endif /* NOT43 */ 304430088Sminshall perror("setsockopt (SO_DEBUG)"); 304530088Sminshall 304630088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 304730088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 304830088Sminshall if (host && host->h_addr_list[1]) { 304930088Sminshall int oerrno = errno; 305030088Sminshall 305130088Sminshall fprintf(stderr, "telnet: connect to address %s: ", 305230088Sminshall inet_ntoa(sin.sin_addr)); 305330088Sminshall errno = oerrno; 305430088Sminshall perror((char *)0); 305530088Sminshall host->h_addr_list++; 305630088Sminshall bcopy(host->h_addr_list[0], 305730088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 305830088Sminshall fprintf(stderr, "Trying %s...\n", 305930088Sminshall inet_ntoa(sin.sin_addr)); 306030088Sminshall (void) close(net); 306130088Sminshall continue; 306230088Sminshall } 306330088Sminshall #endif /* defined(h_addr) */ 306430088Sminshall perror("telnet: Unable to connect to remote host"); 306530088Sminshall #if defined(unix) 306630088Sminshall signal(SIGINT, SIG_DFL); 306730088Sminshall signal(SIGQUIT, SIG_DFL); 306830320Sminshall #endif /* defined(unix) */ 306930088Sminshall return 0; 307030088Sminshall } 307130088Sminshall connected++; 307230088Sminshall } while (connected == 0); 307330088Sminshall call(status, "status", "notmuch", 0); 307430088Sminshall if (setjmp(peerdied) == 0) 307530088Sminshall telnet(); 307630088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1); 307730088Sminshall /*NOTREACHED*/ 307830088Sminshall } 307930088Sminshall 308030088Sminshall 308130088Sminshall #define HELPINDENT (sizeof ("connect")) 308230088Sminshall 308330088Sminshall static char 308430088Sminshall openhelp[] = "connect to a site", 308530088Sminshall closehelp[] = "close current connection", 308630088Sminshall quithelp[] = "exit telnet", 308730088Sminshall zhelp[] = "suspend telnet", 308830088Sminshall statushelp[] = "print status information", 308930088Sminshall helphelp[] = "print help information", 309030088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 309130088Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 309230088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 309330088Sminshall displayhelp[] = "display operating parameters", 309430088Sminshall #if defined(TN3270) && defined(unix) 309530088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 309630088Sminshall #endif /* defined(TN3270) && defined(unix) */ 309730088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 309830088Sminshall 309930088Sminshall extern int help(); 310030088Sminshall 310130088Sminshall static struct cmd cmdtab[] = { 310230088Sminshall { "close", closehelp, bye, 1, 1 }, 310330088Sminshall { "display", displayhelp, display, 1, 0 }, 310430088Sminshall { "mode", modehelp, modecmd, 1, 1 }, 310530088Sminshall { "open", openhelp, tn, 1, 0 }, 310630088Sminshall { "quit", quithelp, quit, 1, 0 }, 310730088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 310830088Sminshall { "set", sethelp, setcmd, 1, 0 }, 310930088Sminshall { "status", statushelp, status, 1, 0 }, 311030088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 311130088Sminshall #if defined(TN3270) && defined(unix) 311230088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 311330088Sminshall #endif /* defined(TN3270) && defined(unix) */ 311430088Sminshall { "z", zhelp, suspend, 1, 0 }, 311530088Sminshall { "?", helphelp, help, 1, 0 }, 311630088Sminshall 0 311730088Sminshall }; 311830088Sminshall 311930088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 312030088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 312130088Sminshall 312230088Sminshall static struct cmd cmdtab2[] = { 312330088Sminshall { "help", helphelp, help, 0, 0 }, 312430088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 312530088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 312630088Sminshall 0 312730088Sminshall }; 312830088Sminshall 312930088Sminshall /* 313030088Sminshall * Call routine with argc, argv set from args (terminated by 0). 313130088Sminshall * VARARGS2 313230088Sminshall */ 313330088Sminshall static 313430088Sminshall call(routine, args) 313530088Sminshall int (*routine)(); 313630088Sminshall char *args; 313730088Sminshall { 313830088Sminshall register char **argp; 313930088Sminshall register int argc; 314030088Sminshall 314130088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 314230088Sminshall ; 314330088Sminshall return (*routine)(argc, &args); 314430088Sminshall } 314530088Sminshall 314630088Sminshall static char ** 314730088Sminshall getnextcmd(name) 314830088Sminshall char *name; 314930088Sminshall { 315030088Sminshall struct cmd *c = (struct cmd *) name; 315130088Sminshall 315230088Sminshall return (char **) (c+1); 315330088Sminshall } 315430088Sminshall 315530088Sminshall static struct cmd * 315630088Sminshall getcmd(name) 315730088Sminshall char *name; 315830088Sminshall { 315930088Sminshall struct cmd *cm; 316030088Sminshall 316130088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 316230088Sminshall return cm; 316330088Sminshall } else { 316430088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 316530088Sminshall } 316630088Sminshall } 316730088Sminshall 316830088Sminshall void 316930088Sminshall command(top) 317030088Sminshall int top; 317130088Sminshall { 317230088Sminshall register struct cmd *c; 317330088Sminshall 317430088Sminshall setcommandmode(); 317530088Sminshall if (!top) { 317630088Sminshall putchar('\n'); 317730088Sminshall } else { 317830088Sminshall #if defined(unix) 317930088Sminshall signal(SIGINT, SIG_DFL); 318030088Sminshall signal(SIGQUIT, SIG_DFL); 318130088Sminshall #endif /* defined(unix) */ 318230088Sminshall } 318330088Sminshall for (;;) { 318430088Sminshall printf("%s> ", prompt); 318530088Sminshall if (gets(line) == NULL) { 318630088Sminshall if (feof(stdin) || ferror(stdin)) 318730088Sminshall quit(); 318830088Sminshall break; 318930088Sminshall } 319030088Sminshall if (line[0] == 0) 319130088Sminshall break; 319230088Sminshall makeargv(); 319330088Sminshall c = getcmd(margv[0]); 319430088Sminshall if (c == Ambiguous(struct cmd *)) { 319530088Sminshall printf("?Ambiguous command\n"); 319630088Sminshall continue; 319730088Sminshall } 319830088Sminshall if (c == 0) { 319930088Sminshall printf("?Invalid command\n"); 320030088Sminshall continue; 320130088Sminshall } 320230088Sminshall if (c->needconnect && !connected) { 320330088Sminshall printf("?Need to be connected first.\n"); 320430088Sminshall continue; 320530088Sminshall } 320630088Sminshall if ((*c->handler)(margc, margv)) { 320730088Sminshall break; 320830088Sminshall } 320930088Sminshall } 321030088Sminshall if (!top) { 321130088Sminshall if (!connected) { 321230088Sminshall longjmp(toplevel, 1); 321330088Sminshall /*NOTREACHED*/ 321430088Sminshall } 321530088Sminshall setconnmode(); 321630088Sminshall } 321730088Sminshall } 321830088Sminshall 321930088Sminshall /* 322030088Sminshall * Help command. 322130088Sminshall */ 322230088Sminshall static 322330088Sminshall help(argc, argv) 322430088Sminshall int argc; 322530088Sminshall char *argv[]; 322630088Sminshall { 322730088Sminshall register struct cmd *c; 322830088Sminshall 322930088Sminshall if (argc == 1) { 323030088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 323130088Sminshall for (c = cmdtab; c->name; c++) 323230088Sminshall if (c->dohelp) { 323330088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 323430088Sminshall c->help); 323530088Sminshall } 323630088Sminshall return 0; 323730088Sminshall } 323830088Sminshall while (--argc > 0) { 323930088Sminshall register char *arg; 324030088Sminshall arg = *++argv; 324130088Sminshall c = getcmd(arg); 324230088Sminshall if (c == Ambiguous(struct cmd *)) 324330088Sminshall printf("?Ambiguous help command %s\n", arg); 324430088Sminshall else if (c == (struct cmd *)0) 324530088Sminshall printf("?Invalid help command %s\n", arg); 324630088Sminshall else 324730088Sminshall printf("%s\n", c->help); 324830088Sminshall } 324930088Sminshall return 0; 325030088Sminshall } 325130088Sminshall 325230088Sminshall /* 325330088Sminshall * main. Parse arguments, invoke the protocol or command parser. 325430088Sminshall */ 325530088Sminshall 325630088Sminshall 325730088Sminshall void 325830088Sminshall main(argc, argv) 325930088Sminshall int argc; 326030088Sminshall char *argv[]; 326130088Sminshall { 326230326Sminshall tninit(); /* Clear out things */ 326330326Sminshall 326430088Sminshall NetTrace = stdout; 326530088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 326630088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 326730088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 326830088Sminshall #if defined(LNOFLSH) 326930088Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 327030088Sminshall autoflush = !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 327130088Sminshall #else /* LNOFLSH */ 327230088Sminshall autoflush = 1; 327330088Sminshall #endif /* LNOFLSH */ 327430088Sminshall ntc = otc; 327530088Sminshall nltc = oltc; 327630088Sminshall nttyb = ottyb; 327730088Sminshall setbuf(stdin, (char *)0); 327830088Sminshall setbuf(stdout, (char *)0); 327930088Sminshall prompt = argv[0]; 328030088Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 328130088Sminshall debug = 1; 328230088Sminshall argv++; 328330088Sminshall argc--; 328430088Sminshall } 328530088Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 328630088Sminshall argv++; 328730088Sminshall argc--; 328830088Sminshall if (argc > 1) { /* get file name */ 328930088Sminshall NetTrace = fopen(argv[1], "w"); 329030088Sminshall argv++; 329130088Sminshall argc--; 329230088Sminshall if (NetTrace == NULL) { 329330088Sminshall NetTrace = stdout; 329430088Sminshall } 329530088Sminshall } 329630088Sminshall } 329730088Sminshall #if defined(TN3270) && defined(unix) 329830088Sminshall if (argc > 1 && !strcmp(argv[1], "-t")) { 329930088Sminshall argv++; 330030088Sminshall argc--; 330130088Sminshall if (argc > 1) { /* get command name */ 330230088Sminshall transcom = tline; 330330088Sminshall (void) strcpy(transcom, argv[1]); 330430088Sminshall argv++; 330530088Sminshall argc--; 330630088Sminshall } 330730088Sminshall } 330830088Sminshall #endif /* defined(TN3270) && defined(unix) */ 330930088Sminshall if (argc != 1) { 331030088Sminshall if (setjmp(toplevel) != 0) 331130088Sminshall Exit(0); 331230088Sminshall tn(argc, argv); 331330088Sminshall } 331430088Sminshall setjmp(toplevel); 331530088Sminshall for (;;) 331630088Sminshall command(1); 331730088Sminshall } 3318