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 * 71*31131Sminshall * MSDOS - Compiles in MSDOS specific stuff. 7230088Sminshall * 7330088Sminshall */ 7430088Sminshall 7530088Sminshall #if !defined(TN3270) 7630088Sminshall #define ExitString(f,s,r) { fprintf(f, s); exit(r); } 7730088Sminshall #define Exit(x) exit(x) 7830088Sminshall #define SetIn3270() 7930088Sminshall 8030088Sminshall void setcommandmode(), command(); /* forward declarations */ 8130088Sminshall #endif /* !defined(TN3270) */ 8230088Sminshall 8330088Sminshall #include <sys/types.h> 8430088Sminshall #include <sys/socket.h> 8530088Sminshall 8630088Sminshall #include <netinet/in.h> 8730088Sminshall 8831124Sminshall #if defined(unix) 8931124Sminshall /* By the way, we need to include curses.h before telnet.h since, 9031124Sminshall * among other things, telnet.h #defines 'DO', which is a variable 9131124Sminshall * declared in curses.h. 9231124Sminshall */ 9330088Sminshall #include <curses.h> 9431124Sminshall #endif /* defined(unix) */ 9530088Sminshall 9630088Sminshall #define TELOPTS 9730088Sminshall #include <arpa/telnet.h> 9830088Sminshall 9930088Sminshall #if !defined(NOT43) 10030088Sminshall #include <arpa/inet.h> 10130088Sminshall #else /* !defined(NOT43) */ 10230088Sminshall extern unsigned long inet_addr(); 10330088Sminshall extern char *inet_ntoa(); 10430088Sminshall #endif /* !defined(NOT43) */ 10530088Sminshall 10630088Sminshall #include <stdio.h> 10730088Sminshall #include <ctype.h> 10830088Sminshall #include <errno.h> 10930088Sminshall #include <setjmp.h> 11030088Sminshall #include <netdb.h> 11131124Sminshall 11231124Sminshall #if defined(unix) 11330088Sminshall #include <strings.h> 11431124Sminshall #else /* defined(unix) */ 11531124Sminshall #include <string.h> 11631124Sminshall #endif /* defined(unix) */ 11730088Sminshall 11830088Sminshall #if defined(TN3270) 11930088Sminshall #include "ctlr/screen.h" 12030088Sminshall #include "system/globals.h" 12130088Sminshall #include "telnet.ext" 12230088Sminshall #include "ctlr/options.ext" 12330088Sminshall #include "ctlr/outbound.ext" 12430088Sminshall #include "keyboard/termin.ext" 125*31131Sminshall #endif /* defined(TN3270) */ 12630722Sminshall #include "general.h" 12730088Sminshall 12830088Sminshall 12930088Sminshall 13030088Sminshall #ifndef FD_SETSIZE 13130088Sminshall /* 13230088Sminshall * The following is defined just in case someone should want to run 13330088Sminshall * this telnet on a 4.2 system. 13430088Sminshall * 13530088Sminshall */ 13630088Sminshall 13730088Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 13830088Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 13930088Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 14030088Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 14130088Sminshall 14230088Sminshall #endif 14330088Sminshall 14430088Sminshall #define strip(x) ((x)&0x7f) 14530088Sminshall #define min(x,y) ((x<y)? x:y) 14630088Sminshall 14730088Sminshall #if defined(TN3270) 14830326Sminshall static char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 14930088Sminshall #endif /* defined(TN3270) */ 15030088Sminshall 15130326Sminshall static char ttyobuf[2*BUFSIZ], *tfrontp, *tbackp; 15230088Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } 15330088Sminshall #define TTYLOC() (tfrontp) 15430088Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) 15530088Sminshall #define TTYMIN() (netobuf) 15630088Sminshall #define TTYBYTES() (tfrontp-tbackp) 15730088Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1) 15830088Sminshall 15930326Sminshall static char netobuf[2*BUFSIZ], *nfrontp, *nbackp; 16030088Sminshall #define NETADD(c) { *nfrontp++ = c; } 16130088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 16230088Sminshall #define NETLOC() (nfrontp) 16330088Sminshall #define NETMAX() (netobuf+sizeof netobuf-1) 16430088Sminshall #define NETBYTES() (nfrontp-nbackp) 16530088Sminshall #define NETROOM() (NETMAX()-NETLOC()+1) 16630326Sminshall static char *neturg; /* one past last byte of urgent data */ 16730088Sminshall 16830326Sminshall static char subbuffer[100], 16930326Sminshall *subpointer, *subend; /* buffer for sub-options */ 17030088Sminshall #define SB_CLEAR() subpointer = subbuffer; 17130088Sminshall #define SB_TERM() subend = subpointer; 17230088Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 17330088Sminshall *subpointer++ = (c); \ 17430088Sminshall } 17530088Sminshall 17630088Sminshall static char sb_terminal[] = { IAC, SB, 17730088Sminshall TELOPT_TTYPE, TELQUAL_IS, 17830088Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 17930088Sminshall IAC, SE }; 18030088Sminshall #define SBTERMMODEL 13 18130088Sminshall 18230088Sminshall 18330326Sminshall static char hisopts[256]; 18430326Sminshall static char myopts[256]; 18530088Sminshall 18630088Sminshall static char doopt[] = { IAC, DO, '%', 'c', 0 }; 18730088Sminshall static char dont[] = { IAC, DONT, '%', 'c', 0 }; 18830088Sminshall static char will[] = { IAC, WILL, '%', 'c', 0 }; 18930088Sminshall static char wont[] = { IAC, WONT, '%', 'c', 0 }; 19030088Sminshall 19130088Sminshall struct cmd { 19230088Sminshall char *name; /* command name */ 19330088Sminshall char *help; /* help string */ 19430088Sminshall int (*handler)(); /* routine which executes command */ 19530088Sminshall int dohelp; /* Should we give general help information? */ 19630088Sminshall int needconnect; /* Do we need to be connected to execute? */ 19730088Sminshall }; 19830088Sminshall 19930326Sminshall static char sibuf[BUFSIZ], *sbp; 20030088Sminshall static char tibuf[BUFSIZ], *tbp; 20130088Sminshall static fd_set ibits, obits, xbits; 20230088Sminshall 20330088Sminshall 20430088Sminshall static int 20530326Sminshall connected, 20630326Sminshall net, 20730326Sminshall scc, 20830326Sminshall tcc, 20930326Sminshall showoptions, 21030326Sminshall In3270, /* Are we in 3270 mode? */ 21130326Sminshall ISend, /* trying to send network data in */ 21230088Sminshall debug = 0, 21330326Sminshall crmod, 21430326Sminshall netdata, 21530722Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 21630088Sminshall telnetport = 1; 21730088Sminshall 21830326Sminshall static FILE *NetTrace = 0; /* Not in bss, since needs to stay */ 21930088Sminshall 22030088Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 22130088Sminshall 22230088Sminshall static char 22330088Sminshall *prompt = 0, 22430326Sminshall escape, 22530326Sminshall echoc; 22630088Sminshall 22730088Sminshall static int 22830326Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 22930326Sminshall flushout, /* flush output */ 23030088Sminshall autoflush = 0, /* flush output when interrupting? */ 23130326Sminshall autosynch, /* send interrupt characters with SYNCH? */ 23230326Sminshall localchars, /* we recognize interrupt/quit */ 23330326Sminshall donelclchars, /* the user has set "localchars" */ 23431124Sminshall dontlecho, /* do we suppress local echoing right now? */ 23531124Sminshall globalmode; 23630088Sminshall 23730088Sminshall /* The following are some tn3270 specific flags */ 23830088Sminshall #if defined(TN3270) 23930088Sminshall 24030088Sminshall static int 24130326Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 24230088Sminshall 243*31131Sminshall /* Some real, live, globals. */ 244*31131Sminshall int 245*31131Sminshall tout, /* Output file descriptor */ 246*31131Sminshall tin; /* Input file descriptor */ 247*31131Sminshall 248*31131Sminshall #else /* defined(TN3270) */ 249*31131Sminshall static int tin, tout; /* file descriptors */ 250*31131Sminshall #endif /* defined(TN3270) */ 251*31131Sminshall 252*31131Sminshall 25330722Sminshall /* 25430722Sminshall * Telnet receiver states for fsm 25530722Sminshall */ 25630722Sminshall #define TS_DATA 0 25730722Sminshall #define TS_IAC 1 25830722Sminshall #define TS_WILL 2 25930722Sminshall #define TS_WONT 3 26030722Sminshall #define TS_DO 4 26130722Sminshall #define TS_DONT 5 26230722Sminshall #define TS_CR 6 26330722Sminshall #define TS_SB 7 /* sub-option collection */ 26430722Sminshall #define TS_SE 8 /* looking for sub-option end */ 26530722Sminshall 26630722Sminshall static int telrcv_state = TS_DATA; 26730088Sminshall 26830088Sminshall static char line[200]; 26930326Sminshall static int margc; 27030088Sminshall static char *margv[20]; 27130088Sminshall 27231124Sminshall static jmp_buf toplevel = { 0 }; 27330088Sminshall static jmp_buf peerdied; 27430088Sminshall 27530088Sminshall extern int errno; 27630088Sminshall 27730088Sminshall 27830088Sminshall static struct sockaddr_in sin; 27930088Sminshall 28030088Sminshall static struct servent *sp = 0; 28130088Sminshall 28230326Sminshall static int flushline; 28330088Sminshall 28430326Sminshall static char *hostname; 28530088Sminshall static char hnamebuf[32]; 28630088Sminshall 28730088Sminshall /* 28830088Sminshall * The following are some clocks used to decide how to interpret 28930088Sminshall * the relationship between various variables. 29030088Sminshall */ 29130088Sminshall 29230088Sminshall static struct { 29330088Sminshall int 29430088Sminshall system, /* what the current time is */ 29530088Sminshall echotoggle, /* last time user entered echo character */ 29630088Sminshall modenegotiated, /* last time operating mode negotiated */ 29730088Sminshall didnetreceive, /* last time we read data from network */ 29830088Sminshall gotDM; /* when did we last see a data mark */ 29930326Sminshall } clocks; 30030088Sminshall 30130088Sminshall #define settimer(x) clocks.x = clocks.system++ 30230088Sminshall 30331124Sminshall /* Various modes */ 30431124Sminshall #define MODE_LINE(m) (modelist[m].modetype & LINE) 30531124Sminshall #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS) 306*31131Sminshall #define MODE_LOCAL_ECHO(m) (modelist[m].modetype & LOCAL_ECHO) 307*31131Sminshall #define MODE_COMMAND_LINE(m) (modelist[m].modetype & COMMAND_LINE) 30831124Sminshall 30931124Sminshall #define LOCAL_CHARS 0x01 /* Characters processed locally */ 31031124Sminshall #define LINE 0x02 /* Line-by-line mode of operation */ 311*31131Sminshall #define LOCAL_ECHO 0x04 /* Echoing locally */ 312*31131Sminshall #define COMMAND_LINE 0x08 /* Command line mode */ 31331124Sminshall 31431124Sminshall static struct { 31531124Sminshall char *modedescriptions; 31631124Sminshall char modetype; 31731124Sminshall } modelist[] = { 318*31131Sminshall { "telnet command mode", COMMAND_LINE }, 31931124Sminshall { "character-at-a-time mode", 0 }, 320*31131Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 32131124Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 322*31131Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 32331124Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 32431124Sminshall { "3270 mode", 0 }, 32531124Sminshall }; 32631124Sminshall 32731124Sminshall 32830088Sminshall /* 32931124Sminshall * The following routines try to encapsulate what is system dependent 33031124Sminshall * (at least between 4.x and dos) which is used in telnet.c. 33131124Sminshall */ 33231124Sminshall 33331124Sminshall #if defined(unix) 33431124Sminshall #include <sys/ioctl.h> 33531124Sminshall #include <sys/time.h> 33631124Sminshall #include <signal.h> 33731124Sminshall 33831124Sminshall int 33931124Sminshall HaveInput; /* There is input available to scan */ 34031124Sminshall 34131124Sminshall #if defined(TN3270) 34231124Sminshall static char tline[200]; 34331124Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 34431124Sminshall #endif /* defined(TN3270) */ 34531124Sminshall 34631124Sminshall static struct tchars otc = { 0 }, ntc = { 0 }; 34731124Sminshall static struct ltchars oltc = { 0 }, nltc = { 0 }; 34831124Sminshall static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 34931124Sminshall 35031124Sminshall 351*31131Sminshall #define TerminalWrite(fd,buf,n) write(fd,buf,n) 352*31131Sminshall #define TerminalRead(fd,buf,n) read(fd,buf,n) 353*31131Sminshall 35431124Sminshall /* 35531124Sminshall * 35631124Sminshall */ 35731124Sminshall 35831124Sminshall static int 359*31131Sminshall TerminalAutoFlush() /* unix */ 36031124Sminshall { 36131124Sminshall #if defined(LNOFLSH) 36231124Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 36331124Sminshall return !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 36431124Sminshall #else /* LNOFLSH */ 36531124Sminshall return 1; 36631124Sminshall #endif /* LNOFLSH */ 36731124Sminshall } 36831124Sminshall 36931124Sminshall /* 370*31131Sminshall * TerminalSpecialChars() 37131124Sminshall * 372*31131Sminshall * Look at an input character to see if it is a special character 373*31131Sminshall * and decide what to do. 37431124Sminshall * 37531124Sminshall * Output: 37631124Sminshall * 37731124Sminshall * 0 Don't add this character. 37831124Sminshall * 1 Do add this character 37931124Sminshall */ 38031124Sminshall 38131124Sminshall int 382*31131Sminshall TerminalSpecialChars(c) /* unix */ 38331124Sminshall int c; 38431124Sminshall { 38531124Sminshall void doflush(), intp(), sendbrk(); 38631124Sminshall 38731124Sminshall if (c == ntc.t_intrc) { 38831124Sminshall intp(); 38931124Sminshall return 0; 39031124Sminshall } else if (c == ntc.t_quitc) { 39131124Sminshall sendbrk(); 39231124Sminshall return 0; 39331124Sminshall } else if (c == nltc.t_flushc) { 39431124Sminshall NET2ADD(IAC, AO); 39531124Sminshall if (autoflush) { 39631124Sminshall doflush(); 39731124Sminshall } 39831124Sminshall return 0; 39931124Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 40031124Sminshall if (c == nttyb.sg_kill) { 40131124Sminshall NET2ADD(IAC, EL); 40231124Sminshall return 0; 40331124Sminshall } else if (c == nttyb.sg_erase) { 40431124Sminshall NET2ADD(IAC, EC); 40531124Sminshall return 0; 40631124Sminshall } 40731124Sminshall } 40831124Sminshall return 1; 40931124Sminshall } 41031124Sminshall 41131124Sminshall 41231124Sminshall /* 41331124Sminshall * Flush output to the terminal 41431124Sminshall */ 41531124Sminshall 41631124Sminshall static void 41731124Sminshall TerminalFlushOutput() /* unix */ 41831124Sminshall { 41931124Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 42031124Sminshall } 42131124Sminshall 42231124Sminshall static void 42331124Sminshall TerminalSaveState() /* unix */ 42431124Sminshall { 42531124Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 42631124Sminshall ioctl(0, TIOCGETC, (char *)&otc); 42731124Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 42831124Sminshall 42931124Sminshall ntc = otc; 43031124Sminshall nltc = oltc; 43131124Sminshall nttyb = ottyb; 43231124Sminshall } 43331124Sminshall 43431124Sminshall static void 43531124Sminshall TerminalRestoreState() /* unix */ 43631124Sminshall { 43731124Sminshall } 43831124Sminshall 43931124Sminshall /* 44031124Sminshall * TerminalNewMode - set up terminal to a specific mode. 44131124Sminshall */ 44231124Sminshall 44331124Sminshall 44431124Sminshall static void 445*31131Sminshall TerminalNewMode(f) /* unix */ 44631124Sminshall register int f; 44731124Sminshall { 44831124Sminshall static int prevmode = 0; 44931124Sminshall struct tchars *tc; 45031124Sminshall struct tchars tc3; 45131124Sminshall struct ltchars *ltc; 45231124Sminshall struct sgttyb sb; 45331124Sminshall int onoff; 45431124Sminshall int old; 45531124Sminshall struct tchars notc2; 45631124Sminshall struct ltchars noltc2; 45731124Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 45831124Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 45931124Sminshall 46031124Sminshall globalmode = f; 46131124Sminshall if (prevmode == f) 46231124Sminshall return; 46331124Sminshall old = prevmode; 46431124Sminshall prevmode = f; 46531124Sminshall sb = nttyb; 46631124Sminshall 46731124Sminshall switch (f) { 46831124Sminshall 46931124Sminshall case 0: 47031124Sminshall onoff = 0; 47131124Sminshall tc = &otc; 47231124Sminshall ltc = &oltc; 47331124Sminshall break; 47431124Sminshall 47531124Sminshall case 1: /* remote character processing, remote echo */ 47631124Sminshall case 2: /* remote character processing, local echo */ 47731124Sminshall case 6: /* 3270 mode - like 1, but with xon/xoff local */ 47831124Sminshall /* (might be nice to have "6" in telnet also...) */ 47931124Sminshall sb.sg_flags |= CBREAK; 48031124Sminshall if ((f == 1) || (f == 6)) { 48131124Sminshall sb.sg_flags &= ~(ECHO|CRMOD); 48231124Sminshall } else { 48331124Sminshall sb.sg_flags |= ECHO|CRMOD; 48431124Sminshall } 48531124Sminshall sb.sg_erase = sb.sg_kill = -1; 48631124Sminshall if (f == 6) { 48731124Sminshall tc = &tc3; 48831124Sminshall tc3 = notc; 48931124Sminshall /* get XON, XOFF characters */ 49031124Sminshall tc3.t_startc = otc.t_startc; 49131124Sminshall tc3.t_stopc = otc.t_stopc; 49231124Sminshall } else { 49331124Sminshall /* 49431124Sminshall * If user hasn't specified one way or the other, 49531124Sminshall * then default to not trapping signals. 49631124Sminshall */ 49731124Sminshall if (!donelclchars) { 49831124Sminshall localchars = 0; 49931124Sminshall } 50031124Sminshall if (localchars) { 50131124Sminshall notc2 = notc; 50231124Sminshall notc2.t_intrc = ntc.t_intrc; 50331124Sminshall notc2.t_quitc = ntc.t_quitc; 50431124Sminshall tc = ¬c2; 50531124Sminshall } else { 50631124Sminshall tc = ¬c; 50731124Sminshall } 50831124Sminshall } 50931124Sminshall ltc = &noltc; 51031124Sminshall onoff = 1; 51131124Sminshall break; 51231124Sminshall case 3: /* local character processing, remote echo */ 51331124Sminshall case 4: /* local character processing, local echo */ 51431124Sminshall case 5: /* local character processing, no echo */ 51531124Sminshall sb.sg_flags &= ~CBREAK; 51631124Sminshall sb.sg_flags |= CRMOD; 51731124Sminshall if (f == 4) 51831124Sminshall sb.sg_flags |= ECHO; 51931124Sminshall else 52031124Sminshall sb.sg_flags &= ~ECHO; 52131124Sminshall notc2 = ntc; 52231124Sminshall tc = ¬c2; 52331124Sminshall noltc2 = oltc; 52431124Sminshall ltc = &noltc2; 52531124Sminshall /* 52631124Sminshall * If user hasn't specified one way or the other, 52731124Sminshall * then default to trapping signals. 52831124Sminshall */ 52931124Sminshall if (!donelclchars) { 53031124Sminshall localchars = 1; 53131124Sminshall } 53231124Sminshall if (localchars) { 53331124Sminshall notc2.t_brkc = nltc.t_flushc; 53431124Sminshall noltc2.t_flushc = -1; 53531124Sminshall } else { 53631124Sminshall notc2.t_intrc = notc2.t_quitc = -1; 53731124Sminshall } 53831124Sminshall noltc2.t_suspc = escape; 53931124Sminshall noltc2.t_dsuspc = -1; 54031124Sminshall onoff = 1; 54131124Sminshall break; 54231124Sminshall 54331124Sminshall default: 54431124Sminshall return; 54531124Sminshall } 54631124Sminshall ioctl(tin, TIOCSLTC, (char *)ltc); 54731124Sminshall ioctl(tin, TIOCSETC, (char *)tc); 54831124Sminshall ioctl(tin, TIOCSETP, (char *)&sb); 54931124Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 55031124Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 55131124Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 55231124Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 55331124Sminshall #if defined(TN3270) && !defined(DEBUG) 55431124Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 55531124Sminshall #endif /* defined(TN3270) && !defined(DEBUG) */ 55631124Sminshall 55731124Sminshall if (MODE_LINE(f)) { 55831124Sminshall void doescape(); 55931124Sminshall 56031124Sminshall signal(SIGTSTP, doescape); 56131124Sminshall } else if (MODE_LINE(old)) { 56231124Sminshall signal(SIGTSTP, SIG_DFL); 56331124Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 56431124Sminshall } 56531124Sminshall } 56631124Sminshall 56731124Sminshall 568*31131Sminshall int 569*31131Sminshall NetClose(net) 570*31131Sminshall int net; 571*31131Sminshall { 572*31131Sminshall return close(net); 573*31131Sminshall } 574*31131Sminshall 575*31131Sminshall 57631124Sminshall static void 57731124Sminshall NetNonblockingIO(fd, onoff) /* unix */ 57831124Sminshall int 57931124Sminshall fd, 58031124Sminshall onoff; 58131124Sminshall { 58231124Sminshall ioctl(net, FIONBIO, (char *)&onoff); 58331124Sminshall } 58431124Sminshall 58531124Sminshall static void 58631124Sminshall NetSigIO(fd, onoff) /* unix */ 58731124Sminshall int 58831124Sminshall fd, 58931124Sminshall onoff; 59031124Sminshall { 59131124Sminshall ioctl(net, FIOASYNC, (char *)&onoff); /* hear about input */ 59231124Sminshall } 59331124Sminshall 59431124Sminshall static void 59531124Sminshall NetSetPgrp(fd) /* unix */ 59631124Sminshall int fd; 59731124Sminshall { 59831124Sminshall int myPid; 59931124Sminshall 60031124Sminshall myPid = getpid(); 60131124Sminshall #if defined(NOT43) 60231124Sminshall myPid = -myPid; 60331124Sminshall #endif /* defined(NOT43) */ 60431124Sminshall ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */ 60531124Sminshall } 60631124Sminshall 60731124Sminshall 60831124Sminshall #endif /* defined(unix) */ 60931124Sminshall 61031124Sminshall #if defined(MSDOS) 61131124Sminshall #include <time.h> 612*31131Sminshall #include <signal.h> 61331124Sminshall 61431124Sminshall #if !defined(SO_OOBINLINE) 61531124Sminshall #define SO_OOBINLINE 61631124Sminshall #endif /* !defined(SO_OOBINLINE) */ 61731124Sminshall 61831124Sminshall 61931124Sminshall static char 620*31131Sminshall termEofChar, 62131124Sminshall termEraseChar, 62231124Sminshall termFlushChar, 62331124Sminshall termIntChar, 62431124Sminshall termKillChar, 625*31131Sminshall termLiteralNextChar, 626*31131Sminshall termQuitChar; 62731124Sminshall 628*31131Sminshall 629*31131Sminshall /* 630*31131Sminshall * MSDOS doesn't have anyway of deciding whether a full-edited line 631*31131Sminshall * is ready to be read in, so we need to do character-by-character 632*31131Sminshall * reads, and then do the editing in the program (in the case where 633*31131Sminshall * we are supporting line-by-line mode). 634*31131Sminshall * 635*31131Sminshall * The following routines, which are internal to the MSDOS-specific 636*31131Sminshall * code, accomplish this miracle. 637*31131Sminshall */ 63831124Sminshall 639*31131Sminshall #define Hex(c) HEX[(c)&0xff] 640*31131Sminshall 641*31131Sminshall static survivorSetup = 0; /* Do we have ^C hooks in? */ 642*31131Sminshall 643*31131Sminshall static int 644*31131Sminshall lineend = 0, /* There is a line terminator */ 645*31131Sminshall ctrlCCount = 0; 646*31131Sminshall 647*31131Sminshall static char linein[200], /* Where input line is assembled */ 648*31131Sminshall *nextin = linein, /* Next input character */ 649*31131Sminshall *nextout = linein; /* Next character to be consumed */ 650*31131Sminshall 651*31131Sminshall #define consumechar() \ 652*31131Sminshall if ((++nextout) >= nextin) { \ 653*31131Sminshall nextout = nextin = linein; \ 654*31131Sminshall lineend = 0; \ 655*31131Sminshall } 656*31131Sminshall 657*31131Sminshall #define characteratatime() (!MODE_LINE(globalmode)) /* one by one */ 658*31131Sminshall 659*31131Sminshall 66031124Sminshall /* 661*31131Sminshall * killone() 662*31131Sminshall * 663*31131Sminshall * Erase the last character on the line. 664*31131Sminshall */ 665*31131Sminshall 666*31131Sminshall static void 667*31131Sminshall killone() 668*31131Sminshall { 669*31131Sminshall if (lineend) { 670*31131Sminshall return; /* ??? XXX */ 671*31131Sminshall } 672*31131Sminshall if (nextin == linein) { 673*31131Sminshall return; /* Nothing to do */ 674*31131Sminshall } 675*31131Sminshall nextin--; 676*31131Sminshall if (!(isspace(*nextin) || isprint(*nextin))) { 677*31131Sminshall putchar('\b'); 678*31131Sminshall putchar(' '); 679*31131Sminshall putchar('\b'); 680*31131Sminshall } 681*31131Sminshall putchar('\b'); 682*31131Sminshall putchar(' '); 683*31131Sminshall putchar('\b'); 684*31131Sminshall } 685*31131Sminshall 686*31131Sminshall 687*31131Sminshall /* 688*31131Sminshall * setlineend() 689*31131Sminshall * 690*31131Sminshall * Decide if it's time to send the current line up to the user 691*31131Sminshall * process. 692*31131Sminshall */ 693*31131Sminshall 694*31131Sminshall static void 695*31131Sminshall setlineend() 696*31131Sminshall { 697*31131Sminshall if (nextin == nextout) { 698*31131Sminshall return; 699*31131Sminshall } 700*31131Sminshall if (characteratatime()) { 701*31131Sminshall lineend = 1; 702*31131Sminshall } else if (nextin >= (linein+sizeof linein)) { 703*31131Sminshall lineend = 1; 704*31131Sminshall } else { 705*31131Sminshall int c = *(nextin-1); 706*31131Sminshall if ((c == termIntChar) 707*31131Sminshall || (c == termQuitChar) 708*31131Sminshall || (c == termEofChar)) { 709*31131Sminshall lineend = 1; 710*31131Sminshall } else if (c == termFlushChar) { 711*31131Sminshall lineend = 1; 712*31131Sminshall } else if ((c == '\n') || (c == '\r')) { 713*31131Sminshall lineend = 1; 714*31131Sminshall } 715*31131Sminshall } 716*31131Sminshall /* Otherwise, leave it alone (reset by 'consumechar') */ 717*31131Sminshall } 718*31131Sminshall 719*31131Sminshall /* 720*31131Sminshall * OK, what we do here is: 721*31131Sminshall * 722*31131Sminshall * o If we are echoing, then 723*31131Sminshall * o Look for character erase, line kill characters 724*31131Sminshall * o Echo the character (using '^' if a control character) 725*31131Sminshall * o Put the character in the input buffer 726*31131Sminshall * o Set 'lineend' as necessary 727*31131Sminshall */ 728*31131Sminshall 729*31131Sminshall static void 730*31131Sminshall DoNextChar(c) 731*31131Sminshall int c; /* Character to process */ 732*31131Sminshall { 733*31131Sminshall static char literalnextcharacter = 0; 734*31131Sminshall 735*31131Sminshall if (nextin >= (linein+sizeof linein)) { 736*31131Sminshall putchar('\7'); /* Ring bell */ 737*31131Sminshall setlineend(); 738*31131Sminshall return; 739*31131Sminshall } 740*31131Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 741*31131Sminshall /* Look for some special character */ 742*31131Sminshall if (!literalnextcharacter) { 743*31131Sminshall if (c == termEraseChar) { 744*31131Sminshall killone(); 745*31131Sminshall setlineend(); 746*31131Sminshall return; 747*31131Sminshall } else if (c == termKillChar) { 748*31131Sminshall while (nextin != linein) { 749*31131Sminshall killone(); 750*31131Sminshall } 751*31131Sminshall setlineend(); 752*31131Sminshall return; 753*31131Sminshall } else if (c == termLiteralNextChar) { 754*31131Sminshall literalnextcharacter = 1; 755*31131Sminshall return; 756*31131Sminshall } 757*31131Sminshall } 758*31131Sminshall 759*31131Sminshall if (MODE_LOCAL_ECHO(globalmode)) { 760*31131Sminshall if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) { 761*31131Sminshall putchar('\r'); 762*31131Sminshall putchar('\n'); 763*31131Sminshall c = '\n'; 764*31131Sminshall } else if (!isprint(c) && !isspace(c)) { 765*31131Sminshall putchar('^'); 766*31131Sminshall putchar(c^0x40); 767*31131Sminshall } else { 768*31131Sminshall putchar(c); 769*31131Sminshall } 770*31131Sminshall } 771*31131Sminshall literalnextcharacter = 0; 772*31131Sminshall } 773*31131Sminshall *nextin++ = c; 774*31131Sminshall setlineend(); 775*31131Sminshall } 776*31131Sminshall 777*31131Sminshall static int 778*31131Sminshall inputExists() 779*31131Sminshall { 780*31131Sminshall int input; 781*31131Sminshall static state = 0; 782*31131Sminshall 783*31131Sminshall while (ctrlCCount) { 784*31131Sminshall DoNextChar(0x03); 785*31131Sminshall ctrlCCount--; 786*31131Sminshall } 787*31131Sminshall if (lineend) { 788*31131Sminshall return 1; 789*31131Sminshall } 790*31131Sminshall if (!kbhit()) { 791*31131Sminshall return lineend; 792*31131Sminshall } 793*31131Sminshall input = getch(); /* MSC - get console character */ 794*31131Sminshall #if 0 /* For BIOS variety of calls */ 795*31131Sminshall if ((input&0xff) == 0) { 796*31131Sminshall if ((input&0xff00) == 0x0300) { /* Null */ 797*31131Sminshall DoNextChar(0); 798*31131Sminshall } else { 799*31131Sminshall DoNextChar(0x01); 800*31131Sminshall if (input&0x8000) { 801*31131Sminshall DoNextChar(0x01); 802*31131Sminshall DoNextChar((input>>8)&0x7f); 803*31131Sminshall } else { 804*31131Sminshall DoNextChar((input>>8)&0xff); 805*31131Sminshall } 806*31131Sminshall } 807*31131Sminshall } else { 808*31131Sminshall DoNextChar(input&0xff); 809*31131Sminshall } 810*31131Sminshall #endif /* 0 */ 811*31131Sminshall if ((input&0xff) == 0) { 812*31131Sminshall DoNextChar(0x01); /* ^A */ 813*31131Sminshall } else { 814*31131Sminshall DoNextChar(input&0xff); 815*31131Sminshall } 816*31131Sminshall return lineend; 817*31131Sminshall } 818*31131Sminshall 819*31131Sminshall 820*31131Sminshall void 821*31131Sminshall CtrlCInterrupt() 822*31131Sminshall { 823*31131Sminshall if (!MODE_COMMAND_LINE(globalmode)) { 824*31131Sminshall ctrlCCount++; /* XXX */ 825*31131Sminshall signal(SIGINT, CtrlCInterrupt); 826*31131Sminshall } else { 827*31131Sminshall closeallsockets(); 828*31131Sminshall exit(); 829*31131Sminshall } 830*31131Sminshall } 831*31131Sminshall 832*31131Sminshall /* 833*31131Sminshall * The MSDOS routines, called from elsewhere. 834*31131Sminshall */ 835*31131Sminshall 836*31131Sminshall 837*31131Sminshall static int 838*31131Sminshall TerminalAutoFlush() /* MSDOS */ 839*31131Sminshall { 840*31131Sminshall return 1; 841*31131Sminshall } 842*31131Sminshall 843*31131Sminshall static int 844*31131Sminshall TerminalCanRead() 845*31131Sminshall { 846*31131Sminshall return inputExists(); 847*31131Sminshall } 848*31131Sminshall 849*31131Sminshall 850*31131Sminshall /* 85131124Sminshall * Flush output to the terminal 85231124Sminshall */ 85331124Sminshall 85431124Sminshall static void 85531124Sminshall TerminalFlushOutput() /* MSDOS */ 85631124Sminshall { 85731124Sminshall } 85831124Sminshall 859*31131Sminshall 86031124Sminshall static void 861*31131Sminshall TerminalNewMode(f) /* MSDOS */ 862*31131Sminshall register int f; 863*31131Sminshall { 864*31131Sminshall globalmode = f; 865*31131Sminshall signal(SIGINT, CtrlCInterrupt); 866*31131Sminshall } 867*31131Sminshall 868*31131Sminshall 869*31131Sminshall int 870*31131Sminshall TerminalRead(fd, buffer, count) 871*31131Sminshall int fd; 872*31131Sminshall char *buffer; 873*31131Sminshall int count; 874*31131Sminshall { 875*31131Sminshall int done = 0; 876*31131Sminshall 877*31131Sminshall for (;;) { 878*31131Sminshall while (inputExists() && (done < count)) { 879*31131Sminshall *buffer++ = *nextout; 880*31131Sminshall consumechar(); 881*31131Sminshall done++; 882*31131Sminshall } 883*31131Sminshall if (done) { 884*31131Sminshall return(done); 885*31131Sminshall } else { 886*31131Sminshall return 0; 887*31131Sminshall } 888*31131Sminshall } 889*31131Sminshall } 890*31131Sminshall 891*31131Sminshall 892*31131Sminshall static void 89331124Sminshall TerminalSaveState() /* MSDOS */ 89431124Sminshall { 89531124Sminshall } 89631124Sminshall 897*31131Sminshall int 898*31131Sminshall TerminalSpecialChars(c) /* MSDOS */ 899*31131Sminshall { 900*31131Sminshall return 1; 901*31131Sminshall } 902*31131Sminshall 903*31131Sminshall 90431124Sminshall static void 90531124Sminshall TerminalRestoreState() /* MSDOS */ 90631124Sminshall { 90731124Sminshall } 90831124Sminshall 909*31131Sminshall 910*31131Sminshall static int 911*31131Sminshall TerminalWrite(fd, buffer, count) /* MSDOS */ 912*31131Sminshall int fd; 913*31131Sminshall char *buffer; 914*31131Sminshall int count; 915*31131Sminshall { 916*31131Sminshall return fwrite(buffer, sizeof (char), count, stdout); 917*31131Sminshall } 918*31131Sminshall 919*31131Sminshall 920*31131Sminshall static int 921*31131Sminshall NetClose(fd) 922*31131Sminshall { 923*31131Sminshall return closesocket(fd); 924*31131Sminshall } 925*31131Sminshall 92631124Sminshall static void 92731124Sminshall NetNonblockingIO(fd, onoff) /* MSDOS */ 92831124Sminshall int 92931124Sminshall fd, 93031124Sminshall onoff; 93131124Sminshall { 93231124Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) { 93331124Sminshall perror("setsockop (SO_NONBLOCKING) "); 934*31131Sminshall ExitString(stderr, "exiting\n", 1); 93531124Sminshall } 93631124Sminshall } 93731124Sminshall 93831124Sminshall static void 93931124Sminshall NetSigIO(fd) /* MSDOS */ 94031124Sminshall int fd; 94131124Sminshall { 94231124Sminshall } 94331124Sminshall 94431124Sminshall static void 94531124Sminshall NetSetPgrp(fd) /* MSDOS */ 94631124Sminshall int fd; 94731124Sminshall { 94831124Sminshall } 94931124Sminshall 95031124Sminshall 95131124Sminshall #endif /* defined(MSDOS) */ 95231124Sminshall 95331124Sminshall /* 95430326Sminshall * Initialize variables. 95530326Sminshall */ 95630326Sminshall 95730326Sminshall static void 95830326Sminshall tninit() 95930326Sminshall { 960*31131Sminshall #if defined(TN3270) 961*31131Sminshall Sent3270TerminalType = 0; 96230326Sminshall Ifrontp = Ibackp = Ibuf; 963*31131Sminshall #endif /* defined(TN3270) */ 964*31131Sminshall 96530326Sminshall tfrontp = tbackp = ttyobuf; 96630326Sminshall nfrontp = nbackp = netobuf; 96730326Sminshall 96830326Sminshall /* Don't change telnetport */ 96930722Sminshall SB_CLEAR(); 97030722Sminshall ClearArray(hisopts); 97130722Sminshall ClearArray(myopts); 97230722Sminshall sbp = sibuf; 97330722Sminshall tbp = tibuf; 97430326Sminshall 97530722Sminshall connected = net = scc = tcc = In3270 = ISend = 0; 97630722Sminshall telnetport = 0; 97731124Sminshall #if defined(unix) 97831124Sminshall HaveInput = 0; 97931124Sminshall #endif /* defined(unix) */ 98030722Sminshall 98130722Sminshall SYNCHing = 0; 98230722Sminshall 98330722Sminshall errno = 0; 98430722Sminshall 98530722Sminshall flushline = 0; 98630722Sminshall 98730326Sminshall /* Don't change NetTrace */ 98830326Sminshall 98930326Sminshall escape = CONTROL(']'); 99030326Sminshall echoc = CONTROL('E'); 99130326Sminshall 99230326Sminshall flushline = 1; 99330326Sminshall sp = getservbyname("telnet", "tcp"); 99430326Sminshall if (sp == 0) { 99530326Sminshall ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1); 99630326Sminshall /*NOTREACHED*/ 99730326Sminshall } 99830326Sminshall 99930326Sminshall #if defined(TN3270) 100030722Sminshall init_ctlr(); /* Initialize some things */ 100130722Sminshall init_keyboard(); 100230722Sminshall init_screen(); 100330722Sminshall init_system(); 100430326Sminshall #endif /* defined(TN3270) */ 100530326Sminshall } 100630326Sminshall 100730326Sminshall /* 100830088Sminshall * Various utility routines. 100930088Sminshall */ 101030088Sminshall 101130088Sminshall static void 101230088Sminshall makeargv() 101330088Sminshall { 101430088Sminshall register char *cp; 101530088Sminshall register char **argp = margv; 101630088Sminshall 101730088Sminshall margc = 0; 101830088Sminshall for (cp = line; *cp;) { 101930088Sminshall while (isspace(*cp)) 102030088Sminshall cp++; 102130088Sminshall if (*cp == '\0') 102230088Sminshall break; 102330088Sminshall *argp++ = cp; 102430088Sminshall margc += 1; 102530088Sminshall while (*cp != '\0' && !isspace(*cp)) 102630088Sminshall cp++; 102730088Sminshall if (*cp == '\0') 102830088Sminshall break; 102930088Sminshall *cp++ = '\0'; 103030088Sminshall } 103130088Sminshall *argp++ = 0; 103230088Sminshall } 103330088Sminshall 103430088Sminshall static char *ambiguous; /* special return value */ 103530088Sminshall #define Ambiguous(t) ((t)&ambiguous) 103630088Sminshall 103730088Sminshall 103830088Sminshall static char ** 103930088Sminshall genget(name, table, next) 104030088Sminshall char *name; /* name to match */ 104130088Sminshall char **table; /* name entry in table */ 104230088Sminshall char **(*next)(); /* routine to return next entry in table */ 104330088Sminshall { 104430088Sminshall register char *p, *q; 104530088Sminshall register char **c, **found; 104630088Sminshall register int nmatches, longest; 104730088Sminshall 104830088Sminshall longest = 0; 104930088Sminshall nmatches = 0; 105030088Sminshall found = 0; 105130088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 105230088Sminshall for (q = name; 105330088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 105430088Sminshall if (*q == 0) /* exact match? */ 105530088Sminshall return (c); 105630088Sminshall if (!*q) { /* the name was a prefix */ 105730088Sminshall if (q - name > longest) { 105830088Sminshall longest = q - name; 105930088Sminshall nmatches = 1; 106030088Sminshall found = c; 106130088Sminshall } else if (q - name == longest) 106230088Sminshall nmatches++; 106330088Sminshall } 106430088Sminshall } 106530088Sminshall if (nmatches > 1) 106630088Sminshall return Ambiguous(char **); 106730088Sminshall return (found); 106830088Sminshall } 106930088Sminshall 107030088Sminshall /* 107130088Sminshall * Make a character string into a number. 107230088Sminshall * 107330088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 107430088Sminshall */ 107530088Sminshall 107630088Sminshall static 107730088Sminshall special(s) 107830088Sminshall register char *s; 107930088Sminshall { 108030088Sminshall register char c; 108130088Sminshall char b; 108230088Sminshall 108330088Sminshall switch (*s) { 108430088Sminshall case '^': 108530088Sminshall b = *++s; 108630088Sminshall if (b == '?') { 108730088Sminshall c = b | 0x40; /* DEL */ 108830088Sminshall } else { 108930088Sminshall c = b & 0x1f; 109030088Sminshall } 109130088Sminshall break; 109230088Sminshall default: 109330088Sminshall c = *s; 109430088Sminshall break; 109530088Sminshall } 109630088Sminshall return c; 109730088Sminshall } 109830088Sminshall 109930088Sminshall /* 110030088Sminshall * Construct a control character sequence 110130088Sminshall * for a special character. 110230088Sminshall */ 110330088Sminshall static char * 110430088Sminshall control(c) 110530088Sminshall register int c; 110630088Sminshall { 110730088Sminshall static char buf[3]; 110830088Sminshall 110930088Sminshall if (c == 0x7f) 111030088Sminshall return ("^?"); 111130088Sminshall if (c == '\377') { 111230088Sminshall return "off"; 111330088Sminshall } 111430088Sminshall if (c >= 0x20) { 111530088Sminshall buf[0] = c; 111630088Sminshall buf[1] = 0; 111730088Sminshall } else { 111830088Sminshall buf[0] = '^'; 111930088Sminshall buf[1] = '@'+c; 112030088Sminshall buf[2] = 0; 112130088Sminshall } 112230088Sminshall return (buf); 112330088Sminshall } 112430088Sminshall 112530088Sminshall 112630088Sminshall /* 112730088Sminshall * upcase() 112830088Sminshall * 112930088Sminshall * Upcase (in place) the argument. 113030088Sminshall */ 113130088Sminshall 113230088Sminshall static void 113330088Sminshall upcase(argument) 113430088Sminshall register char *argument; 113530088Sminshall { 113630088Sminshall register int c; 113730088Sminshall 113830088Sminshall while ((c = *argument) != 0) { 113930088Sminshall if (islower(c)) { 114030088Sminshall *argument = toupper(c); 114130088Sminshall } 114230088Sminshall argument++; 114330088Sminshall } 114430088Sminshall } 114531124Sminshall 114631124Sminshall /* 114731124Sminshall * SetSockOpt() 114831124Sminshall * 114931124Sminshall * Compensate for differences in 4.2 and 4.3 systems. 115031124Sminshall */ 115131124Sminshall 115231124Sminshall static int 115331124Sminshall SetSockOpt(fd, level, option, yesno) 115431124Sminshall int 115531124Sminshall fd, 115631124Sminshall level, 115731124Sminshall option, 115831124Sminshall yesno; 115931124Sminshall { 116031124Sminshall #ifndef NOT43 116131124Sminshall return setsockopt(fd, level, option, 116231124Sminshall (char *)&yesno, sizeof yesno); 116331124Sminshall #else /* NOT43 */ 116431124Sminshall if (yesno == 0) { /* Can't do that in 4.2! */ 116531124Sminshall fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", 116631124Sminshall option); 116731124Sminshall return -1; 116831124Sminshall } 116931124Sminshall return setsockopt(fd, level, option, 0, 0); 117031124Sminshall #endif /* NOT43 */ 117131124Sminshall } 117230088Sminshall 117330088Sminshall /* 117430088Sminshall * The following are routines used to print out debugging information. 117530088Sminshall */ 117630088Sminshall 117730088Sminshall 117830088Sminshall static void 117930088Sminshall Dump(direction, buffer, length) 118030088Sminshall char direction; 118130088Sminshall char *buffer; 118230088Sminshall int length; 118330088Sminshall { 118430088Sminshall # define BYTES_PER_LINE 32 118530088Sminshall # define min(x,y) ((x<y)? x:y) 118630088Sminshall char *pThis; 118730088Sminshall int offset; 118830088Sminshall 118930088Sminshall offset = 0; 119030088Sminshall 119130088Sminshall while (length) { 119230088Sminshall /* print one line */ 119330088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 119430088Sminshall pThis = buffer; 119530088Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 119630088Sminshall while (pThis < buffer) { 119730088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 119830088Sminshall pThis++; 119930088Sminshall } 120030088Sminshall fprintf(NetTrace, "\n"); 120130088Sminshall length -= BYTES_PER_LINE; 120230088Sminshall offset += BYTES_PER_LINE; 120330088Sminshall if (length < 0) { 120430088Sminshall return; 120530088Sminshall } 120630088Sminshall /* find next unique line */ 120730088Sminshall } 120830088Sminshall } 120930088Sminshall 121030088Sminshall 121130088Sminshall /*VARARGS*/ 121230088Sminshall static void 121330088Sminshall printoption(direction, fmt, option, what) 121430088Sminshall char *direction, *fmt; 121530088Sminshall int option, what; 121630088Sminshall { 121730088Sminshall if (!showoptions) 121830088Sminshall return; 121930088Sminshall fprintf(NetTrace, "%s ", direction+1); 122030088Sminshall if (fmt == doopt) 122130088Sminshall fmt = "do"; 122230088Sminshall else if (fmt == dont) 122330088Sminshall fmt = "dont"; 122430088Sminshall else if (fmt == will) 122530088Sminshall fmt = "will"; 122630088Sminshall else if (fmt == wont) 122730088Sminshall fmt = "wont"; 122830088Sminshall else 122930088Sminshall fmt = "???"; 123030088Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 123130088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]); 123230088Sminshall else 123330088Sminshall fprintf(NetTrace, "%s %d", fmt, option); 123430088Sminshall if (*direction == '<') { 123530088Sminshall fprintf(NetTrace, "\r\n"); 123630088Sminshall return; 123730088Sminshall } 123830088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); 123930088Sminshall } 124030088Sminshall 124130088Sminshall static void 124230088Sminshall printsub(direction, pointer, length) 124330088Sminshall char *direction, /* "<" or ">" */ 124430088Sminshall *pointer; /* where suboption data sits */ 124530088Sminshall int length; /* length of suboption data */ 124630088Sminshall { 124730088Sminshall if (showoptions) { 124830088Sminshall fprintf(NetTrace, "%s suboption ", 124930088Sminshall (direction[0] == '<')? "Received":"Sent"); 125030088Sminshall switch (pointer[0]) { 125130088Sminshall case TELOPT_TTYPE: 125230088Sminshall fprintf(NetTrace, "Terminal type "); 125330088Sminshall switch (pointer[1]) { 125430088Sminshall case TELQUAL_IS: 125530088Sminshall { 125630088Sminshall char tmpbuf[sizeof subbuffer]; 125730088Sminshall int minlen = min(length, sizeof tmpbuf); 125830088Sminshall 1259*31131Sminshall memcpy(tmpbuf, pointer+2, minlen); 126030088Sminshall tmpbuf[minlen-1] = 0; 126130088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf); 126230088Sminshall } 126330088Sminshall break; 126430088Sminshall case TELQUAL_SEND: 126530088Sminshall fprintf(NetTrace, "- request to send.\n"); 126630088Sminshall break; 126730088Sminshall default: 126830088Sminshall fprintf(NetTrace, 126930088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]); 127030088Sminshall } 127130088Sminshall break; 127230088Sminshall default: 127330088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n", 127430088Sminshall pointer[0], pointer[0]); 127530088Sminshall } 127630088Sminshall } 127730088Sminshall } 127830088Sminshall 127930088Sminshall /* 128030088Sminshall * Check to see if any out-of-band data exists on a socket (for 128130088Sminshall * Telnet "synch" processing). 128230088Sminshall */ 128330088Sminshall 128430088Sminshall static int 128530088Sminshall stilloob(s) 128630088Sminshall int s; /* socket number */ 128730088Sminshall { 128830088Sminshall static struct timeval timeout = { 0 }; 128930088Sminshall fd_set excepts; 129030088Sminshall int value; 129130088Sminshall 129230088Sminshall do { 129330088Sminshall FD_ZERO(&excepts); 129430088Sminshall FD_SET(s, &excepts); 129530088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 129630088Sminshall } while ((value == -1) && (errno == EINTR)); 129730088Sminshall 129830088Sminshall if (value < 0) { 129930088Sminshall perror("select"); 130030088Sminshall quit(); 130130088Sminshall } 130230088Sminshall if (FD_ISSET(s, &excepts)) { 130330088Sminshall return 1; 130430088Sminshall } else { 130530088Sminshall return 0; 130630088Sminshall } 130730088Sminshall } 130830088Sminshall 130930088Sminshall 131030088Sminshall /* 131130088Sminshall * netflush 131230088Sminshall * Send as much data as possible to the network, 131330088Sminshall * handling requests for urgent data. 131430088Sminshall * 131530088Sminshall * The return value indicates whether we did any 131630088Sminshall * useful work. 131730088Sminshall */ 131830088Sminshall 131930088Sminshall 132030088Sminshall int 132130088Sminshall netflush() 132230088Sminshall { 132330088Sminshall int n; 132430088Sminshall 132530088Sminshall if ((n = nfrontp - nbackp) > 0) { 132630088Sminshall if (!neturg) { 1327*31131Sminshall n = send(net, nbackp, n, 0); /* normal write */ 132830088Sminshall } else { 132930088Sminshall n = neturg - nbackp; 133030088Sminshall /* 133130088Sminshall * In 4.2 (and 4.3) systems, there is some question about 133230088Sminshall * what byte in a sendOOB operation is the "OOB" data. 133330088Sminshall * To make ourselves compatible, we only send ONE byte 133430088Sminshall * out of band, the one WE THINK should be OOB (though 133530088Sminshall * we really have more the TCP philosophy of urgent data 133630088Sminshall * rather than the Unix philosophy of OOB data). 133730088Sminshall */ 133830088Sminshall if (n > 1) { 133930088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 134030088Sminshall } else { 134130088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 134230088Sminshall } 134330088Sminshall } 134430088Sminshall } 134530088Sminshall if (n < 0) { 134630088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 134730088Sminshall setcommandmode(); 134830088Sminshall perror(hostname); 1349*31131Sminshall NetClose(net); 135030088Sminshall neturg = 0; 135130088Sminshall longjmp(peerdied, -1); 135230088Sminshall /*NOTREACHED*/ 135330088Sminshall } 135430088Sminshall n = 0; 135530088Sminshall } 135630088Sminshall if (netdata && n) { 135730088Sminshall Dump('>', nbackp, n); 135830088Sminshall } 135930088Sminshall nbackp += n; 136030088Sminshall if (nbackp >= neturg) { 136130088Sminshall neturg = 0; 136230088Sminshall } 136330088Sminshall if (nbackp == nfrontp) { 136430088Sminshall nbackp = nfrontp = netobuf; 136530088Sminshall } 136630088Sminshall return n > 0; 136730088Sminshall } 136830088Sminshall 136930088Sminshall /* 137030088Sminshall * nextitem() 137130088Sminshall * 137230088Sminshall * Return the address of the next "item" in the TELNET data 137330088Sminshall * stream. This will be the address of the next character if 137430088Sminshall * the current address is a user data character, or it will 137530088Sminshall * be the address of the character following the TELNET command 137630088Sminshall * if the current address is a TELNET IAC ("I Am a Command") 137730088Sminshall * character. 137830088Sminshall */ 137930088Sminshall 138030088Sminshall static char * 138130088Sminshall nextitem(current) 138230088Sminshall char *current; 138330088Sminshall { 138430088Sminshall if ((*current&0xff) != IAC) { 138530088Sminshall return current+1; 138630088Sminshall } 138730088Sminshall switch (*(current+1)&0xff) { 138830088Sminshall case DO: 138930088Sminshall case DONT: 139030088Sminshall case WILL: 139130088Sminshall case WONT: 139230088Sminshall return current+3; 139330088Sminshall case SB: /* loop forever looking for the SE */ 139430088Sminshall { 139530088Sminshall register char *look = current+2; 139630088Sminshall 139730088Sminshall for (;;) { 139830088Sminshall if ((*look++&0xff) == IAC) { 139930088Sminshall if ((*look++&0xff) == SE) { 140030088Sminshall return look; 140130088Sminshall } 140230088Sminshall } 140330088Sminshall } 140430088Sminshall } 140530088Sminshall default: 140630088Sminshall return current+2; 140730088Sminshall } 140830088Sminshall } 140930088Sminshall /* 141030088Sminshall * netclear() 141130088Sminshall * 141230088Sminshall * We are about to do a TELNET SYNCH operation. Clear 141330088Sminshall * the path to the network. 141430088Sminshall * 141530088Sminshall * Things are a bit tricky since we may have sent the first 141630088Sminshall * byte or so of a previous TELNET command into the network. 141730088Sminshall * So, we have to scan the network buffer from the beginning 141830088Sminshall * until we are up to where we want to be. 141930088Sminshall * 142030088Sminshall * A side effect of what we do, just to keep things 142130088Sminshall * simple, is to clear the urgent data pointer. The principal 142230088Sminshall * caller should be setting the urgent data pointer AFTER calling 142330088Sminshall * us in any case. 142430088Sminshall */ 142530088Sminshall 142630088Sminshall static void 142730088Sminshall netclear() 142830088Sminshall { 142930088Sminshall register char *thisitem, *next; 143030088Sminshall char *good; 143130088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 143230088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 143330088Sminshall 143430088Sminshall thisitem = netobuf; 143530088Sminshall 143630088Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 143730088Sminshall thisitem = next; 143830088Sminshall } 143930088Sminshall 144030088Sminshall /* Now, thisitem is first before/at boundary. */ 144130088Sminshall 144230088Sminshall good = netobuf; /* where the good bytes go */ 144330088Sminshall 144430088Sminshall while (nfrontp > thisitem) { 144530088Sminshall if (wewant(thisitem)) { 144630088Sminshall int length; 144730088Sminshall 144830088Sminshall next = thisitem; 144930088Sminshall do { 145030088Sminshall next = nextitem(next); 145130088Sminshall } while (wewant(next) && (nfrontp > next)); 145230088Sminshall length = next-thisitem; 1453*31131Sminshall memcpy(good, thisitem, length); 145430088Sminshall good += length; 145530088Sminshall thisitem = next; 145630088Sminshall } else { 145730088Sminshall thisitem = nextitem(thisitem); 145830088Sminshall } 145930088Sminshall } 146030088Sminshall 146130088Sminshall nbackp = netobuf; 146230088Sminshall nfrontp = good; /* next byte to be sent */ 146330088Sminshall neturg = 0; 146430088Sminshall } 146530088Sminshall 146630088Sminshall /* 146730088Sminshall * These routines add various telnet commands to the data stream. 146830088Sminshall */ 146930088Sminshall 147030088Sminshall #if defined(NOT43) 147130088Sminshall static int 147230088Sminshall #else /* defined(NOT43) */ 147330088Sminshall static void 147430088Sminshall #endif /* defined(NOT43) */ 147530088Sminshall dosynch() 147630088Sminshall { 147730088Sminshall netclear(); /* clear the path to the network */ 147830088Sminshall NET2ADD(IAC, DM); 147930088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 148030088Sminshall 148130088Sminshall #if defined(NOT43) 148230088Sminshall return 0; 148330088Sminshall #endif /* defined(NOT43) */ 148430088Sminshall } 148530088Sminshall 148630088Sminshall static void 148730088Sminshall doflush() 148830088Sminshall { 148930088Sminshall NET2ADD(IAC, DO); 149030088Sminshall NETADD(TELOPT_TM); 149130088Sminshall flushline = 1; 149230088Sminshall flushout = 1; 149330088Sminshall ttyflush(); 149430088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 149530088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 149630088Sminshall } 149730088Sminshall 149830088Sminshall static void 149930088Sminshall intp() 150030088Sminshall { 150130088Sminshall NET2ADD(IAC, IP); 150230088Sminshall if (autoflush) { 150330088Sminshall doflush(); 150430088Sminshall } 150530088Sminshall if (autosynch) { 150630088Sminshall dosynch(); 150730088Sminshall } 150830088Sminshall } 150930088Sminshall 151030088Sminshall static void 151130088Sminshall sendbrk() 151230088Sminshall { 151330088Sminshall NET2ADD(IAC, BREAK); 151430088Sminshall if (autoflush) { 151530088Sminshall doflush(); 151630088Sminshall } 151730088Sminshall if (autosynch) { 151830088Sminshall dosynch(); 151930088Sminshall } 152030088Sminshall } 152130088Sminshall 152230088Sminshall /* 152330088Sminshall * Send as much data as possible to the terminal. 152430088Sminshall * 152530088Sminshall * The return value indicates whether we did any 152630088Sminshall * useful work. 152730088Sminshall */ 152830088Sminshall 152930088Sminshall 153030088Sminshall static int 153130088Sminshall ttyflush() 153230088Sminshall { 153330088Sminshall int n; 153430088Sminshall 153530088Sminshall if ((n = tfrontp - tbackp) > 0) { 153630088Sminshall if (!(SYNCHing||flushout)) { 1537*31131Sminshall n = TerminalWrite(tout, tbackp, n); 153830088Sminshall } else { 153931124Sminshall TerminalFlushOutput(); 154030088Sminshall /* we leave 'n' alone! */ 154130088Sminshall } 154230088Sminshall } 154330088Sminshall if (n >= 0) { 154430088Sminshall tbackp += n; 154530088Sminshall if (tbackp == tfrontp) { 154630088Sminshall tbackp = tfrontp = ttyobuf; 154730088Sminshall } 154830088Sminshall } 154930088Sminshall return n > 0; 155030088Sminshall } 155130088Sminshall 155230088Sminshall #if defined(TN3270) 155330088Sminshall 155430088Sminshall #if defined(unix) 155530088Sminshall static void 155630088Sminshall inputAvailable() 155730088Sminshall { 155830088Sminshall HaveInput = 1; 155930088Sminshall } 156030088Sminshall #endif /* defined(unix) */ 156130088Sminshall 156230088Sminshall void 156330088Sminshall outputPurge() 156430088Sminshall { 156530088Sminshall int tmp = flushout; 156630088Sminshall 156730088Sminshall flushout = 1; 156830088Sminshall 156930088Sminshall ttyflush(); 157030088Sminshall 157130088Sminshall flushout = tmp; 157230088Sminshall } 157330088Sminshall 157430088Sminshall #endif /* defined(TN3270) */ 157530088Sminshall 157630088Sminshall #if defined(unix) 157730088Sminshall /* 157830088Sminshall * Various signal handling routines. 157930088Sminshall */ 158030088Sminshall 158130088Sminshall static void 158230088Sminshall deadpeer() 158330088Sminshall { 158430088Sminshall setcommandmode(); 158530088Sminshall longjmp(peerdied, -1); 158630088Sminshall } 158730088Sminshall 158830088Sminshall static void 158930088Sminshall intr() 159030088Sminshall { 159130088Sminshall if (localchars) { 159230088Sminshall intp(); 159330088Sminshall return; 159430088Sminshall } 159530088Sminshall setcommandmode(); 159630088Sminshall longjmp(toplevel, -1); 159730088Sminshall } 159830088Sminshall 159930088Sminshall static void 160030088Sminshall intr2() 160130088Sminshall { 160230088Sminshall if (localchars) { 160330088Sminshall sendbrk(); 160430088Sminshall return; 160530088Sminshall } 160630088Sminshall } 160730088Sminshall 160830088Sminshall static void 160930088Sminshall doescape() 161030088Sminshall { 161130088Sminshall command(0); 161230088Sminshall } 161330088Sminshall #endif /* defined(unix) */ 161430088Sminshall 161530088Sminshall /* 161630088Sminshall * These routines decides on what the mode should be (based on the values 161730088Sminshall * of various global variables). 161830088Sminshall */ 161930088Sminshall 162030088Sminshall 162130088Sminshall static 162230088Sminshall getconnmode() 162330088Sminshall { 162430088Sminshall static char newmode[16] = 162530088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; 162630088Sminshall int modeindex = 0; 162730088Sminshall 162830088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 162930088Sminshall modeindex += 1; 163030088Sminshall } 163130088Sminshall if (hisopts[TELOPT_ECHO]) { 163230088Sminshall modeindex += 2; 163330088Sminshall } 163430088Sminshall if (hisopts[TELOPT_SGA]) { 163530088Sminshall modeindex += 4; 163630088Sminshall } 163730088Sminshall if (In3270) { 163830088Sminshall modeindex += 8; 163930088Sminshall } 164030088Sminshall return newmode[modeindex]; 164130088Sminshall } 164230088Sminshall 164330088Sminshall void 164430088Sminshall setconnmode() 164530088Sminshall { 164631124Sminshall TerminalNewMode(getconnmode()); 164730088Sminshall } 164830088Sminshall 164930088Sminshall 165030088Sminshall void 165130088Sminshall setcommandmode() 165230088Sminshall { 165331124Sminshall TerminalNewMode(0); 165430088Sminshall } 165530088Sminshall 165630088Sminshall static void 165730088Sminshall willoption(option, reply) 165830088Sminshall int option, reply; 165930088Sminshall { 166030088Sminshall char *fmt; 166130088Sminshall 166230088Sminshall switch (option) { 166330088Sminshall 166430368Sminshall case TELOPT_ECHO: 166530088Sminshall # if defined(TN3270) 166630368Sminshall /* 166730368Sminshall * The following is a pain in the rear-end. 166830368Sminshall * Various IBM servers (some versions of Wiscnet, 166930368Sminshall * possibly Fibronics/Spartacus, and who knows who 167030368Sminshall * else) will NOT allow us to send "DO SGA" too early 167130368Sminshall * in the setup proceedings. On the other hand, 167230368Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 167330368Sminshall * So, we are stuck. Empirically (but, based on 167430368Sminshall * a VERY small sample), the IBM servers don't send 167530368Sminshall * out anything about ECHO, so we postpone our sending 167630368Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 167730368Sminshall * DO send). 167830368Sminshall */ 167930368Sminshall { 168030368Sminshall if (askedSGA == 0) { 168130368Sminshall askedSGA = 1; 168230368Sminshall if (!hisopts[TELOPT_SGA]) { 168330368Sminshall willoption(TELOPT_SGA, 0); 168430368Sminshall } 168530368Sminshall } 168630368Sminshall } 168730368Sminshall /* Fall through */ 168830088Sminshall case TELOPT_EOR: 168930088Sminshall case TELOPT_BINARY: 169030088Sminshall #endif /* defined(TN3270) */ 169130088Sminshall case TELOPT_SGA: 169230088Sminshall settimer(modenegotiated); 169330088Sminshall hisopts[option] = 1; 169430088Sminshall fmt = doopt; 169530088Sminshall setconnmode(); /* possibly set new tty mode */ 169630088Sminshall break; 169730088Sminshall 169830088Sminshall case TELOPT_TM: 169930088Sminshall return; /* Never reply to TM will's/wont's */ 170030088Sminshall 170130088Sminshall default: 170230088Sminshall fmt = dont; 170330088Sminshall break; 170430088Sminshall } 170530088Sminshall sprintf(nfrontp, fmt, option); 170630088Sminshall nfrontp += sizeof (dont) - 2; 170730088Sminshall if (reply) 170830088Sminshall printoption(">SENT", fmt, option, reply); 170930088Sminshall else 171030088Sminshall printoption("<SENT", fmt, option, reply); 171130088Sminshall } 171230088Sminshall 171330088Sminshall static void 171430088Sminshall wontoption(option, reply) 171530088Sminshall int option, reply; 171630088Sminshall { 171730088Sminshall char *fmt; 171830088Sminshall 171930088Sminshall switch (option) { 172030088Sminshall 172130088Sminshall case TELOPT_ECHO: 172230088Sminshall case TELOPT_SGA: 172330088Sminshall settimer(modenegotiated); 172430088Sminshall hisopts[option] = 0; 172530088Sminshall fmt = dont; 172630088Sminshall setconnmode(); /* Set new tty mode */ 172730088Sminshall break; 172830088Sminshall 172930088Sminshall case TELOPT_TM: 173030088Sminshall return; /* Never reply to TM will's/wont's */ 173130088Sminshall 173230088Sminshall default: 173330088Sminshall fmt = dont; 173430088Sminshall } 173530088Sminshall sprintf(nfrontp, fmt, option); 173630088Sminshall nfrontp += sizeof (doopt) - 2; 173730088Sminshall if (reply) 173830088Sminshall printoption(">SENT", fmt, option, reply); 173930088Sminshall else 174030088Sminshall printoption("<SENT", fmt, option, reply); 174130088Sminshall } 174230088Sminshall 174330088Sminshall static void 174430088Sminshall dooption(option) 174530088Sminshall int option; 174630088Sminshall { 174730088Sminshall char *fmt; 174830088Sminshall 174930088Sminshall switch (option) { 175030088Sminshall 175130088Sminshall case TELOPT_TM: 175230088Sminshall fmt = will; 175330088Sminshall break; 175430088Sminshall 175530088Sminshall # if defined(TN3270) 175630088Sminshall case TELOPT_EOR: 175730088Sminshall case TELOPT_BINARY: 175830088Sminshall # endif /* defined(TN3270) */ 175930088Sminshall case TELOPT_TTYPE: /* terminal type option */ 176030088Sminshall case TELOPT_SGA: /* no big deal */ 176130088Sminshall fmt = will; 176230088Sminshall myopts[option] = 1; 176330088Sminshall break; 176430088Sminshall 176530088Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 176630088Sminshall default: 176730088Sminshall fmt = wont; 176830088Sminshall break; 176930088Sminshall } 177030088Sminshall sprintf(nfrontp, fmt, option); 177130088Sminshall nfrontp += sizeof (doopt) - 2; 177230088Sminshall printoption(">SENT", fmt, option, 0); 177330088Sminshall } 177430088Sminshall 177530088Sminshall /* 177630088Sminshall * suboption() 177730088Sminshall * 177830088Sminshall * Look at the sub-option buffer, and try to be helpful to the other 177930088Sminshall * side. 178030088Sminshall * 178130088Sminshall * Currently we recognize: 178230088Sminshall * 178330088Sminshall * Terminal type, send request. 178430088Sminshall */ 178530088Sminshall 178630088Sminshall static void 178730088Sminshall suboption() 178830088Sminshall { 178930088Sminshall printsub("<", subbuffer, subend-subbuffer+1); 179030088Sminshall switch (subbuffer[0]&0xff) { 179130088Sminshall case TELOPT_TTYPE: 179230088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 179330088Sminshall ; 179430088Sminshall } else { 179530088Sminshall char *name; 179630088Sminshall char namebuf[41]; 179730088Sminshall extern char *getenv(); 179830088Sminshall int len; 179930088Sminshall 180030088Sminshall #if defined(TN3270) 180130088Sminshall /* 180230326Sminshall * Try to send a 3270 type terminal name. Decide which one based 180330088Sminshall * on the format of our screen, and (in the future) color 180430088Sminshall * capaiblities. 180530088Sminshall */ 180631124Sminshall #if defined(unix) 1807*31131Sminshall if (initscr() != ERR) { /* Initialize curses to get line size */ 1808*31131Sminshall MaxNumberLines = LINES; 1809*31131Sminshall MaxNumberColumns = COLS; 1810*31131Sminshall } 1811*31131Sminshall #else /* defined(unix) */ 1812*31131Sminshall InitTerminal(); 1813*31131Sminshall #endif /* defined(unix) */ 1814*31131Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 181530088Sminshall Sent3270TerminalType = 1; 1816*31131Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 181730088Sminshall MaxNumberLines = 27; 181830088Sminshall MaxNumberColumns = 132; 181930088Sminshall sb_terminal[SBTERMMODEL] = '5'; 1820*31131Sminshall } else if (MaxNumberLines >= 43) { 182130088Sminshall MaxNumberLines = 43; 182230088Sminshall MaxNumberColumns = 80; 182330088Sminshall sb_terminal[SBTERMMODEL] = '4'; 1824*31131Sminshall } else if (MaxNumberLines >= 32) { 182530088Sminshall MaxNumberLines = 32; 182630088Sminshall MaxNumberColumns = 80; 182730088Sminshall sb_terminal[SBTERMMODEL] = '3'; 182830088Sminshall } else { 182930088Sminshall MaxNumberLines = 24; 183030088Sminshall MaxNumberColumns = 80; 183130088Sminshall sb_terminal[SBTERMMODEL] = '2'; 183230088Sminshall } 183330088Sminshall NumberLines = 24; /* before we start out... */ 183430088Sminshall NumberColumns = 80; 183530088Sminshall ScreenSize = NumberLines*NumberColumns; 183630088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 183730088Sminshall ExitString(stderr, 183830088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 183930088Sminshall /*NOTREACHED*/ 184030088Sminshall } 1841*31131Sminshall memcpy(nfrontp, sb_terminal, sizeof sb_terminal); 184230088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 184330088Sminshall nfrontp += sizeof sb_terminal; 184430088Sminshall return; 184530088Sminshall } 184630088Sminshall #endif /* defined(TN3270) */ 184730088Sminshall 184830088Sminshall name = getenv("TERM"); 184930088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 185030088Sminshall name = "UNKNOWN"; 185130088Sminshall } 185230088Sminshall if ((len + 4+2) < NETROOM()) { 185330088Sminshall strcpy(namebuf, name); 185430088Sminshall upcase(namebuf); 185530088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 185630088Sminshall TELQUAL_IS, namebuf, IAC, SE); 185730088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 185830088Sminshall nfrontp += 4+strlen(namebuf)+2; 185930088Sminshall } else { 186030088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 186130088Sminshall 1); 186230088Sminshall /*NOTREACHED*/ 186330088Sminshall } 186430088Sminshall } 186530088Sminshall 186630088Sminshall default: 186730088Sminshall break; 186830088Sminshall } 186930088Sminshall } 187030088Sminshall 187130088Sminshall #if defined(TN3270) 187230088Sminshall static void 187330088Sminshall SetIn3270() 187430088Sminshall { 187530088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 187630088Sminshall && hisopts[TELOPT_BINARY]) { 187730088Sminshall if (!In3270) { 187830088Sminshall In3270 = 1; 187930326Sminshall Init3270(); /* Initialize 3270 functions */ 188030088Sminshall /* initialize terminal key mapping */ 188130326Sminshall InitTerminal(); /* Start terminal going */ 188230088Sminshall setconnmode(); 188330088Sminshall } 188430088Sminshall } else { 188530088Sminshall if (In3270) { 188630088Sminshall StopScreen(1); 188730088Sminshall In3270 = 0; 188830088Sminshall setconnmode(); 188930088Sminshall } 189030088Sminshall } 189130088Sminshall } 189230088Sminshall #endif /* defined(TN3270) */ 189330088Sminshall 189430088Sminshall 189530088Sminshall static void 189630088Sminshall telrcv() 189730088Sminshall { 189830088Sminshall register int c; 189930722Sminshall static int telrcv_state = TS_DATA; 190030088Sminshall # if defined(TN3270) 190130088Sminshall register int Scc; 190230088Sminshall register char *Sbp; 190330088Sminshall # endif /* defined(TN3270) */ 190430088Sminshall 190530088Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 190630088Sminshall c = *sbp++ & 0xff, scc--; 190730722Sminshall switch (telrcv_state) { 190830088Sminshall 190930088Sminshall case TS_CR: 191030722Sminshall telrcv_state = TS_DATA; 191130088Sminshall if (c == '\0') { 191230088Sminshall break; /* Ignore \0 after CR */ 191330088Sminshall } else if (c == '\n') { 191430088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 191530088Sminshall TTYADD(c); 191630088Sminshall } 191730088Sminshall break; 191830088Sminshall } 191930088Sminshall /* Else, fall through */ 192030088Sminshall 192130088Sminshall case TS_DATA: 192230088Sminshall if (c == IAC) { 192330722Sminshall telrcv_state = TS_IAC; 192430088Sminshall continue; 192530088Sminshall } 192630088Sminshall # if defined(TN3270) 192730088Sminshall if (In3270) { 192830088Sminshall *Ifrontp++ = c; 192930088Sminshall Sbp = sbp; 193030088Sminshall Scc = scc; 193130088Sminshall while (Scc > 0) { 193230088Sminshall c = *Sbp++ & 0377, Scc--; 193330088Sminshall if (c == IAC) { 193430722Sminshall telrcv_state = TS_IAC; 193530088Sminshall break; 193630088Sminshall } 193730088Sminshall *Ifrontp++ = c; 193830088Sminshall } 193930088Sminshall sbp = Sbp; 194030088Sminshall scc = Scc; 194130088Sminshall } else 194230088Sminshall # endif /* defined(TN3270) */ 194330088Sminshall /* 194430088Sminshall * The 'crmod' hack (see following) is needed 194530088Sminshall * since we can't * set CRMOD on output only. 194630088Sminshall * Machines like MULTICS like to send \r without 194730088Sminshall * \n; since we must turn off CRMOD to get proper 194830088Sminshall * input, the mapping is done here (sigh). 194930088Sminshall */ 195030088Sminshall if (c == '\r') { 195130088Sminshall if (scc > 0) { 195230088Sminshall c = *sbp&0xff; 195330088Sminshall if (c == 0) { 195430088Sminshall sbp++, scc--; 195530088Sminshall /* a "true" CR */ 195630088Sminshall TTYADD('\r'); 195730088Sminshall } else if (!hisopts[TELOPT_ECHO] && 195830088Sminshall (c == '\n')) { 195930088Sminshall sbp++, scc--; 196030088Sminshall TTYADD('\n'); 196130088Sminshall } else { 196230088Sminshall TTYADD('\r'); 196330088Sminshall if (crmod) { 196430088Sminshall TTYADD('\n'); 196530088Sminshall } 196630088Sminshall } 196730088Sminshall } else { 196830722Sminshall telrcv_state = TS_CR; 196930088Sminshall TTYADD('\r'); 197030088Sminshall if (crmod) { 197130088Sminshall TTYADD('\n'); 197230088Sminshall } 197330088Sminshall } 197430088Sminshall } else { 197530088Sminshall TTYADD(c); 197630088Sminshall } 197730088Sminshall continue; 197830088Sminshall 197930088Sminshall case TS_IAC: 198030088Sminshall switch (c) { 198130088Sminshall 198230088Sminshall case WILL: 198330722Sminshall telrcv_state = TS_WILL; 198430088Sminshall continue; 198530088Sminshall 198630088Sminshall case WONT: 198730722Sminshall telrcv_state = TS_WONT; 198830088Sminshall continue; 198930088Sminshall 199030088Sminshall case DO: 199130722Sminshall telrcv_state = TS_DO; 199230088Sminshall continue; 199330088Sminshall 199430088Sminshall case DONT: 199530722Sminshall telrcv_state = TS_DONT; 199630088Sminshall continue; 199730088Sminshall 199830088Sminshall case DM: 199930088Sminshall /* 200030088Sminshall * We may have missed an urgent notification, 200130088Sminshall * so make sure we flush whatever is in the 200230088Sminshall * buffer currently. 200330088Sminshall */ 200430088Sminshall SYNCHing = 1; 200530088Sminshall ttyflush(); 200630088Sminshall SYNCHing = stilloob(net); 200730088Sminshall settimer(gotDM); 200830088Sminshall break; 200930088Sminshall 201030088Sminshall case NOP: 201130088Sminshall case GA: 201230088Sminshall break; 201330088Sminshall 201430088Sminshall case SB: 201530088Sminshall SB_CLEAR(); 201630722Sminshall telrcv_state = TS_SB; 201730088Sminshall continue; 201830088Sminshall 201930088Sminshall # if defined(TN3270) 202030088Sminshall case EOR: 202130088Sminshall if (In3270) { 202230088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 202330088Sminshall if (Ibackp == Ifrontp) { 202430088Sminshall Ibackp = Ifrontp = Ibuf; 202530088Sminshall ISend = 0; /* should have been! */ 202630088Sminshall } else { 202730088Sminshall ISend = 1; 202830088Sminshall } 202930088Sminshall } 203030088Sminshall break; 203130088Sminshall # endif /* defined(TN3270) */ 203230088Sminshall 203330088Sminshall case IAC: 203430088Sminshall # if !defined(TN3270) 203530088Sminshall TTYADD(IAC); 203630088Sminshall # else /* !defined(TN3270) */ 203730088Sminshall if (In3270) { 203830088Sminshall *Ifrontp++ = IAC; 203930088Sminshall } else { 204030088Sminshall TTYADD(IAC); 204130088Sminshall } 204230088Sminshall # endif /* !defined(TN3270) */ 204330088Sminshall break; 204430088Sminshall 204530088Sminshall default: 204630088Sminshall break; 204730088Sminshall } 204830722Sminshall telrcv_state = TS_DATA; 204930088Sminshall continue; 205030088Sminshall 205130088Sminshall case TS_WILL: 205230088Sminshall printoption(">RCVD", will, c, !hisopts[c]); 205330088Sminshall if (c == TELOPT_TM) { 205430088Sminshall if (flushout) { 205530088Sminshall flushout = 0; 205630088Sminshall } 205730088Sminshall } else if (!hisopts[c]) { 205830088Sminshall willoption(c, 1); 205930088Sminshall } 206030088Sminshall SetIn3270(); 206130722Sminshall telrcv_state = TS_DATA; 206230088Sminshall continue; 206330088Sminshall 206430088Sminshall case TS_WONT: 206530088Sminshall printoption(">RCVD", wont, c, hisopts[c]); 206630088Sminshall if (c == TELOPT_TM) { 206730088Sminshall if (flushout) { 206830088Sminshall flushout = 0; 206930088Sminshall } 207030088Sminshall } else if (hisopts[c]) { 207130088Sminshall wontoption(c, 1); 207230088Sminshall } 207330088Sminshall SetIn3270(); 207430722Sminshall telrcv_state = TS_DATA; 207530088Sminshall continue; 207630088Sminshall 207730088Sminshall case TS_DO: 207830088Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 207930088Sminshall if (!myopts[c]) 208030088Sminshall dooption(c); 208130088Sminshall SetIn3270(); 208230722Sminshall telrcv_state = TS_DATA; 208330088Sminshall continue; 208430088Sminshall 208530088Sminshall case TS_DONT: 208630088Sminshall printoption(">RCVD", dont, c, myopts[c]); 208730088Sminshall if (myopts[c]) { 208830088Sminshall myopts[c] = 0; 208930088Sminshall sprintf(nfrontp, wont, c); 209030088Sminshall nfrontp += sizeof (wont) - 2; 209130088Sminshall flushline = 1; 209230088Sminshall setconnmode(); /* set new tty mode (maybe) */ 209330088Sminshall printoption(">SENT", wont, c, 0); 209430088Sminshall } 209530088Sminshall SetIn3270(); 209630722Sminshall telrcv_state = TS_DATA; 209730088Sminshall continue; 209830088Sminshall 209930088Sminshall case TS_SB: 210030088Sminshall if (c == IAC) { 210130722Sminshall telrcv_state = TS_SE; 210230088Sminshall } else { 210330088Sminshall SB_ACCUM(c); 210430088Sminshall } 210530088Sminshall continue; 210630088Sminshall 210730088Sminshall case TS_SE: 210830088Sminshall if (c != SE) { 210930088Sminshall if (c != IAC) { 211030088Sminshall SB_ACCUM(IAC); 211130088Sminshall } 211230088Sminshall SB_ACCUM(c); 211330722Sminshall telrcv_state = TS_SB; 211430088Sminshall } else { 211530088Sminshall SB_TERM(); 211630088Sminshall suboption(); /* handle sub-option */ 211730088Sminshall SetIn3270(); 211830722Sminshall telrcv_state = TS_DATA; 211930088Sminshall } 212030088Sminshall } 212130088Sminshall } 212230088Sminshall } 212330088Sminshall 212430088Sminshall #if defined(TN3270) 212530088Sminshall 212630088Sminshall /* 212730088Sminshall * The following routines are places where the various tn3270 212830088Sminshall * routines make calls into telnet.c. 212930088Sminshall */ 213030088Sminshall 213130088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 213230088Sminshall TtyChars() 213330088Sminshall { 213430088Sminshall return(tfrontp-tbackp); 213530088Sminshall } 213630088Sminshall 213730088Sminshall /* 213830088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 213930088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 214030088Sminshall * don't call us with "done" until you want that done...) 214130088Sminshall * 214230088Sminshall * We actually do send all the data to the network buffer, since our 214330088Sminshall * only client needs for us to do that. 214430088Sminshall */ 214530088Sminshall 214630088Sminshall int 214730088Sminshall DataToNetwork(buffer, count, done) 214830088Sminshall register char *buffer; /* where the data is */ 214930088Sminshall register int count; /* how much to send */ 215030088Sminshall int done; /* is this the last of a logical block */ 215130088Sminshall { 215230088Sminshall register int c; 215330088Sminshall int origCount; 215430088Sminshall fd_set o; 215530088Sminshall 215630088Sminshall origCount = count; 215730088Sminshall FD_ZERO(&o); 215830088Sminshall 215930088Sminshall while (count) { 216030088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 216130088Sminshall netflush(); 216230088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) { 216330088Sminshall FD_SET(net, &o); 216430088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 216530088Sminshall (struct timeval *) 0); 216630088Sminshall netflush(); 216730088Sminshall } 216830088Sminshall } 216930088Sminshall c = *buffer++; 217030088Sminshall count--; 217130088Sminshall if (c == IAC) { 217230088Sminshall *nfrontp++ = IAC; 217330088Sminshall *nfrontp++ = IAC; 217430088Sminshall } else { 217530088Sminshall *nfrontp++ = c; 217630088Sminshall } 217730088Sminshall } 217830088Sminshall 217930088Sminshall if (done && !count) { 218030088Sminshall *nfrontp++ = IAC; 218130088Sminshall *nfrontp++ = EOR; 218230088Sminshall netflush(); /* try to move along as quickly as ... */ 218330088Sminshall } 218430088Sminshall return(origCount - count); 218530088Sminshall } 218630088Sminshall 218730088Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 218830088Sminshall 218930088Sminshall int 219030088Sminshall DataToTerminal(buffer, count) 219130088Sminshall register char *buffer; /* where the data is */ 219230088Sminshall register int count; /* how much to send */ 219330088Sminshall { 219430088Sminshall int origCount; 2195*31131Sminshall #if defined(unix) 219630088Sminshall fd_set o; 219730088Sminshall 2198*31131Sminshall FD_ZERO(&o); 2199*31131Sminshall #endif /* defined(unix) */ 220030088Sminshall origCount = count; 220130088Sminshall 220230088Sminshall while (count) { 220330088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 220430088Sminshall ttyflush(); 220530088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 2206*31131Sminshall #if defined(unix) 220730088Sminshall FD_SET(tout, &o); 220830088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 220930088Sminshall (struct timeval *) 0); 2210*31131Sminshall #endif /* defined(unix) */ 221130088Sminshall ttyflush(); 221230088Sminshall } 221330088Sminshall } 221430088Sminshall *tfrontp++ = *buffer++; 221530088Sminshall count--; 221630088Sminshall } 221730088Sminshall return(origCount - count); 221830088Sminshall } 221930088Sminshall 222030088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 222130088Sminshall * Note that we consider the buffer to run all the 222230088Sminshall * way to the kernel (thus the select). 222330088Sminshall */ 222430088Sminshall 222530088Sminshall void 222630088Sminshall EmptyTerminal() 222730088Sminshall { 2228*31131Sminshall #if defined(unix) 222930088Sminshall fd_set o; 223030088Sminshall 223130088Sminshall FD_ZERO(&o); 2232*31131Sminshall #endif /* defined(unix) */ 223330088Sminshall 223430088Sminshall if (tfrontp == tbackp) { 2235*31131Sminshall #if defined(unix) 223630088Sminshall FD_SET(tout, &o); 223730088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 223830088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 2239*31131Sminshall #endif /* defined(unix) */ 224030088Sminshall } else { 224130088Sminshall while (tfrontp != tbackp) { 224230088Sminshall ttyflush(); 2243*31131Sminshall #if defined(unix) 224430088Sminshall FD_SET(tout, &o); 224530088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 224630088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 2247*31131Sminshall #endif /* defined(unix) */ 224830088Sminshall } 224930088Sminshall } 225030088Sminshall } 225130088Sminshall 225230088Sminshall /* 225330088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 225430088Sminshall */ 225530088Sminshall 225630088Sminshall static int 225730088Sminshall Push3270() 225830088Sminshall { 225930088Sminshall int save = scc; 226030088Sminshall 226130088Sminshall if (scc) { 226230088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 226330088Sminshall if (Ibackp != Ibuf) { 2264*31131Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 226530088Sminshall Ifrontp -= (Ibackp-Ibuf); 226630088Sminshall Ibackp = Ibuf; 226730088Sminshall } 226830088Sminshall } 226930088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 227030088Sminshall telrcv(); 227130088Sminshall } 227230088Sminshall } 227330088Sminshall return save != scc; 227430088Sminshall } 227530088Sminshall 227630088Sminshall 227730088Sminshall /* 227830088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 227930088Sminshall * before quitting. 228030088Sminshall */ 228130088Sminshall 228230088Sminshall static void 228330088Sminshall Finish3270() 228430088Sminshall { 228530088Sminshall while (Push3270() || !DoTerminalOutput()) { 228630088Sminshall ; 228730088Sminshall } 228830088Sminshall } 228930088Sminshall 229030088Sminshall 229130088Sminshall 229230088Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 229330088Sminshall 229430088Sminshall void 229530088Sminshall StringToTerminal(s) 229630088Sminshall char *s; 229730088Sminshall { 229830088Sminshall int count; 229930088Sminshall 230030088Sminshall count = strlen(s); 230130088Sminshall if (count) { 230230088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 230330088Sminshall } 230430088Sminshall } 230530088Sminshall 230630088Sminshall 230730088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) 230830088Sminshall /* _putchar - output a single character to the terminal. This name is so that 230930088Sminshall * curses(3x) can call us to send out data. 231030088Sminshall */ 231130088Sminshall 231230088Sminshall void 231330088Sminshall _putchar(c) 231430088Sminshall char c; 231530088Sminshall { 231630088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 231730088Sminshall (void) DataToTerminal(&c, 1); 231830088Sminshall } else { 231930088Sminshall *tfrontp++ = c; /* optimize if possible. */ 232030088Sminshall } 232130088Sminshall } 232230088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ 232330088Sminshall 232430088Sminshall static void 232530088Sminshall SetForExit() 232630088Sminshall { 232730088Sminshall setconnmode(); 232830088Sminshall if (In3270) { 232930088Sminshall Finish3270(); 233030088Sminshall } 233130088Sminshall setcommandmode(); 233230088Sminshall fflush(stdout); 233330088Sminshall fflush(stderr); 233430088Sminshall if (In3270) { 233530088Sminshall StopScreen(1); 233630088Sminshall } 233730088Sminshall setconnmode(); 233830088Sminshall setcommandmode(); 233930088Sminshall } 234030088Sminshall 234130088Sminshall static void 234230088Sminshall Exit(returnCode) 234330088Sminshall int returnCode; 234430088Sminshall { 234530088Sminshall SetForExit(); 234630088Sminshall exit(returnCode); 234730088Sminshall } 234830088Sminshall 234930088Sminshall void 235030088Sminshall ExitString(file, string, returnCode) 235130088Sminshall FILE *file; 235230088Sminshall char *string; 235330088Sminshall int returnCode; 235430088Sminshall { 235530088Sminshall SetForExit(); 235630088Sminshall fwrite(string, 1, strlen(string), file); 235730088Sminshall exit(returnCode); 235830088Sminshall } 235930088Sminshall 236030088Sminshall void 236130088Sminshall ExitPerror(string, returnCode) 236230088Sminshall char *string; 236330088Sminshall int returnCode; 236430088Sminshall { 236530088Sminshall SetForExit(); 236630088Sminshall perror(string); 236730088Sminshall exit(returnCode); 236830088Sminshall } 236930088Sminshall 237030088Sminshall #endif /* defined(TN3270) */ 237130088Sminshall 237230088Sminshall static 237330088Sminshall Scheduler(block) 237430088Sminshall int block; /* should we block in the select ? */ 237530088Sminshall { 237630088Sminshall register int c; 237730088Sminshall /* One wants to be a bit careful about setting returnValue 237830088Sminshall * to one, since a one implies we did some useful work, 237930088Sminshall * and therefore probably won't be called to block next 238030088Sminshall * time (TN3270 mode only). 238130088Sminshall */ 238230088Sminshall int returnValue = 0; 238330088Sminshall static struct timeval TimeValue = { 0 }; 238430088Sminshall 238530088Sminshall if (scc < 0 && tcc < 0) { 238630088Sminshall return -1; 238730088Sminshall } 238830088Sminshall 238930088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 239030088Sminshall FD_SET(net, &obits); 239130088Sminshall } 2392*31131Sminshall #if !defined(MSDOS) 239330088Sminshall if (TTYBYTES()) { 239430088Sminshall FD_SET(tout, &obits); 239530088Sminshall } 239630088Sminshall if ((tcc == 0) && NETROOM()) { 239730088Sminshall FD_SET(tin, &ibits); 239830088Sminshall } 2399*31131Sminshall #endif /* !defined(MSDOS) */ 240030088Sminshall # if !defined(TN3270) 240130088Sminshall if (TTYROOM()) { 240230088Sminshall FD_SET(net, &ibits); 240330088Sminshall } 240430088Sminshall # else /* !defined(TN3270) */ 240530088Sminshall if (!ISend && TTYROOM()) { 240630088Sminshall FD_SET(net, &ibits); 240730088Sminshall } 240830088Sminshall # endif /* !defined(TN3270) */ 240930088Sminshall if (!SYNCHing) { 241030088Sminshall FD_SET(net, &xbits); 241130088Sminshall } 241230088Sminshall # if defined(TN3270) && defined(unix) 241330088Sminshall if (HaveInput) { 241430088Sminshall HaveInput = 0; 241530088Sminshall signal(SIGIO, inputAvailable); 241630088Sminshall } 241730088Sminshall #endif /* defined(TN3270) && defined(unix) */ 241830088Sminshall if ((c = select(16, &ibits, &obits, &xbits, 2419*31131Sminshall block? (struct timeval *)0 : &TimeValue)) < 0) { 242030088Sminshall if (c == -1) { 242130088Sminshall /* 242230088Sminshall * we can get EINTR if we are in line mode, 242330088Sminshall * and the user does an escape (TSTP), or 242430088Sminshall * some other signal generator. 242530088Sminshall */ 242630088Sminshall if (errno == EINTR) { 242730088Sminshall return 0; 242830088Sminshall } 242930088Sminshall # if defined(TN3270) 243030088Sminshall /* 243130088Sminshall * we can get EBADF if we were in transparent 243230088Sminshall * mode, and the transcom process died. 243330088Sminshall */ 243430088Sminshall if (errno == EBADF) { 243530088Sminshall /* 243630088Sminshall * zero the bits (even though kernel does it) 243730088Sminshall * to make sure we are selecting on the right 243830088Sminshall * ones. 243930088Sminshall */ 244030088Sminshall FD_ZERO(&ibits); 244130088Sminshall FD_ZERO(&obits); 244230088Sminshall FD_ZERO(&xbits); 244330088Sminshall return 0; 244430088Sminshall } 244530088Sminshall # endif /* defined(TN3270) */ 244630088Sminshall /* I don't like this, does it ever happen? */ 244730088Sminshall printf("sleep(5) from telnet, after select\r\n"); 244830088Sminshall #if defined(unix) 244930088Sminshall sleep(5); 245030088Sminshall #endif /* defined(unix) */ 245130088Sminshall } 245230088Sminshall return 0; 245330088Sminshall } 245430088Sminshall 245530088Sminshall /* 245630088Sminshall * Any urgent data? 245730088Sminshall */ 245830088Sminshall if (FD_ISSET(net, &xbits)) { 245930088Sminshall FD_CLR(net, &xbits); 246030088Sminshall SYNCHing = 1; 246130088Sminshall ttyflush(); /* flush already enqueued data */ 246230088Sminshall } 246330088Sminshall 246430088Sminshall /* 246530088Sminshall * Something to read from the network... 246630088Sminshall */ 246730088Sminshall if (FD_ISSET(net, &ibits)) { 246830088Sminshall int canread; 246930088Sminshall 247030088Sminshall FD_CLR(net, &ibits); 247130088Sminshall if (scc == 0) { 247230088Sminshall sbp = sibuf; 247330088Sminshall } 247430422Sminshall canread = sibuf + sizeof sibuf - (sbp+scc); 247530088Sminshall #if !defined(SO_OOBINLINE) 247630088Sminshall /* 247730088Sminshall * In 4.2 (and some early 4.3) systems, the 247830088Sminshall * OOB indication and data handling in the kernel 247930088Sminshall * is such that if two separate TCP Urgent requests 248030088Sminshall * come in, one byte of TCP data will be overlaid. 248130088Sminshall * This is fatal for Telnet, but we try to live 248230088Sminshall * with it. 248330088Sminshall * 248430088Sminshall * In addition, in 4.2 (and...), a special protocol 248530088Sminshall * is needed to pick up the TCP Urgent data in 248630088Sminshall * the correct sequence. 248730088Sminshall * 248830088Sminshall * What we do is: if we think we are in urgent 248930088Sminshall * mode, we look to see if we are "at the mark". 249030088Sminshall * If we are, we do an OOB receive. If we run 249130088Sminshall * this twice, we will do the OOB receive twice, 249230088Sminshall * but the second will fail, since the second 249330088Sminshall * time we were "at the mark", but there wasn't 249430088Sminshall * any data there (the kernel doesn't reset 249530088Sminshall * "at the mark" until we do a normal read). 249630088Sminshall * Once we've read the OOB data, we go ahead 249730088Sminshall * and do normal reads. 249830088Sminshall * 249930088Sminshall * There is also another problem, which is that 250030088Sminshall * since the OOB byte we read doesn't put us 250130088Sminshall * out of OOB state, and since that byte is most 250230088Sminshall * likely the TELNET DM (data mark), we would 250330088Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 250430088Sminshall * So, clocks to the rescue. If we've "just" 250530088Sminshall * received a DM, then we test for the 250630088Sminshall * presence of OOB data when the receive OOB 250730088Sminshall * fails (and AFTER we did the normal mode read 250830088Sminshall * to clear "at the mark"). 250930088Sminshall */ 251030088Sminshall if (SYNCHing) { 251130088Sminshall int atmark; 251230088Sminshall 251330088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 251430088Sminshall if (atmark) { 251530422Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 251630088Sminshall if ((c == -1) && (errno == EINVAL)) { 2517*31131Sminshall c = recv(net, sbp+scc, canread, 0); 251830088Sminshall if (clocks.didnetreceive < clocks.gotDM) { 251930088Sminshall SYNCHing = stilloob(net); 252030088Sminshall } 252130088Sminshall } 252230088Sminshall } else { 2523*31131Sminshall c = recv(net, sbp+scc, canread, 0); 252430088Sminshall } 252530088Sminshall } else { 2526*31131Sminshall c = recv(net, sbp+scc, canread, 0); 252730088Sminshall } 252830088Sminshall settimer(didnetreceive); 252930088Sminshall #else /* !defined(SO_OOBINLINE) */ 2530*31131Sminshall c = recv(net, sbp+scc, canread, 0); 253130088Sminshall #endif /* !defined(SO_OOBINLINE) */ 253230088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 253330088Sminshall c = 0; 253430088Sminshall } else if (c <= 0) { 253530088Sminshall return -1; 253630088Sminshall } 253730088Sminshall if (netdata) { 253830422Sminshall Dump('<', sbp+scc, c); 253930088Sminshall } 254030088Sminshall scc += c; 254130088Sminshall returnValue = 1; 254230088Sminshall } 254330088Sminshall 254430088Sminshall /* 254530088Sminshall * Something to read from the tty... 254630088Sminshall */ 2547*31131Sminshall #if defined(MSDOS) 2548*31131Sminshall if ((tcc == 0) && NETROOM() && TerminalCanRead()) 2549*31131Sminshall #else /* defined(MSDOS) */ 2550*31131Sminshall if (FD_ISSET(tin, &ibits)) 2551*31131Sminshall #endif /* defined(MSDOS) */ 2552*31131Sminshall { 255330088Sminshall FD_CLR(tin, &ibits); 255430088Sminshall if (tcc == 0) { 255530088Sminshall tbp = tibuf; /* nothing left, reset */ 255630088Sminshall } 2557*31131Sminshall c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp); 255830088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 255930088Sminshall c = 0; 256030088Sminshall } else { 256131124Sminshall #if defined(unix) 256230088Sminshall /* EOF detection for line mode!!!! */ 256330088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 256430088Sminshall /* must be an EOF... */ 256530088Sminshall *tbp = ntc.t_eofc; 256630088Sminshall c = 1; 256730088Sminshall } 256831124Sminshall #endif /* defined(unix) */ 256930088Sminshall if (c <= 0) { 257030088Sminshall tcc = c; 257130088Sminshall return -1; 257230088Sminshall } 257330088Sminshall } 257430088Sminshall tcc += c; 257530088Sminshall returnValue = 1; /* did something useful */ 257630088Sminshall } 257730088Sminshall 257830088Sminshall # if defined(TN3270) 257930088Sminshall if (tcc > 0) { 258030088Sminshall if (In3270) { 258130088Sminshall c = DataFromTerminal(tbp, tcc); 258230088Sminshall if (c) { 258330088Sminshall returnValue = 1; 258430088Sminshall } 258530088Sminshall tcc -= c; 258630088Sminshall tbp += c; 258730088Sminshall } else { 258830320Sminshall # endif /* defined(TN3270) */ 258930088Sminshall returnValue = 1; 259030088Sminshall while (tcc > 0) { 259130088Sminshall register int sc; 259230088Sminshall 259330088Sminshall if (NETROOM() < 2) { 259430088Sminshall flushline = 1; 259530088Sminshall break; 259630088Sminshall } 259730088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 259830088Sminshall if (sc == escape) { 259930088Sminshall command(0); 260030088Sminshall tcc = 0; 260130088Sminshall flushline = 1; 260230088Sminshall break; 260330088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 260430088Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 260530088Sminshall tbp++; 260630088Sminshall tcc--; 260730088Sminshall } else { 260830088Sminshall dontlecho = !dontlecho; 260930088Sminshall settimer(echotoggle); 261030088Sminshall setconnmode(); 261130088Sminshall tcc = 0; 261230088Sminshall flushline = 1; 261330088Sminshall break; 261430088Sminshall } 261530088Sminshall } 261630088Sminshall if (localchars) { 2617*31131Sminshall if (TerminalSpecialChars(sc) == 0) { 261830088Sminshall break; 261930088Sminshall } 262030088Sminshall } 262130088Sminshall switch (c) { 262230088Sminshall case '\n': 262330088Sminshall /* 262430088Sminshall * If we are in CRMOD mode (\r ==> \n) 262530088Sminshall * on our local machine, then probably 262630088Sminshall * a newline (unix) is CRLF (TELNET). 262730088Sminshall */ 262830088Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 262930088Sminshall NETADD('\r'); 263030088Sminshall } 263130088Sminshall NETADD('\n'); 263230088Sminshall flushline = 1; 263330088Sminshall break; 263430088Sminshall case '\r': 263530088Sminshall NET2ADD('\r', '\0'); 263630088Sminshall flushline = 1; 263730088Sminshall break; 263830088Sminshall case IAC: 263930088Sminshall NET2ADD(IAC, IAC); 264030088Sminshall break; 264130088Sminshall default: 264230088Sminshall NETADD(c); 264330088Sminshall break; 264430088Sminshall } 264530088Sminshall } 264630088Sminshall # if defined(TN3270) 264730088Sminshall } 264830088Sminshall } 264930088Sminshall # endif /* defined(TN3270) */ 265030088Sminshall 265130088Sminshall if ((!MODE_LINE(globalmode) || flushline) && 265230088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 265330088Sminshall FD_CLR(net, &obits); 265430088Sminshall returnValue = netflush(); 265530088Sminshall } 265630088Sminshall if (scc > 0) { 265730088Sminshall # if !defined(TN3270) 265830088Sminshall telrcv(); 265930088Sminshall returnValue = 1; 266030088Sminshall # else /* !defined(TN3270) */ 266130088Sminshall returnValue = Push3270(); 266230088Sminshall # endif /* !defined(TN3270) */ 266330088Sminshall } 2664*31131Sminshall #if defined(MSDOS) 2665*31131Sminshall if (TTYBYTES()) 2666*31131Sminshall #else /* defined(MSDOS) */ 2667*31131Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 2668*31131Sminshall #endif /* defined(MSDOS) */ 2669*31131Sminshall { 267030088Sminshall FD_CLR(tout, &obits); 267130088Sminshall returnValue = ttyflush(); 267230088Sminshall } 267330088Sminshall return returnValue; 267430088Sminshall } 267530088Sminshall 267630088Sminshall /* 267730088Sminshall * Select from tty and network... 267830088Sminshall */ 267930088Sminshall static void 268030088Sminshall telnet() 268130088Sminshall { 2682*31131Sminshall #if defined(MSDOS) 2683*31131Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */ 2684*31131Sminshall #else /* defined(MSDOS) */ 2685*31131Sminshall #define SCHED_BLOCK 1 2686*31131Sminshall #endif /* defined(MSDOS) */ 2687*31131Sminshall 268830088Sminshall #if defined(TN3270) && defined(unix) 268930088Sminshall int myPid; 269030088Sminshall #endif /* defined(TN3270) */ 269130088Sminshall 269230088Sminshall tout = fileno(stdout); 269330088Sminshall tin = fileno(stdin); 269430088Sminshall setconnmode(); 269530088Sminshall scc = 0; 269630088Sminshall tcc = 0; 269730088Sminshall FD_ZERO(&ibits); 269830088Sminshall FD_ZERO(&obits); 269930088Sminshall FD_ZERO(&xbits); 270030088Sminshall 270131124Sminshall NetNonblockingIO(net, 1); 270230088Sminshall 270330088Sminshall #if defined(TN3270) 270430088Sminshall #if !defined(DEBUG) /* DBX can't handle! */ 270531124Sminshall NetSigIO(net, 1); 270630088Sminshall #endif /* !defined(DEBUG) */ 270730088Sminshall 270831124Sminshall NetSetPgrp(net); 270930088Sminshall #endif /* defined(TN3270) */ 271030088Sminshall 271130088Sminshall 271231124Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 271331124Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 271431124Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 271531124Sminshall 271630320Sminshall # if !defined(TN3270) 271730088Sminshall if (telnetport) { 271830088Sminshall if (!hisopts[TELOPT_SGA]) { 271930088Sminshall willoption(TELOPT_SGA, 0); 272030088Sminshall } 272130088Sminshall if (!myopts[TELOPT_TTYPE]) { 272230088Sminshall dooption(TELOPT_TTYPE, 0); 272330088Sminshall } 272430088Sminshall } 272530320Sminshall # endif /* !defined(TN3270) */ 272630088Sminshall 272730088Sminshall # if !defined(TN3270) 272830088Sminshall for (;;) { 2729*31131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 273030088Sminshall setcommandmode(); 273130088Sminshall return; 273230088Sminshall } 273330088Sminshall } 273430088Sminshall # else /* !defined(TN3270) */ 273530088Sminshall for (;;) { 273630088Sminshall int schedValue; 273730088Sminshall 273830088Sminshall while (!In3270) { 2739*31131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 274030088Sminshall setcommandmode(); 274130088Sminshall return; 274230088Sminshall } 274330088Sminshall } 274430088Sminshall 274530088Sminshall while ((schedValue = Scheduler(0)) != 0) { 274630088Sminshall if (schedValue == -1) { 274730088Sminshall setcommandmode(); 274830088Sminshall return; 274930088Sminshall } 275030088Sminshall } 275130088Sminshall /* If there is data waiting to go out to terminal, don't 275230088Sminshall * schedule any more data for the terminal. 275330088Sminshall */ 275430088Sminshall if (tfrontp-tbackp) { 275530088Sminshall schedValue = 1; 275630088Sminshall } else { 275730088Sminshall schedValue = DoTerminalOutput(); 275830088Sminshall } 275930088Sminshall if (schedValue) { 2760*31131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 276130088Sminshall setcommandmode(); 276230088Sminshall return; 276330088Sminshall } 276430088Sminshall } 276530088Sminshall } 276630088Sminshall # endif /* !defined(TN3270) */ 276730088Sminshall } 276830088Sminshall 276930088Sminshall /* 277030088Sminshall * The following are data structures and routines for 277130088Sminshall * the "send" command. 277230088Sminshall * 277330088Sminshall */ 277430088Sminshall 277530088Sminshall struct sendlist { 277630088Sminshall char *name; /* How user refers to it (case independent) */ 277730088Sminshall int what; /* Character to be sent (<0 ==> special) */ 277830088Sminshall char *help; /* Help information (0 ==> no help) */ 277930088Sminshall #if defined(NOT43) 278030088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 278130088Sminshall #else /* defined(NOT43) */ 278230088Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 278330088Sminshall #endif /* defined(NOT43) */ 278430088Sminshall }; 278530088Sminshall 278630088Sminshall #define SENDQUESTION -1 278730088Sminshall #define SENDESCAPE -3 278830088Sminshall 278930088Sminshall static struct sendlist Sendlist[] = { 279030088Sminshall { "ao", AO, "Send Telnet Abort output" }, 279130088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 279230088Sminshall { "brk", BREAK, "Send Telnet Break" }, 279330088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 279430088Sminshall { "el", EL, "Send Telnet Erase Line" }, 279530088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 279630088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 279730088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 279830088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 279930088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 280030088Sminshall { "?", SENDQUESTION, "Display send options" }, 280130088Sminshall { 0 } 280230088Sminshall }; 280330088Sminshall 280430088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 280530088Sminshall { "break", BREAK, 0 }, 280630088Sminshall 280730088Sminshall { "intp", IP, 0 }, 280830088Sminshall { "interrupt", IP, 0 }, 280930088Sminshall { "intr", IP, 0 }, 281030088Sminshall 281130088Sminshall { "help", SENDQUESTION, 0 }, 281230088Sminshall 281330088Sminshall { 0 } 281430088Sminshall }; 281530088Sminshall 281630088Sminshall static char ** 281730088Sminshall getnextsend(name) 281830088Sminshall char *name; 281930088Sminshall { 282030088Sminshall struct sendlist *c = (struct sendlist *) name; 282130088Sminshall 282230088Sminshall return (char **) (c+1); 282330088Sminshall } 282430088Sminshall 282530088Sminshall static struct sendlist * 282630088Sminshall getsend(name) 282730088Sminshall char *name; 282830088Sminshall { 282930088Sminshall struct sendlist *sl; 283030088Sminshall 283130088Sminshall if ((sl = (struct sendlist *) 283230088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 283330088Sminshall return sl; 283430088Sminshall } else { 283530088Sminshall return (struct sendlist *) 283630088Sminshall genget(name, (char **) Sendlist2, getnextsend); 283730088Sminshall } 283830088Sminshall } 283930088Sminshall 284030088Sminshall static 284130088Sminshall sendcmd(argc, argv) 284230088Sminshall int argc; 284330088Sminshall char **argv; 284430088Sminshall { 284530088Sminshall int what; /* what we are sending this time */ 284630088Sminshall int count; /* how many bytes we are going to need to send */ 284730088Sminshall int i; 284830088Sminshall int question = 0; /* was at least one argument a question */ 284930088Sminshall struct sendlist *s; /* pointer to current command */ 285030088Sminshall 285130088Sminshall if (argc < 2) { 285230088Sminshall printf("need at least one argument for 'send' command\n"); 285330088Sminshall printf("'send ?' for help\n"); 285430088Sminshall return 0; 285530088Sminshall } 285630088Sminshall /* 285730088Sminshall * First, validate all the send arguments. 285830088Sminshall * In addition, we see how much space we are going to need, and 285930088Sminshall * whether or not we will be doing a "SYNCH" operation (which 286030088Sminshall * flushes the network queue). 286130088Sminshall */ 286230088Sminshall count = 0; 286330088Sminshall for (i = 1; i < argc; i++) { 286430088Sminshall s = getsend(argv[i]); 286530088Sminshall if (s == 0) { 286630088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 286730088Sminshall argv[i]); 286830088Sminshall return 0; 286930088Sminshall } else if (s == Ambiguous(struct sendlist *)) { 287030088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 287130088Sminshall argv[i]); 287230088Sminshall return 0; 287330088Sminshall } 287430088Sminshall switch (s->what) { 287530088Sminshall case SENDQUESTION: 287630088Sminshall break; 287730088Sminshall case SENDESCAPE: 287830088Sminshall count += 1; 287930088Sminshall break; 288030088Sminshall case SYNCH: 288130088Sminshall count += 2; 288230088Sminshall break; 288330088Sminshall default: 288430088Sminshall count += 2; 288530088Sminshall break; 288630088Sminshall } 288730088Sminshall } 288830088Sminshall /* Now, do we have enough room? */ 288930088Sminshall if (NETROOM() < count) { 289030088Sminshall printf("There is not enough room in the buffer TO the network\n"); 289130088Sminshall printf("to process your request. Nothing will be done.\n"); 289230088Sminshall printf("('send synch' will throw away most data in the network\n"); 289330088Sminshall printf("buffer, if this might help.)\n"); 289430088Sminshall return 0; 289530088Sminshall } 289630088Sminshall /* OK, they are all OK, now go through again and actually send */ 289730088Sminshall for (i = 1; i < argc; i++) { 289830088Sminshall if ((s = getsend(argv[i])) == 0) { 289930088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 290030088Sminshall quit(); 290130088Sminshall /*NOTREACHED*/ 290230088Sminshall } 290330088Sminshall if (s->routine) { 290430088Sminshall (*s->routine)(s); 290530088Sminshall } else { 290630088Sminshall switch (what = s->what) { 290730088Sminshall case SYNCH: 290830088Sminshall dosynch(); 290930088Sminshall break; 291030088Sminshall case SENDQUESTION: 291130088Sminshall for (s = Sendlist; s->name; s++) { 291230088Sminshall if (s->help) { 291330088Sminshall printf(s->name); 291430088Sminshall if (s->help) { 291530088Sminshall printf("\t%s", s->help); 291630088Sminshall } 291730088Sminshall printf("\n"); 291830088Sminshall } 291930088Sminshall } 292030088Sminshall question = 1; 292130088Sminshall break; 292230088Sminshall case SENDESCAPE: 292330088Sminshall NETADD(escape); 292430088Sminshall break; 292530088Sminshall default: 292630088Sminshall NET2ADD(IAC, what); 292730088Sminshall break; 292830088Sminshall } 292930088Sminshall } 293030088Sminshall } 293130088Sminshall return !question; 293230088Sminshall } 293330088Sminshall 293430088Sminshall /* 293530088Sminshall * The following are the routines and data structures referred 293630088Sminshall * to by the arguments to the "toggle" command. 293730088Sminshall */ 293830088Sminshall 293930088Sminshall static 294030088Sminshall lclchars() 294130088Sminshall { 294230088Sminshall donelclchars = 1; 294330088Sminshall return 1; 294430088Sminshall } 294530088Sminshall 294630088Sminshall static 294730088Sminshall togdebug() 294830088Sminshall { 294930088Sminshall #ifndef NOT43 295030088Sminshall if (net > 0 && 295131124Sminshall (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 295230088Sminshall perror("setsockopt (SO_DEBUG)"); 295330088Sminshall } 295430320Sminshall #else /* NOT43 */ 295530088Sminshall if (debug) { 295631124Sminshall if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 295730088Sminshall perror("setsockopt (SO_DEBUG)"); 295830088Sminshall } else 295930088Sminshall printf("Cannot turn off socket debugging\n"); 296030320Sminshall #endif /* NOT43 */ 296130088Sminshall return 1; 296230088Sminshall } 296330088Sminshall 296430088Sminshall 296530088Sminshall 296630088Sminshall extern int togglehelp(); 296730088Sminshall 296830088Sminshall struct togglelist { 296930088Sminshall char *name; /* name of toggle */ 297030088Sminshall char *help; /* help message */ 297130088Sminshall int (*handler)(); /* routine to do actual setting */ 297230088Sminshall int dohelp; /* should we display help information */ 297330088Sminshall int *variable; 297430088Sminshall char *actionexplanation; 297530088Sminshall }; 297630088Sminshall 297730088Sminshall static struct togglelist Togglelist[] = { 297830088Sminshall { "autoflush", 297930088Sminshall "toggle flushing of output when sending interrupt characters", 298030088Sminshall 0, 298130088Sminshall 1, 298230088Sminshall &autoflush, 298330088Sminshall "flush output when sending interrupt characters" }, 298430088Sminshall { "autosynch", 298530088Sminshall "toggle automatic sending of interrupt characters in urgent mode", 298630088Sminshall 0, 298730088Sminshall 1, 298830088Sminshall &autosynch, 298930088Sminshall "send interrupt characters in urgent mode" }, 299030088Sminshall { "crmod", 299130088Sminshall "toggle mapping of received carriage returns", 299230088Sminshall 0, 299330088Sminshall 1, 299430088Sminshall &crmod, 299530088Sminshall "map carriage return on output" }, 299630088Sminshall { "localchars", 299730088Sminshall "toggle local recognition of certain control characters", 299830088Sminshall lclchars, 299930088Sminshall 1, 300030088Sminshall &localchars, 300130088Sminshall "recognize certain control characters" }, 300230088Sminshall { " ", "", 0, 1 }, /* empty line */ 300330088Sminshall { "debug", 300430088Sminshall "(debugging) toggle debugging", 300530088Sminshall togdebug, 300630088Sminshall 1, 300730088Sminshall &debug, 300830088Sminshall "turn on socket level debugging" }, 300930088Sminshall { "netdata", 301030088Sminshall "(debugging) toggle printing of hexadecimal network data", 301130088Sminshall 0, 301230088Sminshall 1, 301330088Sminshall &netdata, 301430088Sminshall "print hexadecimal representation of network traffic" }, 301530088Sminshall { "options", 301630088Sminshall "(debugging) toggle viewing of options processing", 301730088Sminshall 0, 301830088Sminshall 1, 301930088Sminshall &showoptions, 302030088Sminshall "show option processing" }, 302130088Sminshall { " ", "", 0, 1 }, /* empty line */ 302230088Sminshall { "?", 302330088Sminshall "display help information", 302430088Sminshall togglehelp, 302530088Sminshall 1 }, 302630088Sminshall { "help", 302730088Sminshall "display help information", 302830088Sminshall togglehelp, 302930088Sminshall 0 }, 303030088Sminshall { 0 } 303130088Sminshall }; 303230088Sminshall 303330088Sminshall static 303430088Sminshall togglehelp() 303530088Sminshall { 303630088Sminshall struct togglelist *c; 303730088Sminshall 303830088Sminshall for (c = Togglelist; c->name; c++) { 303930088Sminshall if (c->dohelp) { 304030088Sminshall printf("%s\t%s\n", c->name, c->help); 304130088Sminshall } 304230088Sminshall } 304330088Sminshall return 0; 304430088Sminshall } 304530088Sminshall 304630088Sminshall static char ** 304730088Sminshall getnexttoggle(name) 304830088Sminshall char *name; 304930088Sminshall { 305030088Sminshall struct togglelist *c = (struct togglelist *) name; 305130088Sminshall 305230088Sminshall return (char **) (c+1); 305330088Sminshall } 305430088Sminshall 305530088Sminshall static struct togglelist * 305630088Sminshall gettoggle(name) 305730088Sminshall char *name; 305830088Sminshall { 305930088Sminshall return (struct togglelist *) 306030088Sminshall genget(name, (char **) Togglelist, getnexttoggle); 306130088Sminshall } 306230088Sminshall 306330088Sminshall static 306430088Sminshall toggle(argc, argv) 306530088Sminshall int argc; 306630088Sminshall char *argv[]; 306730088Sminshall { 306830088Sminshall int retval = 1; 306930088Sminshall char *name; 307030088Sminshall struct togglelist *c; 307130088Sminshall 307230088Sminshall if (argc < 2) { 307330088Sminshall fprintf(stderr, 307430088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 307530088Sminshall return 0; 307630088Sminshall } 307730088Sminshall argc--; 307830088Sminshall argv++; 307930088Sminshall while (argc--) { 308030088Sminshall name = *argv++; 308130088Sminshall c = gettoggle(name); 308230088Sminshall if (c == Ambiguous(struct togglelist *)) { 308330088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 308430088Sminshall name); 308530088Sminshall return 0; 308630088Sminshall } else if (c == 0) { 308730088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 308830088Sminshall name); 308930088Sminshall return 0; 309030088Sminshall } else { 309130088Sminshall if (c->variable) { 309230088Sminshall *c->variable = !*c->variable; /* invert it */ 309330088Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 309430088Sminshall c->actionexplanation); 309530088Sminshall } 309630088Sminshall if (c->handler) { 309730088Sminshall retval &= (*c->handler)(c); 309830088Sminshall } 309930088Sminshall } 310030088Sminshall } 310130088Sminshall return retval; 310230088Sminshall } 310330088Sminshall 310430088Sminshall /* 310530088Sminshall * The following perform the "set" command. 310630088Sminshall */ 310730088Sminshall 310830088Sminshall struct setlist { 310930088Sminshall char *name; /* name */ 311030088Sminshall char *help; /* help information */ 311130088Sminshall char *charp; /* where it is located at */ 311230088Sminshall }; 311330088Sminshall 311430088Sminshall static struct setlist Setlist[] = { 311530088Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 311630088Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 311730088Sminshall { " ", "" }, 311830088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 311931124Sminshall #if defined(unix) 312030088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 312130088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 312230088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 312330088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 312430088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 312530088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 312631124Sminshall #endif /* defined(unix) */ 312731124Sminshall #if defined(MSDOS) 312831124Sminshall { "erase", "character to cause an Erase Character", &termEraseChar }, 312931124Sminshall { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 313031124Sminshall { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 313131124Sminshall { "kill", "character to cause an Erase Line", &termKillChar }, 313231124Sminshall { "quit", "character to cause a Break", &termQuitChar }, 313331124Sminshall { "eof", "character to cause an EOF ", &termEofChar }, 313431124Sminshall #endif /* defined(MSDOS) */ 313530088Sminshall { 0 } 313630088Sminshall }; 313730088Sminshall 313830088Sminshall static char ** 313930088Sminshall getnextset(name) 314030088Sminshall char *name; 314130088Sminshall { 314230088Sminshall struct setlist *c = (struct setlist *)name; 314330088Sminshall 314430088Sminshall return (char **) (c+1); 314530088Sminshall } 314630088Sminshall 314730088Sminshall static struct setlist * 314830088Sminshall getset(name) 314930088Sminshall char *name; 315030088Sminshall { 315130088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 315230088Sminshall } 315330088Sminshall 315430088Sminshall static 315530088Sminshall setcmd(argc, argv) 315630088Sminshall int argc; 315730088Sminshall char *argv[]; 315830088Sminshall { 315930088Sminshall int value; 316030088Sminshall struct setlist *ct; 316130088Sminshall 316230088Sminshall /* XXX back we go... sigh */ 316330088Sminshall if (argc != 3) { 316430088Sminshall if ((argc == 2) && 316530088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 316630088Sminshall for (ct = Setlist; ct->name; ct++) { 316730088Sminshall printf("%s\t%s\n", ct->name, ct->help); 316830088Sminshall } 316930088Sminshall printf("?\tdisplay help information\n"); 317030088Sminshall } else { 317130088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 317230088Sminshall } 317330088Sminshall return 0; 317430088Sminshall } 317530088Sminshall 317630088Sminshall ct = getset(argv[1]); 317730088Sminshall if (ct == 0) { 317830088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 317930088Sminshall argv[1]); 318030088Sminshall return 0; 318130088Sminshall } else if (ct == Ambiguous(struct setlist *)) { 318230088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 318330088Sminshall argv[1]); 318430088Sminshall return 0; 318530088Sminshall } else { 318630088Sminshall if (strcmp("off", argv[2])) { 318730088Sminshall value = special(argv[2]); 318830088Sminshall } else { 318930088Sminshall value = -1; 319030088Sminshall } 319130088Sminshall *(ct->charp) = value; 319230088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 319330088Sminshall } 319430088Sminshall return 1; 319530088Sminshall } 319630088Sminshall 319730088Sminshall /* 319830088Sminshall * The following are the data structures and routines for the 319930088Sminshall * 'mode' command. 320030088Sminshall */ 320130088Sminshall 320230088Sminshall static 320330088Sminshall dolinemode() 320430088Sminshall { 320530088Sminshall if (hisopts[TELOPT_SGA]) { 320630088Sminshall wontoption(TELOPT_SGA, 0); 320730088Sminshall } 320830088Sminshall if (hisopts[TELOPT_ECHO]) { 320930088Sminshall wontoption(TELOPT_ECHO, 0); 321030088Sminshall } 321130088Sminshall return 1; 321230088Sminshall } 321330088Sminshall 321430088Sminshall static 321530088Sminshall docharmode() 321630088Sminshall { 321730088Sminshall if (!hisopts[TELOPT_SGA]) { 321830088Sminshall willoption(TELOPT_SGA, 0); 321930088Sminshall } 322030088Sminshall if (!hisopts[TELOPT_ECHO]) { 322130088Sminshall willoption(TELOPT_ECHO, 0); 322230088Sminshall } 322330088Sminshall return 1; 322430088Sminshall } 322530088Sminshall 322630088Sminshall static struct cmd Modelist[] = { 322730088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 322830088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 322930088Sminshall { 0 }, 323030088Sminshall }; 323130088Sminshall 323230088Sminshall static char ** 323330088Sminshall getnextmode(name) 323430088Sminshall char *name; 323530088Sminshall { 323630088Sminshall struct cmd *c = (struct cmd *) name; 323730088Sminshall 323830088Sminshall return (char **) (c+1); 323930088Sminshall } 324030088Sminshall 324130088Sminshall static struct cmd * 324230088Sminshall getmodecmd(name) 324330088Sminshall char *name; 324430088Sminshall { 324530088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 324630088Sminshall } 324730088Sminshall 324830088Sminshall static 324930088Sminshall modecmd(argc, argv) 325030088Sminshall int argc; 325130088Sminshall char *argv[]; 325230088Sminshall { 325330088Sminshall struct cmd *mt; 325430088Sminshall 325530088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 325630088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 325730088Sminshall for (mt = Modelist; mt->name; mt++) { 325830088Sminshall printf("%s\t%s\n", mt->name, mt->help); 325930088Sminshall } 326030088Sminshall return 0; 326130088Sminshall } 326230088Sminshall mt = getmodecmd(argv[1]); 326330088Sminshall if (mt == 0) { 326430088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 326530088Sminshall return 0; 326630088Sminshall } else if (mt == Ambiguous(struct cmd *)) { 326730088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 326830088Sminshall return 0; 326930088Sminshall } else { 327030088Sminshall (*mt->handler)(); 327130088Sminshall } 327230088Sminshall return 1; 327330088Sminshall } 327430088Sminshall 327530088Sminshall /* 327630088Sminshall * The following data structures and routines implement the 327730088Sminshall * "display" command. 327830088Sminshall */ 327930088Sminshall 328030088Sminshall static 328130088Sminshall display(argc, argv) 328230088Sminshall int argc; 328330088Sminshall char *argv[]; 328430088Sminshall { 328530088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 328630088Sminshall if (*tl->variable) { \ 328730088Sminshall printf("will"); \ 328830088Sminshall } else { \ 328930088Sminshall printf("won't"); \ 329030088Sminshall } \ 329130088Sminshall printf(" %s.\n", tl->actionexplanation); \ 329230088Sminshall } 329330088Sminshall 329430088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 329530088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 329630088Sminshall } 329730088Sminshall 329830088Sminshall struct togglelist *tl; 329930088Sminshall struct setlist *sl; 330030088Sminshall 330130088Sminshall if (argc == 1) { 330230088Sminshall for (tl = Togglelist; tl->name; tl++) { 330330088Sminshall dotog(tl); 330430088Sminshall } 330530088Sminshall printf("\n"); 330630088Sminshall for (sl = Setlist; sl->name; sl++) { 330730088Sminshall doset(sl); 330830088Sminshall } 330930088Sminshall } else { 331030088Sminshall int i; 331130088Sminshall 331230088Sminshall for (i = 1; i < argc; i++) { 331330088Sminshall sl = getset(argv[i]); 331430088Sminshall tl = gettoggle(argv[i]); 331530088Sminshall if ((sl == Ambiguous(struct setlist *)) || 331630088Sminshall (tl == Ambiguous(struct togglelist *))) { 331730088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 331830088Sminshall return 0; 331930088Sminshall } else if (!sl && !tl) { 332030088Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 332130088Sminshall return 0; 332230088Sminshall } else { 332330088Sminshall if (tl) { 332430088Sminshall dotog(tl); 332530088Sminshall } 332630088Sminshall if (sl) { 332730088Sminshall doset(sl); 332830088Sminshall } 332930088Sminshall } 333030088Sminshall } 333130088Sminshall } 333230088Sminshall return 1; 333330088Sminshall #undef doset 333430088Sminshall #undef dotog 333530088Sminshall } 333630088Sminshall 333730088Sminshall /* 333830088Sminshall * The following are the data structures, and many of the routines, 333930088Sminshall * relating to command processing. 334030088Sminshall */ 334130088Sminshall 334230088Sminshall /* 334330088Sminshall * Set the escape character. 334430088Sminshall */ 334530088Sminshall static 334630088Sminshall setescape(argc, argv) 334730088Sminshall int argc; 334830088Sminshall char *argv[]; 334930088Sminshall { 335030088Sminshall register char *arg; 335130088Sminshall char buf[50]; 335230088Sminshall 335330088Sminshall printf( 335430088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 335530088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 335630088Sminshall if (argc > 2) 335730088Sminshall arg = argv[1]; 335830088Sminshall else { 335930088Sminshall printf("new escape character: "); 336030088Sminshall gets(buf); 336130088Sminshall arg = buf; 336230088Sminshall } 336330088Sminshall if (arg[0] != '\0') 336430088Sminshall escape = arg[0]; 336530088Sminshall if (!In3270) { 336630088Sminshall printf("Escape character is '%s'.\n", control(escape)); 336730088Sminshall } 336830088Sminshall fflush(stdout); 336930088Sminshall return 1; 337030088Sminshall } 337130088Sminshall 337230088Sminshall /*VARARGS*/ 337330088Sminshall static 337430088Sminshall togcrmod() 337530088Sminshall { 337630088Sminshall crmod = !crmod; 337730088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 337830088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 337930088Sminshall fflush(stdout); 338030088Sminshall return 1; 338130088Sminshall } 338230088Sminshall 338330088Sminshall /*VARARGS*/ 338430088Sminshall suspend() 338530088Sminshall { 338630088Sminshall setcommandmode(); 338730088Sminshall #if defined(unix) 338830088Sminshall kill(0, SIGTSTP); 338931124Sminshall /* reget parameters in case they were changed */ 339031124Sminshall TerminalSaveState(); 339130088Sminshall #endif /* defined(unix) */ 339230088Sminshall return 1; 339330088Sminshall } 339430088Sminshall 339530088Sminshall /*VARARGS*/ 339630088Sminshall static 339730326Sminshall bye(argc, argv) 339830326Sminshall int argc; /* Number of arguments */ 339930326Sminshall char *argv[]; /* arguments */ 340030088Sminshall { 340130088Sminshall if (connected) { 340230088Sminshall shutdown(net, 2); 340330088Sminshall printf("Connection closed.\n"); 3404*31131Sminshall NetClose(net); 340530088Sminshall connected = 0; 340630088Sminshall /* reset options */ 340730326Sminshall tninit(); 340830088Sminshall #if defined(TN3270) 340930326Sminshall SetIn3270(); /* Get out of 3270 mode */ 341030088Sminshall #endif /* defined(TN3270) */ 341130088Sminshall } 341230326Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 341330326Sminshall longjmp(toplevel, 1); 341430326Sminshall /* NOTREACHED */ 341530326Sminshall } 341630326Sminshall return 1; /* Keep lint, etc., happy */ 341730088Sminshall } 341830088Sminshall 341930088Sminshall /*VARARGS*/ 342030088Sminshall quit() 342130088Sminshall { 342230326Sminshall (void) call(bye, "bye", "fromquit", 0); 342330088Sminshall Exit(0); 342430088Sminshall /*NOTREACHED*/ 342530088Sminshall return 1; /* just to keep lint happy */ 342630088Sminshall } 342730088Sminshall 342830088Sminshall /* 342930088Sminshall * Print status about the connection. 343030088Sminshall */ 343130088Sminshall static 343230088Sminshall status(argc, argv) 343330088Sminshall int argc; 343430088Sminshall char *argv[]; 343530088Sminshall { 343630088Sminshall if (connected) { 343730088Sminshall printf("Connected to %s.\n", hostname); 343830088Sminshall if (argc < 2) { 343930088Sminshall printf("Operating in %s.\n", 344030088Sminshall modelist[getconnmode()].modedescriptions); 344130088Sminshall if (localchars) { 344230088Sminshall printf("Catching signals locally.\n"); 344330088Sminshall } 344430088Sminshall } 344530088Sminshall } else { 344630088Sminshall printf("No connection.\n"); 344730088Sminshall } 344830088Sminshall # if !defined(TN3270) 344930088Sminshall printf("Escape character is '%s'.\n", control(escape)); 345030088Sminshall fflush(stdout); 345130088Sminshall # else /* !defined(TN3270) */ 345230088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 345330088Sminshall printf("Escape character is '%s'.\n", control(escape)); 345430088Sminshall } 345530088Sminshall # if defined(unix) 345630088Sminshall if (In3270 && transcom) { 345730088Sminshall printf("Transparent mode command is '%s'.\n", transcom); 345830088Sminshall } 345930088Sminshall # endif /* defined(unix) */ 346030088Sminshall fflush(stdout); 346130088Sminshall if (In3270) { 346230088Sminshall return 0; 346330088Sminshall } 346430088Sminshall # endif /* defined(TN3270) */ 346530088Sminshall return 1; 346630088Sminshall } 346730088Sminshall 346830088Sminshall #if defined(TN3270) && defined(unix) 346930088Sminshall static 347030088Sminshall settranscom(argc, argv) 347130088Sminshall int argc; 347230088Sminshall char *argv[]; 347330088Sminshall { 347430088Sminshall int i, len = 0; 347530088Sminshall char *strcpy(), *strcat(); 347630088Sminshall 347730088Sminshall if (argc == 1 && transcom) { 347830088Sminshall transcom = 0; 347930088Sminshall } 348030088Sminshall if (argc == 1) { 348130088Sminshall return; 348230088Sminshall } 348330088Sminshall for (i = 1; i < argc; ++i) { 348430088Sminshall len += 1 + strlen(argv[1]); 348530088Sminshall } 348630088Sminshall transcom = tline; 348730088Sminshall (void) strcpy(transcom, argv[1]); 348830088Sminshall for (i = 2; i < argc; ++i) { 348930088Sminshall (void) strcat(transcom, " "); 349030088Sminshall (void) strcat(transcom, argv[i]); 349130088Sminshall } 349230088Sminshall } 349330088Sminshall #endif /* defined(TN3270) && defined(unix) */ 349430088Sminshall 349530088Sminshall 349630088Sminshall static 349730088Sminshall tn(argc, argv) 349830088Sminshall int argc; 349930088Sminshall char *argv[]; 350030088Sminshall { 350130088Sminshall register struct hostent *host = 0; 3502*31131Sminshall #if defined(MSDOS) 350330088Sminshall char *cp; 3504*31131Sminshall #endif /* defined(MSDOS) */ 350530088Sminshall 350630088Sminshall if (connected) { 350730088Sminshall printf("?Already connected to %s\n", hostname); 350830088Sminshall return 0; 350930088Sminshall } 351030088Sminshall if (argc < 2) { 351130088Sminshall (void) strcpy(line, "Connect "); 351230088Sminshall printf("(to) "); 351330088Sminshall gets(&line[strlen(line)]); 351430088Sminshall makeargv(); 351530088Sminshall argc = margc; 351630088Sminshall argv = margv; 351730088Sminshall } 351830088Sminshall if (argc > 3) { 351930088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 352030088Sminshall return 0; 352130088Sminshall } 3522*31131Sminshall #if defined(MSDOS) 352330088Sminshall for (cp = argv[1]; *cp; cp++) { 352430088Sminshall if (isupper(*cp)) { 352530088Sminshall *cp = tolower(*cp); 352630088Sminshall } 352730088Sminshall } 3528*31131Sminshall #endif /* defined(MSDOS) */ 352930088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 353030088Sminshall if (sin.sin_addr.s_addr != -1) { 353130088Sminshall sin.sin_family = AF_INET; 353230088Sminshall (void) strcpy(hnamebuf, argv[1]); 353330088Sminshall hostname = hnamebuf; 353430088Sminshall } else { 353530088Sminshall host = gethostbyname(argv[1]); 353630088Sminshall if (host) { 353730088Sminshall sin.sin_family = host->h_addrtype; 353830088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 3539*31131Sminshall memcpy((caddr_t)&sin.sin_addr, 3540*31131Sminshall host->h_addr_list[0], host->h_length); 354130088Sminshall #else /* defined(h_addr) */ 3542*31131Sminshall memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 354330088Sminshall #endif /* defined(h_addr) */ 354430088Sminshall hostname = host->h_name; 354530088Sminshall } else { 354630088Sminshall printf("%s: unknown host\n", argv[1]); 354730088Sminshall return 0; 354830088Sminshall } 354930088Sminshall } 355030088Sminshall sin.sin_port = sp->s_port; 355130088Sminshall if (argc == 3) { 355230088Sminshall sin.sin_port = atoi(argv[2]); 355330088Sminshall if (sin.sin_port == 0) { 355430088Sminshall sp = getservbyname(argv[2], "tcp"); 355530088Sminshall if (sp) 355630088Sminshall sin.sin_port = sp->s_port; 355730088Sminshall else { 355830088Sminshall printf("%s: bad port number\n", argv[2]); 355930088Sminshall return 0; 356030088Sminshall } 356130088Sminshall } else { 356230088Sminshall sin.sin_port = atoi(argv[2]); 356330088Sminshall sin.sin_port = htons(sin.sin_port); 356430088Sminshall } 356530088Sminshall telnetport = 0; 356630088Sminshall } else { 356730088Sminshall telnetport = 1; 356830088Sminshall } 356930088Sminshall #if defined(unix) 357030088Sminshall signal(SIGINT, intr); 357130088Sminshall signal(SIGQUIT, intr2); 357230088Sminshall signal(SIGPIPE, deadpeer); 357330088Sminshall #endif /* defined(unix) */ 357430088Sminshall printf("Trying...\n"); 357530088Sminshall do { 357630088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 357730088Sminshall if (net < 0) { 357830088Sminshall perror("telnet: socket"); 357930088Sminshall return 0; 358030088Sminshall } 358131124Sminshall if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 358230088Sminshall perror("setsockopt (SO_DEBUG)"); 358331124Sminshall } 358430088Sminshall 358530088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 358630088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 358730088Sminshall if (host && host->h_addr_list[1]) { 358830088Sminshall int oerrno = errno; 358930088Sminshall 359030088Sminshall fprintf(stderr, "telnet: connect to address %s: ", 359130088Sminshall inet_ntoa(sin.sin_addr)); 359230088Sminshall errno = oerrno; 359330088Sminshall perror((char *)0); 359430088Sminshall host->h_addr_list++; 3595*31131Sminshall memcpy((caddr_t)&sin.sin_addr, 3596*31131Sminshall host->h_addr_list[0], host->h_length); 359730088Sminshall fprintf(stderr, "Trying %s...\n", 359830088Sminshall inet_ntoa(sin.sin_addr)); 3599*31131Sminshall (void) NetClose(net); 360030088Sminshall continue; 360130088Sminshall } 360230088Sminshall #endif /* defined(h_addr) */ 360330088Sminshall perror("telnet: Unable to connect to remote host"); 360430088Sminshall #if defined(unix) 360530088Sminshall signal(SIGINT, SIG_DFL); 360630088Sminshall signal(SIGQUIT, SIG_DFL); 360730320Sminshall #endif /* defined(unix) */ 360830088Sminshall return 0; 360930088Sminshall } 361030088Sminshall connected++; 361130088Sminshall } while (connected == 0); 361230088Sminshall call(status, "status", "notmuch", 0); 361330088Sminshall if (setjmp(peerdied) == 0) 361430088Sminshall telnet(); 3615*31131Sminshall NetClose(net); 361630088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1); 361730088Sminshall /*NOTREACHED*/ 361830088Sminshall } 361930088Sminshall 362030088Sminshall 362130088Sminshall #define HELPINDENT (sizeof ("connect")) 362230088Sminshall 362330088Sminshall static char 362430088Sminshall openhelp[] = "connect to a site", 362530088Sminshall closehelp[] = "close current connection", 362630088Sminshall quithelp[] = "exit telnet", 362730088Sminshall zhelp[] = "suspend telnet", 362830088Sminshall statushelp[] = "print status information", 362930088Sminshall helphelp[] = "print help information", 363030088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 363130088Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 363230088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 363330088Sminshall displayhelp[] = "display operating parameters", 363430088Sminshall #if defined(TN3270) && defined(unix) 363530088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 363630088Sminshall #endif /* defined(TN3270) && defined(unix) */ 363730088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 363830088Sminshall 363930088Sminshall extern int help(); 364030088Sminshall 364130088Sminshall static struct cmd cmdtab[] = { 364230088Sminshall { "close", closehelp, bye, 1, 1 }, 364330088Sminshall { "display", displayhelp, display, 1, 0 }, 364430088Sminshall { "mode", modehelp, modecmd, 1, 1 }, 364530088Sminshall { "open", openhelp, tn, 1, 0 }, 364630088Sminshall { "quit", quithelp, quit, 1, 0 }, 364730088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 364830088Sminshall { "set", sethelp, setcmd, 1, 0 }, 364930088Sminshall { "status", statushelp, status, 1, 0 }, 365030088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 365130088Sminshall #if defined(TN3270) && defined(unix) 365230088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 365330088Sminshall #endif /* defined(TN3270) && defined(unix) */ 365430088Sminshall { "z", zhelp, suspend, 1, 0 }, 365530088Sminshall { "?", helphelp, help, 1, 0 }, 365630088Sminshall 0 365730088Sminshall }; 365830088Sminshall 365930088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 366030088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 366130088Sminshall 366230088Sminshall static struct cmd cmdtab2[] = { 366330088Sminshall { "help", helphelp, help, 0, 0 }, 366430088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 366530088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 366630088Sminshall 0 366730088Sminshall }; 366830088Sminshall 366930088Sminshall /* 367030088Sminshall * Call routine with argc, argv set from args (terminated by 0). 367130088Sminshall * VARARGS2 367230088Sminshall */ 367330088Sminshall static 367430088Sminshall call(routine, args) 367530088Sminshall int (*routine)(); 367630088Sminshall char *args; 367730088Sminshall { 367830088Sminshall register char **argp; 367930088Sminshall register int argc; 368030088Sminshall 368130088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 368230088Sminshall ; 368330088Sminshall return (*routine)(argc, &args); 368430088Sminshall } 368530088Sminshall 368630088Sminshall static char ** 368730088Sminshall getnextcmd(name) 368830088Sminshall char *name; 368930088Sminshall { 369030088Sminshall struct cmd *c = (struct cmd *) name; 369130088Sminshall 369230088Sminshall return (char **) (c+1); 369330088Sminshall } 369430088Sminshall 369530088Sminshall static struct cmd * 369630088Sminshall getcmd(name) 369730088Sminshall char *name; 369830088Sminshall { 369930088Sminshall struct cmd *cm; 370030088Sminshall 370130088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 370230088Sminshall return cm; 370330088Sminshall } else { 370430088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 370530088Sminshall } 370630088Sminshall } 370730088Sminshall 370830088Sminshall void 370930088Sminshall command(top) 371030088Sminshall int top; 371130088Sminshall { 371230088Sminshall register struct cmd *c; 371330088Sminshall 371430088Sminshall setcommandmode(); 371530088Sminshall if (!top) { 371630088Sminshall putchar('\n'); 371730088Sminshall } else { 371830088Sminshall #if defined(unix) 371930088Sminshall signal(SIGINT, SIG_DFL); 372030088Sminshall signal(SIGQUIT, SIG_DFL); 372130088Sminshall #endif /* defined(unix) */ 372230088Sminshall } 372330088Sminshall for (;;) { 372430088Sminshall printf("%s> ", prompt); 372530088Sminshall if (gets(line) == NULL) { 372630088Sminshall if (feof(stdin) || ferror(stdin)) 372730088Sminshall quit(); 372830088Sminshall break; 372930088Sminshall } 373030088Sminshall if (line[0] == 0) 373130088Sminshall break; 373230088Sminshall makeargv(); 373330088Sminshall c = getcmd(margv[0]); 373430088Sminshall if (c == Ambiguous(struct cmd *)) { 373530088Sminshall printf("?Ambiguous command\n"); 373630088Sminshall continue; 373730088Sminshall } 373830088Sminshall if (c == 0) { 373930088Sminshall printf("?Invalid command\n"); 374030088Sminshall continue; 374130088Sminshall } 374230088Sminshall if (c->needconnect && !connected) { 374330088Sminshall printf("?Need to be connected first.\n"); 374430088Sminshall continue; 374530088Sminshall } 374630088Sminshall if ((*c->handler)(margc, margv)) { 374730088Sminshall break; 374830088Sminshall } 374930088Sminshall } 375030088Sminshall if (!top) { 375130088Sminshall if (!connected) { 375230088Sminshall longjmp(toplevel, 1); 375330088Sminshall /*NOTREACHED*/ 375430088Sminshall } 375530088Sminshall setconnmode(); 375630088Sminshall } 375730088Sminshall } 375830088Sminshall 375930088Sminshall /* 376030088Sminshall * Help command. 376130088Sminshall */ 376230088Sminshall static 376330088Sminshall help(argc, argv) 376430088Sminshall int argc; 376530088Sminshall char *argv[]; 376630088Sminshall { 376730088Sminshall register struct cmd *c; 376830088Sminshall 376930088Sminshall if (argc == 1) { 377030088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 377130088Sminshall for (c = cmdtab; c->name; c++) 377230088Sminshall if (c->dohelp) { 377330088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 377430088Sminshall c->help); 377530088Sminshall } 377630088Sminshall return 0; 377730088Sminshall } 377830088Sminshall while (--argc > 0) { 377930088Sminshall register char *arg; 378030088Sminshall arg = *++argv; 378130088Sminshall c = getcmd(arg); 378230088Sminshall if (c == Ambiguous(struct cmd *)) 378330088Sminshall printf("?Ambiguous help command %s\n", arg); 378430088Sminshall else if (c == (struct cmd *)0) 378530088Sminshall printf("?Invalid help command %s\n", arg); 378630088Sminshall else 378730088Sminshall printf("%s\n", c->help); 378830088Sminshall } 378930088Sminshall return 0; 379030088Sminshall } 379130088Sminshall 379230088Sminshall /* 379330088Sminshall * main. Parse arguments, invoke the protocol or command parser. 379430088Sminshall */ 379530088Sminshall 379630088Sminshall 379730088Sminshall void 379830088Sminshall main(argc, argv) 379930088Sminshall int argc; 380030088Sminshall char *argv[]; 380130088Sminshall { 380230326Sminshall tninit(); /* Clear out things */ 380330326Sminshall 380430088Sminshall NetTrace = stdout; 380531124Sminshall TerminalSaveState(); 380631124Sminshall autoflush = TerminalAutoFlush(); 380731124Sminshall 380830088Sminshall prompt = argv[0]; 380930088Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 381030088Sminshall debug = 1; 381130088Sminshall argv++; 381230088Sminshall argc--; 381330088Sminshall } 381430088Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 381530088Sminshall argv++; 381630088Sminshall argc--; 381730088Sminshall if (argc > 1) { /* get file name */ 381830088Sminshall NetTrace = fopen(argv[1], "w"); 381930088Sminshall argv++; 382030088Sminshall argc--; 382130088Sminshall if (NetTrace == NULL) { 382230088Sminshall NetTrace = stdout; 382330088Sminshall } 382430088Sminshall } 382530088Sminshall } 382630088Sminshall #if defined(TN3270) && defined(unix) 382730088Sminshall if (argc > 1 && !strcmp(argv[1], "-t")) { 382830088Sminshall argv++; 382930088Sminshall argc--; 383030088Sminshall if (argc > 1) { /* get command name */ 383130088Sminshall transcom = tline; 383230088Sminshall (void) strcpy(transcom, argv[1]); 383330088Sminshall argv++; 383430088Sminshall argc--; 383530088Sminshall } 383630088Sminshall } 383730088Sminshall #endif /* defined(TN3270) && defined(unix) */ 383830088Sminshall if (argc != 1) { 383930088Sminshall if (setjmp(toplevel) != 0) 384030088Sminshall Exit(0); 384130088Sminshall tn(argc, argv); 384230088Sminshall } 384330088Sminshall setjmp(toplevel); 384430088Sminshall for (;;) 384530088Sminshall command(1); 384630088Sminshall } 3847