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