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