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 * NOT43 - Allows the program to compile and run on 4730088Sminshall * a 4.2BSD system. 4830088Sminshall * 4930088Sminshall * PUTCHAR - Within tn3270, on a NOT43 system, 5030088Sminshall * allows the use of the 4.3 curses 5130088Sminshall * (greater speed updating the screen). 5230088Sminshall * You need the 4.3 curses for this to work. 5330088Sminshall * 5430088Sminshall * FD_SETSIZE - On whichever system, if this isn't defined, 5530088Sminshall * we patch over the FD_SET, etc., macros with 5630088Sminshall * some homebrewed ones. 5730088Sminshall * 5830088Sminshall * SO_OOBINLINE - This is a socket option which we would like 5930088Sminshall * to set to allow TCP urgent data to come 6030088Sminshall * to us "inline". This is NECESSARY for 6130088Sminshall * CORRECT operation, and desireable for 6230088Sminshall * simpler operation. 6330088Sminshall * 6430088Sminshall * LNOFLSH - Detects the presence of the LNOFLSH bit 6530088Sminshall * in the tty structure. 6630088Sminshall * 6730088Sminshall * unix - Compiles in unix specific stuff. 6830088Sminshall * 6931131Sminshall * MSDOS - Compiles in MSDOS specific stuff. 7030088Sminshall * 7130088Sminshall */ 7230088Sminshall 7330088Sminshall #if !defined(TN3270) 7430088Sminshall #define ExitString(f,s,r) { fprintf(f, s); exit(r); } 7530088Sminshall #define Exit(x) exit(x) 7630088Sminshall #define SetIn3270() 7730088Sminshall 7830088Sminshall void setcommandmode(), command(); /* forward declarations */ 7930088Sminshall #endif /* !defined(TN3270) */ 8030088Sminshall 8130088Sminshall #include <sys/types.h> 8230088Sminshall #include <sys/socket.h> 8330088Sminshall 8430088Sminshall #include <netinet/in.h> 8530088Sminshall 8631124Sminshall #if defined(unix) 8731124Sminshall /* By the way, we need to include curses.h before telnet.h since, 8831124Sminshall * among other things, telnet.h #defines 'DO', which is a variable 8931124Sminshall * declared in curses.h. 9031124Sminshall */ 9130088Sminshall #include <curses.h> 9231124Sminshall #endif /* defined(unix) */ 9330088Sminshall 9430088Sminshall #define TELOPTS 9530088Sminshall #include <arpa/telnet.h> 9630088Sminshall 9730088Sminshall #if !defined(NOT43) 9830088Sminshall #include <arpa/inet.h> 9930088Sminshall #else /* !defined(NOT43) */ 10030088Sminshall extern unsigned long inet_addr(); 10130088Sminshall extern char *inet_ntoa(); 10230088Sminshall #endif /* !defined(NOT43) */ 10330088Sminshall 10430088Sminshall #include <stdio.h> 10530088Sminshall #include <ctype.h> 10630088Sminshall #include <errno.h> 10730088Sminshall #include <setjmp.h> 10830088Sminshall #include <netdb.h> 10931124Sminshall 11031124Sminshall #if defined(unix) 11130088Sminshall #include <strings.h> 11231124Sminshall #else /* defined(unix) */ 11331124Sminshall #include <string.h> 11431124Sminshall #endif /* defined(unix) */ 11530088Sminshall 11630088Sminshall #if defined(TN3270) 11731215Sminshall #include "ascii/termin.ext" 11830088Sminshall #include "ctlr/screen.h" 11931215Sminshall #include "ctlr/oia.h" 12031215Sminshall #include "ctlr/options.ext" 12131215Sminshall #include "ctlr/outbound.ext" 12231187Sminshall #include "general/globals.h" 12330088Sminshall #include "telnet.ext" 12431131Sminshall #endif /* defined(TN3270) */ 12531215Sminshall 12631187Sminshall #include "general/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, 215*31478Sminshall noasynch = 0, /* User specified "-noasynch" on command line */ 21630722Sminshall askedSGA = 0, /* We have talked about suppress go ahead */ 21730088Sminshall telnetport = 1; 21830088Sminshall 21930326Sminshall static FILE *NetTrace = 0; /* Not in bss, since needs to stay */ 22030088Sminshall 22130088Sminshall #define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ 22230088Sminshall 22330088Sminshall static char 22430088Sminshall *prompt = 0, 22530326Sminshall escape, 22630326Sminshall echoc; 22730088Sminshall 22830088Sminshall static int 22930326Sminshall SYNCHing, /* we are in TELNET SYNCH mode */ 23030326Sminshall flushout, /* flush output */ 23130088Sminshall autoflush = 0, /* flush output when interrupting? */ 23230326Sminshall autosynch, /* send interrupt characters with SYNCH? */ 23330326Sminshall localchars, /* we recognize interrupt/quit */ 23430326Sminshall donelclchars, /* the user has set "localchars" */ 23531124Sminshall dontlecho, /* do we suppress local echoing right now? */ 23631124Sminshall globalmode; 23730088Sminshall 23830088Sminshall /* The following are some tn3270 specific flags */ 23930088Sminshall #if defined(TN3270) 24030088Sminshall 24130088Sminshall static int 24230326Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 24330088Sminshall 24431131Sminshall /* Some real, live, globals. */ 24531131Sminshall int 24631131Sminshall tout, /* Output file descriptor */ 24731131Sminshall tin; /* Input file descriptor */ 24831131Sminshall 24931131Sminshall #else /* defined(TN3270) */ 25031131Sminshall static int tin, tout; /* file descriptors */ 25131131Sminshall #endif /* defined(TN3270) */ 25231131Sminshall 25331131Sminshall 25430722Sminshall /* 25530722Sminshall * Telnet receiver states for fsm 25630722Sminshall */ 25730722Sminshall #define TS_DATA 0 25830722Sminshall #define TS_IAC 1 25930722Sminshall #define TS_WILL 2 26030722Sminshall #define TS_WONT 3 26130722Sminshall #define TS_DO 4 26230722Sminshall #define TS_DONT 5 26330722Sminshall #define TS_CR 6 26430722Sminshall #define TS_SB 7 /* sub-option collection */ 26530722Sminshall #define TS_SE 8 /* looking for sub-option end */ 26630722Sminshall 26730722Sminshall static int telrcv_state = TS_DATA; 26830088Sminshall 26930088Sminshall static char line[200]; 27030326Sminshall static int margc; 27130088Sminshall static char *margv[20]; 27230088Sminshall 27331124Sminshall static jmp_buf toplevel = { 0 }; 27430088Sminshall static jmp_buf peerdied; 27530088Sminshall 27630088Sminshall extern int errno; 27730088Sminshall 27830088Sminshall 27930088Sminshall static struct sockaddr_in sin; 28030088Sminshall 28130088Sminshall static struct servent *sp = 0; 28230088Sminshall 28330326Sminshall static int flushline; 28430088Sminshall 28530326Sminshall static char *hostname; 28630088Sminshall static char hnamebuf[32]; 28730088Sminshall 28830088Sminshall /* 28930088Sminshall * The following are some clocks used to decide how to interpret 29030088Sminshall * the relationship between various variables. 29130088Sminshall */ 29230088Sminshall 29330088Sminshall static struct { 29430088Sminshall int 29530088Sminshall system, /* what the current time is */ 29630088Sminshall echotoggle, /* last time user entered echo character */ 29730088Sminshall modenegotiated, /* last time operating mode negotiated */ 29830088Sminshall didnetreceive, /* last time we read data from network */ 29930088Sminshall gotDM; /* when did we last see a data mark */ 30030326Sminshall } clocks; 30130088Sminshall 30230088Sminshall #define settimer(x) clocks.x = clocks.system++ 30330088Sminshall 30431124Sminshall /* Various modes */ 30531124Sminshall #define MODE_LINE(m) (modelist[m].modetype & LINE) 30631124Sminshall #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS) 30731131Sminshall #define MODE_LOCAL_ECHO(m) (modelist[m].modetype & LOCAL_ECHO) 30831131Sminshall #define MODE_COMMAND_LINE(m) (modelist[m].modetype & COMMAND_LINE) 30931124Sminshall 31031124Sminshall #define LOCAL_CHARS 0x01 /* Characters processed locally */ 31131124Sminshall #define LINE 0x02 /* Line-by-line mode of operation */ 31231131Sminshall #define LOCAL_ECHO 0x04 /* Echoing locally */ 31331131Sminshall #define COMMAND_LINE 0x08 /* Command line mode */ 31431124Sminshall 31531124Sminshall static struct { 31631124Sminshall char *modedescriptions; 31731124Sminshall char modetype; 31831124Sminshall } modelist[] = { 31931131Sminshall { "telnet command mode", COMMAND_LINE }, 32031124Sminshall { "character-at-a-time mode", 0 }, 32131131Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 32231124Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 32331131Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 32431124Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 32531124Sminshall { "3270 mode", 0 }, 32631124Sminshall }; 32731124Sminshall 32831124Sminshall 32930088Sminshall /* 33031124Sminshall * The following routines try to encapsulate what is system dependent 33131124Sminshall * (at least between 4.x and dos) which is used in telnet.c. 33231124Sminshall */ 33331124Sminshall 33431124Sminshall #if defined(unix) 33531124Sminshall #include <sys/ioctl.h> 33631124Sminshall #include <sys/time.h> 33731124Sminshall #include <signal.h> 33831124Sminshall 33931124Sminshall int 34031124Sminshall HaveInput; /* There is input available to scan */ 34131124Sminshall 34231124Sminshall #if defined(TN3270) 34331124Sminshall static char tline[200]; 34431124Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 34531124Sminshall #endif /* defined(TN3270) */ 34631124Sminshall 34731124Sminshall static struct tchars otc = { 0 }, ntc = { 0 }; 34831124Sminshall static struct ltchars oltc = { 0 }, nltc = { 0 }; 34931124Sminshall static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 35031124Sminshall 35131124Sminshall 35231131Sminshall #define TerminalWrite(fd,buf,n) write(fd,buf,n) 35331131Sminshall #define TerminalRead(fd,buf,n) read(fd,buf,n) 35431131Sminshall 35531124Sminshall /* 35631124Sminshall * 35731124Sminshall */ 35831124Sminshall 35931124Sminshall static int 36031131Sminshall TerminalAutoFlush() /* unix */ 36131124Sminshall { 36231124Sminshall #if defined(LNOFLSH) 36331124Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 36431124Sminshall return !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 36531124Sminshall #else /* LNOFLSH */ 36631124Sminshall return 1; 36731124Sminshall #endif /* LNOFLSH */ 36831124Sminshall } 36931124Sminshall 37031124Sminshall /* 37131131Sminshall * TerminalSpecialChars() 37231124Sminshall * 37331131Sminshall * Look at an input character to see if it is a special character 37431131Sminshall * and decide what to do. 37531124Sminshall * 37631124Sminshall * Output: 37731124Sminshall * 37831124Sminshall * 0 Don't add this character. 37931124Sminshall * 1 Do add this character 38031124Sminshall */ 38131124Sminshall 38231124Sminshall int 38331131Sminshall TerminalSpecialChars(c) /* unix */ 38431124Sminshall int c; 38531124Sminshall { 38631124Sminshall void doflush(), intp(), sendbrk(); 38731124Sminshall 38831124Sminshall if (c == ntc.t_intrc) { 38931124Sminshall intp(); 39031124Sminshall return 0; 39131124Sminshall } else if (c == ntc.t_quitc) { 39231124Sminshall sendbrk(); 39331124Sminshall return 0; 39431124Sminshall } else if (c == nltc.t_flushc) { 39531124Sminshall NET2ADD(IAC, AO); 39631124Sminshall if (autoflush) { 39731124Sminshall doflush(); 39831124Sminshall } 39931124Sminshall return 0; 40031124Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 40131124Sminshall if (c == nttyb.sg_kill) { 40231124Sminshall NET2ADD(IAC, EL); 40331124Sminshall return 0; 40431124Sminshall } else if (c == nttyb.sg_erase) { 40531124Sminshall NET2ADD(IAC, EC); 40631124Sminshall return 0; 40731124Sminshall } 40831124Sminshall } 40931124Sminshall return 1; 41031124Sminshall } 41131124Sminshall 41231124Sminshall 41331124Sminshall /* 41431124Sminshall * Flush output to the terminal 41531124Sminshall */ 41631124Sminshall 41731124Sminshall static void 41831124Sminshall TerminalFlushOutput() /* unix */ 41931124Sminshall { 42031124Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 42131124Sminshall } 42231124Sminshall 42331124Sminshall static void 42431124Sminshall TerminalSaveState() /* unix */ 42531124Sminshall { 42631124Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 42731124Sminshall ioctl(0, TIOCGETC, (char *)&otc); 42831124Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 42931124Sminshall 43031124Sminshall ntc = otc; 43131124Sminshall nltc = oltc; 43231124Sminshall nttyb = ottyb; 43331124Sminshall } 43431124Sminshall 43531124Sminshall static void 43631124Sminshall TerminalRestoreState() /* unix */ 43731124Sminshall { 43831124Sminshall } 43931124Sminshall 44031124Sminshall /* 44131124Sminshall * TerminalNewMode - set up terminal to a specific mode. 44231124Sminshall */ 44331124Sminshall 44431124Sminshall 44531124Sminshall static void 44631131Sminshall TerminalNewMode(f) /* unix */ 44731124Sminshall register int f; 44831124Sminshall { 44931124Sminshall static int prevmode = 0; 45031124Sminshall struct tchars *tc; 45131124Sminshall struct tchars tc3; 45231124Sminshall struct ltchars *ltc; 45331124Sminshall struct sgttyb sb; 45431124Sminshall int onoff; 45531124Sminshall int old; 45631124Sminshall struct tchars notc2; 45731124Sminshall struct ltchars noltc2; 45831124Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 45931124Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 46031124Sminshall 46131124Sminshall globalmode = f; 46231124Sminshall if (prevmode == f) 46331124Sminshall return; 46431124Sminshall old = prevmode; 46531124Sminshall prevmode = f; 46631124Sminshall sb = nttyb; 46731124Sminshall 46831124Sminshall switch (f) { 46931124Sminshall 47031124Sminshall case 0: 47131124Sminshall onoff = 0; 47231124Sminshall tc = &otc; 47331124Sminshall ltc = &oltc; 47431124Sminshall break; 47531124Sminshall 47631124Sminshall case 1: /* remote character processing, remote echo */ 47731124Sminshall case 2: /* remote character processing, local echo */ 47831124Sminshall case 6: /* 3270 mode - like 1, but with xon/xoff local */ 47931124Sminshall /* (might be nice to have "6" in telnet also...) */ 48031124Sminshall sb.sg_flags |= CBREAK; 48131124Sminshall if ((f == 1) || (f == 6)) { 48231124Sminshall sb.sg_flags &= ~(ECHO|CRMOD); 48331124Sminshall } else { 48431124Sminshall sb.sg_flags |= ECHO|CRMOD; 48531124Sminshall } 48631124Sminshall sb.sg_erase = sb.sg_kill = -1; 48731124Sminshall if (f == 6) { 48831124Sminshall tc = &tc3; 48931124Sminshall tc3 = notc; 49031124Sminshall /* get XON, XOFF characters */ 49131124Sminshall tc3.t_startc = otc.t_startc; 49231124Sminshall tc3.t_stopc = otc.t_stopc; 49331124Sminshall } else { 49431124Sminshall /* 49531124Sminshall * If user hasn't specified one way or the other, 49631124Sminshall * then default to not trapping signals. 49731124Sminshall */ 49831124Sminshall if (!donelclchars) { 49931124Sminshall localchars = 0; 50031124Sminshall } 50131124Sminshall if (localchars) { 50231124Sminshall notc2 = notc; 50331124Sminshall notc2.t_intrc = ntc.t_intrc; 50431124Sminshall notc2.t_quitc = ntc.t_quitc; 50531124Sminshall tc = ¬c2; 50631124Sminshall } else { 50731124Sminshall tc = ¬c; 50831124Sminshall } 50931124Sminshall } 51031124Sminshall ltc = &noltc; 51131124Sminshall onoff = 1; 51231124Sminshall break; 51331124Sminshall case 3: /* local character processing, remote echo */ 51431124Sminshall case 4: /* local character processing, local echo */ 51531124Sminshall case 5: /* local character processing, no echo */ 51631124Sminshall sb.sg_flags &= ~CBREAK; 51731124Sminshall sb.sg_flags |= CRMOD; 51831124Sminshall if (f == 4) 51931124Sminshall sb.sg_flags |= ECHO; 52031124Sminshall else 52131124Sminshall sb.sg_flags &= ~ECHO; 52231124Sminshall notc2 = ntc; 52331124Sminshall tc = ¬c2; 52431124Sminshall noltc2 = oltc; 52531124Sminshall ltc = &noltc2; 52631124Sminshall /* 52731124Sminshall * If user hasn't specified one way or the other, 52831124Sminshall * then default to trapping signals. 52931124Sminshall */ 53031124Sminshall if (!donelclchars) { 53131124Sminshall localchars = 1; 53231124Sminshall } 53331124Sminshall if (localchars) { 53431124Sminshall notc2.t_brkc = nltc.t_flushc; 53531124Sminshall noltc2.t_flushc = -1; 53631124Sminshall } else { 53731124Sminshall notc2.t_intrc = notc2.t_quitc = -1; 53831124Sminshall } 53931124Sminshall noltc2.t_suspc = escape; 54031124Sminshall noltc2.t_dsuspc = -1; 54131124Sminshall onoff = 1; 54231124Sminshall break; 54331124Sminshall 54431124Sminshall default: 54531124Sminshall return; 54631124Sminshall } 54731124Sminshall ioctl(tin, TIOCSLTC, (char *)ltc); 54831124Sminshall ioctl(tin, TIOCSETC, (char *)tc); 54931124Sminshall ioctl(tin, TIOCSETP, (char *)&sb); 55031124Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 55131124Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 55231124Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 55331124Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 554*31478Sminshall #if defined(TN3270) 555*31478Sminshall if (noasynch == 0) { 556*31478Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 557*31478Sminshall } 558*31478Sminshall #endif /* defined(TN3270) */ 55931124Sminshall 56031124Sminshall if (MODE_LINE(f)) { 56131124Sminshall void doescape(); 56231124Sminshall 56331124Sminshall signal(SIGTSTP, doescape); 56431124Sminshall } else if (MODE_LINE(old)) { 56531124Sminshall signal(SIGTSTP, SIG_DFL); 56631124Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 56731124Sminshall } 56831124Sminshall } 56931124Sminshall 57031124Sminshall 57131131Sminshall int 57231131Sminshall NetClose(net) 57331131Sminshall int net; 57431131Sminshall { 57531131Sminshall return close(net); 57631131Sminshall } 57731131Sminshall 57831131Sminshall 57931124Sminshall static void 58031124Sminshall NetNonblockingIO(fd, onoff) /* unix */ 58131124Sminshall int 58231124Sminshall fd, 58331124Sminshall onoff; 58431124Sminshall { 58531124Sminshall ioctl(net, FIONBIO, (char *)&onoff); 58631124Sminshall } 58731124Sminshall 58831124Sminshall static void 58931124Sminshall NetSigIO(fd, onoff) /* unix */ 59031124Sminshall int 59131124Sminshall fd, 59231124Sminshall onoff; 59331124Sminshall { 59431124Sminshall ioctl(net, FIOASYNC, (char *)&onoff); /* hear about input */ 59531124Sminshall } 59631124Sminshall 59731124Sminshall static void 59831124Sminshall NetSetPgrp(fd) /* unix */ 59931124Sminshall int fd; 60031124Sminshall { 60131124Sminshall int myPid; 60231124Sminshall 60331124Sminshall myPid = getpid(); 60431124Sminshall #if defined(NOT43) 60531124Sminshall myPid = -myPid; 60631124Sminshall #endif /* defined(NOT43) */ 60731124Sminshall ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */ 60831124Sminshall } 60931124Sminshall 61031124Sminshall 61131124Sminshall #endif /* defined(unix) */ 61231124Sminshall 61331124Sminshall #if defined(MSDOS) 61431124Sminshall #include <time.h> 61531131Sminshall #include <signal.h> 61631169Sminshall #include <process.h> 61731124Sminshall 61831124Sminshall #if !defined(SO_OOBINLINE) 61931124Sminshall #define SO_OOBINLINE 62031124Sminshall #endif /* !defined(SO_OOBINLINE) */ 62131124Sminshall 62231124Sminshall 62331124Sminshall static char 62431131Sminshall termEofChar, 62531124Sminshall termEraseChar, 62631124Sminshall termFlushChar, 62731124Sminshall termIntChar, 62831124Sminshall termKillChar, 62931131Sminshall termLiteralNextChar, 63031131Sminshall termQuitChar; 63131124Sminshall 63231131Sminshall 63331131Sminshall /* 63431131Sminshall * MSDOS doesn't have anyway of deciding whether a full-edited line 63531131Sminshall * is ready to be read in, so we need to do character-by-character 63631131Sminshall * reads, and then do the editing in the program (in the case where 63731131Sminshall * we are supporting line-by-line mode). 63831131Sminshall * 63931131Sminshall * The following routines, which are internal to the MSDOS-specific 64031131Sminshall * code, accomplish this miracle. 64131131Sminshall */ 64231124Sminshall 64331131Sminshall #define Hex(c) HEX[(c)&0xff] 64431131Sminshall 64531131Sminshall static survivorSetup = 0; /* Do we have ^C hooks in? */ 64631131Sminshall 64731131Sminshall static int 64831131Sminshall lineend = 0, /* There is a line terminator */ 64931131Sminshall ctrlCCount = 0; 65031131Sminshall 65131131Sminshall static char linein[200], /* Where input line is assembled */ 65231131Sminshall *nextin = linein, /* Next input character */ 65331131Sminshall *nextout = linein; /* Next character to be consumed */ 65431131Sminshall 65531131Sminshall #define consumechar() \ 65631131Sminshall if ((++nextout) >= nextin) { \ 65731131Sminshall nextout = nextin = linein; \ 65831131Sminshall lineend = 0; \ 65931131Sminshall } 66031131Sminshall 66131131Sminshall #define characteratatime() (!MODE_LINE(globalmode)) /* one by one */ 66231131Sminshall 66331131Sminshall 66431124Sminshall /* 66531131Sminshall * killone() 66631131Sminshall * 66731131Sminshall * Erase the last character on the line. 66831131Sminshall */ 66931131Sminshall 67031131Sminshall static void 67131131Sminshall killone() 67231131Sminshall { 67331131Sminshall if (lineend) { 67431131Sminshall return; /* ??? XXX */ 67531131Sminshall } 67631131Sminshall if (nextin == linein) { 67731131Sminshall return; /* Nothing to do */ 67831131Sminshall } 67931131Sminshall nextin--; 68031131Sminshall if (!(isspace(*nextin) || isprint(*nextin))) { 68131131Sminshall putchar('\b'); 68231131Sminshall putchar(' '); 68331131Sminshall putchar('\b'); 68431131Sminshall } 68531131Sminshall putchar('\b'); 68631131Sminshall putchar(' '); 68731131Sminshall putchar('\b'); 68831131Sminshall } 68931131Sminshall 69031131Sminshall 69131131Sminshall /* 69231131Sminshall * setlineend() 69331131Sminshall * 69431131Sminshall * Decide if it's time to send the current line up to the user 69531131Sminshall * process. 69631131Sminshall */ 69731131Sminshall 69831131Sminshall static void 69931131Sminshall setlineend() 70031131Sminshall { 70131131Sminshall if (nextin == nextout) { 70231131Sminshall return; 70331131Sminshall } 70431131Sminshall if (characteratatime()) { 70531131Sminshall lineend = 1; 70631131Sminshall } else if (nextin >= (linein+sizeof linein)) { 70731131Sminshall lineend = 1; 70831131Sminshall } else { 70931131Sminshall int c = *(nextin-1); 71031131Sminshall if ((c == termIntChar) 71131131Sminshall || (c == termQuitChar) 71231131Sminshall || (c == termEofChar)) { 71331131Sminshall lineend = 1; 71431131Sminshall } else if (c == termFlushChar) { 71531131Sminshall lineend = 1; 71631131Sminshall } else if ((c == '\n') || (c == '\r')) { 71731131Sminshall lineend = 1; 71831131Sminshall } 71931131Sminshall } 72031131Sminshall /* Otherwise, leave it alone (reset by 'consumechar') */ 72131131Sminshall } 72231131Sminshall 72331131Sminshall /* 72431131Sminshall * OK, what we do here is: 72531131Sminshall * 72631131Sminshall * o If we are echoing, then 72731131Sminshall * o Look for character erase, line kill characters 72831131Sminshall * o Echo the character (using '^' if a control character) 72931131Sminshall * o Put the character in the input buffer 73031131Sminshall * o Set 'lineend' as necessary 73131131Sminshall */ 73231131Sminshall 73331131Sminshall static void 73431131Sminshall DoNextChar(c) 73531131Sminshall int c; /* Character to process */ 73631131Sminshall { 73731131Sminshall static char literalnextcharacter = 0; 73831131Sminshall 73931131Sminshall if (nextin >= (linein+sizeof linein)) { 74031131Sminshall putchar('\7'); /* Ring bell */ 74131131Sminshall setlineend(); 74231131Sminshall return; 74331131Sminshall } 74431131Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 74531131Sminshall /* Look for some special character */ 74631131Sminshall if (!literalnextcharacter) { 74731131Sminshall if (c == termEraseChar) { 74831131Sminshall killone(); 74931131Sminshall setlineend(); 75031131Sminshall return; 75131131Sminshall } else if (c == termKillChar) { 75231131Sminshall while (nextin != linein) { 75331131Sminshall killone(); 75431131Sminshall } 75531131Sminshall setlineend(); 75631131Sminshall return; 75731131Sminshall } else if (c == termLiteralNextChar) { 75831131Sminshall literalnextcharacter = 1; 75931131Sminshall return; 76031131Sminshall } 76131131Sminshall } 76231131Sminshall 76331131Sminshall if (MODE_LOCAL_ECHO(globalmode)) { 76431131Sminshall if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) { 76531131Sminshall putchar('\r'); 76631131Sminshall putchar('\n'); 76731131Sminshall c = '\n'; 76831131Sminshall } else if (!isprint(c) && !isspace(c)) { 76931131Sminshall putchar('^'); 77031131Sminshall putchar(c^0x40); 77131131Sminshall } else { 77231131Sminshall putchar(c); 77331131Sminshall } 77431131Sminshall } 77531131Sminshall literalnextcharacter = 0; 77631131Sminshall } 77731131Sminshall *nextin++ = c; 77831131Sminshall setlineend(); 77931131Sminshall } 78031131Sminshall 78131131Sminshall static int 78231131Sminshall inputExists() 78331131Sminshall { 78431131Sminshall int input; 78531131Sminshall static state = 0; 78631131Sminshall 78731131Sminshall while (ctrlCCount) { 78831131Sminshall DoNextChar(0x03); 78931131Sminshall ctrlCCount--; 79031131Sminshall } 79131131Sminshall if (lineend) { 79231131Sminshall return 1; 79331131Sminshall } 79431169Sminshall #if 1 /* For BIOS variety of calls */ 79531169Sminshall if (kbhit() == 0) { 79631131Sminshall return lineend; 79731131Sminshall } 79831131Sminshall input = getch(); /* MSC - get console character */ 79931131Sminshall if ((input&0xff) == 0) { 80031169Sminshall DoNextChar(0x01); /* ^A */ 80131169Sminshall } else { 80231169Sminshall DoNextChar(input&0xff); 80331169Sminshall } 80431169Sminshall #else /* 0 */ 80531169Sminshall if ((input = dirconio()) == -1) { 80631169Sminshall return lineend; 80731169Sminshall } 80831169Sminshall if ((input&0xff) == 0) { 80931131Sminshall if ((input&0xff00) == 0x0300) { /* Null */ 81031131Sminshall DoNextChar(0); 81131131Sminshall } else { 81231131Sminshall DoNextChar(0x01); 81331131Sminshall if (input&0x8000) { 81431131Sminshall DoNextChar(0x01); 81531131Sminshall DoNextChar((input>>8)&0x7f); 81631131Sminshall } else { 81731131Sminshall DoNextChar((input>>8)&0xff); 81831131Sminshall } 81931131Sminshall } 82031131Sminshall } else { 82131131Sminshall DoNextChar(input&0xff); 82231131Sminshall } 82331131Sminshall #endif /* 0 */ 82431131Sminshall return lineend; 82531131Sminshall } 82631131Sminshall 82731131Sminshall 82831131Sminshall void 82931131Sminshall CtrlCInterrupt() 83031131Sminshall { 83131131Sminshall if (!MODE_COMMAND_LINE(globalmode)) { 83231131Sminshall ctrlCCount++; /* XXX */ 83331131Sminshall signal(SIGINT, CtrlCInterrupt); 83431131Sminshall } else { 83531131Sminshall closeallsockets(); 83631169Sminshall exit(1); 83731131Sminshall } 83831131Sminshall } 83931131Sminshall 84031131Sminshall /* 84131131Sminshall * The MSDOS routines, called from elsewhere. 84231131Sminshall */ 84331131Sminshall 84431131Sminshall 84531131Sminshall static int 84631131Sminshall TerminalAutoFlush() /* MSDOS */ 84731131Sminshall { 84831131Sminshall return 1; 84931131Sminshall } 85031131Sminshall 85131131Sminshall static int 85231131Sminshall TerminalCanRead() 85331131Sminshall { 85431131Sminshall return inputExists(); 85531131Sminshall } 85631131Sminshall 85731131Sminshall 85831131Sminshall /* 85931124Sminshall * Flush output to the terminal 86031124Sminshall */ 86131124Sminshall 86231124Sminshall static void 86331124Sminshall TerminalFlushOutput() /* MSDOS */ 86431124Sminshall { 86531124Sminshall } 86631124Sminshall 86731131Sminshall 86831124Sminshall static void 86931131Sminshall TerminalNewMode(f) /* MSDOS */ 87031131Sminshall register int f; 87131131Sminshall { 87231131Sminshall globalmode = f; 87331131Sminshall signal(SIGINT, CtrlCInterrupt); 87431131Sminshall } 87531131Sminshall 87631131Sminshall 87731131Sminshall int 87831131Sminshall TerminalRead(fd, buffer, count) 87931131Sminshall int fd; 88031131Sminshall char *buffer; 88131131Sminshall int count; 88231131Sminshall { 88331131Sminshall int done = 0; 88431131Sminshall 88531131Sminshall for (;;) { 88631131Sminshall while (inputExists() && (done < count)) { 88731131Sminshall *buffer++ = *nextout; 88831131Sminshall consumechar(); 88931131Sminshall done++; 89031131Sminshall } 89131131Sminshall if (done) { 89231131Sminshall return(done); 89331131Sminshall } else { 89431131Sminshall return 0; 89531131Sminshall } 89631131Sminshall } 89731131Sminshall } 89831131Sminshall 89931131Sminshall 90031131Sminshall static void 90131124Sminshall TerminalSaveState() /* MSDOS */ 90231124Sminshall { 90331124Sminshall } 90431124Sminshall 90531131Sminshall int 90631131Sminshall TerminalSpecialChars(c) /* MSDOS */ 90731131Sminshall { 90831131Sminshall return 1; 90931131Sminshall } 91031131Sminshall 91131131Sminshall 91231124Sminshall static void 91331124Sminshall TerminalRestoreState() /* MSDOS */ 91431124Sminshall { 91531124Sminshall } 91631124Sminshall 91731131Sminshall 91831131Sminshall static int 91931131Sminshall TerminalWrite(fd, buffer, count) /* MSDOS */ 92031131Sminshall int fd; 92131131Sminshall char *buffer; 92231131Sminshall int count; 92331131Sminshall { 92431131Sminshall return fwrite(buffer, sizeof (char), count, stdout); 92531131Sminshall } 92631131Sminshall 92731131Sminshall 92831131Sminshall static int 92931131Sminshall NetClose(fd) 93031131Sminshall { 93131131Sminshall return closesocket(fd); 93231131Sminshall } 93331131Sminshall 93431124Sminshall static void 93531124Sminshall NetNonblockingIO(fd, onoff) /* MSDOS */ 93631124Sminshall int 93731124Sminshall fd, 93831124Sminshall onoff; 93931124Sminshall { 94031124Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) { 94131124Sminshall perror("setsockop (SO_NONBLOCKING) "); 94231131Sminshall ExitString(stderr, "exiting\n", 1); 94331124Sminshall } 94431124Sminshall } 94531124Sminshall 94631124Sminshall static void 94731124Sminshall NetSigIO(fd) /* MSDOS */ 94831124Sminshall int fd; 94931124Sminshall { 95031124Sminshall } 95131124Sminshall 95231124Sminshall static void 95331124Sminshall NetSetPgrp(fd) /* MSDOS */ 95431124Sminshall int fd; 95531124Sminshall { 95631124Sminshall } 95731124Sminshall 95831124Sminshall 95931124Sminshall #endif /* defined(MSDOS) */ 96031124Sminshall 96131124Sminshall /* 96230326Sminshall * Initialize variables. 96330326Sminshall */ 96430326Sminshall 96530326Sminshall static void 96630326Sminshall tninit() 96730326Sminshall { 96831131Sminshall #if defined(TN3270) 96931131Sminshall Sent3270TerminalType = 0; 97030326Sminshall Ifrontp = Ibackp = Ibuf; 97131131Sminshall #endif /* defined(TN3270) */ 97231131Sminshall 97330326Sminshall tfrontp = tbackp = ttyobuf; 97430326Sminshall nfrontp = nbackp = netobuf; 97530326Sminshall 97630326Sminshall /* Don't change telnetport */ 97730722Sminshall SB_CLEAR(); 97830722Sminshall ClearArray(hisopts); 97930722Sminshall ClearArray(myopts); 98030722Sminshall sbp = sibuf; 98130722Sminshall tbp = tibuf; 98230326Sminshall 98330722Sminshall connected = net = scc = tcc = In3270 = ISend = 0; 98430722Sminshall telnetport = 0; 98531124Sminshall #if defined(unix) 98631124Sminshall HaveInput = 0; 98731124Sminshall #endif /* defined(unix) */ 98830722Sminshall 98930722Sminshall SYNCHing = 0; 99030722Sminshall 99130722Sminshall errno = 0; 99230722Sminshall 99330722Sminshall flushline = 0; 99430722Sminshall 99530326Sminshall /* Don't change NetTrace */ 99630326Sminshall 99730326Sminshall escape = CONTROL(']'); 99830326Sminshall echoc = CONTROL('E'); 99930326Sminshall 100030326Sminshall flushline = 1; 100130326Sminshall sp = getservbyname("telnet", "tcp"); 100230326Sminshall if (sp == 0) { 100330326Sminshall ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1); 100430326Sminshall /*NOTREACHED*/ 100530326Sminshall } 100630326Sminshall 100730326Sminshall #if defined(TN3270) 100830722Sminshall init_ctlr(); /* Initialize some things */ 100930722Sminshall init_keyboard(); 101030722Sminshall init_screen(); 101130722Sminshall init_system(); 101230326Sminshall #endif /* defined(TN3270) */ 101330326Sminshall } 101430326Sminshall 101530326Sminshall /* 101630088Sminshall * Various utility routines. 101730088Sminshall */ 101830088Sminshall 101930088Sminshall static void 102030088Sminshall makeargv() 102130088Sminshall { 102231215Sminshall register char *cp; 102331215Sminshall register char **argp = margv; 102430088Sminshall 102531215Sminshall margc = 0; 102631215Sminshall cp = line; 102731215Sminshall if (*cp == '!') { /* Special case shell escape */ 102831215Sminshall *argp++ = "!"; /* No room in string to get this */ 102931215Sminshall margc++; 103031215Sminshall cp++; 103131215Sminshall } 103231215Sminshall while (*cp) { 103331215Sminshall while (isspace(*cp)) 103431215Sminshall cp++; 103531215Sminshall if (*cp == '\0') 103631215Sminshall break; 103731215Sminshall *argp++ = cp; 103831215Sminshall margc += 1; 103931215Sminshall while (*cp != '\0' && !isspace(*cp)) 104031215Sminshall cp++; 104131215Sminshall if (*cp == '\0') 104231215Sminshall break; 104331215Sminshall *cp++ = '\0'; 104431215Sminshall } 104531215Sminshall *argp++ = 0; 104630088Sminshall } 104730088Sminshall 104830088Sminshall static char *ambiguous; /* special return value */ 104930088Sminshall #define Ambiguous(t) ((t)&ambiguous) 105030088Sminshall 105130088Sminshall 105230088Sminshall static char ** 105330088Sminshall genget(name, table, next) 105430088Sminshall char *name; /* name to match */ 105530088Sminshall char **table; /* name entry in table */ 105630088Sminshall char **(*next)(); /* routine to return next entry in table */ 105730088Sminshall { 105830088Sminshall register char *p, *q; 105930088Sminshall register char **c, **found; 106030088Sminshall register int nmatches, longest; 106130088Sminshall 106230088Sminshall longest = 0; 106330088Sminshall nmatches = 0; 106430088Sminshall found = 0; 106530088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 106630088Sminshall for (q = name; 106730088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 106830088Sminshall if (*q == 0) /* exact match? */ 106930088Sminshall return (c); 107030088Sminshall if (!*q) { /* the name was a prefix */ 107130088Sminshall if (q - name > longest) { 107230088Sminshall longest = q - name; 107330088Sminshall nmatches = 1; 107430088Sminshall found = c; 107530088Sminshall } else if (q - name == longest) 107630088Sminshall nmatches++; 107730088Sminshall } 107830088Sminshall } 107930088Sminshall if (nmatches > 1) 108030088Sminshall return Ambiguous(char **); 108130088Sminshall return (found); 108230088Sminshall } 108330088Sminshall 108430088Sminshall /* 108530088Sminshall * Make a character string into a number. 108630088Sminshall * 108730088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 108830088Sminshall */ 108930088Sminshall 109030088Sminshall static 109130088Sminshall special(s) 109230088Sminshall register char *s; 109330088Sminshall { 109430088Sminshall register char c; 109530088Sminshall char b; 109630088Sminshall 109730088Sminshall switch (*s) { 109830088Sminshall case '^': 109930088Sminshall b = *++s; 110030088Sminshall if (b == '?') { 110130088Sminshall c = b | 0x40; /* DEL */ 110230088Sminshall } else { 110330088Sminshall c = b & 0x1f; 110430088Sminshall } 110530088Sminshall break; 110630088Sminshall default: 110730088Sminshall c = *s; 110830088Sminshall break; 110930088Sminshall } 111030088Sminshall return c; 111130088Sminshall } 111230088Sminshall 111330088Sminshall /* 111430088Sminshall * Construct a control character sequence 111530088Sminshall * for a special character. 111630088Sminshall */ 111730088Sminshall static char * 111830088Sminshall control(c) 111930088Sminshall register int c; 112030088Sminshall { 112130088Sminshall static char buf[3]; 112230088Sminshall 112330088Sminshall if (c == 0x7f) 112430088Sminshall return ("^?"); 112530088Sminshall if (c == '\377') { 112630088Sminshall return "off"; 112730088Sminshall } 112830088Sminshall if (c >= 0x20) { 112930088Sminshall buf[0] = c; 113030088Sminshall buf[1] = 0; 113130088Sminshall } else { 113230088Sminshall buf[0] = '^'; 113330088Sminshall buf[1] = '@'+c; 113430088Sminshall buf[2] = 0; 113530088Sminshall } 113630088Sminshall return (buf); 113730088Sminshall } 113830088Sminshall 113930088Sminshall 114030088Sminshall /* 114130088Sminshall * upcase() 114230088Sminshall * 114330088Sminshall * Upcase (in place) the argument. 114430088Sminshall */ 114530088Sminshall 114630088Sminshall static void 114730088Sminshall upcase(argument) 114830088Sminshall register char *argument; 114930088Sminshall { 115030088Sminshall register int c; 115130088Sminshall 115230088Sminshall while ((c = *argument) != 0) { 115330088Sminshall if (islower(c)) { 115430088Sminshall *argument = toupper(c); 115530088Sminshall } 115630088Sminshall argument++; 115730088Sminshall } 115830088Sminshall } 115931124Sminshall 116031124Sminshall /* 116131124Sminshall * SetSockOpt() 116231124Sminshall * 116331124Sminshall * Compensate for differences in 4.2 and 4.3 systems. 116431124Sminshall */ 116531124Sminshall 116631124Sminshall static int 116731124Sminshall SetSockOpt(fd, level, option, yesno) 116831124Sminshall int 116931124Sminshall fd, 117031124Sminshall level, 117131124Sminshall option, 117231124Sminshall yesno; 117331124Sminshall { 117431124Sminshall #ifndef NOT43 117531124Sminshall return setsockopt(fd, level, option, 117631124Sminshall (char *)&yesno, sizeof yesno); 117731124Sminshall #else /* NOT43 */ 117831124Sminshall if (yesno == 0) { /* Can't do that in 4.2! */ 117931124Sminshall fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", 118031124Sminshall option); 118131124Sminshall return -1; 118231124Sminshall } 118331124Sminshall return setsockopt(fd, level, option, 0, 0); 118431124Sminshall #endif /* NOT43 */ 118531124Sminshall } 118630088Sminshall 118730088Sminshall /* 118830088Sminshall * The following are routines used to print out debugging information. 118930088Sminshall */ 119030088Sminshall 119130088Sminshall 119230088Sminshall static void 119330088Sminshall Dump(direction, buffer, length) 119430088Sminshall char direction; 119530088Sminshall char *buffer; 119630088Sminshall int length; 119730088Sminshall { 119830088Sminshall # define BYTES_PER_LINE 32 119930088Sminshall # define min(x,y) ((x<y)? x:y) 120030088Sminshall char *pThis; 120130088Sminshall int offset; 120230088Sminshall 120330088Sminshall offset = 0; 120430088Sminshall 120530088Sminshall while (length) { 120630088Sminshall /* print one line */ 120730088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 120830088Sminshall pThis = buffer; 120930088Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 121030088Sminshall while (pThis < buffer) { 121130088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 121230088Sminshall pThis++; 121330088Sminshall } 121430088Sminshall fprintf(NetTrace, "\n"); 121530088Sminshall length -= BYTES_PER_LINE; 121630088Sminshall offset += BYTES_PER_LINE; 121730088Sminshall if (length < 0) { 121830088Sminshall return; 121930088Sminshall } 122030088Sminshall /* find next unique line */ 122130088Sminshall } 122230088Sminshall } 122330088Sminshall 122430088Sminshall 122530088Sminshall /*VARARGS*/ 122630088Sminshall static void 122730088Sminshall printoption(direction, fmt, option, what) 122830088Sminshall char *direction, *fmt; 122930088Sminshall int option, what; 123030088Sminshall { 123130088Sminshall if (!showoptions) 123230088Sminshall return; 123330088Sminshall fprintf(NetTrace, "%s ", direction+1); 123430088Sminshall if (fmt == doopt) 123530088Sminshall fmt = "do"; 123630088Sminshall else if (fmt == dont) 123730088Sminshall fmt = "dont"; 123830088Sminshall else if (fmt == will) 123930088Sminshall fmt = "will"; 124030088Sminshall else if (fmt == wont) 124130088Sminshall fmt = "wont"; 124230088Sminshall else 124330088Sminshall fmt = "???"; 124430088Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 124530088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]); 124630088Sminshall else 124730088Sminshall fprintf(NetTrace, "%s %d", fmt, option); 124830088Sminshall if (*direction == '<') { 124930088Sminshall fprintf(NetTrace, "\r\n"); 125030088Sminshall return; 125130088Sminshall } 125230088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); 125330088Sminshall } 125430088Sminshall 125530088Sminshall static void 125630088Sminshall printsub(direction, pointer, length) 125730088Sminshall char *direction, /* "<" or ">" */ 125830088Sminshall *pointer; /* where suboption data sits */ 125930088Sminshall int length; /* length of suboption data */ 126030088Sminshall { 126130088Sminshall if (showoptions) { 126230088Sminshall fprintf(NetTrace, "%s suboption ", 126330088Sminshall (direction[0] == '<')? "Received":"Sent"); 126430088Sminshall switch (pointer[0]) { 126530088Sminshall case TELOPT_TTYPE: 126630088Sminshall fprintf(NetTrace, "Terminal type "); 126730088Sminshall switch (pointer[1]) { 126830088Sminshall case TELQUAL_IS: 126930088Sminshall { 127030088Sminshall char tmpbuf[sizeof subbuffer]; 127130088Sminshall int minlen = min(length, sizeof tmpbuf); 127230088Sminshall 127331131Sminshall memcpy(tmpbuf, pointer+2, minlen); 127430088Sminshall tmpbuf[minlen-1] = 0; 127530088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf); 127630088Sminshall } 127730088Sminshall break; 127830088Sminshall case TELQUAL_SEND: 127930088Sminshall fprintf(NetTrace, "- request to send.\n"); 128030088Sminshall break; 128130088Sminshall default: 128230088Sminshall fprintf(NetTrace, 128330088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]); 128430088Sminshall } 128530088Sminshall break; 128630088Sminshall default: 128730088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n", 128830088Sminshall pointer[0], pointer[0]); 128930088Sminshall } 129030088Sminshall } 129130088Sminshall } 129230088Sminshall 129330088Sminshall /* 129430088Sminshall * Check to see if any out-of-band data exists on a socket (for 129530088Sminshall * Telnet "synch" processing). 129630088Sminshall */ 129730088Sminshall 129830088Sminshall static int 129930088Sminshall stilloob(s) 130030088Sminshall int s; /* socket number */ 130130088Sminshall { 130230088Sminshall static struct timeval timeout = { 0 }; 130330088Sminshall fd_set excepts; 130430088Sminshall int value; 130530088Sminshall 130630088Sminshall do { 130730088Sminshall FD_ZERO(&excepts); 130830088Sminshall FD_SET(s, &excepts); 130930088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 131030088Sminshall } while ((value == -1) && (errno == EINTR)); 131130088Sminshall 131230088Sminshall if (value < 0) { 131330088Sminshall perror("select"); 131430088Sminshall quit(); 131530088Sminshall } 131630088Sminshall if (FD_ISSET(s, &excepts)) { 131730088Sminshall return 1; 131830088Sminshall } else { 131930088Sminshall return 0; 132030088Sminshall } 132130088Sminshall } 132230088Sminshall 132330088Sminshall 132430088Sminshall /* 132530088Sminshall * netflush 132630088Sminshall * Send as much data as possible to the network, 132730088Sminshall * handling requests for urgent data. 132830088Sminshall * 132930088Sminshall * The return value indicates whether we did any 133030088Sminshall * useful work. 133130088Sminshall */ 133230088Sminshall 133330088Sminshall 133430088Sminshall int 133530088Sminshall netflush() 133630088Sminshall { 133730088Sminshall int n; 133830088Sminshall 133930088Sminshall if ((n = nfrontp - nbackp) > 0) { 134030088Sminshall if (!neturg) { 134131131Sminshall n = send(net, nbackp, n, 0); /* normal write */ 134230088Sminshall } else { 134330088Sminshall n = neturg - nbackp; 134430088Sminshall /* 134530088Sminshall * In 4.2 (and 4.3) systems, there is some question about 134630088Sminshall * what byte in a sendOOB operation is the "OOB" data. 134730088Sminshall * To make ourselves compatible, we only send ONE byte 134830088Sminshall * out of band, the one WE THINK should be OOB (though 134930088Sminshall * we really have more the TCP philosophy of urgent data 135030088Sminshall * rather than the Unix philosophy of OOB data). 135130088Sminshall */ 135230088Sminshall if (n > 1) { 135330088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 135430088Sminshall } else { 135530088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 135630088Sminshall } 135730088Sminshall } 135830088Sminshall } 135930088Sminshall if (n < 0) { 136030088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 136130088Sminshall setcommandmode(); 136230088Sminshall perror(hostname); 136331131Sminshall NetClose(net); 136430088Sminshall neturg = 0; 136530088Sminshall longjmp(peerdied, -1); 136630088Sminshall /*NOTREACHED*/ 136730088Sminshall } 136830088Sminshall n = 0; 136930088Sminshall } 137030088Sminshall if (netdata && n) { 137130088Sminshall Dump('>', nbackp, n); 137230088Sminshall } 137330088Sminshall nbackp += n; 137430088Sminshall if (nbackp >= neturg) { 137530088Sminshall neturg = 0; 137630088Sminshall } 137730088Sminshall if (nbackp == nfrontp) { 137830088Sminshall nbackp = nfrontp = netobuf; 137930088Sminshall } 138030088Sminshall return n > 0; 138130088Sminshall } 138230088Sminshall 138330088Sminshall /* 138430088Sminshall * nextitem() 138530088Sminshall * 138630088Sminshall * Return the address of the next "item" in the TELNET data 138730088Sminshall * stream. This will be the address of the next character if 138830088Sminshall * the current address is a user data character, or it will 138930088Sminshall * be the address of the character following the TELNET command 139030088Sminshall * if the current address is a TELNET IAC ("I Am a Command") 139130088Sminshall * character. 139230088Sminshall */ 139330088Sminshall 139430088Sminshall static char * 139530088Sminshall nextitem(current) 139630088Sminshall char *current; 139730088Sminshall { 139830088Sminshall if ((*current&0xff) != IAC) { 139930088Sminshall return current+1; 140030088Sminshall } 140130088Sminshall switch (*(current+1)&0xff) { 140230088Sminshall case DO: 140330088Sminshall case DONT: 140430088Sminshall case WILL: 140530088Sminshall case WONT: 140630088Sminshall return current+3; 140730088Sminshall case SB: /* loop forever looking for the SE */ 140830088Sminshall { 140930088Sminshall register char *look = current+2; 141030088Sminshall 141130088Sminshall for (;;) { 141230088Sminshall if ((*look++&0xff) == IAC) { 141330088Sminshall if ((*look++&0xff) == SE) { 141430088Sminshall return look; 141530088Sminshall } 141630088Sminshall } 141730088Sminshall } 141830088Sminshall } 141930088Sminshall default: 142030088Sminshall return current+2; 142130088Sminshall } 142230088Sminshall } 142330088Sminshall /* 142430088Sminshall * netclear() 142530088Sminshall * 142630088Sminshall * We are about to do a TELNET SYNCH operation. Clear 142730088Sminshall * the path to the network. 142830088Sminshall * 142930088Sminshall * Things are a bit tricky since we may have sent the first 143030088Sminshall * byte or so of a previous TELNET command into the network. 143130088Sminshall * So, we have to scan the network buffer from the beginning 143230088Sminshall * until we are up to where we want to be. 143330088Sminshall * 143430088Sminshall * A side effect of what we do, just to keep things 143530088Sminshall * simple, is to clear the urgent data pointer. The principal 143630088Sminshall * caller should be setting the urgent data pointer AFTER calling 143730088Sminshall * us in any case. 143830088Sminshall */ 143930088Sminshall 144030088Sminshall static void 144130088Sminshall netclear() 144230088Sminshall { 144330088Sminshall register char *thisitem, *next; 144430088Sminshall char *good; 144530088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 144630088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 144730088Sminshall 144830088Sminshall thisitem = netobuf; 144930088Sminshall 145030088Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 145130088Sminshall thisitem = next; 145230088Sminshall } 145330088Sminshall 145430088Sminshall /* Now, thisitem is first before/at boundary. */ 145530088Sminshall 145630088Sminshall good = netobuf; /* where the good bytes go */ 145730088Sminshall 145830088Sminshall while (nfrontp > thisitem) { 145930088Sminshall if (wewant(thisitem)) { 146030088Sminshall int length; 146130088Sminshall 146230088Sminshall next = thisitem; 146330088Sminshall do { 146430088Sminshall next = nextitem(next); 146530088Sminshall } while (wewant(next) && (nfrontp > next)); 146630088Sminshall length = next-thisitem; 146731131Sminshall memcpy(good, thisitem, length); 146830088Sminshall good += length; 146930088Sminshall thisitem = next; 147030088Sminshall } else { 147130088Sminshall thisitem = nextitem(thisitem); 147230088Sminshall } 147330088Sminshall } 147430088Sminshall 147530088Sminshall nbackp = netobuf; 147630088Sminshall nfrontp = good; /* next byte to be sent */ 147730088Sminshall neturg = 0; 147830088Sminshall } 147930088Sminshall 148030088Sminshall /* 148130088Sminshall * These routines add various telnet commands to the data stream. 148230088Sminshall */ 148330088Sminshall 148430088Sminshall #if defined(NOT43) 148530088Sminshall static int 148630088Sminshall #else /* defined(NOT43) */ 148730088Sminshall static void 148830088Sminshall #endif /* defined(NOT43) */ 148930088Sminshall dosynch() 149030088Sminshall { 149130088Sminshall netclear(); /* clear the path to the network */ 149230088Sminshall NET2ADD(IAC, DM); 149330088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 149430088Sminshall 149530088Sminshall #if defined(NOT43) 149630088Sminshall return 0; 149730088Sminshall #endif /* defined(NOT43) */ 149830088Sminshall } 149930088Sminshall 150030088Sminshall static void 150130088Sminshall doflush() 150230088Sminshall { 150330088Sminshall NET2ADD(IAC, DO); 150430088Sminshall NETADD(TELOPT_TM); 150530088Sminshall flushline = 1; 150630088Sminshall flushout = 1; 150730088Sminshall ttyflush(); 150830088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 150930088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 151030088Sminshall } 151130088Sminshall 151230088Sminshall static void 151330088Sminshall intp() 151430088Sminshall { 151530088Sminshall NET2ADD(IAC, IP); 151630088Sminshall if (autoflush) { 151730088Sminshall doflush(); 151830088Sminshall } 151930088Sminshall if (autosynch) { 152030088Sminshall dosynch(); 152130088Sminshall } 152230088Sminshall } 152330088Sminshall 152430088Sminshall static void 152530088Sminshall sendbrk() 152630088Sminshall { 152730088Sminshall NET2ADD(IAC, BREAK); 152830088Sminshall if (autoflush) { 152930088Sminshall doflush(); 153030088Sminshall } 153130088Sminshall if (autosynch) { 153230088Sminshall dosynch(); 153330088Sminshall } 153430088Sminshall } 153530088Sminshall 153630088Sminshall /* 153730088Sminshall * Send as much data as possible to the terminal. 153830088Sminshall * 153930088Sminshall * The return value indicates whether we did any 154030088Sminshall * useful work. 154130088Sminshall */ 154230088Sminshall 154330088Sminshall 154430088Sminshall static int 154530088Sminshall ttyflush() 154630088Sminshall { 154730088Sminshall int n; 154830088Sminshall 154930088Sminshall if ((n = tfrontp - tbackp) > 0) { 155030088Sminshall if (!(SYNCHing||flushout)) { 155131131Sminshall n = TerminalWrite(tout, tbackp, n); 155230088Sminshall } else { 155331124Sminshall TerminalFlushOutput(); 155430088Sminshall /* we leave 'n' alone! */ 155530088Sminshall } 155630088Sminshall } 155730088Sminshall if (n >= 0) { 155830088Sminshall tbackp += n; 155930088Sminshall if (tbackp == tfrontp) { 156030088Sminshall tbackp = tfrontp = ttyobuf; 156130088Sminshall } 156230088Sminshall } 156330088Sminshall return n > 0; 156430088Sminshall } 156530088Sminshall 156630088Sminshall #if defined(TN3270) 156730088Sminshall 156830088Sminshall #if defined(unix) 156930088Sminshall static void 157030088Sminshall inputAvailable() 157130088Sminshall { 157230088Sminshall HaveInput = 1; 157330088Sminshall } 157430088Sminshall #endif /* defined(unix) */ 157530088Sminshall 157630088Sminshall void 157730088Sminshall outputPurge() 157830088Sminshall { 157930088Sminshall int tmp = flushout; 158030088Sminshall 158130088Sminshall flushout = 1; 158230088Sminshall 158330088Sminshall ttyflush(); 158430088Sminshall 158530088Sminshall flushout = tmp; 158630088Sminshall } 158730088Sminshall 158830088Sminshall #endif /* defined(TN3270) */ 158930088Sminshall 159030088Sminshall #if defined(unix) 159130088Sminshall /* 159230088Sminshall * Various signal handling routines. 159330088Sminshall */ 159430088Sminshall 159530088Sminshall static void 159630088Sminshall deadpeer() 159730088Sminshall { 159830088Sminshall setcommandmode(); 159930088Sminshall longjmp(peerdied, -1); 160030088Sminshall } 160130088Sminshall 160230088Sminshall static void 160330088Sminshall intr() 160430088Sminshall { 160530088Sminshall if (localchars) { 160630088Sminshall intp(); 160730088Sminshall return; 160830088Sminshall } 160930088Sminshall setcommandmode(); 161030088Sminshall longjmp(toplevel, -1); 161130088Sminshall } 161230088Sminshall 161330088Sminshall static void 161430088Sminshall intr2() 161530088Sminshall { 161630088Sminshall if (localchars) { 161730088Sminshall sendbrk(); 161830088Sminshall return; 161930088Sminshall } 162030088Sminshall } 162130088Sminshall 162230088Sminshall static void 162330088Sminshall doescape() 162430088Sminshall { 162530088Sminshall command(0); 162630088Sminshall } 162730088Sminshall #endif /* defined(unix) */ 162830088Sminshall 162930088Sminshall /* 163030088Sminshall * These routines decides on what the mode should be (based on the values 163130088Sminshall * of various global variables). 163230088Sminshall */ 163330088Sminshall 163430088Sminshall 163530088Sminshall static 163630088Sminshall getconnmode() 163730088Sminshall { 163830088Sminshall static char newmode[16] = 163930088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; 164030088Sminshall int modeindex = 0; 164130088Sminshall 164230088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 164330088Sminshall modeindex += 1; 164430088Sminshall } 164530088Sminshall if (hisopts[TELOPT_ECHO]) { 164630088Sminshall modeindex += 2; 164730088Sminshall } 164830088Sminshall if (hisopts[TELOPT_SGA]) { 164930088Sminshall modeindex += 4; 165030088Sminshall } 165130088Sminshall if (In3270) { 165230088Sminshall modeindex += 8; 165330088Sminshall } 165430088Sminshall return newmode[modeindex]; 165530088Sminshall } 165630088Sminshall 165730088Sminshall void 165830088Sminshall setconnmode() 165930088Sminshall { 166031124Sminshall TerminalNewMode(getconnmode()); 166130088Sminshall } 166230088Sminshall 166330088Sminshall 166430088Sminshall void 166530088Sminshall setcommandmode() 166630088Sminshall { 166731124Sminshall TerminalNewMode(0); 166830088Sminshall } 166930088Sminshall 167030088Sminshall static void 167130088Sminshall willoption(option, reply) 167230088Sminshall int option, reply; 167330088Sminshall { 167430088Sminshall char *fmt; 167530088Sminshall 167630088Sminshall switch (option) { 167730088Sminshall 167830368Sminshall case TELOPT_ECHO: 167930088Sminshall # if defined(TN3270) 168030368Sminshall /* 168130368Sminshall * The following is a pain in the rear-end. 168230368Sminshall * Various IBM servers (some versions of Wiscnet, 168330368Sminshall * possibly Fibronics/Spartacus, and who knows who 168430368Sminshall * else) will NOT allow us to send "DO SGA" too early 168530368Sminshall * in the setup proceedings. On the other hand, 168630368Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 168730368Sminshall * So, we are stuck. Empirically (but, based on 168830368Sminshall * a VERY small sample), the IBM servers don't send 168930368Sminshall * out anything about ECHO, so we postpone our sending 169030368Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 169130368Sminshall * DO send). 169230368Sminshall */ 169330368Sminshall { 169430368Sminshall if (askedSGA == 0) { 169530368Sminshall askedSGA = 1; 169630368Sminshall if (!hisopts[TELOPT_SGA]) { 169730368Sminshall willoption(TELOPT_SGA, 0); 169830368Sminshall } 169930368Sminshall } 170030368Sminshall } 170130368Sminshall /* Fall through */ 170230088Sminshall case TELOPT_EOR: 170330088Sminshall case TELOPT_BINARY: 170430088Sminshall #endif /* defined(TN3270) */ 170530088Sminshall case TELOPT_SGA: 170630088Sminshall settimer(modenegotiated); 170730088Sminshall hisopts[option] = 1; 170830088Sminshall fmt = doopt; 170930088Sminshall setconnmode(); /* possibly set new tty mode */ 171030088Sminshall break; 171130088Sminshall 171230088Sminshall case TELOPT_TM: 171330088Sminshall return; /* Never reply to TM will's/wont's */ 171430088Sminshall 171530088Sminshall default: 171630088Sminshall fmt = dont; 171730088Sminshall break; 171830088Sminshall } 171930088Sminshall sprintf(nfrontp, fmt, option); 172030088Sminshall nfrontp += sizeof (dont) - 2; 172130088Sminshall if (reply) 172230088Sminshall printoption(">SENT", fmt, option, reply); 172330088Sminshall else 172430088Sminshall printoption("<SENT", fmt, option, reply); 172530088Sminshall } 172630088Sminshall 172730088Sminshall static void 172830088Sminshall wontoption(option, reply) 172930088Sminshall int option, reply; 173030088Sminshall { 173130088Sminshall char *fmt; 173230088Sminshall 173330088Sminshall switch (option) { 173430088Sminshall 173530088Sminshall case TELOPT_ECHO: 173630088Sminshall case TELOPT_SGA: 173730088Sminshall settimer(modenegotiated); 173830088Sminshall hisopts[option] = 0; 173930088Sminshall fmt = dont; 174030088Sminshall setconnmode(); /* Set new tty mode */ 174130088Sminshall break; 174230088Sminshall 174330088Sminshall case TELOPT_TM: 174430088Sminshall return; /* Never reply to TM will's/wont's */ 174530088Sminshall 174630088Sminshall default: 174730088Sminshall fmt = dont; 174830088Sminshall } 174930088Sminshall sprintf(nfrontp, fmt, option); 175030088Sminshall nfrontp += sizeof (doopt) - 2; 175130088Sminshall if (reply) 175230088Sminshall printoption(">SENT", fmt, option, reply); 175330088Sminshall else 175430088Sminshall printoption("<SENT", fmt, option, reply); 175530088Sminshall } 175630088Sminshall 175730088Sminshall static void 175830088Sminshall dooption(option) 175930088Sminshall int option; 176030088Sminshall { 176130088Sminshall char *fmt; 176230088Sminshall 176330088Sminshall switch (option) { 176430088Sminshall 176530088Sminshall case TELOPT_TM: 176630088Sminshall fmt = will; 176730088Sminshall break; 176830088Sminshall 176930088Sminshall # if defined(TN3270) 177030088Sminshall case TELOPT_EOR: 177130088Sminshall case TELOPT_BINARY: 177230088Sminshall # endif /* defined(TN3270) */ 177330088Sminshall case TELOPT_TTYPE: /* terminal type option */ 177430088Sminshall case TELOPT_SGA: /* no big deal */ 177530088Sminshall fmt = will; 177630088Sminshall myopts[option] = 1; 177730088Sminshall break; 177830088Sminshall 177930088Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 178030088Sminshall default: 178130088Sminshall fmt = wont; 178230088Sminshall break; 178330088Sminshall } 178430088Sminshall sprintf(nfrontp, fmt, option); 178530088Sminshall nfrontp += sizeof (doopt) - 2; 178630088Sminshall printoption(">SENT", fmt, option, 0); 178730088Sminshall } 178830088Sminshall 178930088Sminshall /* 179030088Sminshall * suboption() 179130088Sminshall * 179230088Sminshall * Look at the sub-option buffer, and try to be helpful to the other 179330088Sminshall * side. 179430088Sminshall * 179530088Sminshall * Currently we recognize: 179630088Sminshall * 179730088Sminshall * Terminal type, send request. 179830088Sminshall */ 179930088Sminshall 180030088Sminshall static void 180130088Sminshall suboption() 180230088Sminshall { 180330088Sminshall printsub("<", subbuffer, subend-subbuffer+1); 180430088Sminshall switch (subbuffer[0]&0xff) { 180530088Sminshall case TELOPT_TTYPE: 180630088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 180730088Sminshall ; 180830088Sminshall } else { 180930088Sminshall char *name; 181030088Sminshall char namebuf[41]; 181130088Sminshall extern char *getenv(); 181230088Sminshall int len; 181330088Sminshall 181430088Sminshall #if defined(TN3270) 181530088Sminshall /* 181630326Sminshall * Try to send a 3270 type terminal name. Decide which one based 181730088Sminshall * on the format of our screen, and (in the future) color 181830088Sminshall * capaiblities. 181930088Sminshall */ 182031124Sminshall #if defined(unix) 182131131Sminshall if (initscr() != ERR) { /* Initialize curses to get line size */ 182231131Sminshall MaxNumberLines = LINES; 182331131Sminshall MaxNumberColumns = COLS; 182431131Sminshall } 182531131Sminshall #else /* defined(unix) */ 182631131Sminshall InitTerminal(); 182731131Sminshall #endif /* defined(unix) */ 182831131Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 182930088Sminshall Sent3270TerminalType = 1; 183031131Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 183130088Sminshall MaxNumberLines = 27; 183230088Sminshall MaxNumberColumns = 132; 183330088Sminshall sb_terminal[SBTERMMODEL] = '5'; 183431131Sminshall } else if (MaxNumberLines >= 43) { 183530088Sminshall MaxNumberLines = 43; 183630088Sminshall MaxNumberColumns = 80; 183730088Sminshall sb_terminal[SBTERMMODEL] = '4'; 183831131Sminshall } else if (MaxNumberLines >= 32) { 183930088Sminshall MaxNumberLines = 32; 184030088Sminshall MaxNumberColumns = 80; 184130088Sminshall sb_terminal[SBTERMMODEL] = '3'; 184230088Sminshall } else { 184330088Sminshall MaxNumberLines = 24; 184430088Sminshall MaxNumberColumns = 80; 184530088Sminshall sb_terminal[SBTERMMODEL] = '2'; 184630088Sminshall } 184730088Sminshall NumberLines = 24; /* before we start out... */ 184830088Sminshall NumberColumns = 80; 184930088Sminshall ScreenSize = NumberLines*NumberColumns; 185030088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 185130088Sminshall ExitString(stderr, 185230088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 185330088Sminshall /*NOTREACHED*/ 185430088Sminshall } 185531131Sminshall memcpy(nfrontp, sb_terminal, sizeof sb_terminal); 185630088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 185730088Sminshall nfrontp += sizeof sb_terminal; 185830088Sminshall return; 185930088Sminshall } 186030088Sminshall #endif /* defined(TN3270) */ 186130088Sminshall 186230088Sminshall name = getenv("TERM"); 186330088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 186430088Sminshall name = "UNKNOWN"; 186530088Sminshall } 186630088Sminshall if ((len + 4+2) < NETROOM()) { 186730088Sminshall strcpy(namebuf, name); 186830088Sminshall upcase(namebuf); 186930088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 187030088Sminshall TELQUAL_IS, namebuf, IAC, SE); 187130088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 187230088Sminshall nfrontp += 4+strlen(namebuf)+2; 187330088Sminshall } else { 187430088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 187530088Sminshall 1); 187630088Sminshall /*NOTREACHED*/ 187730088Sminshall } 187830088Sminshall } 187930088Sminshall 188030088Sminshall default: 188130088Sminshall break; 188230088Sminshall } 188330088Sminshall } 188430088Sminshall 188530088Sminshall #if defined(TN3270) 188630088Sminshall static void 188730088Sminshall SetIn3270() 188830088Sminshall { 188930088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 189030088Sminshall && hisopts[TELOPT_BINARY]) { 189130088Sminshall if (!In3270) { 189230088Sminshall In3270 = 1; 189330326Sminshall Init3270(); /* Initialize 3270 functions */ 189430088Sminshall /* initialize terminal key mapping */ 189530326Sminshall InitTerminal(); /* Start terminal going */ 189630088Sminshall setconnmode(); 189730088Sminshall } 189830088Sminshall } else { 189930088Sminshall if (In3270) { 190030088Sminshall StopScreen(1); 190130088Sminshall In3270 = 0; 190231215Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 190330088Sminshall setconnmode(); 190430088Sminshall } 190530088Sminshall } 190630088Sminshall } 190730088Sminshall #endif /* defined(TN3270) */ 190830088Sminshall 190930088Sminshall 191030088Sminshall static void 191130088Sminshall telrcv() 191230088Sminshall { 191330088Sminshall register int c; 191430722Sminshall static int telrcv_state = TS_DATA; 191530088Sminshall # if defined(TN3270) 191630088Sminshall register int Scc; 191730088Sminshall register char *Sbp; 191830088Sminshall # endif /* defined(TN3270) */ 191930088Sminshall 192030088Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 192130088Sminshall c = *sbp++ & 0xff, scc--; 192230722Sminshall switch (telrcv_state) { 192330088Sminshall 192430088Sminshall case TS_CR: 192530722Sminshall telrcv_state = TS_DATA; 192630088Sminshall if (c == '\0') { 192730088Sminshall break; /* Ignore \0 after CR */ 192830088Sminshall } else if (c == '\n') { 192930088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 193030088Sminshall TTYADD(c); 193130088Sminshall } 193230088Sminshall break; 193330088Sminshall } 193430088Sminshall /* Else, fall through */ 193530088Sminshall 193630088Sminshall case TS_DATA: 193730088Sminshall if (c == IAC) { 193830722Sminshall telrcv_state = TS_IAC; 193930088Sminshall continue; 194030088Sminshall } 194130088Sminshall # if defined(TN3270) 194230088Sminshall if (In3270) { 194330088Sminshall *Ifrontp++ = c; 194430088Sminshall Sbp = sbp; 194530088Sminshall Scc = scc; 194630088Sminshall while (Scc > 0) { 194730088Sminshall c = *Sbp++ & 0377, Scc--; 194830088Sminshall if (c == IAC) { 194930722Sminshall telrcv_state = TS_IAC; 195030088Sminshall break; 195130088Sminshall } 195230088Sminshall *Ifrontp++ = c; 195330088Sminshall } 195430088Sminshall sbp = Sbp; 195530088Sminshall scc = Scc; 195630088Sminshall } else 195730088Sminshall # endif /* defined(TN3270) */ 195830088Sminshall /* 195930088Sminshall * The 'crmod' hack (see following) is needed 196030088Sminshall * since we can't * set CRMOD on output only. 196130088Sminshall * Machines like MULTICS like to send \r without 196230088Sminshall * \n; since we must turn off CRMOD to get proper 196330088Sminshall * input, the mapping is done here (sigh). 196430088Sminshall */ 196530088Sminshall if (c == '\r') { 196630088Sminshall if (scc > 0) { 196730088Sminshall c = *sbp&0xff; 196830088Sminshall if (c == 0) { 196930088Sminshall sbp++, scc--; 197030088Sminshall /* a "true" CR */ 197130088Sminshall TTYADD('\r'); 197230088Sminshall } else if (!hisopts[TELOPT_ECHO] && 197330088Sminshall (c == '\n')) { 197430088Sminshall sbp++, scc--; 197530088Sminshall TTYADD('\n'); 197630088Sminshall } else { 197730088Sminshall TTYADD('\r'); 197830088Sminshall if (crmod) { 197930088Sminshall TTYADD('\n'); 198030088Sminshall } 198130088Sminshall } 198230088Sminshall } else { 198330722Sminshall telrcv_state = TS_CR; 198430088Sminshall TTYADD('\r'); 198530088Sminshall if (crmod) { 198630088Sminshall TTYADD('\n'); 198730088Sminshall } 198830088Sminshall } 198930088Sminshall } else { 199030088Sminshall TTYADD(c); 199130088Sminshall } 199230088Sminshall continue; 199330088Sminshall 199430088Sminshall case TS_IAC: 199530088Sminshall switch (c) { 199630088Sminshall 199730088Sminshall case WILL: 199830722Sminshall telrcv_state = TS_WILL; 199930088Sminshall continue; 200030088Sminshall 200130088Sminshall case WONT: 200230722Sminshall telrcv_state = TS_WONT; 200330088Sminshall continue; 200430088Sminshall 200530088Sminshall case DO: 200630722Sminshall telrcv_state = TS_DO; 200730088Sminshall continue; 200830088Sminshall 200930088Sminshall case DONT: 201030722Sminshall telrcv_state = TS_DONT; 201130088Sminshall continue; 201230088Sminshall 201330088Sminshall case DM: 201430088Sminshall /* 201530088Sminshall * We may have missed an urgent notification, 201630088Sminshall * so make sure we flush whatever is in the 201730088Sminshall * buffer currently. 201830088Sminshall */ 201930088Sminshall SYNCHing = 1; 202030088Sminshall ttyflush(); 202130088Sminshall SYNCHing = stilloob(net); 202230088Sminshall settimer(gotDM); 202330088Sminshall break; 202430088Sminshall 202530088Sminshall case NOP: 202630088Sminshall case GA: 202730088Sminshall break; 202830088Sminshall 202930088Sminshall case SB: 203030088Sminshall SB_CLEAR(); 203130722Sminshall telrcv_state = TS_SB; 203230088Sminshall continue; 203330088Sminshall 203430088Sminshall # if defined(TN3270) 203530088Sminshall case EOR: 203630088Sminshall if (In3270) { 203730088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 203830088Sminshall if (Ibackp == Ifrontp) { 203930088Sminshall Ibackp = Ifrontp = Ibuf; 204030088Sminshall ISend = 0; /* should have been! */ 204130088Sminshall } else { 204230088Sminshall ISend = 1; 204330088Sminshall } 204430088Sminshall } 204530088Sminshall break; 204630088Sminshall # endif /* defined(TN3270) */ 204730088Sminshall 204830088Sminshall case IAC: 204930088Sminshall # if !defined(TN3270) 205030088Sminshall TTYADD(IAC); 205130088Sminshall # else /* !defined(TN3270) */ 205230088Sminshall if (In3270) { 205330088Sminshall *Ifrontp++ = IAC; 205430088Sminshall } else { 205530088Sminshall TTYADD(IAC); 205630088Sminshall } 205730088Sminshall # endif /* !defined(TN3270) */ 205830088Sminshall break; 205930088Sminshall 206030088Sminshall default: 206130088Sminshall break; 206230088Sminshall } 206330722Sminshall telrcv_state = TS_DATA; 206430088Sminshall continue; 206530088Sminshall 206630088Sminshall case TS_WILL: 206730088Sminshall printoption(">RCVD", will, c, !hisopts[c]); 206830088Sminshall if (c == TELOPT_TM) { 206930088Sminshall if (flushout) { 207030088Sminshall flushout = 0; 207130088Sminshall } 207230088Sminshall } else if (!hisopts[c]) { 207330088Sminshall willoption(c, 1); 207430088Sminshall } 207530088Sminshall SetIn3270(); 207630722Sminshall telrcv_state = TS_DATA; 207730088Sminshall continue; 207830088Sminshall 207930088Sminshall case TS_WONT: 208030088Sminshall printoption(">RCVD", wont, c, hisopts[c]); 208130088Sminshall if (c == TELOPT_TM) { 208230088Sminshall if (flushout) { 208330088Sminshall flushout = 0; 208430088Sminshall } 208530088Sminshall } else if (hisopts[c]) { 208630088Sminshall wontoption(c, 1); 208730088Sminshall } 208830088Sminshall SetIn3270(); 208930722Sminshall telrcv_state = TS_DATA; 209030088Sminshall continue; 209130088Sminshall 209230088Sminshall case TS_DO: 209330088Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 209430088Sminshall if (!myopts[c]) 209530088Sminshall dooption(c); 209630088Sminshall SetIn3270(); 209730722Sminshall telrcv_state = TS_DATA; 209830088Sminshall continue; 209930088Sminshall 210030088Sminshall case TS_DONT: 210130088Sminshall printoption(">RCVD", dont, c, myopts[c]); 210230088Sminshall if (myopts[c]) { 210330088Sminshall myopts[c] = 0; 210430088Sminshall sprintf(nfrontp, wont, c); 210530088Sminshall nfrontp += sizeof (wont) - 2; 210630088Sminshall flushline = 1; 210730088Sminshall setconnmode(); /* set new tty mode (maybe) */ 210830088Sminshall printoption(">SENT", wont, c, 0); 210930088Sminshall } 211030088Sminshall SetIn3270(); 211130722Sminshall telrcv_state = TS_DATA; 211230088Sminshall continue; 211330088Sminshall 211430088Sminshall case TS_SB: 211530088Sminshall if (c == IAC) { 211630722Sminshall telrcv_state = TS_SE; 211730088Sminshall } else { 211830088Sminshall SB_ACCUM(c); 211930088Sminshall } 212030088Sminshall continue; 212130088Sminshall 212230088Sminshall case TS_SE: 212330088Sminshall if (c != SE) { 212430088Sminshall if (c != IAC) { 212530088Sminshall SB_ACCUM(IAC); 212630088Sminshall } 212730088Sminshall SB_ACCUM(c); 212830722Sminshall telrcv_state = TS_SB; 212930088Sminshall } else { 213030088Sminshall SB_TERM(); 213130088Sminshall suboption(); /* handle sub-option */ 213230088Sminshall SetIn3270(); 213330722Sminshall telrcv_state = TS_DATA; 213430088Sminshall } 213530088Sminshall } 213630088Sminshall } 213730088Sminshall } 213830088Sminshall 213930088Sminshall #if defined(TN3270) 214030088Sminshall 214130088Sminshall /* 214230088Sminshall * The following routines are places where the various tn3270 214330088Sminshall * routines make calls into telnet.c. 214430088Sminshall */ 214530088Sminshall 214630088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 214730088Sminshall TtyChars() 214830088Sminshall { 214930088Sminshall return(tfrontp-tbackp); 215030088Sminshall } 215130088Sminshall 215230088Sminshall /* 215330088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 215430088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 215530088Sminshall * don't call us with "done" until you want that done...) 215630088Sminshall * 215730088Sminshall * We actually do send all the data to the network buffer, since our 215830088Sminshall * only client needs for us to do that. 215930088Sminshall */ 216030088Sminshall 216130088Sminshall int 216230088Sminshall DataToNetwork(buffer, count, done) 216330088Sminshall register char *buffer; /* where the data is */ 216430088Sminshall register int count; /* how much to send */ 216530088Sminshall int done; /* is this the last of a logical block */ 216630088Sminshall { 216730088Sminshall register int c; 216830088Sminshall int origCount; 216930088Sminshall fd_set o; 217030088Sminshall 217130088Sminshall origCount = count; 217230088Sminshall FD_ZERO(&o); 217330088Sminshall 217430088Sminshall while (count) { 217530088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 217630088Sminshall netflush(); 217730088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) { 217830088Sminshall FD_SET(net, &o); 217930088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 218030088Sminshall (struct timeval *) 0); 218130088Sminshall netflush(); 218230088Sminshall } 218330088Sminshall } 218430088Sminshall c = *buffer++; 218530088Sminshall count--; 218630088Sminshall if (c == IAC) { 218730088Sminshall *nfrontp++ = IAC; 218830088Sminshall *nfrontp++ = IAC; 218930088Sminshall } else { 219030088Sminshall *nfrontp++ = c; 219130088Sminshall } 219230088Sminshall } 219330088Sminshall 219430088Sminshall if (done && !count) { 219530088Sminshall *nfrontp++ = IAC; 219630088Sminshall *nfrontp++ = EOR; 219730088Sminshall netflush(); /* try to move along as quickly as ... */ 219830088Sminshall } 219930088Sminshall return(origCount - count); 220030088Sminshall } 220130088Sminshall 220230088Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 220330088Sminshall 220430088Sminshall int 220530088Sminshall DataToTerminal(buffer, count) 220630088Sminshall register char *buffer; /* where the data is */ 220730088Sminshall register int count; /* how much to send */ 220830088Sminshall { 220930088Sminshall int origCount; 221031131Sminshall #if defined(unix) 221130088Sminshall fd_set o; 221230088Sminshall 221331131Sminshall FD_ZERO(&o); 221431131Sminshall #endif /* defined(unix) */ 221530088Sminshall origCount = count; 221630088Sminshall 221730088Sminshall while (count) { 221830088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 221930088Sminshall ttyflush(); 222030088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 222131131Sminshall #if defined(unix) 222230088Sminshall FD_SET(tout, &o); 222330088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 222430088Sminshall (struct timeval *) 0); 222531131Sminshall #endif /* defined(unix) */ 222630088Sminshall ttyflush(); 222730088Sminshall } 222830088Sminshall } 222930088Sminshall *tfrontp++ = *buffer++; 223030088Sminshall count--; 223130088Sminshall } 223230088Sminshall return(origCount - count); 223330088Sminshall } 223430088Sminshall 223530088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 223630088Sminshall * Note that we consider the buffer to run all the 223730088Sminshall * way to the kernel (thus the select). 223830088Sminshall */ 223930088Sminshall 224030088Sminshall void 224130088Sminshall EmptyTerminal() 224230088Sminshall { 224331131Sminshall #if defined(unix) 224430088Sminshall fd_set o; 224530088Sminshall 224630088Sminshall FD_ZERO(&o); 224731131Sminshall #endif /* defined(unix) */ 224830088Sminshall 224930088Sminshall if (tfrontp == tbackp) { 225031131Sminshall #if defined(unix) 225130088Sminshall FD_SET(tout, &o); 225230088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 225330088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 225431131Sminshall #endif /* defined(unix) */ 225530088Sminshall } else { 225630088Sminshall while (tfrontp != tbackp) { 225730088Sminshall ttyflush(); 225831131Sminshall #if defined(unix) 225930088Sminshall FD_SET(tout, &o); 226030088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 226130088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 226231131Sminshall #endif /* defined(unix) */ 226330088Sminshall } 226430088Sminshall } 226530088Sminshall } 226630088Sminshall 226730088Sminshall /* 226830088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 226930088Sminshall */ 227030088Sminshall 227130088Sminshall static int 227230088Sminshall Push3270() 227330088Sminshall { 227430088Sminshall int save = scc; 227530088Sminshall 227630088Sminshall if (scc) { 227730088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 227830088Sminshall if (Ibackp != Ibuf) { 227931131Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 228030088Sminshall Ifrontp -= (Ibackp-Ibuf); 228130088Sminshall Ibackp = Ibuf; 228230088Sminshall } 228330088Sminshall } 228430088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 228530088Sminshall telrcv(); 228630088Sminshall } 228730088Sminshall } 228830088Sminshall return save != scc; 228930088Sminshall } 229030088Sminshall 229130088Sminshall 229230088Sminshall /* 229330088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 229430088Sminshall * before quitting. 229530088Sminshall */ 229630088Sminshall 229730088Sminshall static void 229830088Sminshall Finish3270() 229930088Sminshall { 230030088Sminshall while (Push3270() || !DoTerminalOutput()) { 230130088Sminshall ; 230230088Sminshall } 230330088Sminshall } 230430088Sminshall 230530088Sminshall 230630088Sminshall 230730088Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 230830088Sminshall 230930088Sminshall void 231030088Sminshall StringToTerminal(s) 231130088Sminshall char *s; 231230088Sminshall { 231330088Sminshall int count; 231430088Sminshall 231530088Sminshall count = strlen(s); 231630088Sminshall if (count) { 231730088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 231830088Sminshall } 231930088Sminshall } 232030088Sminshall 232130088Sminshall 232230088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) 232330088Sminshall /* _putchar - output a single character to the terminal. This name is so that 232430088Sminshall * curses(3x) can call us to send out data. 232530088Sminshall */ 232630088Sminshall 232730088Sminshall void 232830088Sminshall _putchar(c) 232930088Sminshall char c; 233030088Sminshall { 233130088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 233230088Sminshall (void) DataToTerminal(&c, 1); 233330088Sminshall } else { 233430088Sminshall *tfrontp++ = c; /* optimize if possible. */ 233530088Sminshall } 233630088Sminshall } 233730088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ 233830088Sminshall 233930088Sminshall static void 234030088Sminshall SetForExit() 234130088Sminshall { 234230088Sminshall setconnmode(); 234330088Sminshall if (In3270) { 234430088Sminshall Finish3270(); 234530088Sminshall } 234630088Sminshall setcommandmode(); 234730088Sminshall fflush(stdout); 234830088Sminshall fflush(stderr); 234930088Sminshall if (In3270) { 235030088Sminshall StopScreen(1); 235130088Sminshall } 235230088Sminshall setconnmode(); 235330088Sminshall setcommandmode(); 235430088Sminshall } 235530088Sminshall 235630088Sminshall static void 235730088Sminshall Exit(returnCode) 235830088Sminshall int returnCode; 235930088Sminshall { 236030088Sminshall SetForExit(); 236130088Sminshall exit(returnCode); 236230088Sminshall } 236330088Sminshall 236430088Sminshall void 236530088Sminshall ExitString(file, string, returnCode) 236630088Sminshall FILE *file; 236730088Sminshall char *string; 236830088Sminshall int returnCode; 236930088Sminshall { 237030088Sminshall SetForExit(); 237130088Sminshall fwrite(string, 1, strlen(string), file); 237230088Sminshall exit(returnCode); 237330088Sminshall } 237430088Sminshall 237530088Sminshall void 237630088Sminshall ExitPerror(string, returnCode) 237730088Sminshall char *string; 237830088Sminshall int returnCode; 237930088Sminshall { 238030088Sminshall SetForExit(); 238130088Sminshall perror(string); 238230088Sminshall exit(returnCode); 238330088Sminshall } 238430088Sminshall 238530088Sminshall #endif /* defined(TN3270) */ 238630088Sminshall 238731215Sminshall /* 238831215Sminshall * Scheduler() 238931215Sminshall * 239031215Sminshall * Try to do something. 239131215Sminshall * 239231215Sminshall * If we do something useful, return 1; else return 0. 239331215Sminshall * 239431215Sminshall */ 239531215Sminshall 239631215Sminshall 239731215Sminshall int 239830088Sminshall Scheduler(block) 239930088Sminshall int block; /* should we block in the select ? */ 240030088Sminshall { 240130088Sminshall register int c; 240230088Sminshall /* One wants to be a bit careful about setting returnValue 240330088Sminshall * to one, since a one implies we did some useful work, 240430088Sminshall * and therefore probably won't be called to block next 240530088Sminshall * time (TN3270 mode only). 240630088Sminshall */ 240730088Sminshall int returnValue = 0; 240830088Sminshall static struct timeval TimeValue = { 0 }; 240930088Sminshall 241030088Sminshall if (scc < 0 && tcc < 0) { 241130088Sminshall return -1; 241230088Sminshall } 241330088Sminshall 241430088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 241530088Sminshall FD_SET(net, &obits); 241630088Sminshall } 241731131Sminshall #if !defined(MSDOS) 241830088Sminshall if (TTYBYTES()) { 241930088Sminshall FD_SET(tout, &obits); 242030088Sminshall } 242131215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0)) { 242230088Sminshall FD_SET(tin, &ibits); 242330088Sminshall } 242431131Sminshall #endif /* !defined(MSDOS) */ 242530088Sminshall # if !defined(TN3270) 242630088Sminshall if (TTYROOM()) { 242730088Sminshall FD_SET(net, &ibits); 242830088Sminshall } 242930088Sminshall # else /* !defined(TN3270) */ 243030088Sminshall if (!ISend && TTYROOM()) { 243130088Sminshall FD_SET(net, &ibits); 243230088Sminshall } 243330088Sminshall # endif /* !defined(TN3270) */ 243430088Sminshall if (!SYNCHing) { 243530088Sminshall FD_SET(net, &xbits); 243630088Sminshall } 243730088Sminshall # if defined(TN3270) && defined(unix) 243830088Sminshall if (HaveInput) { 243930088Sminshall HaveInput = 0; 244030088Sminshall signal(SIGIO, inputAvailable); 244130088Sminshall } 244230088Sminshall #endif /* defined(TN3270) && defined(unix) */ 244330088Sminshall if ((c = select(16, &ibits, &obits, &xbits, 244431131Sminshall block? (struct timeval *)0 : &TimeValue)) < 0) { 244530088Sminshall if (c == -1) { 244630088Sminshall /* 244730088Sminshall * we can get EINTR if we are in line mode, 244830088Sminshall * and the user does an escape (TSTP), or 244930088Sminshall * some other signal generator. 245030088Sminshall */ 245130088Sminshall if (errno == EINTR) { 245230088Sminshall return 0; 245330088Sminshall } 245430088Sminshall # if defined(TN3270) 245530088Sminshall /* 245630088Sminshall * we can get EBADF if we were in transparent 245730088Sminshall * mode, and the transcom process died. 245830088Sminshall */ 245930088Sminshall if (errno == EBADF) { 246030088Sminshall /* 246130088Sminshall * zero the bits (even though kernel does it) 246230088Sminshall * to make sure we are selecting on the right 246330088Sminshall * ones. 246430088Sminshall */ 246530088Sminshall FD_ZERO(&ibits); 246630088Sminshall FD_ZERO(&obits); 246730088Sminshall FD_ZERO(&xbits); 246830088Sminshall return 0; 246930088Sminshall } 247030088Sminshall # endif /* defined(TN3270) */ 247130088Sminshall /* I don't like this, does it ever happen? */ 247230088Sminshall printf("sleep(5) from telnet, after select\r\n"); 247330088Sminshall #if defined(unix) 247430088Sminshall sleep(5); 247530088Sminshall #endif /* defined(unix) */ 247630088Sminshall } 247730088Sminshall return 0; 247830088Sminshall } 247930088Sminshall 248030088Sminshall /* 248130088Sminshall * Any urgent data? 248230088Sminshall */ 248330088Sminshall if (FD_ISSET(net, &xbits)) { 248430088Sminshall FD_CLR(net, &xbits); 248530088Sminshall SYNCHing = 1; 248630088Sminshall ttyflush(); /* flush already enqueued data */ 248730088Sminshall } 248830088Sminshall 248930088Sminshall /* 249030088Sminshall * Something to read from the network... 249130088Sminshall */ 249230088Sminshall if (FD_ISSET(net, &ibits)) { 249330088Sminshall int canread; 249430088Sminshall 249530088Sminshall FD_CLR(net, &ibits); 249630088Sminshall if (scc == 0) { 249730088Sminshall sbp = sibuf; 249830088Sminshall } 249930422Sminshall canread = sibuf + sizeof sibuf - (sbp+scc); 250030088Sminshall #if !defined(SO_OOBINLINE) 250130088Sminshall /* 250230088Sminshall * In 4.2 (and some early 4.3) systems, the 250330088Sminshall * OOB indication and data handling in the kernel 250430088Sminshall * is such that if two separate TCP Urgent requests 250530088Sminshall * come in, one byte of TCP data will be overlaid. 250630088Sminshall * This is fatal for Telnet, but we try to live 250730088Sminshall * with it. 250830088Sminshall * 250930088Sminshall * In addition, in 4.2 (and...), a special protocol 251030088Sminshall * is needed to pick up the TCP Urgent data in 251130088Sminshall * the correct sequence. 251230088Sminshall * 251330088Sminshall * What we do is: if we think we are in urgent 251430088Sminshall * mode, we look to see if we are "at the mark". 251530088Sminshall * If we are, we do an OOB receive. If we run 251630088Sminshall * this twice, we will do the OOB receive twice, 251730088Sminshall * but the second will fail, since the second 251830088Sminshall * time we were "at the mark", but there wasn't 251930088Sminshall * any data there (the kernel doesn't reset 252030088Sminshall * "at the mark" until we do a normal read). 252130088Sminshall * Once we've read the OOB data, we go ahead 252230088Sminshall * and do normal reads. 252330088Sminshall * 252430088Sminshall * There is also another problem, which is that 252530088Sminshall * since the OOB byte we read doesn't put us 252630088Sminshall * out of OOB state, and since that byte is most 252730088Sminshall * likely the TELNET DM (data mark), we would 252830088Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 252930088Sminshall * So, clocks to the rescue. If we've "just" 253030088Sminshall * received a DM, then we test for the 253130088Sminshall * presence of OOB data when the receive OOB 253230088Sminshall * fails (and AFTER we did the normal mode read 253330088Sminshall * to clear "at the mark"). 253430088Sminshall */ 253530088Sminshall if (SYNCHing) { 253630088Sminshall int atmark; 253730088Sminshall 253830088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 253930088Sminshall if (atmark) { 254030422Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 254130088Sminshall if ((c == -1) && (errno == EINVAL)) { 254231131Sminshall c = recv(net, sbp+scc, canread, 0); 254330088Sminshall if (clocks.didnetreceive < clocks.gotDM) { 254430088Sminshall SYNCHing = stilloob(net); 254530088Sminshall } 254630088Sminshall } 254730088Sminshall } else { 254831131Sminshall c = recv(net, sbp+scc, canread, 0); 254930088Sminshall } 255030088Sminshall } else { 255131131Sminshall c = recv(net, sbp+scc, canread, 0); 255230088Sminshall } 255330088Sminshall settimer(didnetreceive); 255430088Sminshall #else /* !defined(SO_OOBINLINE) */ 255531131Sminshall c = recv(net, sbp+scc, canread, 0); 255630088Sminshall #endif /* !defined(SO_OOBINLINE) */ 255730088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 255830088Sminshall c = 0; 255930088Sminshall } else if (c <= 0) { 256030088Sminshall return -1; 256130088Sminshall } 256230088Sminshall if (netdata) { 256330422Sminshall Dump('<', sbp+scc, c); 256430088Sminshall } 256530088Sminshall scc += c; 256630088Sminshall returnValue = 1; 256730088Sminshall } 256830088Sminshall 256930088Sminshall /* 257030088Sminshall * Something to read from the tty... 257130088Sminshall */ 257231131Sminshall #if defined(MSDOS) 257331215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead()) 257431131Sminshall #else /* defined(MSDOS) */ 257531131Sminshall if (FD_ISSET(tin, &ibits)) 257631131Sminshall #endif /* defined(MSDOS) */ 257731131Sminshall { 257830088Sminshall FD_CLR(tin, &ibits); 257930088Sminshall if (tcc == 0) { 258030088Sminshall tbp = tibuf; /* nothing left, reset */ 258130088Sminshall } 258231131Sminshall c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp); 258330088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 258430088Sminshall c = 0; 258530088Sminshall } else { 258631124Sminshall #if defined(unix) 258730088Sminshall /* EOF detection for line mode!!!! */ 258830088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 258930088Sminshall /* must be an EOF... */ 259030088Sminshall *tbp = ntc.t_eofc; 259130088Sminshall c = 1; 259230088Sminshall } 259331124Sminshall #endif /* defined(unix) */ 259430088Sminshall if (c <= 0) { 259530088Sminshall tcc = c; 259630088Sminshall return -1; 259730088Sminshall } 259830088Sminshall } 259930088Sminshall tcc += c; 260030088Sminshall returnValue = 1; /* did something useful */ 260130088Sminshall } 260230088Sminshall 260330088Sminshall # if defined(TN3270) 260430088Sminshall if (tcc > 0) { 260530088Sminshall if (In3270) { 260630088Sminshall c = DataFromTerminal(tbp, tcc); 260730088Sminshall if (c) { 260830088Sminshall returnValue = 1; 260930088Sminshall } 261030088Sminshall tcc -= c; 261130088Sminshall tbp += c; 261230088Sminshall } else { 261330320Sminshall # endif /* defined(TN3270) */ 261430088Sminshall returnValue = 1; 261530088Sminshall while (tcc > 0) { 261630088Sminshall register int sc; 261730088Sminshall 261830088Sminshall if (NETROOM() < 2) { 261930088Sminshall flushline = 1; 262030088Sminshall break; 262130088Sminshall } 262230088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 262330088Sminshall if (sc == escape) { 262430088Sminshall command(0); 262530088Sminshall tcc = 0; 262630088Sminshall flushline = 1; 262730088Sminshall break; 262830088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 262930088Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 263030088Sminshall tbp++; 263130088Sminshall tcc--; 263230088Sminshall } else { 263330088Sminshall dontlecho = !dontlecho; 263430088Sminshall settimer(echotoggle); 263530088Sminshall setconnmode(); 263630088Sminshall tcc = 0; 263730088Sminshall flushline = 1; 263830088Sminshall break; 263930088Sminshall } 264030088Sminshall } 264130088Sminshall if (localchars) { 264231131Sminshall if (TerminalSpecialChars(sc) == 0) { 264330088Sminshall break; 264430088Sminshall } 264530088Sminshall } 264630088Sminshall switch (c) { 264730088Sminshall case '\n': 264830088Sminshall /* 264930088Sminshall * If we are in CRMOD mode (\r ==> \n) 265030088Sminshall * on our local machine, then probably 265130088Sminshall * a newline (unix) is CRLF (TELNET). 265230088Sminshall */ 265330088Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 265430088Sminshall NETADD('\r'); 265530088Sminshall } 265630088Sminshall NETADD('\n'); 265730088Sminshall flushline = 1; 265830088Sminshall break; 265930088Sminshall case '\r': 266030088Sminshall NET2ADD('\r', '\0'); 266130088Sminshall flushline = 1; 266230088Sminshall break; 266330088Sminshall case IAC: 266430088Sminshall NET2ADD(IAC, IAC); 266530088Sminshall break; 266630088Sminshall default: 266730088Sminshall NETADD(c); 266830088Sminshall break; 266930088Sminshall } 267030088Sminshall } 267130088Sminshall # if defined(TN3270) 267230088Sminshall } 267330088Sminshall } 267430088Sminshall # endif /* defined(TN3270) */ 267530088Sminshall 267630088Sminshall if ((!MODE_LINE(globalmode) || flushline) && 267730088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 267830088Sminshall FD_CLR(net, &obits); 267930088Sminshall returnValue = netflush(); 268030088Sminshall } 268130088Sminshall if (scc > 0) { 268230088Sminshall # if !defined(TN3270) 268330088Sminshall telrcv(); 268430088Sminshall returnValue = 1; 268530088Sminshall # else /* !defined(TN3270) */ 268630088Sminshall returnValue = Push3270(); 268730088Sminshall # endif /* !defined(TN3270) */ 268830088Sminshall } 268931131Sminshall #if defined(MSDOS) 269031131Sminshall if (TTYBYTES()) 269131131Sminshall #else /* defined(MSDOS) */ 269231131Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 269331131Sminshall #endif /* defined(MSDOS) */ 269431131Sminshall { 269530088Sminshall FD_CLR(tout, &obits); 269630088Sminshall returnValue = ttyflush(); 269730088Sminshall } 269830088Sminshall return returnValue; 269930088Sminshall } 270030088Sminshall 270130088Sminshall /* 270230088Sminshall * Select from tty and network... 270330088Sminshall */ 270430088Sminshall static void 270530088Sminshall telnet() 270630088Sminshall { 270731131Sminshall #if defined(MSDOS) 270831131Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */ 270931131Sminshall #else /* defined(MSDOS) */ 271031131Sminshall #define SCHED_BLOCK 1 271131131Sminshall #endif /* defined(MSDOS) */ 271231131Sminshall 271330088Sminshall #if defined(TN3270) && defined(unix) 271430088Sminshall int myPid; 271530088Sminshall #endif /* defined(TN3270) */ 271630088Sminshall 271730088Sminshall tout = fileno(stdout); 271830088Sminshall tin = fileno(stdin); 271930088Sminshall setconnmode(); 272030088Sminshall scc = 0; 272130088Sminshall tcc = 0; 272230088Sminshall FD_ZERO(&ibits); 272330088Sminshall FD_ZERO(&obits); 272430088Sminshall FD_ZERO(&xbits); 272530088Sminshall 272631124Sminshall NetNonblockingIO(net, 1); 272730088Sminshall 272830088Sminshall #if defined(TN3270) 2729*31478Sminshall if (noasynch == 0) { /* DBX can't handle! */ 2730*31478Sminshall NetSigIO(net, 1); 2731*31478Sminshall } 273231124Sminshall NetSetPgrp(net); 273330088Sminshall #endif /* defined(TN3270) */ 273430088Sminshall 273530088Sminshall 273631124Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 273731124Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 273831124Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 273931124Sminshall 274030320Sminshall # if !defined(TN3270) 274130088Sminshall if (telnetport) { 274230088Sminshall if (!hisopts[TELOPT_SGA]) { 274330088Sminshall willoption(TELOPT_SGA, 0); 274430088Sminshall } 274530088Sminshall if (!myopts[TELOPT_TTYPE]) { 274630088Sminshall dooption(TELOPT_TTYPE, 0); 274730088Sminshall } 274830088Sminshall } 274930320Sminshall # endif /* !defined(TN3270) */ 275030088Sminshall 275130088Sminshall # if !defined(TN3270) 275230088Sminshall for (;;) { 275331131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 275430088Sminshall setcommandmode(); 275530088Sminshall return; 275630088Sminshall } 275730088Sminshall } 275830088Sminshall # else /* !defined(TN3270) */ 275930088Sminshall for (;;) { 276030088Sminshall int schedValue; 276130088Sminshall 276230088Sminshall while (!In3270) { 276331131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 276430088Sminshall setcommandmode(); 276530088Sminshall return; 276630088Sminshall } 276730088Sminshall } 276830088Sminshall 276930088Sminshall while ((schedValue = Scheduler(0)) != 0) { 277030088Sminshall if (schedValue == -1) { 277130088Sminshall setcommandmode(); 277230088Sminshall return; 277330088Sminshall } 277430088Sminshall } 277530088Sminshall /* If there is data waiting to go out to terminal, don't 277630088Sminshall * schedule any more data for the terminal. 277730088Sminshall */ 277830088Sminshall if (tfrontp-tbackp) { 277930088Sminshall schedValue = 1; 278030088Sminshall } else { 278131215Sminshall if (shell_active) { 278231215Sminshall #if defined(MSDOS) 278331215Sminshall static int haventstopped = 1; 278431215Sminshall 278531215Sminshall setcommandmode(); 278631215Sminshall if (haventstopped) { 278731215Sminshall StopScreen(1); 278831215Sminshall haventstopped = 0; 278931215Sminshall } 2790*31478Sminshall #endif /* defined(MSDOS) */ 279131215Sminshall if (shell_continue() == 0) { 279231215Sminshall ConnectScreen(); 2793*31478Sminshall #if defined(MSDOS) 279431215Sminshall haventstopped = 1; 2795*31478Sminshall #endif /* defined(MSDOS) */ 279631215Sminshall } 2797*31478Sminshall #if defined(MSDOS) 279831215Sminshall setconnmode(); 279931215Sminshall #endif /* defined(MSDOS) */ 280031215Sminshall } else { 280131215Sminshall schedValue = DoTerminalOutput(); 280231215Sminshall } 280330088Sminshall } 280431215Sminshall if (schedValue && (shell_active == 0)) { 280531131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 280630088Sminshall setcommandmode(); 280730088Sminshall return; 280830088Sminshall } 280930088Sminshall } 281030088Sminshall } 281130088Sminshall # endif /* !defined(TN3270) */ 281230088Sminshall } 281330088Sminshall 281430088Sminshall /* 281530088Sminshall * The following are data structures and routines for 281630088Sminshall * the "send" command. 281730088Sminshall * 281830088Sminshall */ 281930088Sminshall 282030088Sminshall struct sendlist { 282130088Sminshall char *name; /* How user refers to it (case independent) */ 282230088Sminshall int what; /* Character to be sent (<0 ==> special) */ 282330088Sminshall char *help; /* Help information (0 ==> no help) */ 282430088Sminshall #if defined(NOT43) 282530088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 282630088Sminshall #else /* defined(NOT43) */ 282730088Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 282830088Sminshall #endif /* defined(NOT43) */ 282930088Sminshall }; 283030088Sminshall 283130088Sminshall #define SENDQUESTION -1 283230088Sminshall #define SENDESCAPE -3 283330088Sminshall 283430088Sminshall static struct sendlist Sendlist[] = { 283530088Sminshall { "ao", AO, "Send Telnet Abort output" }, 283630088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 283730088Sminshall { "brk", BREAK, "Send Telnet Break" }, 283830088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 283930088Sminshall { "el", EL, "Send Telnet Erase Line" }, 284030088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 284130088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 284230088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 284330088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 284430088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 284530088Sminshall { "?", SENDQUESTION, "Display send options" }, 284630088Sminshall { 0 } 284730088Sminshall }; 284830088Sminshall 284930088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 285030088Sminshall { "break", BREAK, 0 }, 285130088Sminshall 285230088Sminshall { "intp", IP, 0 }, 285330088Sminshall { "interrupt", IP, 0 }, 285430088Sminshall { "intr", IP, 0 }, 285530088Sminshall 285630088Sminshall { "help", SENDQUESTION, 0 }, 285730088Sminshall 285830088Sminshall { 0 } 285930088Sminshall }; 286030088Sminshall 286130088Sminshall static char ** 286230088Sminshall getnextsend(name) 286330088Sminshall char *name; 286430088Sminshall { 286530088Sminshall struct sendlist *c = (struct sendlist *) name; 286630088Sminshall 286730088Sminshall return (char **) (c+1); 286830088Sminshall } 286930088Sminshall 287030088Sminshall static struct sendlist * 287130088Sminshall getsend(name) 287230088Sminshall char *name; 287330088Sminshall { 287430088Sminshall struct sendlist *sl; 287530088Sminshall 287630088Sminshall if ((sl = (struct sendlist *) 287730088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 287830088Sminshall return sl; 287930088Sminshall } else { 288030088Sminshall return (struct sendlist *) 288130088Sminshall genget(name, (char **) Sendlist2, getnextsend); 288230088Sminshall } 288330088Sminshall } 288430088Sminshall 288530088Sminshall static 288630088Sminshall sendcmd(argc, argv) 288730088Sminshall int argc; 288830088Sminshall char **argv; 288930088Sminshall { 289030088Sminshall int what; /* what we are sending this time */ 289130088Sminshall int count; /* how many bytes we are going to need to send */ 289230088Sminshall int i; 289330088Sminshall int question = 0; /* was at least one argument a question */ 289430088Sminshall struct sendlist *s; /* pointer to current command */ 289530088Sminshall 289630088Sminshall if (argc < 2) { 289730088Sminshall printf("need at least one argument for 'send' command\n"); 289830088Sminshall printf("'send ?' for help\n"); 289930088Sminshall return 0; 290030088Sminshall } 290130088Sminshall /* 290230088Sminshall * First, validate all the send arguments. 290330088Sminshall * In addition, we see how much space we are going to need, and 290430088Sminshall * whether or not we will be doing a "SYNCH" operation (which 290530088Sminshall * flushes the network queue). 290630088Sminshall */ 290730088Sminshall count = 0; 290830088Sminshall for (i = 1; i < argc; i++) { 290930088Sminshall s = getsend(argv[i]); 291030088Sminshall if (s == 0) { 291130088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 291230088Sminshall argv[i]); 291330088Sminshall return 0; 291430088Sminshall } else if (s == Ambiguous(struct sendlist *)) { 291530088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 291630088Sminshall argv[i]); 291730088Sminshall return 0; 291830088Sminshall } 291930088Sminshall switch (s->what) { 292030088Sminshall case SENDQUESTION: 292130088Sminshall break; 292230088Sminshall case SENDESCAPE: 292330088Sminshall count += 1; 292430088Sminshall break; 292530088Sminshall case SYNCH: 292630088Sminshall count += 2; 292730088Sminshall break; 292830088Sminshall default: 292930088Sminshall count += 2; 293030088Sminshall break; 293130088Sminshall } 293230088Sminshall } 293330088Sminshall /* Now, do we have enough room? */ 293430088Sminshall if (NETROOM() < count) { 293530088Sminshall printf("There is not enough room in the buffer TO the network\n"); 293630088Sminshall printf("to process your request. Nothing will be done.\n"); 293730088Sminshall printf("('send synch' will throw away most data in the network\n"); 293830088Sminshall printf("buffer, if this might help.)\n"); 293930088Sminshall return 0; 294030088Sminshall } 294130088Sminshall /* OK, they are all OK, now go through again and actually send */ 294230088Sminshall for (i = 1; i < argc; i++) { 294330088Sminshall if ((s = getsend(argv[i])) == 0) { 294430088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 294530088Sminshall quit(); 294630088Sminshall /*NOTREACHED*/ 294730088Sminshall } 294830088Sminshall if (s->routine) { 294930088Sminshall (*s->routine)(s); 295030088Sminshall } else { 295130088Sminshall switch (what = s->what) { 295230088Sminshall case SYNCH: 295330088Sminshall dosynch(); 295430088Sminshall break; 295530088Sminshall case SENDQUESTION: 295630088Sminshall for (s = Sendlist; s->name; s++) { 295730088Sminshall if (s->help) { 295830088Sminshall printf(s->name); 295930088Sminshall if (s->help) { 296030088Sminshall printf("\t%s", s->help); 296130088Sminshall } 296230088Sminshall printf("\n"); 296330088Sminshall } 296430088Sminshall } 296530088Sminshall question = 1; 296630088Sminshall break; 296730088Sminshall case SENDESCAPE: 296830088Sminshall NETADD(escape); 296930088Sminshall break; 297030088Sminshall default: 297130088Sminshall NET2ADD(IAC, what); 297230088Sminshall break; 297330088Sminshall } 297430088Sminshall } 297530088Sminshall } 297630088Sminshall return !question; 297730088Sminshall } 297830088Sminshall 297930088Sminshall /* 298030088Sminshall * The following are the routines and data structures referred 298130088Sminshall * to by the arguments to the "toggle" command. 298230088Sminshall */ 298330088Sminshall 298430088Sminshall static 298530088Sminshall lclchars() 298630088Sminshall { 298730088Sminshall donelclchars = 1; 298830088Sminshall return 1; 298930088Sminshall } 299030088Sminshall 299130088Sminshall static 299230088Sminshall togdebug() 299330088Sminshall { 299430088Sminshall #ifndef NOT43 299530088Sminshall if (net > 0 && 299631124Sminshall (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 299730088Sminshall perror("setsockopt (SO_DEBUG)"); 299830088Sminshall } 299930320Sminshall #else /* NOT43 */ 300030088Sminshall if (debug) { 300131124Sminshall if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 300230088Sminshall perror("setsockopt (SO_DEBUG)"); 300330088Sminshall } else 300430088Sminshall printf("Cannot turn off socket debugging\n"); 300530320Sminshall #endif /* NOT43 */ 300630088Sminshall return 1; 300730088Sminshall } 300830088Sminshall 300930088Sminshall 301030088Sminshall 301130088Sminshall extern int togglehelp(); 301230088Sminshall 301330088Sminshall struct togglelist { 301430088Sminshall char *name; /* name of toggle */ 301530088Sminshall char *help; /* help message */ 301630088Sminshall int (*handler)(); /* routine to do actual setting */ 301730088Sminshall int dohelp; /* should we display help information */ 301830088Sminshall int *variable; 301930088Sminshall char *actionexplanation; 302030088Sminshall }; 302130088Sminshall 302230088Sminshall static struct togglelist Togglelist[] = { 302330088Sminshall { "autoflush", 302430088Sminshall "toggle flushing of output when sending interrupt characters", 302530088Sminshall 0, 302630088Sminshall 1, 302730088Sminshall &autoflush, 302830088Sminshall "flush output when sending interrupt characters" }, 302930088Sminshall { "autosynch", 303030088Sminshall "toggle automatic sending of interrupt characters in urgent mode", 303130088Sminshall 0, 303230088Sminshall 1, 303330088Sminshall &autosynch, 303430088Sminshall "send interrupt characters in urgent mode" }, 303530088Sminshall { "crmod", 303630088Sminshall "toggle mapping of received carriage returns", 303730088Sminshall 0, 303830088Sminshall 1, 303930088Sminshall &crmod, 304030088Sminshall "map carriage return on output" }, 304130088Sminshall { "localchars", 304230088Sminshall "toggle local recognition of certain control characters", 304330088Sminshall lclchars, 304430088Sminshall 1, 304530088Sminshall &localchars, 304630088Sminshall "recognize certain control characters" }, 304730088Sminshall { " ", "", 0, 1 }, /* empty line */ 304830088Sminshall { "debug", 304930088Sminshall "(debugging) toggle debugging", 305030088Sminshall togdebug, 305130088Sminshall 1, 305230088Sminshall &debug, 305330088Sminshall "turn on socket level debugging" }, 305430088Sminshall { "netdata", 305530088Sminshall "(debugging) toggle printing of hexadecimal network data", 305630088Sminshall 0, 305730088Sminshall 1, 305830088Sminshall &netdata, 305930088Sminshall "print hexadecimal representation of network traffic" }, 306030088Sminshall { "options", 306130088Sminshall "(debugging) toggle viewing of options processing", 306230088Sminshall 0, 306330088Sminshall 1, 306430088Sminshall &showoptions, 306530088Sminshall "show option processing" }, 306630088Sminshall { " ", "", 0, 1 }, /* empty line */ 306730088Sminshall { "?", 306830088Sminshall "display help information", 306930088Sminshall togglehelp, 307030088Sminshall 1 }, 307130088Sminshall { "help", 307230088Sminshall "display help information", 307330088Sminshall togglehelp, 307430088Sminshall 0 }, 307530088Sminshall { 0 } 307630088Sminshall }; 307730088Sminshall 307830088Sminshall static 307930088Sminshall togglehelp() 308030088Sminshall { 308130088Sminshall struct togglelist *c; 308230088Sminshall 308330088Sminshall for (c = Togglelist; c->name; c++) { 308430088Sminshall if (c->dohelp) { 308530088Sminshall printf("%s\t%s\n", c->name, c->help); 308630088Sminshall } 308730088Sminshall } 308830088Sminshall return 0; 308930088Sminshall } 309030088Sminshall 309130088Sminshall static char ** 309230088Sminshall getnexttoggle(name) 309330088Sminshall char *name; 309430088Sminshall { 309530088Sminshall struct togglelist *c = (struct togglelist *) name; 309630088Sminshall 309730088Sminshall return (char **) (c+1); 309830088Sminshall } 309930088Sminshall 310030088Sminshall static struct togglelist * 310130088Sminshall gettoggle(name) 310230088Sminshall char *name; 310330088Sminshall { 310430088Sminshall return (struct togglelist *) 310530088Sminshall genget(name, (char **) Togglelist, getnexttoggle); 310630088Sminshall } 310730088Sminshall 310830088Sminshall static 310930088Sminshall toggle(argc, argv) 311030088Sminshall int argc; 311130088Sminshall char *argv[]; 311230088Sminshall { 311330088Sminshall int retval = 1; 311430088Sminshall char *name; 311530088Sminshall struct togglelist *c; 311630088Sminshall 311730088Sminshall if (argc < 2) { 311830088Sminshall fprintf(stderr, 311930088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 312030088Sminshall return 0; 312130088Sminshall } 312230088Sminshall argc--; 312330088Sminshall argv++; 312430088Sminshall while (argc--) { 312530088Sminshall name = *argv++; 312630088Sminshall c = gettoggle(name); 312730088Sminshall if (c == Ambiguous(struct togglelist *)) { 312830088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 312930088Sminshall name); 313030088Sminshall return 0; 313130088Sminshall } else if (c == 0) { 313230088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 313330088Sminshall name); 313430088Sminshall return 0; 313530088Sminshall } else { 313630088Sminshall if (c->variable) { 313730088Sminshall *c->variable = !*c->variable; /* invert it */ 313830088Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 313930088Sminshall c->actionexplanation); 314030088Sminshall } 314130088Sminshall if (c->handler) { 314230088Sminshall retval &= (*c->handler)(c); 314330088Sminshall } 314430088Sminshall } 314530088Sminshall } 314630088Sminshall return retval; 314730088Sminshall } 314830088Sminshall 314930088Sminshall /* 315030088Sminshall * The following perform the "set" command. 315130088Sminshall */ 315230088Sminshall 315330088Sminshall struct setlist { 315430088Sminshall char *name; /* name */ 315530088Sminshall char *help; /* help information */ 315630088Sminshall char *charp; /* where it is located at */ 315730088Sminshall }; 315830088Sminshall 315930088Sminshall static struct setlist Setlist[] = { 316030088Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 316130088Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 316230088Sminshall { " ", "" }, 316330088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 316431124Sminshall #if defined(unix) 316530088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 316630088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 316730088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 316830088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 316930088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 317030088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 317131124Sminshall #endif /* defined(unix) */ 317231124Sminshall #if defined(MSDOS) 317331124Sminshall { "erase", "character to cause an Erase Character", &termEraseChar }, 317431124Sminshall { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 317531124Sminshall { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 317631124Sminshall { "kill", "character to cause an Erase Line", &termKillChar }, 317731124Sminshall { "quit", "character to cause a Break", &termQuitChar }, 317831124Sminshall { "eof", "character to cause an EOF ", &termEofChar }, 317931124Sminshall #endif /* defined(MSDOS) */ 318030088Sminshall { 0 } 318130088Sminshall }; 318230088Sminshall 318330088Sminshall static char ** 318430088Sminshall getnextset(name) 318530088Sminshall char *name; 318630088Sminshall { 318730088Sminshall struct setlist *c = (struct setlist *)name; 318830088Sminshall 318930088Sminshall return (char **) (c+1); 319030088Sminshall } 319130088Sminshall 319230088Sminshall static struct setlist * 319330088Sminshall getset(name) 319430088Sminshall char *name; 319530088Sminshall { 319630088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 319730088Sminshall } 319830088Sminshall 319930088Sminshall static 320030088Sminshall setcmd(argc, argv) 320130088Sminshall int argc; 320230088Sminshall char *argv[]; 320330088Sminshall { 320430088Sminshall int value; 320530088Sminshall struct setlist *ct; 320630088Sminshall 320730088Sminshall /* XXX back we go... sigh */ 320830088Sminshall if (argc != 3) { 320930088Sminshall if ((argc == 2) && 321030088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 321130088Sminshall for (ct = Setlist; ct->name; ct++) { 321230088Sminshall printf("%s\t%s\n", ct->name, ct->help); 321330088Sminshall } 321430088Sminshall printf("?\tdisplay help information\n"); 321530088Sminshall } else { 321630088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 321730088Sminshall } 321830088Sminshall return 0; 321930088Sminshall } 322030088Sminshall 322130088Sminshall ct = getset(argv[1]); 322230088Sminshall if (ct == 0) { 322330088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 322430088Sminshall argv[1]); 322530088Sminshall return 0; 322630088Sminshall } else if (ct == Ambiguous(struct setlist *)) { 322730088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 322830088Sminshall argv[1]); 322930088Sminshall return 0; 323030088Sminshall } else { 323130088Sminshall if (strcmp("off", argv[2])) { 323230088Sminshall value = special(argv[2]); 323330088Sminshall } else { 323430088Sminshall value = -1; 323530088Sminshall } 323630088Sminshall *(ct->charp) = value; 323730088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 323830088Sminshall } 323930088Sminshall return 1; 324030088Sminshall } 324130088Sminshall 324230088Sminshall /* 324330088Sminshall * The following are the data structures and routines for the 324430088Sminshall * 'mode' command. 324530088Sminshall */ 324630088Sminshall 324730088Sminshall static 324830088Sminshall dolinemode() 324930088Sminshall { 325030088Sminshall if (hisopts[TELOPT_SGA]) { 325130088Sminshall wontoption(TELOPT_SGA, 0); 325230088Sminshall } 325330088Sminshall if (hisopts[TELOPT_ECHO]) { 325430088Sminshall wontoption(TELOPT_ECHO, 0); 325530088Sminshall } 325630088Sminshall return 1; 325730088Sminshall } 325830088Sminshall 325930088Sminshall static 326030088Sminshall docharmode() 326130088Sminshall { 326230088Sminshall if (!hisopts[TELOPT_SGA]) { 326330088Sminshall willoption(TELOPT_SGA, 0); 326430088Sminshall } 326530088Sminshall if (!hisopts[TELOPT_ECHO]) { 326630088Sminshall willoption(TELOPT_ECHO, 0); 326730088Sminshall } 326830088Sminshall return 1; 326930088Sminshall } 327030088Sminshall 327130088Sminshall static struct cmd Modelist[] = { 327230088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 327330088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 327430088Sminshall { 0 }, 327530088Sminshall }; 327630088Sminshall 327730088Sminshall static char ** 327830088Sminshall getnextmode(name) 327930088Sminshall char *name; 328030088Sminshall { 328130088Sminshall struct cmd *c = (struct cmd *) name; 328230088Sminshall 328330088Sminshall return (char **) (c+1); 328430088Sminshall } 328530088Sminshall 328630088Sminshall static struct cmd * 328730088Sminshall getmodecmd(name) 328830088Sminshall char *name; 328930088Sminshall { 329030088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 329130088Sminshall } 329230088Sminshall 329330088Sminshall static 329430088Sminshall modecmd(argc, argv) 329530088Sminshall int argc; 329630088Sminshall char *argv[]; 329730088Sminshall { 329830088Sminshall struct cmd *mt; 329930088Sminshall 330030088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 330130088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 330230088Sminshall for (mt = Modelist; mt->name; mt++) { 330330088Sminshall printf("%s\t%s\n", mt->name, mt->help); 330430088Sminshall } 330530088Sminshall return 0; 330630088Sminshall } 330730088Sminshall mt = getmodecmd(argv[1]); 330830088Sminshall if (mt == 0) { 330930088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 331030088Sminshall return 0; 331130088Sminshall } else if (mt == Ambiguous(struct cmd *)) { 331230088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 331330088Sminshall return 0; 331430088Sminshall } else { 331530088Sminshall (*mt->handler)(); 331630088Sminshall } 331730088Sminshall return 1; 331830088Sminshall } 331930088Sminshall 332030088Sminshall /* 332130088Sminshall * The following data structures and routines implement the 332230088Sminshall * "display" command. 332330088Sminshall */ 332430088Sminshall 332530088Sminshall static 332630088Sminshall display(argc, argv) 332730088Sminshall int argc; 332830088Sminshall char *argv[]; 332930088Sminshall { 333030088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 333130088Sminshall if (*tl->variable) { \ 333230088Sminshall printf("will"); \ 333330088Sminshall } else { \ 333430088Sminshall printf("won't"); \ 333530088Sminshall } \ 333630088Sminshall printf(" %s.\n", tl->actionexplanation); \ 333730088Sminshall } 333830088Sminshall 333930088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 334030088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 334130088Sminshall } 334230088Sminshall 334330088Sminshall struct togglelist *tl; 334430088Sminshall struct setlist *sl; 334530088Sminshall 334630088Sminshall if (argc == 1) { 334730088Sminshall for (tl = Togglelist; tl->name; tl++) { 334830088Sminshall dotog(tl); 334930088Sminshall } 335030088Sminshall printf("\n"); 335130088Sminshall for (sl = Setlist; sl->name; sl++) { 335230088Sminshall doset(sl); 335330088Sminshall } 335430088Sminshall } else { 335530088Sminshall int i; 335630088Sminshall 335730088Sminshall for (i = 1; i < argc; i++) { 335830088Sminshall sl = getset(argv[i]); 335930088Sminshall tl = gettoggle(argv[i]); 336030088Sminshall if ((sl == Ambiguous(struct setlist *)) || 336130088Sminshall (tl == Ambiguous(struct togglelist *))) { 336230088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 336330088Sminshall return 0; 336430088Sminshall } else if (!sl && !tl) { 336530088Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 336630088Sminshall return 0; 336730088Sminshall } else { 336830088Sminshall if (tl) { 336930088Sminshall dotog(tl); 337030088Sminshall } 337130088Sminshall if (sl) { 337230088Sminshall doset(sl); 337330088Sminshall } 337430088Sminshall } 337530088Sminshall } 337630088Sminshall } 337730088Sminshall return 1; 337830088Sminshall #undef doset 337930088Sminshall #undef dotog 338030088Sminshall } 338130088Sminshall 338230088Sminshall /* 338330088Sminshall * The following are the data structures, and many of the routines, 338430088Sminshall * relating to command processing. 338530088Sminshall */ 338630088Sminshall 338730088Sminshall /* 338830088Sminshall * Set the escape character. 338930088Sminshall */ 339030088Sminshall static 339130088Sminshall setescape(argc, argv) 339230088Sminshall int argc; 339330088Sminshall char *argv[]; 339430088Sminshall { 339530088Sminshall register char *arg; 339630088Sminshall char buf[50]; 339730088Sminshall 339830088Sminshall printf( 339930088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 340030088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 340130088Sminshall if (argc > 2) 340230088Sminshall arg = argv[1]; 340330088Sminshall else { 340430088Sminshall printf("new escape character: "); 340530088Sminshall gets(buf); 340630088Sminshall arg = buf; 340730088Sminshall } 340830088Sminshall if (arg[0] != '\0') 340930088Sminshall escape = arg[0]; 341030088Sminshall if (!In3270) { 341130088Sminshall printf("Escape character is '%s'.\n", control(escape)); 341230088Sminshall } 341330088Sminshall fflush(stdout); 341430088Sminshall return 1; 341530088Sminshall } 341630088Sminshall 341730088Sminshall /*VARARGS*/ 341830088Sminshall static 341930088Sminshall togcrmod() 342030088Sminshall { 342130088Sminshall crmod = !crmod; 342230088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 342330088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 342430088Sminshall fflush(stdout); 342530088Sminshall return 1; 342630088Sminshall } 342730088Sminshall 342830088Sminshall /*VARARGS*/ 342930088Sminshall suspend() 343030088Sminshall { 343130088Sminshall setcommandmode(); 343230088Sminshall #if defined(unix) 343330088Sminshall kill(0, SIGTSTP); 343431215Sminshall #endif /* defined(unix) */ 343531124Sminshall /* reget parameters in case they were changed */ 343631124Sminshall TerminalSaveState(); 343731215Sminshall setconnmode(); 343830088Sminshall return 1; 343930088Sminshall } 344030088Sminshall 344130088Sminshall /*VARARGS*/ 344230088Sminshall static 344330326Sminshall bye(argc, argv) 344430326Sminshall int argc; /* Number of arguments */ 344530326Sminshall char *argv[]; /* arguments */ 344630088Sminshall { 344730088Sminshall if (connected) { 344830088Sminshall shutdown(net, 2); 344930088Sminshall printf("Connection closed.\n"); 345031131Sminshall NetClose(net); 345130088Sminshall connected = 0; 345230088Sminshall /* reset options */ 345330326Sminshall tninit(); 345430088Sminshall #if defined(TN3270) 345530326Sminshall SetIn3270(); /* Get out of 3270 mode */ 345630088Sminshall #endif /* defined(TN3270) */ 345730088Sminshall } 345830326Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 345930326Sminshall longjmp(toplevel, 1); 346030326Sminshall /* NOTREACHED */ 346130326Sminshall } 346230326Sminshall return 1; /* Keep lint, etc., happy */ 346330088Sminshall } 346430088Sminshall 346530088Sminshall /*VARARGS*/ 346630088Sminshall quit() 346730088Sminshall { 346830326Sminshall (void) call(bye, "bye", "fromquit", 0); 346930088Sminshall Exit(0); 347030088Sminshall /*NOTREACHED*/ 347130088Sminshall return 1; /* just to keep lint happy */ 347230088Sminshall } 347330088Sminshall 347430088Sminshall /* 347530088Sminshall * Print status about the connection. 347630088Sminshall */ 347730088Sminshall static 347830088Sminshall status(argc, argv) 347930088Sminshall int argc; 348030088Sminshall char *argv[]; 348130088Sminshall { 348230088Sminshall if (connected) { 348330088Sminshall printf("Connected to %s.\n", hostname); 348430088Sminshall if (argc < 2) { 348530088Sminshall printf("Operating in %s.\n", 348630088Sminshall modelist[getconnmode()].modedescriptions); 348730088Sminshall if (localchars) { 348830088Sminshall printf("Catching signals locally.\n"); 348930088Sminshall } 349030088Sminshall } 349130088Sminshall } else { 349230088Sminshall printf("No connection.\n"); 349330088Sminshall } 349430088Sminshall # if !defined(TN3270) 349530088Sminshall printf("Escape character is '%s'.\n", control(escape)); 349630088Sminshall fflush(stdout); 349730088Sminshall # else /* !defined(TN3270) */ 349830088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 349930088Sminshall printf("Escape character is '%s'.\n", control(escape)); 350030088Sminshall } 350130088Sminshall # if defined(unix) 350230088Sminshall if (In3270 && transcom) { 350330088Sminshall printf("Transparent mode command is '%s'.\n", transcom); 350430088Sminshall } 350530088Sminshall # endif /* defined(unix) */ 350630088Sminshall fflush(stdout); 350730088Sminshall if (In3270) { 350830088Sminshall return 0; 350930088Sminshall } 351030088Sminshall # endif /* defined(TN3270) */ 351130088Sminshall return 1; 351230088Sminshall } 351330088Sminshall 351430088Sminshall #if defined(TN3270) && defined(unix) 351530088Sminshall static 351630088Sminshall settranscom(argc, argv) 351730088Sminshall int argc; 351830088Sminshall char *argv[]; 351930088Sminshall { 352030088Sminshall int i, len = 0; 352130088Sminshall char *strcpy(), *strcat(); 352230088Sminshall 352330088Sminshall if (argc == 1 && transcom) { 352430088Sminshall transcom = 0; 352530088Sminshall } 352630088Sminshall if (argc == 1) { 352730088Sminshall return; 352830088Sminshall } 352930088Sminshall for (i = 1; i < argc; ++i) { 353030088Sminshall len += 1 + strlen(argv[1]); 353130088Sminshall } 353230088Sminshall transcom = tline; 353330088Sminshall (void) strcpy(transcom, argv[1]); 353430088Sminshall for (i = 2; i < argc; ++i) { 353530088Sminshall (void) strcat(transcom, " "); 353630088Sminshall (void) strcat(transcom, argv[i]); 353730088Sminshall } 353830088Sminshall } 353930088Sminshall #endif /* defined(TN3270) && defined(unix) */ 354030088Sminshall 354130088Sminshall 354231169Sminshall 354330088Sminshall static 354430088Sminshall tn(argc, argv) 354530088Sminshall int argc; 354630088Sminshall char *argv[]; 354730088Sminshall { 354830088Sminshall register struct hostent *host = 0; 354931131Sminshall #if defined(MSDOS) 355030088Sminshall char *cp; 355131131Sminshall #endif /* defined(MSDOS) */ 355230088Sminshall 355330088Sminshall if (connected) { 355430088Sminshall printf("?Already connected to %s\n", hostname); 355530088Sminshall return 0; 355630088Sminshall } 355730088Sminshall if (argc < 2) { 355830088Sminshall (void) strcpy(line, "Connect "); 355930088Sminshall printf("(to) "); 356030088Sminshall gets(&line[strlen(line)]); 356130088Sminshall makeargv(); 356230088Sminshall argc = margc; 356330088Sminshall argv = margv; 356430088Sminshall } 356530088Sminshall if (argc > 3) { 356630088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 356730088Sminshall return 0; 356830088Sminshall } 356931131Sminshall #if defined(MSDOS) 357030088Sminshall for (cp = argv[1]; *cp; cp++) { 357130088Sminshall if (isupper(*cp)) { 357230088Sminshall *cp = tolower(*cp); 357330088Sminshall } 357430088Sminshall } 357531131Sminshall #endif /* defined(MSDOS) */ 357630088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 357730088Sminshall if (sin.sin_addr.s_addr != -1) { 357830088Sminshall sin.sin_family = AF_INET; 357930088Sminshall (void) strcpy(hnamebuf, argv[1]); 358030088Sminshall hostname = hnamebuf; 358130088Sminshall } else { 358230088Sminshall host = gethostbyname(argv[1]); 358330088Sminshall if (host) { 358430088Sminshall sin.sin_family = host->h_addrtype; 358530088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 358631131Sminshall memcpy((caddr_t)&sin.sin_addr, 358731131Sminshall host->h_addr_list[0], host->h_length); 358830088Sminshall #else /* defined(h_addr) */ 358931131Sminshall memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 359030088Sminshall #endif /* defined(h_addr) */ 359130088Sminshall hostname = host->h_name; 359230088Sminshall } else { 359330088Sminshall printf("%s: unknown host\n", argv[1]); 359430088Sminshall return 0; 359530088Sminshall } 359630088Sminshall } 359730088Sminshall sin.sin_port = sp->s_port; 359830088Sminshall if (argc == 3) { 359930088Sminshall sin.sin_port = atoi(argv[2]); 360030088Sminshall if (sin.sin_port == 0) { 360130088Sminshall sp = getservbyname(argv[2], "tcp"); 360230088Sminshall if (sp) 360330088Sminshall sin.sin_port = sp->s_port; 360430088Sminshall else { 360530088Sminshall printf("%s: bad port number\n", argv[2]); 360630088Sminshall return 0; 360730088Sminshall } 360830088Sminshall } else { 360930088Sminshall sin.sin_port = atoi(argv[2]); 361030088Sminshall sin.sin_port = htons(sin.sin_port); 361130088Sminshall } 361230088Sminshall telnetport = 0; 361330088Sminshall } else { 361430088Sminshall telnetport = 1; 361530088Sminshall } 361630088Sminshall #if defined(unix) 361730088Sminshall signal(SIGINT, intr); 361830088Sminshall signal(SIGQUIT, intr2); 361930088Sminshall signal(SIGPIPE, deadpeer); 362030088Sminshall #endif /* defined(unix) */ 362130088Sminshall printf("Trying...\n"); 362230088Sminshall do { 362330088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 362430088Sminshall if (net < 0) { 362530088Sminshall perror("telnet: socket"); 362630088Sminshall return 0; 362730088Sminshall } 362831124Sminshall if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 362930088Sminshall perror("setsockopt (SO_DEBUG)"); 363031124Sminshall } 363130088Sminshall 363230088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 363330088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 363430088Sminshall if (host && host->h_addr_list[1]) { 363530088Sminshall int oerrno = errno; 363630088Sminshall 363730088Sminshall fprintf(stderr, "telnet: connect to address %s: ", 363830088Sminshall inet_ntoa(sin.sin_addr)); 363930088Sminshall errno = oerrno; 364030088Sminshall perror((char *)0); 364130088Sminshall host->h_addr_list++; 364231131Sminshall memcpy((caddr_t)&sin.sin_addr, 364331131Sminshall host->h_addr_list[0], host->h_length); 364430088Sminshall fprintf(stderr, "Trying %s...\n", 364530088Sminshall inet_ntoa(sin.sin_addr)); 364631131Sminshall (void) NetClose(net); 364730088Sminshall continue; 364830088Sminshall } 364930088Sminshall #endif /* defined(h_addr) */ 365030088Sminshall perror("telnet: Unable to connect to remote host"); 365130088Sminshall #if defined(unix) 365230088Sminshall signal(SIGINT, SIG_DFL); 365330088Sminshall signal(SIGQUIT, SIG_DFL); 365430320Sminshall #endif /* defined(unix) */ 365530088Sminshall return 0; 365630088Sminshall } 365730088Sminshall connected++; 365830088Sminshall } while (connected == 0); 365930088Sminshall call(status, "status", "notmuch", 0); 366030088Sminshall if (setjmp(peerdied) == 0) 366130088Sminshall telnet(); 366231131Sminshall NetClose(net); 366330088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1); 366430088Sminshall /*NOTREACHED*/ 366530088Sminshall } 366630088Sminshall 366730088Sminshall 366830088Sminshall #define HELPINDENT (sizeof ("connect")) 366930088Sminshall 367030088Sminshall static char 367130088Sminshall openhelp[] = "connect to a site", 367230088Sminshall closehelp[] = "close current connection", 367330088Sminshall quithelp[] = "exit telnet", 367430088Sminshall statushelp[] = "print status information", 367530088Sminshall helphelp[] = "print help information", 367630088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 367730088Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 367830088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 367930088Sminshall displayhelp[] = "display operating parameters", 368030088Sminshall #if defined(TN3270) && defined(unix) 368130088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 368230088Sminshall #endif /* defined(TN3270) && defined(unix) */ 368331169Sminshall #if defined(unix) 368431169Sminshall zhelp[] = "suspend telnet", 368531169Sminshall #endif /* defined(unix */ 3686*31478Sminshall #if defined(TN3270) 368731169Sminshall shellhelp[] = "invoke a subshell", 3688*31478Sminshall #endif /* defined(TN3270) */ 368930088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 369030088Sminshall 369131169Sminshall extern int help(), shell(); 369230088Sminshall 369330088Sminshall static struct cmd cmdtab[] = { 369430088Sminshall { "close", closehelp, bye, 1, 1 }, 369530088Sminshall { "display", displayhelp, display, 1, 0 }, 369630088Sminshall { "mode", modehelp, modecmd, 1, 1 }, 369730088Sminshall { "open", openhelp, tn, 1, 0 }, 369830088Sminshall { "quit", quithelp, quit, 1, 0 }, 369930088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 370030088Sminshall { "set", sethelp, setcmd, 1, 0 }, 370130088Sminshall { "status", statushelp, status, 1, 0 }, 370230088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 370330088Sminshall #if defined(TN3270) && defined(unix) 370430088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 370530088Sminshall #endif /* defined(TN3270) && defined(unix) */ 370631169Sminshall #if defined(unix) 370730088Sminshall { "z", zhelp, suspend, 1, 0 }, 370831169Sminshall #endif /* defined(unix) */ 3709*31478Sminshall #if defined(TN3270) 3710*31478Sminshall { "!", shellhelp, shell, 1, 1 }, 3711*31478Sminshall #endif /* defined(TN3270) */ 371230088Sminshall { "?", helphelp, help, 1, 0 }, 371330088Sminshall 0 371430088Sminshall }; 371530088Sminshall 371630088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 371730088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 371830088Sminshall 371930088Sminshall static struct cmd cmdtab2[] = { 372030088Sminshall { "help", helphelp, help, 0, 0 }, 372130088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 372230088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 372330088Sminshall 0 372430088Sminshall }; 372530088Sminshall 372630088Sminshall /* 372730088Sminshall * Call routine with argc, argv set from args (terminated by 0). 372830088Sminshall * VARARGS2 372930088Sminshall */ 373030088Sminshall static 373130088Sminshall call(routine, args) 373230088Sminshall int (*routine)(); 373330088Sminshall char *args; 373430088Sminshall { 373530088Sminshall register char **argp; 373630088Sminshall register int argc; 373730088Sminshall 373830088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 373930088Sminshall ; 374030088Sminshall return (*routine)(argc, &args); 374130088Sminshall } 374230088Sminshall 374330088Sminshall static char ** 374430088Sminshall getnextcmd(name) 374530088Sminshall char *name; 374630088Sminshall { 374730088Sminshall struct cmd *c = (struct cmd *) name; 374830088Sminshall 374930088Sminshall return (char **) (c+1); 375030088Sminshall } 375130088Sminshall 375230088Sminshall static struct cmd * 375330088Sminshall getcmd(name) 375430088Sminshall char *name; 375530088Sminshall { 375630088Sminshall struct cmd *cm; 375730088Sminshall 375830088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 375930088Sminshall return cm; 376030088Sminshall } else { 376130088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 376230088Sminshall } 376330088Sminshall } 376430088Sminshall 376530088Sminshall void 376630088Sminshall command(top) 376730088Sminshall int top; 376830088Sminshall { 3769*31478Sminshall register struct cmd *c; 377030088Sminshall 3771*31478Sminshall setcommandmode(); 3772*31478Sminshall if (!top) { 3773*31478Sminshall putchar('\n'); 3774*31478Sminshall } else { 377530088Sminshall #if defined(unix) 3776*31478Sminshall signal(SIGINT, SIG_DFL); 3777*31478Sminshall signal(SIGQUIT, SIG_DFL); 377830088Sminshall #endif /* defined(unix) */ 3779*31478Sminshall } 3780*31478Sminshall for (;;) { 3781*31478Sminshall printf("%s> ", prompt); 3782*31478Sminshall if (gets(line) == NULL) { 3783*31478Sminshall if (feof(stdin) || ferror(stdin)) 3784*31478Sminshall quit(); 3785*31478Sminshall break; 378630088Sminshall } 3787*31478Sminshall if (line[0] == 0) 3788*31478Sminshall break; 3789*31478Sminshall makeargv(); 3790*31478Sminshall c = getcmd(margv[0]); 3791*31478Sminshall if (c == Ambiguous(struct cmd *)) { 3792*31478Sminshall printf("?Ambiguous command\n"); 3793*31478Sminshall continue; 379430088Sminshall } 3795*31478Sminshall if (c == 0) { 3796*31478Sminshall printf("?Invalid command\n"); 3797*31478Sminshall continue; 379830088Sminshall } 3799*31478Sminshall if (c->needconnect && !connected) { 3800*31478Sminshall printf("?Need to be connected first.\n"); 3801*31478Sminshall continue; 3802*31478Sminshall } 3803*31478Sminshall if ((*c->handler)(margc, margv)) { 3804*31478Sminshall break; 3805*31478Sminshall } 3806*31478Sminshall } 3807*31478Sminshall if (!top) { 3808*31478Sminshall if (!connected) { 3809*31478Sminshall longjmp(toplevel, 1); 3810*31478Sminshall /*NOTREACHED*/ 3811*31478Sminshall } 3812*31478Sminshall if (shell_active == 0) { 3813*31478Sminshall setconnmode(); 3814*31478Sminshall } 3815*31478Sminshall } 381630088Sminshall } 381730088Sminshall 381830088Sminshall /* 381930088Sminshall * Help command. 382030088Sminshall */ 382130088Sminshall static 382230088Sminshall help(argc, argv) 382330088Sminshall int argc; 382430088Sminshall char *argv[]; 382530088Sminshall { 382630088Sminshall register struct cmd *c; 382730088Sminshall 382830088Sminshall if (argc == 1) { 382930088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 383030088Sminshall for (c = cmdtab; c->name; c++) 383130088Sminshall if (c->dohelp) { 383230088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 383330088Sminshall c->help); 383430088Sminshall } 383530088Sminshall return 0; 383630088Sminshall } 383730088Sminshall while (--argc > 0) { 383830088Sminshall register char *arg; 383930088Sminshall arg = *++argv; 384030088Sminshall c = getcmd(arg); 384130088Sminshall if (c == Ambiguous(struct cmd *)) 384230088Sminshall printf("?Ambiguous help command %s\n", arg); 384330088Sminshall else if (c == (struct cmd *)0) 384430088Sminshall printf("?Invalid help command %s\n", arg); 384530088Sminshall else 384630088Sminshall printf("%s\n", c->help); 384730088Sminshall } 384830088Sminshall return 0; 384930088Sminshall } 385030088Sminshall 385130088Sminshall /* 385230088Sminshall * main. Parse arguments, invoke the protocol or command parser. 385330088Sminshall */ 385430088Sminshall 385530088Sminshall 385630088Sminshall void 385730088Sminshall main(argc, argv) 385830088Sminshall int argc; 385930088Sminshall char *argv[]; 386030088Sminshall { 386130326Sminshall tninit(); /* Clear out things */ 386230326Sminshall 386330088Sminshall NetTrace = stdout; 386431124Sminshall TerminalSaveState(); 386531124Sminshall autoflush = TerminalAutoFlush(); 386631124Sminshall 386730088Sminshall prompt = argv[0]; 3868*31478Sminshall while ((argc > 1) && (argv[1][0] == '-')) { 3869*31478Sminshall if (!strcmp(argv[1], "-d")) { 3870*31478Sminshall debug = 1; 3871*31478Sminshall } else if (!strcmp(argv[1], "-n")) { 3872*31478Sminshall if ((argc > 1) && (argv[1][0] != '-')) { /* get file name */ 3873*31478Sminshall NetTrace = fopen(argv[1], "w"); 3874*31478Sminshall argv++; 3875*31478Sminshall argc--; 3876*31478Sminshall if (NetTrace == NULL) { 3877*31478Sminshall NetTrace = stdout; 3878*31478Sminshall } 387930088Sminshall } 3880*31478Sminshall } else { 3881*31478Sminshall #if defined(TN3270) && defined(unix) 3882*31478Sminshall if (!strcmp(argv[1], "-t")) { 3883*31478Sminshall if ((argc > 1) && (argv[1][0] != '-')) { /* get file name */ 3884*31478Sminshall transcom = tline; 3885*31478Sminshall (void) strcpy(transcom, argv[1]); 3886*31478Sminshall argv++; 3887*31478Sminshall argc--; 3888*31478Sminshall } 3889*31478Sminshall } else if (!strcmp(argv[1], "-noasynch")) { 3890*31478Sminshall noasynch = 1; 3891*31478Sminshall } else 3892*31478Sminshall #endif /* defined(TN3270) && defined(unix) */ 3893*31478Sminshall if (argv[1][1] != '\0') { 3894*31478Sminshall fprintf(stderr, "Unknown option *%s*.\n", argv[1]); 3895*31478Sminshall } 389630088Sminshall } 3897*31478Sminshall argc--; 389830088Sminshall argv++; 389930088Sminshall } 390030088Sminshall if (argc != 1) { 390130088Sminshall if (setjmp(toplevel) != 0) 390230088Sminshall Exit(0); 390330088Sminshall tn(argc, argv); 390430088Sminshall } 390530088Sminshall setjmp(toplevel); 390631215Sminshall for (;;) { 390731215Sminshall #if !defined(TN3270) 390830088Sminshall command(1); 390931215Sminshall #else /* !defined(TN3270) */ 391031215Sminshall if (!shell_active) { 391131215Sminshall command(1); 391231215Sminshall } else { 3913*31478Sminshall #if defined(TN3270) 391431215Sminshall shell_continue(); 3915*31478Sminshall #endif /* defined(TN3270) */ 391631215Sminshall } 391731215Sminshall #endif /* !defined(TN3270) */ 391831215Sminshall } 391930088Sminshall } 3920