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, 21531478Sminshall 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 */ 234*31791Sminshall donelclchars, /* the user has set "localchars" */ 235*31791Sminshall donebinarytoggle, /* the user has put us in binary */ 23631124Sminshall dontlecho, /* do we suppress local echoing right now? */ 23731124Sminshall globalmode; 23830088Sminshall 23930088Sminshall /* The following are some tn3270 specific flags */ 24030088Sminshall #if defined(TN3270) 24130088Sminshall 24230088Sminshall static int 24330326Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 24430088Sminshall 24531131Sminshall /* Some real, live, globals. */ 24631131Sminshall int 24731131Sminshall tout, /* Output file descriptor */ 24831131Sminshall tin; /* Input file descriptor */ 24931131Sminshall 25031131Sminshall #else /* defined(TN3270) */ 25131131Sminshall static int tin, tout; /* file descriptors */ 25231131Sminshall #endif /* defined(TN3270) */ 25331131Sminshall 25431131Sminshall 25530722Sminshall /* 25630722Sminshall * Telnet receiver states for fsm 25730722Sminshall */ 25830722Sminshall #define TS_DATA 0 25930722Sminshall #define TS_IAC 1 26030722Sminshall #define TS_WILL 2 26130722Sminshall #define TS_WONT 3 26230722Sminshall #define TS_DO 4 26330722Sminshall #define TS_DONT 5 26430722Sminshall #define TS_CR 6 26530722Sminshall #define TS_SB 7 /* sub-option collection */ 26630722Sminshall #define TS_SE 8 /* looking for sub-option end */ 26730722Sminshall 26830722Sminshall static int telrcv_state = TS_DATA; 26930088Sminshall 27030088Sminshall static char line[200]; 27130326Sminshall static int margc; 27230088Sminshall static char *margv[20]; 27330088Sminshall 27431124Sminshall static jmp_buf toplevel = { 0 }; 27530088Sminshall static jmp_buf peerdied; 27630088Sminshall 27730088Sminshall extern int errno; 27830088Sminshall 27930088Sminshall 28030088Sminshall static struct sockaddr_in sin; 28130088Sminshall 28230088Sminshall static struct servent *sp = 0; 28330088Sminshall 28430326Sminshall static int flushline; 28530088Sminshall 28630326Sminshall static char *hostname; 28730088Sminshall static char hnamebuf[32]; 28830088Sminshall 28930088Sminshall /* 29030088Sminshall * The following are some clocks used to decide how to interpret 29130088Sminshall * the relationship between various variables. 29230088Sminshall */ 29330088Sminshall 29430088Sminshall static struct { 29530088Sminshall int 29630088Sminshall system, /* what the current time is */ 29730088Sminshall echotoggle, /* last time user entered echo character */ 29830088Sminshall modenegotiated, /* last time operating mode negotiated */ 29930088Sminshall didnetreceive, /* last time we read data from network */ 30030088Sminshall gotDM; /* when did we last see a data mark */ 30130326Sminshall } clocks; 30230088Sminshall 30330088Sminshall #define settimer(x) clocks.x = clocks.system++ 30430088Sminshall 30531124Sminshall /* Various modes */ 30631124Sminshall #define MODE_LINE(m) (modelist[m].modetype & LINE) 30731124Sminshall #define MODE_LOCAL_CHARS(m) (modelist[m].modetype & LOCAL_CHARS) 30831131Sminshall #define MODE_LOCAL_ECHO(m) (modelist[m].modetype & LOCAL_ECHO) 30931131Sminshall #define MODE_COMMAND_LINE(m) (modelist[m].modetype & COMMAND_LINE) 31031124Sminshall 31131124Sminshall #define LOCAL_CHARS 0x01 /* Characters processed locally */ 31231124Sminshall #define LINE 0x02 /* Line-by-line mode of operation */ 31331131Sminshall #define LOCAL_ECHO 0x04 /* Echoing locally */ 31431131Sminshall #define COMMAND_LINE 0x08 /* Command line mode */ 31531124Sminshall 31631124Sminshall static struct { 31731124Sminshall char *modedescriptions; 31831124Sminshall char modetype; 31931124Sminshall } modelist[] = { 32031131Sminshall { "telnet command mode", COMMAND_LINE }, 32131124Sminshall { "character-at-a-time mode", 0 }, 32231131Sminshall { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 32331124Sminshall { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 32431131Sminshall { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 32531124Sminshall { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 32631124Sminshall { "3270 mode", 0 }, 32731124Sminshall }; 32831124Sminshall 32931124Sminshall 33030088Sminshall /* 33131124Sminshall * The following routines try to encapsulate what is system dependent 33231124Sminshall * (at least between 4.x and dos) which is used in telnet.c. 33331124Sminshall */ 33431124Sminshall 33531124Sminshall #if defined(unix) 33631124Sminshall #include <sys/ioctl.h> 33731124Sminshall #include <sys/time.h> 33831124Sminshall #include <signal.h> 33931124Sminshall 34031124Sminshall int 34131124Sminshall HaveInput; /* There is input available to scan */ 34231124Sminshall 34331124Sminshall #if defined(TN3270) 34431124Sminshall static char tline[200]; 34531124Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 34631124Sminshall #endif /* defined(TN3270) */ 34731124Sminshall 34831124Sminshall static struct tchars otc = { 0 }, ntc = { 0 }; 34931124Sminshall static struct ltchars oltc = { 0 }, nltc = { 0 }; 35031124Sminshall static struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 35131124Sminshall 35231124Sminshall 35331131Sminshall #define TerminalWrite(fd,buf,n) write(fd,buf,n) 35431131Sminshall #define TerminalRead(fd,buf,n) read(fd,buf,n) 35531131Sminshall 35631124Sminshall /* 35731124Sminshall * 35831124Sminshall */ 35931124Sminshall 36031124Sminshall static int 36131131Sminshall TerminalAutoFlush() /* unix */ 36231124Sminshall { 36331124Sminshall #if defined(LNOFLSH) 36431124Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 36531124Sminshall return !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 36631124Sminshall #else /* LNOFLSH */ 36731124Sminshall return 1; 36831124Sminshall #endif /* LNOFLSH */ 36931124Sminshall } 37031124Sminshall 37131124Sminshall /* 37231131Sminshall * TerminalSpecialChars() 37331124Sminshall * 37431131Sminshall * Look at an input character to see if it is a special character 37531131Sminshall * and decide what to do. 37631124Sminshall * 37731124Sminshall * Output: 37831124Sminshall * 37931124Sminshall * 0 Don't add this character. 38031124Sminshall * 1 Do add this character 38131124Sminshall */ 38231124Sminshall 38331124Sminshall int 38431131Sminshall TerminalSpecialChars(c) /* unix */ 38531124Sminshall int c; 38631124Sminshall { 38731124Sminshall void doflush(), intp(), sendbrk(); 38831124Sminshall 38931124Sminshall if (c == ntc.t_intrc) { 39031124Sminshall intp(); 39131124Sminshall return 0; 39231124Sminshall } else if (c == ntc.t_quitc) { 39331124Sminshall sendbrk(); 39431124Sminshall return 0; 39531124Sminshall } else if (c == nltc.t_flushc) { 39631124Sminshall NET2ADD(IAC, AO); 39731124Sminshall if (autoflush) { 39831124Sminshall doflush(); 39931124Sminshall } 40031124Sminshall return 0; 40131124Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 40231124Sminshall if (c == nttyb.sg_kill) { 40331124Sminshall NET2ADD(IAC, EL); 40431124Sminshall return 0; 40531124Sminshall } else if (c == nttyb.sg_erase) { 40631124Sminshall NET2ADD(IAC, EC); 40731124Sminshall return 0; 40831124Sminshall } 40931124Sminshall } 41031124Sminshall return 1; 41131124Sminshall } 41231124Sminshall 41331124Sminshall 41431124Sminshall /* 41531124Sminshall * Flush output to the terminal 41631124Sminshall */ 41731124Sminshall 41831124Sminshall static void 41931124Sminshall TerminalFlushOutput() /* unix */ 42031124Sminshall { 42131124Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 42231124Sminshall } 42331124Sminshall 42431124Sminshall static void 42531124Sminshall TerminalSaveState() /* unix */ 42631124Sminshall { 42731124Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 42831124Sminshall ioctl(0, TIOCGETC, (char *)&otc); 42931124Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 43031124Sminshall 43131124Sminshall ntc = otc; 43231124Sminshall nltc = oltc; 43331124Sminshall nttyb = ottyb; 43431124Sminshall } 43531124Sminshall 43631124Sminshall static void 43731124Sminshall TerminalRestoreState() /* unix */ 43831124Sminshall { 43931124Sminshall } 44031124Sminshall 44131124Sminshall /* 44231124Sminshall * TerminalNewMode - set up terminal to a specific mode. 44331124Sminshall */ 44431124Sminshall 44531124Sminshall 44631124Sminshall static void 44731131Sminshall TerminalNewMode(f) /* unix */ 44831124Sminshall register int f; 44931124Sminshall { 45031124Sminshall static int prevmode = 0; 45131124Sminshall struct tchars *tc; 45231124Sminshall struct tchars tc3; 45331124Sminshall struct ltchars *ltc; 45431124Sminshall struct sgttyb sb; 45531124Sminshall int onoff; 45631124Sminshall int old; 45731124Sminshall struct tchars notc2; 45831124Sminshall struct ltchars noltc2; 45931124Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 46031124Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 46131124Sminshall 46231124Sminshall globalmode = f; 46331124Sminshall if (prevmode == f) 46431124Sminshall return; 46531124Sminshall old = prevmode; 46631124Sminshall prevmode = f; 46731124Sminshall sb = nttyb; 46831124Sminshall 46931124Sminshall switch (f) { 47031124Sminshall 47131124Sminshall case 0: 47231124Sminshall onoff = 0; 47331124Sminshall tc = &otc; 47431124Sminshall ltc = &oltc; 47531124Sminshall break; 47631124Sminshall 47731124Sminshall case 1: /* remote character processing, remote echo */ 47831124Sminshall case 2: /* remote character processing, local echo */ 47931124Sminshall case 6: /* 3270 mode - like 1, but with xon/xoff local */ 48031124Sminshall /* (might be nice to have "6" in telnet also...) */ 48131124Sminshall sb.sg_flags |= CBREAK; 48231124Sminshall if ((f == 1) || (f == 6)) { 48331124Sminshall sb.sg_flags &= ~(ECHO|CRMOD); 48431124Sminshall } else { 48531124Sminshall sb.sg_flags |= ECHO|CRMOD; 48631124Sminshall } 48731124Sminshall sb.sg_erase = sb.sg_kill = -1; 48831124Sminshall if (f == 6) { 48931124Sminshall tc = &tc3; 49031124Sminshall tc3 = notc; 49131124Sminshall /* get XON, XOFF characters */ 49231124Sminshall tc3.t_startc = otc.t_startc; 49331124Sminshall tc3.t_stopc = otc.t_stopc; 49431124Sminshall } else { 49531124Sminshall /* 49631124Sminshall * If user hasn't specified one way or the other, 49731124Sminshall * then default to not trapping signals. 49831124Sminshall */ 49931124Sminshall if (!donelclchars) { 50031124Sminshall localchars = 0; 50131124Sminshall } 50231124Sminshall if (localchars) { 50331124Sminshall notc2 = notc; 50431124Sminshall notc2.t_intrc = ntc.t_intrc; 50531124Sminshall notc2.t_quitc = ntc.t_quitc; 50631124Sminshall tc = ¬c2; 50731124Sminshall } else { 50831124Sminshall tc = ¬c; 50931124Sminshall } 51031124Sminshall } 51131124Sminshall ltc = &noltc; 51231124Sminshall onoff = 1; 51331124Sminshall break; 51431124Sminshall case 3: /* local character processing, remote echo */ 51531124Sminshall case 4: /* local character processing, local echo */ 51631124Sminshall case 5: /* local character processing, no echo */ 51731124Sminshall sb.sg_flags &= ~CBREAK; 51831124Sminshall sb.sg_flags |= CRMOD; 51931124Sminshall if (f == 4) 52031124Sminshall sb.sg_flags |= ECHO; 52131124Sminshall else 52231124Sminshall sb.sg_flags &= ~ECHO; 52331124Sminshall notc2 = ntc; 52431124Sminshall tc = ¬c2; 52531124Sminshall noltc2 = oltc; 52631124Sminshall ltc = &noltc2; 52731124Sminshall /* 52831124Sminshall * If user hasn't specified one way or the other, 52931124Sminshall * then default to trapping signals. 53031124Sminshall */ 53131124Sminshall if (!donelclchars) { 53231124Sminshall localchars = 1; 53331124Sminshall } 53431124Sminshall if (localchars) { 53531124Sminshall notc2.t_brkc = nltc.t_flushc; 53631124Sminshall noltc2.t_flushc = -1; 53731124Sminshall } else { 53831124Sminshall notc2.t_intrc = notc2.t_quitc = -1; 53931124Sminshall } 54031124Sminshall noltc2.t_suspc = escape; 54131124Sminshall noltc2.t_dsuspc = -1; 54231124Sminshall onoff = 1; 54331124Sminshall break; 54431124Sminshall 54531124Sminshall default: 54631124Sminshall return; 54731124Sminshall } 54831124Sminshall ioctl(tin, TIOCSLTC, (char *)ltc); 54931124Sminshall ioctl(tin, TIOCSETC, (char *)tc); 55031124Sminshall ioctl(tin, TIOCSETP, (char *)&sb); 55131124Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 55231124Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 55331124Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 55431124Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 55531478Sminshall #if defined(TN3270) 55631478Sminshall if (noasynch == 0) { 55731478Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 55831478Sminshall } 55931478Sminshall #endif /* defined(TN3270) */ 56031124Sminshall 56131124Sminshall if (MODE_LINE(f)) { 56231124Sminshall void doescape(); 56331124Sminshall 56431124Sminshall signal(SIGTSTP, doescape); 56531124Sminshall } else if (MODE_LINE(old)) { 56631124Sminshall signal(SIGTSTP, SIG_DFL); 56731124Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 56831124Sminshall } 56931124Sminshall } 57031124Sminshall 57131124Sminshall 57231131Sminshall int 57331131Sminshall NetClose(net) 57431131Sminshall int net; 57531131Sminshall { 57631131Sminshall return close(net); 57731131Sminshall } 57831131Sminshall 57931131Sminshall 58031124Sminshall static void 58131124Sminshall NetNonblockingIO(fd, onoff) /* unix */ 58231124Sminshall int 58331124Sminshall fd, 58431124Sminshall onoff; 58531124Sminshall { 58631124Sminshall ioctl(net, FIONBIO, (char *)&onoff); 58731124Sminshall } 58831124Sminshall 58931124Sminshall static void 59031124Sminshall NetSigIO(fd, onoff) /* unix */ 59131124Sminshall int 59231124Sminshall fd, 59331124Sminshall onoff; 59431124Sminshall { 59531124Sminshall ioctl(net, FIOASYNC, (char *)&onoff); /* hear about input */ 59631124Sminshall } 59731124Sminshall 59831124Sminshall static void 59931124Sminshall NetSetPgrp(fd) /* unix */ 60031124Sminshall int fd; 60131124Sminshall { 60231124Sminshall int myPid; 60331124Sminshall 60431124Sminshall myPid = getpid(); 60531124Sminshall #if defined(NOT43) 60631124Sminshall myPid = -myPid; 60731124Sminshall #endif /* defined(NOT43) */ 60831124Sminshall ioctl(net, SIOCSPGRP, (char *)&myPid); /* set my pid */ 60931124Sminshall } 61031124Sminshall 61131124Sminshall 61231124Sminshall #endif /* defined(unix) */ 61331124Sminshall 61431124Sminshall #if defined(MSDOS) 61531124Sminshall #include <time.h> 61631131Sminshall #include <signal.h> 61731169Sminshall #include <process.h> 61831124Sminshall 61931124Sminshall #if !defined(SO_OOBINLINE) 62031124Sminshall #define SO_OOBINLINE 62131124Sminshall #endif /* !defined(SO_OOBINLINE) */ 62231124Sminshall 62331124Sminshall 62431124Sminshall static char 62531131Sminshall termEofChar, 62631124Sminshall termEraseChar, 62731124Sminshall termFlushChar, 62831124Sminshall termIntChar, 62931124Sminshall termKillChar, 63031131Sminshall termLiteralNextChar, 63131131Sminshall termQuitChar; 63231124Sminshall 63331131Sminshall 63431131Sminshall /* 63531131Sminshall * MSDOS doesn't have anyway of deciding whether a full-edited line 63631131Sminshall * is ready to be read in, so we need to do character-by-character 63731131Sminshall * reads, and then do the editing in the program (in the case where 63831131Sminshall * we are supporting line-by-line mode). 63931131Sminshall * 64031131Sminshall * The following routines, which are internal to the MSDOS-specific 64131131Sminshall * code, accomplish this miracle. 64231131Sminshall */ 64331124Sminshall 64431131Sminshall #define Hex(c) HEX[(c)&0xff] 64531131Sminshall 64631131Sminshall static survivorSetup = 0; /* Do we have ^C hooks in? */ 64731131Sminshall 64831131Sminshall static int 64931131Sminshall lineend = 0, /* There is a line terminator */ 65031131Sminshall ctrlCCount = 0; 65131131Sminshall 65231131Sminshall static char linein[200], /* Where input line is assembled */ 65331131Sminshall *nextin = linein, /* Next input character */ 65431131Sminshall *nextout = linein; /* Next character to be consumed */ 65531131Sminshall 65631131Sminshall #define consumechar() \ 65731131Sminshall if ((++nextout) >= nextin) { \ 65831131Sminshall nextout = nextin = linein; \ 65931131Sminshall lineend = 0; \ 66031131Sminshall } 66131131Sminshall 66231131Sminshall #define characteratatime() (!MODE_LINE(globalmode)) /* one by one */ 66331131Sminshall 66431131Sminshall 66531124Sminshall /* 66631131Sminshall * killone() 66731131Sminshall * 66831131Sminshall * Erase the last character on the line. 66931131Sminshall */ 67031131Sminshall 67131131Sminshall static void 67231131Sminshall killone() 67331131Sminshall { 67431131Sminshall if (lineend) { 67531131Sminshall return; /* ??? XXX */ 67631131Sminshall } 67731131Sminshall if (nextin == linein) { 67831131Sminshall return; /* Nothing to do */ 67931131Sminshall } 68031131Sminshall nextin--; 68131131Sminshall if (!(isspace(*nextin) || isprint(*nextin))) { 68231131Sminshall putchar('\b'); 68331131Sminshall putchar(' '); 68431131Sminshall putchar('\b'); 68531131Sminshall } 68631131Sminshall putchar('\b'); 68731131Sminshall putchar(' '); 68831131Sminshall putchar('\b'); 68931131Sminshall } 69031131Sminshall 69131131Sminshall 69231131Sminshall /* 69331131Sminshall * setlineend() 69431131Sminshall * 69531131Sminshall * Decide if it's time to send the current line up to the user 69631131Sminshall * process. 69731131Sminshall */ 69831131Sminshall 69931131Sminshall static void 70031131Sminshall setlineend() 70131131Sminshall { 70231131Sminshall if (nextin == nextout) { 70331131Sminshall return; 70431131Sminshall } 70531131Sminshall if (characteratatime()) { 70631131Sminshall lineend = 1; 70731131Sminshall } else if (nextin >= (linein+sizeof linein)) { 70831131Sminshall lineend = 1; 70931131Sminshall } else { 71031131Sminshall int c = *(nextin-1); 71131131Sminshall if ((c == termIntChar) 71231131Sminshall || (c == termQuitChar) 71331131Sminshall || (c == termEofChar)) { 71431131Sminshall lineend = 1; 71531131Sminshall } else if (c == termFlushChar) { 71631131Sminshall lineend = 1; 71731131Sminshall } else if ((c == '\n') || (c == '\r')) { 71831131Sminshall lineend = 1; 71931131Sminshall } 72031131Sminshall } 72131131Sminshall /* Otherwise, leave it alone (reset by 'consumechar') */ 72231131Sminshall } 72331131Sminshall 72431131Sminshall /* 72531131Sminshall * OK, what we do here is: 72631131Sminshall * 72731131Sminshall * o If we are echoing, then 72831131Sminshall * o Look for character erase, line kill characters 72931131Sminshall * o Echo the character (using '^' if a control character) 73031131Sminshall * o Put the character in the input buffer 73131131Sminshall * o Set 'lineend' as necessary 73231131Sminshall */ 73331131Sminshall 73431131Sminshall static void 73531131Sminshall DoNextChar(c) 73631131Sminshall int c; /* Character to process */ 73731131Sminshall { 73831131Sminshall static char literalnextcharacter = 0; 73931131Sminshall 74031131Sminshall if (nextin >= (linein+sizeof linein)) { 74131131Sminshall putchar('\7'); /* Ring bell */ 74231131Sminshall setlineend(); 74331131Sminshall return; 74431131Sminshall } 74531131Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 74631131Sminshall /* Look for some special character */ 74731131Sminshall if (!literalnextcharacter) { 74831131Sminshall if (c == termEraseChar) { 74931131Sminshall killone(); 75031131Sminshall setlineend(); 75131131Sminshall return; 75231131Sminshall } else if (c == termKillChar) { 75331131Sminshall while (nextin != linein) { 75431131Sminshall killone(); 75531131Sminshall } 75631131Sminshall setlineend(); 75731131Sminshall return; 75831131Sminshall } else if (c == termLiteralNextChar) { 75931131Sminshall literalnextcharacter = 1; 76031131Sminshall return; 76131131Sminshall } 76231131Sminshall } 76331131Sminshall 76431131Sminshall if (MODE_LOCAL_ECHO(globalmode)) { 76531131Sminshall if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) { 76631131Sminshall putchar('\r'); 76731131Sminshall putchar('\n'); 76831131Sminshall c = '\n'; 76931131Sminshall } else if (!isprint(c) && !isspace(c)) { 77031131Sminshall putchar('^'); 77131131Sminshall putchar(c^0x40); 77231131Sminshall } else { 77331131Sminshall putchar(c); 77431131Sminshall } 77531131Sminshall } 77631131Sminshall literalnextcharacter = 0; 77731131Sminshall } 77831131Sminshall *nextin++ = c; 77931131Sminshall setlineend(); 78031131Sminshall } 78131131Sminshall 78231131Sminshall static int 78331131Sminshall inputExists() 78431131Sminshall { 78531131Sminshall int input; 78631131Sminshall static state = 0; 78731131Sminshall 78831131Sminshall while (ctrlCCount) { 78931131Sminshall DoNextChar(0x03); 79031131Sminshall ctrlCCount--; 79131131Sminshall } 79231131Sminshall if (lineend) { 79331131Sminshall return 1; 79431131Sminshall } 79531169Sminshall #if 1 /* For BIOS variety of calls */ 79631169Sminshall if (kbhit() == 0) { 79731131Sminshall return lineend; 79831131Sminshall } 79931131Sminshall input = getch(); /* MSC - get console character */ 80031131Sminshall if ((input&0xff) == 0) { 80131169Sminshall DoNextChar(0x01); /* ^A */ 80231169Sminshall } else { 80331169Sminshall DoNextChar(input&0xff); 80431169Sminshall } 80531169Sminshall #else /* 0 */ 80631169Sminshall if ((input = dirconio()) == -1) { 80731169Sminshall return lineend; 80831169Sminshall } 80931169Sminshall if ((input&0xff) == 0) { 81031131Sminshall if ((input&0xff00) == 0x0300) { /* Null */ 81131131Sminshall DoNextChar(0); 81231131Sminshall } else { 81331131Sminshall DoNextChar(0x01); 81431131Sminshall if (input&0x8000) { 81531131Sminshall DoNextChar(0x01); 81631131Sminshall DoNextChar((input>>8)&0x7f); 81731131Sminshall } else { 81831131Sminshall DoNextChar((input>>8)&0xff); 81931131Sminshall } 82031131Sminshall } 82131131Sminshall } else { 82231131Sminshall DoNextChar(input&0xff); 82331131Sminshall } 82431131Sminshall #endif /* 0 */ 82531131Sminshall return lineend; 82631131Sminshall } 82731131Sminshall 82831131Sminshall 82931131Sminshall void 83031131Sminshall CtrlCInterrupt() 83131131Sminshall { 83231131Sminshall if (!MODE_COMMAND_LINE(globalmode)) { 83331131Sminshall ctrlCCount++; /* XXX */ 83431131Sminshall signal(SIGINT, CtrlCInterrupt); 83531131Sminshall } else { 83631131Sminshall closeallsockets(); 83731169Sminshall exit(1); 83831131Sminshall } 83931131Sminshall } 84031131Sminshall 84131131Sminshall /* 84231131Sminshall * The MSDOS routines, called from elsewhere. 84331131Sminshall */ 84431131Sminshall 84531131Sminshall 84631131Sminshall static int 84731131Sminshall TerminalAutoFlush() /* MSDOS */ 84831131Sminshall { 84931131Sminshall return 1; 85031131Sminshall } 85131131Sminshall 85231131Sminshall static int 85331131Sminshall TerminalCanRead() 85431131Sminshall { 85531131Sminshall return inputExists(); 85631131Sminshall } 85731131Sminshall 85831131Sminshall 85931131Sminshall /* 86031124Sminshall * Flush output to the terminal 86131124Sminshall */ 86231124Sminshall 86331124Sminshall static void 86431124Sminshall TerminalFlushOutput() /* MSDOS */ 86531124Sminshall { 86631124Sminshall } 86731124Sminshall 86831131Sminshall 86931124Sminshall static void 87031131Sminshall TerminalNewMode(f) /* MSDOS */ 87131131Sminshall register int f; 87231131Sminshall { 87331131Sminshall globalmode = f; 87431131Sminshall signal(SIGINT, CtrlCInterrupt); 87531131Sminshall } 87631131Sminshall 87731131Sminshall 87831131Sminshall int 87931131Sminshall TerminalRead(fd, buffer, count) 88031131Sminshall int fd; 88131131Sminshall char *buffer; 88231131Sminshall int count; 88331131Sminshall { 88431131Sminshall int done = 0; 88531131Sminshall 88631131Sminshall for (;;) { 88731131Sminshall while (inputExists() && (done < count)) { 88831131Sminshall *buffer++ = *nextout; 88931131Sminshall consumechar(); 89031131Sminshall done++; 89131131Sminshall } 89231131Sminshall if (done) { 89331131Sminshall return(done); 89431131Sminshall } else { 89531131Sminshall return 0; 89631131Sminshall } 89731131Sminshall } 89831131Sminshall } 89931131Sminshall 90031131Sminshall 90131131Sminshall static void 90231124Sminshall TerminalSaveState() /* MSDOS */ 90331124Sminshall { 90431124Sminshall } 90531124Sminshall 90631131Sminshall int 90731131Sminshall TerminalSpecialChars(c) /* MSDOS */ 90831131Sminshall { 90931131Sminshall return 1; 91031131Sminshall } 91131131Sminshall 91231131Sminshall 91331124Sminshall static void 91431124Sminshall TerminalRestoreState() /* MSDOS */ 91531124Sminshall { 91631124Sminshall } 91731124Sminshall 91831131Sminshall 91931131Sminshall static int 92031131Sminshall TerminalWrite(fd, buffer, count) /* MSDOS */ 92131131Sminshall int fd; 92231131Sminshall char *buffer; 92331131Sminshall int count; 92431131Sminshall { 92531131Sminshall return fwrite(buffer, sizeof (char), count, stdout); 92631131Sminshall } 92731131Sminshall 92831131Sminshall 92931131Sminshall static int 93031131Sminshall NetClose(fd) 93131131Sminshall { 93231131Sminshall return closesocket(fd); 93331131Sminshall } 93431131Sminshall 93531124Sminshall static void 93631124Sminshall NetNonblockingIO(fd, onoff) /* MSDOS */ 93731124Sminshall int 93831124Sminshall fd, 93931124Sminshall onoff; 94031124Sminshall { 94131124Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) { 94231124Sminshall perror("setsockop (SO_NONBLOCKING) "); 94331131Sminshall ExitString(stderr, "exiting\n", 1); 94431124Sminshall } 94531124Sminshall } 94631124Sminshall 94731124Sminshall static void 94831124Sminshall NetSigIO(fd) /* MSDOS */ 94931124Sminshall int fd; 95031124Sminshall { 95131124Sminshall } 95231124Sminshall 95331124Sminshall static void 95431124Sminshall NetSetPgrp(fd) /* MSDOS */ 95531124Sminshall int fd; 95631124Sminshall { 95731124Sminshall } 95831124Sminshall 95931124Sminshall 96031124Sminshall #endif /* defined(MSDOS) */ 96131124Sminshall 96231124Sminshall /* 96330326Sminshall * Initialize variables. 96430326Sminshall */ 96530326Sminshall 96630326Sminshall static void 96730326Sminshall tninit() 96830326Sminshall { 96931131Sminshall #if defined(TN3270) 97031131Sminshall Sent3270TerminalType = 0; 97130326Sminshall Ifrontp = Ibackp = Ibuf; 97231131Sminshall #endif /* defined(TN3270) */ 97331131Sminshall 97430326Sminshall tfrontp = tbackp = ttyobuf; 97530326Sminshall nfrontp = nbackp = netobuf; 97630326Sminshall 97730326Sminshall /* Don't change telnetport */ 97830722Sminshall SB_CLEAR(); 97930722Sminshall ClearArray(hisopts); 98030722Sminshall ClearArray(myopts); 98130722Sminshall sbp = sibuf; 98230722Sminshall tbp = tibuf; 98330326Sminshall 984*31791Sminshall connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0; 98530722Sminshall telnetport = 0; 98631124Sminshall #if defined(unix) 98731124Sminshall HaveInput = 0; 98831124Sminshall #endif /* defined(unix) */ 98930722Sminshall 99030722Sminshall SYNCHing = 0; 99130722Sminshall 99230722Sminshall errno = 0; 99330722Sminshall 99430722Sminshall flushline = 0; 99530722Sminshall 99630326Sminshall /* Don't change NetTrace */ 99730326Sminshall 99830326Sminshall escape = CONTROL(']'); 99930326Sminshall echoc = CONTROL('E'); 100030326Sminshall 100130326Sminshall flushline = 1; 100230326Sminshall sp = getservbyname("telnet", "tcp"); 100330326Sminshall if (sp == 0) { 100430326Sminshall ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1); 100530326Sminshall /*NOTREACHED*/ 100630326Sminshall } 100730326Sminshall 100830326Sminshall #if defined(TN3270) 100930722Sminshall init_ctlr(); /* Initialize some things */ 101030722Sminshall init_keyboard(); 101130722Sminshall init_screen(); 101230722Sminshall init_system(); 101330326Sminshall #endif /* defined(TN3270) */ 101430326Sminshall } 101530326Sminshall 101630326Sminshall /* 101730088Sminshall * Various utility routines. 101830088Sminshall */ 101930088Sminshall 102030088Sminshall static void 102130088Sminshall makeargv() 102230088Sminshall { 102331215Sminshall register char *cp; 102431215Sminshall register char **argp = margv; 102530088Sminshall 102631215Sminshall margc = 0; 102731215Sminshall cp = line; 102831215Sminshall if (*cp == '!') { /* Special case shell escape */ 102931215Sminshall *argp++ = "!"; /* No room in string to get this */ 103031215Sminshall margc++; 103131215Sminshall cp++; 103231215Sminshall } 103331215Sminshall while (*cp) { 103431215Sminshall while (isspace(*cp)) 103531215Sminshall cp++; 103631215Sminshall if (*cp == '\0') 103731215Sminshall break; 103831215Sminshall *argp++ = cp; 103931215Sminshall margc += 1; 104031215Sminshall while (*cp != '\0' && !isspace(*cp)) 104131215Sminshall cp++; 104231215Sminshall if (*cp == '\0') 104331215Sminshall break; 104431215Sminshall *cp++ = '\0'; 104531215Sminshall } 104631215Sminshall *argp++ = 0; 104730088Sminshall } 104830088Sminshall 104930088Sminshall static char *ambiguous; /* special return value */ 105030088Sminshall #define Ambiguous(t) ((t)&ambiguous) 105130088Sminshall 105230088Sminshall 105330088Sminshall static char ** 105430088Sminshall genget(name, table, next) 105530088Sminshall char *name; /* name to match */ 105630088Sminshall char **table; /* name entry in table */ 105730088Sminshall char **(*next)(); /* routine to return next entry in table */ 105830088Sminshall { 105930088Sminshall register char *p, *q; 106030088Sminshall register char **c, **found; 106130088Sminshall register int nmatches, longest; 106230088Sminshall 106330088Sminshall longest = 0; 106430088Sminshall nmatches = 0; 106530088Sminshall found = 0; 106630088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 106730088Sminshall for (q = name; 106830088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 106930088Sminshall if (*q == 0) /* exact match? */ 107030088Sminshall return (c); 107130088Sminshall if (!*q) { /* the name was a prefix */ 107230088Sminshall if (q - name > longest) { 107330088Sminshall longest = q - name; 107430088Sminshall nmatches = 1; 107530088Sminshall found = c; 107630088Sminshall } else if (q - name == longest) 107730088Sminshall nmatches++; 107830088Sminshall } 107930088Sminshall } 108030088Sminshall if (nmatches > 1) 108130088Sminshall return Ambiguous(char **); 108230088Sminshall return (found); 108330088Sminshall } 108430088Sminshall 108530088Sminshall /* 108630088Sminshall * Make a character string into a number. 108730088Sminshall * 108830088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 108930088Sminshall */ 109030088Sminshall 109130088Sminshall static 109230088Sminshall special(s) 109330088Sminshall register char *s; 109430088Sminshall { 109530088Sminshall register char c; 109630088Sminshall char b; 109730088Sminshall 109830088Sminshall switch (*s) { 109930088Sminshall case '^': 110030088Sminshall b = *++s; 110130088Sminshall if (b == '?') { 110230088Sminshall c = b | 0x40; /* DEL */ 110330088Sminshall } else { 110430088Sminshall c = b & 0x1f; 110530088Sminshall } 110630088Sminshall break; 110730088Sminshall default: 110830088Sminshall c = *s; 110930088Sminshall break; 111030088Sminshall } 111130088Sminshall return c; 111230088Sminshall } 111330088Sminshall 111430088Sminshall /* 111530088Sminshall * Construct a control character sequence 111630088Sminshall * for a special character. 111730088Sminshall */ 111830088Sminshall static char * 111930088Sminshall control(c) 112030088Sminshall register int c; 112130088Sminshall { 112230088Sminshall static char buf[3]; 112330088Sminshall 112430088Sminshall if (c == 0x7f) 112530088Sminshall return ("^?"); 112630088Sminshall if (c == '\377') { 112730088Sminshall return "off"; 112830088Sminshall } 112930088Sminshall if (c >= 0x20) { 113030088Sminshall buf[0] = c; 113130088Sminshall buf[1] = 0; 113230088Sminshall } else { 113330088Sminshall buf[0] = '^'; 113430088Sminshall buf[1] = '@'+c; 113530088Sminshall buf[2] = 0; 113630088Sminshall } 113730088Sminshall return (buf); 113830088Sminshall } 113930088Sminshall 114030088Sminshall 114130088Sminshall /* 114230088Sminshall * upcase() 114330088Sminshall * 114430088Sminshall * Upcase (in place) the argument. 114530088Sminshall */ 114630088Sminshall 114730088Sminshall static void 114830088Sminshall upcase(argument) 114930088Sminshall register char *argument; 115030088Sminshall { 115130088Sminshall register int c; 115230088Sminshall 115330088Sminshall while ((c = *argument) != 0) { 115430088Sminshall if (islower(c)) { 115530088Sminshall *argument = toupper(c); 115630088Sminshall } 115730088Sminshall argument++; 115830088Sminshall } 115930088Sminshall } 116031124Sminshall 116131124Sminshall /* 116231124Sminshall * SetSockOpt() 116331124Sminshall * 116431124Sminshall * Compensate for differences in 4.2 and 4.3 systems. 116531124Sminshall */ 116631124Sminshall 116731124Sminshall static int 116831124Sminshall SetSockOpt(fd, level, option, yesno) 116931124Sminshall int 117031124Sminshall fd, 117131124Sminshall level, 117231124Sminshall option, 117331124Sminshall yesno; 117431124Sminshall { 117531124Sminshall #ifndef NOT43 117631124Sminshall return setsockopt(fd, level, option, 117731124Sminshall (char *)&yesno, sizeof yesno); 117831124Sminshall #else /* NOT43 */ 117931124Sminshall if (yesno == 0) { /* Can't do that in 4.2! */ 118031124Sminshall fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", 118131124Sminshall option); 118231124Sminshall return -1; 118331124Sminshall } 118431124Sminshall return setsockopt(fd, level, option, 0, 0); 118531124Sminshall #endif /* NOT43 */ 118631124Sminshall } 118730088Sminshall 118830088Sminshall /* 118930088Sminshall * The following are routines used to print out debugging information. 119030088Sminshall */ 119130088Sminshall 119230088Sminshall 119330088Sminshall static void 119430088Sminshall Dump(direction, buffer, length) 119530088Sminshall char direction; 119630088Sminshall char *buffer; 119730088Sminshall int length; 119830088Sminshall { 119930088Sminshall # define BYTES_PER_LINE 32 120030088Sminshall # define min(x,y) ((x<y)? x:y) 120130088Sminshall char *pThis; 120230088Sminshall int offset; 120330088Sminshall 120430088Sminshall offset = 0; 120530088Sminshall 120630088Sminshall while (length) { 120730088Sminshall /* print one line */ 120830088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 120930088Sminshall pThis = buffer; 121030088Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 121130088Sminshall while (pThis < buffer) { 121230088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 121330088Sminshall pThis++; 121430088Sminshall } 121530088Sminshall fprintf(NetTrace, "\n"); 121630088Sminshall length -= BYTES_PER_LINE; 121730088Sminshall offset += BYTES_PER_LINE; 121830088Sminshall if (length < 0) { 121930088Sminshall return; 122030088Sminshall } 122130088Sminshall /* find next unique line */ 122230088Sminshall } 122330088Sminshall } 122430088Sminshall 122530088Sminshall 122630088Sminshall /*VARARGS*/ 122730088Sminshall static void 122830088Sminshall printoption(direction, fmt, option, what) 122930088Sminshall char *direction, *fmt; 123030088Sminshall int option, what; 123130088Sminshall { 123230088Sminshall if (!showoptions) 123330088Sminshall return; 123430088Sminshall fprintf(NetTrace, "%s ", direction+1); 123530088Sminshall if (fmt == doopt) 123630088Sminshall fmt = "do"; 123730088Sminshall else if (fmt == dont) 123830088Sminshall fmt = "dont"; 123930088Sminshall else if (fmt == will) 124030088Sminshall fmt = "will"; 124130088Sminshall else if (fmt == wont) 124230088Sminshall fmt = "wont"; 124330088Sminshall else 124430088Sminshall fmt = "???"; 124530088Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 124630088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]); 124730088Sminshall else 124830088Sminshall fprintf(NetTrace, "%s %d", fmt, option); 124930088Sminshall if (*direction == '<') { 125030088Sminshall fprintf(NetTrace, "\r\n"); 125130088Sminshall return; 125230088Sminshall } 125330088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); 125430088Sminshall } 125530088Sminshall 125630088Sminshall static void 125730088Sminshall printsub(direction, pointer, length) 125830088Sminshall char *direction, /* "<" or ">" */ 125930088Sminshall *pointer; /* where suboption data sits */ 126030088Sminshall int length; /* length of suboption data */ 126130088Sminshall { 126230088Sminshall if (showoptions) { 126330088Sminshall fprintf(NetTrace, "%s suboption ", 126430088Sminshall (direction[0] == '<')? "Received":"Sent"); 126530088Sminshall switch (pointer[0]) { 126630088Sminshall case TELOPT_TTYPE: 126730088Sminshall fprintf(NetTrace, "Terminal type "); 126830088Sminshall switch (pointer[1]) { 126930088Sminshall case TELQUAL_IS: 127030088Sminshall { 127130088Sminshall char tmpbuf[sizeof subbuffer]; 127230088Sminshall int minlen = min(length, sizeof tmpbuf); 127330088Sminshall 127431131Sminshall memcpy(tmpbuf, pointer+2, minlen); 127530088Sminshall tmpbuf[minlen-1] = 0; 127630088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf); 127730088Sminshall } 127830088Sminshall break; 127930088Sminshall case TELQUAL_SEND: 128030088Sminshall fprintf(NetTrace, "- request to send.\n"); 128130088Sminshall break; 128230088Sminshall default: 128330088Sminshall fprintf(NetTrace, 128430088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]); 128530088Sminshall } 128630088Sminshall break; 128730088Sminshall default: 128830088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n", 128930088Sminshall pointer[0], pointer[0]); 129030088Sminshall } 129130088Sminshall } 129230088Sminshall } 129330088Sminshall 129430088Sminshall /* 129530088Sminshall * Check to see if any out-of-band data exists on a socket (for 129630088Sminshall * Telnet "synch" processing). 129730088Sminshall */ 129830088Sminshall 129930088Sminshall static int 130030088Sminshall stilloob(s) 130130088Sminshall int s; /* socket number */ 130230088Sminshall { 130330088Sminshall static struct timeval timeout = { 0 }; 130430088Sminshall fd_set excepts; 130530088Sminshall int value; 130630088Sminshall 130730088Sminshall do { 130830088Sminshall FD_ZERO(&excepts); 130930088Sminshall FD_SET(s, &excepts); 131030088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 131130088Sminshall } while ((value == -1) && (errno == EINTR)); 131230088Sminshall 131330088Sminshall if (value < 0) { 131430088Sminshall perror("select"); 131530088Sminshall quit(); 131630088Sminshall } 131730088Sminshall if (FD_ISSET(s, &excepts)) { 131830088Sminshall return 1; 131930088Sminshall } else { 132030088Sminshall return 0; 132130088Sminshall } 132230088Sminshall } 132330088Sminshall 132430088Sminshall 132530088Sminshall /* 132630088Sminshall * netflush 132730088Sminshall * Send as much data as possible to the network, 132830088Sminshall * handling requests for urgent data. 132930088Sminshall * 133030088Sminshall * The return value indicates whether we did any 133130088Sminshall * useful work. 133230088Sminshall */ 133330088Sminshall 133430088Sminshall 133530088Sminshall int 133630088Sminshall netflush() 133730088Sminshall { 133830088Sminshall int n; 133930088Sminshall 134030088Sminshall if ((n = nfrontp - nbackp) > 0) { 134130088Sminshall if (!neturg) { 134231131Sminshall n = send(net, nbackp, n, 0); /* normal write */ 134330088Sminshall } else { 134430088Sminshall n = neturg - nbackp; 134530088Sminshall /* 134630088Sminshall * In 4.2 (and 4.3) systems, there is some question about 134730088Sminshall * what byte in a sendOOB operation is the "OOB" data. 134830088Sminshall * To make ourselves compatible, we only send ONE byte 134930088Sminshall * out of band, the one WE THINK should be OOB (though 135030088Sminshall * we really have more the TCP philosophy of urgent data 135130088Sminshall * rather than the Unix philosophy of OOB data). 135230088Sminshall */ 135330088Sminshall if (n > 1) { 135430088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 135530088Sminshall } else { 135630088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 135730088Sminshall } 135830088Sminshall } 135930088Sminshall } 136030088Sminshall if (n < 0) { 136130088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 136230088Sminshall setcommandmode(); 136330088Sminshall perror(hostname); 136431131Sminshall NetClose(net); 136530088Sminshall neturg = 0; 136630088Sminshall longjmp(peerdied, -1); 136730088Sminshall /*NOTREACHED*/ 136830088Sminshall } 136930088Sminshall n = 0; 137030088Sminshall } 137130088Sminshall if (netdata && n) { 137230088Sminshall Dump('>', nbackp, n); 137330088Sminshall } 137430088Sminshall nbackp += n; 137530088Sminshall if (nbackp >= neturg) { 137630088Sminshall neturg = 0; 137730088Sminshall } 137830088Sminshall if (nbackp == nfrontp) { 137930088Sminshall nbackp = nfrontp = netobuf; 138030088Sminshall } 138130088Sminshall return n > 0; 138230088Sminshall } 138330088Sminshall 138430088Sminshall /* 138530088Sminshall * nextitem() 138630088Sminshall * 138730088Sminshall * Return the address of the next "item" in the TELNET data 138830088Sminshall * stream. This will be the address of the next character if 138930088Sminshall * the current address is a user data character, or it will 139030088Sminshall * be the address of the character following the TELNET command 139130088Sminshall * if the current address is a TELNET IAC ("I Am a Command") 139230088Sminshall * character. 139330088Sminshall */ 139430088Sminshall 139530088Sminshall static char * 139630088Sminshall nextitem(current) 139730088Sminshall char *current; 139830088Sminshall { 139930088Sminshall if ((*current&0xff) != IAC) { 140030088Sminshall return current+1; 140130088Sminshall } 140230088Sminshall switch (*(current+1)&0xff) { 140330088Sminshall case DO: 140430088Sminshall case DONT: 140530088Sminshall case WILL: 140630088Sminshall case WONT: 140730088Sminshall return current+3; 140830088Sminshall case SB: /* loop forever looking for the SE */ 140930088Sminshall { 141030088Sminshall register char *look = current+2; 141130088Sminshall 141230088Sminshall for (;;) { 141330088Sminshall if ((*look++&0xff) == IAC) { 141430088Sminshall if ((*look++&0xff) == SE) { 141530088Sminshall return look; 141630088Sminshall } 141730088Sminshall } 141830088Sminshall } 141930088Sminshall } 142030088Sminshall default: 142130088Sminshall return current+2; 142230088Sminshall } 142330088Sminshall } 142430088Sminshall /* 142530088Sminshall * netclear() 142630088Sminshall * 142730088Sminshall * We are about to do a TELNET SYNCH operation. Clear 142830088Sminshall * the path to the network. 142930088Sminshall * 143030088Sminshall * Things are a bit tricky since we may have sent the first 143130088Sminshall * byte or so of a previous TELNET command into the network. 143230088Sminshall * So, we have to scan the network buffer from the beginning 143330088Sminshall * until we are up to where we want to be. 143430088Sminshall * 143530088Sminshall * A side effect of what we do, just to keep things 143630088Sminshall * simple, is to clear the urgent data pointer. The principal 143730088Sminshall * caller should be setting the urgent data pointer AFTER calling 143830088Sminshall * us in any case. 143930088Sminshall */ 144030088Sminshall 144130088Sminshall static void 144230088Sminshall netclear() 144330088Sminshall { 144430088Sminshall register char *thisitem, *next; 144530088Sminshall char *good; 144630088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 144730088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 144830088Sminshall 144930088Sminshall thisitem = netobuf; 145030088Sminshall 145130088Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 145230088Sminshall thisitem = next; 145330088Sminshall } 145430088Sminshall 145530088Sminshall /* Now, thisitem is first before/at boundary. */ 145630088Sminshall 145730088Sminshall good = netobuf; /* where the good bytes go */ 145830088Sminshall 145930088Sminshall while (nfrontp > thisitem) { 146030088Sminshall if (wewant(thisitem)) { 146130088Sminshall int length; 146230088Sminshall 146330088Sminshall next = thisitem; 146430088Sminshall do { 146530088Sminshall next = nextitem(next); 146630088Sminshall } while (wewant(next) && (nfrontp > next)); 146730088Sminshall length = next-thisitem; 146831131Sminshall memcpy(good, thisitem, length); 146930088Sminshall good += length; 147030088Sminshall thisitem = next; 147130088Sminshall } else { 147230088Sminshall thisitem = nextitem(thisitem); 147330088Sminshall } 147430088Sminshall } 147530088Sminshall 147630088Sminshall nbackp = netobuf; 147730088Sminshall nfrontp = good; /* next byte to be sent */ 147830088Sminshall neturg = 0; 147930088Sminshall } 148030088Sminshall 148130088Sminshall /* 148230088Sminshall * These routines add various telnet commands to the data stream. 148330088Sminshall */ 148430088Sminshall 148530088Sminshall #if defined(NOT43) 148630088Sminshall static int 148730088Sminshall #else /* defined(NOT43) */ 148830088Sminshall static void 148930088Sminshall #endif /* defined(NOT43) */ 149030088Sminshall dosynch() 149130088Sminshall { 149230088Sminshall netclear(); /* clear the path to the network */ 149330088Sminshall NET2ADD(IAC, DM); 149430088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 149530088Sminshall 149630088Sminshall #if defined(NOT43) 149730088Sminshall return 0; 149830088Sminshall #endif /* defined(NOT43) */ 149930088Sminshall } 150030088Sminshall 150130088Sminshall static void 150230088Sminshall doflush() 150330088Sminshall { 150430088Sminshall NET2ADD(IAC, DO); 150530088Sminshall NETADD(TELOPT_TM); 150630088Sminshall flushline = 1; 150730088Sminshall flushout = 1; 150830088Sminshall ttyflush(); 150930088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 151030088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 151130088Sminshall } 151230088Sminshall 151330088Sminshall static void 151430088Sminshall intp() 151530088Sminshall { 151630088Sminshall NET2ADD(IAC, IP); 151730088Sminshall if (autoflush) { 151830088Sminshall doflush(); 151930088Sminshall } 152030088Sminshall if (autosynch) { 152130088Sminshall dosynch(); 152230088Sminshall } 152330088Sminshall } 152430088Sminshall 152530088Sminshall static void 152630088Sminshall sendbrk() 152730088Sminshall { 152830088Sminshall NET2ADD(IAC, BREAK); 152930088Sminshall if (autoflush) { 153030088Sminshall doflush(); 153130088Sminshall } 153230088Sminshall if (autosynch) { 153330088Sminshall dosynch(); 153430088Sminshall } 153530088Sminshall } 153630088Sminshall 153730088Sminshall /* 153830088Sminshall * Send as much data as possible to the terminal. 153930088Sminshall * 154030088Sminshall * The return value indicates whether we did any 154130088Sminshall * useful work. 154230088Sminshall */ 154330088Sminshall 154430088Sminshall 154530088Sminshall static int 154630088Sminshall ttyflush() 154730088Sminshall { 154830088Sminshall int n; 154930088Sminshall 155030088Sminshall if ((n = tfrontp - tbackp) > 0) { 155130088Sminshall if (!(SYNCHing||flushout)) { 155231131Sminshall n = TerminalWrite(tout, tbackp, n); 155330088Sminshall } else { 155431124Sminshall TerminalFlushOutput(); 155530088Sminshall /* we leave 'n' alone! */ 155630088Sminshall } 155730088Sminshall } 155830088Sminshall if (n >= 0) { 155930088Sminshall tbackp += n; 156030088Sminshall if (tbackp == tfrontp) { 156130088Sminshall tbackp = tfrontp = ttyobuf; 156230088Sminshall } 156330088Sminshall } 156430088Sminshall return n > 0; 156530088Sminshall } 156630088Sminshall 156730088Sminshall #if defined(TN3270) 156830088Sminshall 156930088Sminshall #if defined(unix) 157030088Sminshall static void 157130088Sminshall inputAvailable() 157230088Sminshall { 157330088Sminshall HaveInput = 1; 157430088Sminshall } 157530088Sminshall #endif /* defined(unix) */ 157630088Sminshall 157730088Sminshall void 157830088Sminshall outputPurge() 157930088Sminshall { 158030088Sminshall int tmp = flushout; 158130088Sminshall 158230088Sminshall flushout = 1; 158330088Sminshall 158430088Sminshall ttyflush(); 158530088Sminshall 158630088Sminshall flushout = tmp; 158730088Sminshall } 158830088Sminshall 158930088Sminshall #endif /* defined(TN3270) */ 159030088Sminshall 159130088Sminshall #if defined(unix) 159230088Sminshall /* 159330088Sminshall * Various signal handling routines. 159430088Sminshall */ 159530088Sminshall 159630088Sminshall static void 159730088Sminshall deadpeer() 159830088Sminshall { 159930088Sminshall setcommandmode(); 160030088Sminshall longjmp(peerdied, -1); 160130088Sminshall } 160230088Sminshall 160330088Sminshall static void 160430088Sminshall intr() 160530088Sminshall { 160630088Sminshall if (localchars) { 160730088Sminshall intp(); 160830088Sminshall return; 160930088Sminshall } 161030088Sminshall setcommandmode(); 161130088Sminshall longjmp(toplevel, -1); 161230088Sminshall } 161330088Sminshall 161430088Sminshall static void 161530088Sminshall intr2() 161630088Sminshall { 161730088Sminshall if (localchars) { 161830088Sminshall sendbrk(); 161930088Sminshall return; 162030088Sminshall } 162130088Sminshall } 162230088Sminshall 162330088Sminshall static void 162430088Sminshall doescape() 162530088Sminshall { 162630088Sminshall command(0); 162730088Sminshall } 162830088Sminshall #endif /* defined(unix) */ 162930088Sminshall 163030088Sminshall /* 163130088Sminshall * These routines decides on what the mode should be (based on the values 163230088Sminshall * of various global variables). 163330088Sminshall */ 163430088Sminshall 163530088Sminshall 163630088Sminshall static 163730088Sminshall getconnmode() 163830088Sminshall { 163930088Sminshall static char newmode[16] = 164030088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; 164130088Sminshall int modeindex = 0; 164230088Sminshall 164330088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 164430088Sminshall modeindex += 1; 164530088Sminshall } 164630088Sminshall if (hisopts[TELOPT_ECHO]) { 164730088Sminshall modeindex += 2; 164830088Sminshall } 164930088Sminshall if (hisopts[TELOPT_SGA]) { 165030088Sminshall modeindex += 4; 165130088Sminshall } 165230088Sminshall if (In3270) { 165330088Sminshall modeindex += 8; 165430088Sminshall } 165530088Sminshall return newmode[modeindex]; 165630088Sminshall } 165730088Sminshall 165830088Sminshall void 165930088Sminshall setconnmode() 166030088Sminshall { 166131124Sminshall TerminalNewMode(getconnmode()); 166230088Sminshall } 166330088Sminshall 166430088Sminshall 166530088Sminshall void 166630088Sminshall setcommandmode() 166730088Sminshall { 166831124Sminshall TerminalNewMode(0); 166930088Sminshall } 167030088Sminshall 167130088Sminshall static void 167230088Sminshall willoption(option, reply) 167330088Sminshall int option, reply; 167430088Sminshall { 167530088Sminshall char *fmt; 167630088Sminshall 167730088Sminshall switch (option) { 167830088Sminshall 167930368Sminshall case TELOPT_ECHO: 168030088Sminshall # if defined(TN3270) 168130368Sminshall /* 168230368Sminshall * The following is a pain in the rear-end. 168330368Sminshall * Various IBM servers (some versions of Wiscnet, 168430368Sminshall * possibly Fibronics/Spartacus, and who knows who 168530368Sminshall * else) will NOT allow us to send "DO SGA" too early 168630368Sminshall * in the setup proceedings. On the other hand, 168730368Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 168830368Sminshall * So, we are stuck. Empirically (but, based on 168930368Sminshall * a VERY small sample), the IBM servers don't send 169030368Sminshall * out anything about ECHO, so we postpone our sending 169130368Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 169230368Sminshall * DO send). 169330368Sminshall */ 169430368Sminshall { 169530368Sminshall if (askedSGA == 0) { 169630368Sminshall askedSGA = 1; 169730368Sminshall if (!hisopts[TELOPT_SGA]) { 169830368Sminshall willoption(TELOPT_SGA, 0); 169930368Sminshall } 170030368Sminshall } 170130368Sminshall } 170230368Sminshall /* Fall through */ 170330088Sminshall case TELOPT_EOR: 170430088Sminshall case TELOPT_BINARY: 170530088Sminshall #endif /* defined(TN3270) */ 170630088Sminshall case TELOPT_SGA: 170730088Sminshall settimer(modenegotiated); 170830088Sminshall hisopts[option] = 1; 170930088Sminshall fmt = doopt; 171030088Sminshall setconnmode(); /* possibly set new tty mode */ 171130088Sminshall break; 171230088Sminshall 171330088Sminshall case TELOPT_TM: 171430088Sminshall return; /* Never reply to TM will's/wont's */ 171530088Sminshall 171630088Sminshall default: 171730088Sminshall fmt = dont; 171830088Sminshall break; 171930088Sminshall } 172030088Sminshall sprintf(nfrontp, fmt, option); 172130088Sminshall nfrontp += sizeof (dont) - 2; 172230088Sminshall if (reply) 172330088Sminshall printoption(">SENT", fmt, option, reply); 172430088Sminshall else 172530088Sminshall printoption("<SENT", fmt, option, reply); 172630088Sminshall } 172730088Sminshall 172830088Sminshall static void 172930088Sminshall wontoption(option, reply) 173030088Sminshall int option, reply; 173130088Sminshall { 173230088Sminshall char *fmt; 173330088Sminshall 173430088Sminshall switch (option) { 173530088Sminshall 173630088Sminshall case TELOPT_ECHO: 173730088Sminshall case TELOPT_SGA: 173830088Sminshall settimer(modenegotiated); 173930088Sminshall hisopts[option] = 0; 174030088Sminshall fmt = dont; 174130088Sminshall setconnmode(); /* Set new tty mode */ 174230088Sminshall break; 174330088Sminshall 174430088Sminshall case TELOPT_TM: 174530088Sminshall return; /* Never reply to TM will's/wont's */ 174630088Sminshall 174730088Sminshall default: 174830088Sminshall fmt = dont; 174930088Sminshall } 175030088Sminshall sprintf(nfrontp, fmt, option); 175130088Sminshall nfrontp += sizeof (doopt) - 2; 175230088Sminshall if (reply) 175330088Sminshall printoption(">SENT", fmt, option, reply); 175430088Sminshall else 175530088Sminshall printoption("<SENT", fmt, option, reply); 175630088Sminshall } 175730088Sminshall 175830088Sminshall static void 175930088Sminshall dooption(option) 176030088Sminshall int option; 176130088Sminshall { 176230088Sminshall char *fmt; 176330088Sminshall 176430088Sminshall switch (option) { 176530088Sminshall 176630088Sminshall case TELOPT_TM: 176730088Sminshall fmt = will; 176830088Sminshall break; 176930088Sminshall 177030088Sminshall # if defined(TN3270) 177130088Sminshall case TELOPT_EOR: 177230088Sminshall case TELOPT_BINARY: 177330088Sminshall # endif /* defined(TN3270) */ 177430088Sminshall case TELOPT_TTYPE: /* terminal type option */ 177530088Sminshall case TELOPT_SGA: /* no big deal */ 177630088Sminshall fmt = will; 177730088Sminshall myopts[option] = 1; 177830088Sminshall break; 177930088Sminshall 178030088Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 178130088Sminshall default: 178230088Sminshall fmt = wont; 178330088Sminshall break; 178430088Sminshall } 178530088Sminshall sprintf(nfrontp, fmt, option); 178630088Sminshall nfrontp += sizeof (doopt) - 2; 178730088Sminshall printoption(">SENT", fmt, option, 0); 178830088Sminshall } 178930088Sminshall 179030088Sminshall /* 179130088Sminshall * suboption() 179230088Sminshall * 179330088Sminshall * Look at the sub-option buffer, and try to be helpful to the other 179430088Sminshall * side. 179530088Sminshall * 179630088Sminshall * Currently we recognize: 179730088Sminshall * 179830088Sminshall * Terminal type, send request. 179930088Sminshall */ 180030088Sminshall 180130088Sminshall static void 180230088Sminshall suboption() 180330088Sminshall { 180430088Sminshall printsub("<", subbuffer, subend-subbuffer+1); 180530088Sminshall switch (subbuffer[0]&0xff) { 180630088Sminshall case TELOPT_TTYPE: 180730088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 180830088Sminshall ; 180930088Sminshall } else { 181030088Sminshall char *name; 181130088Sminshall char namebuf[41]; 181230088Sminshall extern char *getenv(); 181330088Sminshall int len; 181430088Sminshall 181530088Sminshall #if defined(TN3270) 181630088Sminshall /* 181730326Sminshall * Try to send a 3270 type terminal name. Decide which one based 181830088Sminshall * on the format of our screen, and (in the future) color 181930088Sminshall * capaiblities. 182030088Sminshall */ 182131124Sminshall #if defined(unix) 182231131Sminshall if (initscr() != ERR) { /* Initialize curses to get line size */ 182331131Sminshall MaxNumberLines = LINES; 182431131Sminshall MaxNumberColumns = COLS; 182531131Sminshall } 182631131Sminshall #else /* defined(unix) */ 182731131Sminshall InitTerminal(); 182831131Sminshall #endif /* defined(unix) */ 182931131Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 183030088Sminshall Sent3270TerminalType = 1; 183131131Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 183230088Sminshall MaxNumberLines = 27; 183330088Sminshall MaxNumberColumns = 132; 183430088Sminshall sb_terminal[SBTERMMODEL] = '5'; 183531131Sminshall } else if (MaxNumberLines >= 43) { 183630088Sminshall MaxNumberLines = 43; 183730088Sminshall MaxNumberColumns = 80; 183830088Sminshall sb_terminal[SBTERMMODEL] = '4'; 183931131Sminshall } else if (MaxNumberLines >= 32) { 184030088Sminshall MaxNumberLines = 32; 184130088Sminshall MaxNumberColumns = 80; 184230088Sminshall sb_terminal[SBTERMMODEL] = '3'; 184330088Sminshall } else { 184430088Sminshall MaxNumberLines = 24; 184530088Sminshall MaxNumberColumns = 80; 184630088Sminshall sb_terminal[SBTERMMODEL] = '2'; 184730088Sminshall } 184830088Sminshall NumberLines = 24; /* before we start out... */ 184930088Sminshall NumberColumns = 80; 185030088Sminshall ScreenSize = NumberLines*NumberColumns; 185130088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 185230088Sminshall ExitString(stderr, 185330088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 185430088Sminshall /*NOTREACHED*/ 185530088Sminshall } 185631131Sminshall memcpy(nfrontp, sb_terminal, sizeof sb_terminal); 185730088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 185830088Sminshall nfrontp += sizeof sb_terminal; 185930088Sminshall return; 186030088Sminshall } 186130088Sminshall #endif /* defined(TN3270) */ 186230088Sminshall 186330088Sminshall name = getenv("TERM"); 186430088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 186530088Sminshall name = "UNKNOWN"; 186630088Sminshall } 186730088Sminshall if ((len + 4+2) < NETROOM()) { 186830088Sminshall strcpy(namebuf, name); 186930088Sminshall upcase(namebuf); 187030088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 187130088Sminshall TELQUAL_IS, namebuf, IAC, SE); 187230088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 187330088Sminshall nfrontp += 4+strlen(namebuf)+2; 187430088Sminshall } else { 187530088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 187630088Sminshall 1); 187730088Sminshall /*NOTREACHED*/ 187830088Sminshall } 187930088Sminshall } 188030088Sminshall 188130088Sminshall default: 188230088Sminshall break; 188330088Sminshall } 188430088Sminshall } 188530088Sminshall 188630088Sminshall #if defined(TN3270) 188730088Sminshall static void 188830088Sminshall SetIn3270() 188930088Sminshall { 189030088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 1891*31791Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 189230088Sminshall if (!In3270) { 189330088Sminshall In3270 = 1; 189430326Sminshall Init3270(); /* Initialize 3270 functions */ 189530088Sminshall /* initialize terminal key mapping */ 189630326Sminshall InitTerminal(); /* Start terminal going */ 189730088Sminshall setconnmode(); 189830088Sminshall } 189930088Sminshall } else { 190030088Sminshall if (In3270) { 190130088Sminshall StopScreen(1); 190230088Sminshall In3270 = 0; 190331215Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 190430088Sminshall setconnmode(); 190530088Sminshall } 190630088Sminshall } 190730088Sminshall } 190830088Sminshall #endif /* defined(TN3270) */ 190930088Sminshall 191030088Sminshall 191130088Sminshall static void 191230088Sminshall telrcv() 191330088Sminshall { 191430088Sminshall register int c; 191530722Sminshall static int telrcv_state = TS_DATA; 191630088Sminshall # if defined(TN3270) 191730088Sminshall register int Scc; 191830088Sminshall register char *Sbp; 191930088Sminshall # endif /* defined(TN3270) */ 192030088Sminshall 192130088Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 192230088Sminshall c = *sbp++ & 0xff, scc--; 192330722Sminshall switch (telrcv_state) { 192430088Sminshall 192530088Sminshall case TS_CR: 192630722Sminshall telrcv_state = TS_DATA; 192730088Sminshall if (c == '\0') { 192830088Sminshall break; /* Ignore \0 after CR */ 192930088Sminshall } else if (c == '\n') { 193030088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 193130088Sminshall TTYADD(c); 193230088Sminshall } 193330088Sminshall break; 193430088Sminshall } 193530088Sminshall /* Else, fall through */ 193630088Sminshall 193730088Sminshall case TS_DATA: 193830088Sminshall if (c == IAC) { 193930722Sminshall telrcv_state = TS_IAC; 194030088Sminshall continue; 194130088Sminshall } 194230088Sminshall # if defined(TN3270) 194330088Sminshall if (In3270) { 194430088Sminshall *Ifrontp++ = c; 194530088Sminshall Sbp = sbp; 194630088Sminshall Scc = scc; 194730088Sminshall while (Scc > 0) { 194830088Sminshall c = *Sbp++ & 0377, Scc--; 194930088Sminshall if (c == IAC) { 195030722Sminshall telrcv_state = TS_IAC; 195130088Sminshall break; 195230088Sminshall } 195330088Sminshall *Ifrontp++ = c; 195430088Sminshall } 195530088Sminshall sbp = Sbp; 195630088Sminshall scc = Scc; 195730088Sminshall } else 195830088Sminshall # endif /* defined(TN3270) */ 195930088Sminshall /* 196030088Sminshall * The 'crmod' hack (see following) is needed 196130088Sminshall * since we can't * set CRMOD on output only. 196230088Sminshall * Machines like MULTICS like to send \r without 196330088Sminshall * \n; since we must turn off CRMOD to get proper 196430088Sminshall * input, the mapping is done here (sigh). 196530088Sminshall */ 196630088Sminshall if (c == '\r') { 196730088Sminshall if (scc > 0) { 196830088Sminshall c = *sbp&0xff; 196930088Sminshall if (c == 0) { 197030088Sminshall sbp++, scc--; 197130088Sminshall /* a "true" CR */ 197230088Sminshall TTYADD('\r'); 197330088Sminshall } else if (!hisopts[TELOPT_ECHO] && 197430088Sminshall (c == '\n')) { 197530088Sminshall sbp++, scc--; 197630088Sminshall TTYADD('\n'); 197730088Sminshall } else { 197830088Sminshall TTYADD('\r'); 197930088Sminshall if (crmod) { 198030088Sminshall TTYADD('\n'); 198130088Sminshall } 198230088Sminshall } 198330088Sminshall } else { 198430722Sminshall telrcv_state = TS_CR; 198530088Sminshall TTYADD('\r'); 198630088Sminshall if (crmod) { 198730088Sminshall TTYADD('\n'); 198830088Sminshall } 198930088Sminshall } 199030088Sminshall } else { 199130088Sminshall TTYADD(c); 199230088Sminshall } 199330088Sminshall continue; 199430088Sminshall 199530088Sminshall case TS_IAC: 199630088Sminshall switch (c) { 199730088Sminshall 199830088Sminshall case WILL: 199930722Sminshall telrcv_state = TS_WILL; 200030088Sminshall continue; 200130088Sminshall 200230088Sminshall case WONT: 200330722Sminshall telrcv_state = TS_WONT; 200430088Sminshall continue; 200530088Sminshall 200630088Sminshall case DO: 200730722Sminshall telrcv_state = TS_DO; 200830088Sminshall continue; 200930088Sminshall 201030088Sminshall case DONT: 201130722Sminshall telrcv_state = TS_DONT; 201230088Sminshall continue; 201330088Sminshall 201430088Sminshall case DM: 201530088Sminshall /* 201630088Sminshall * We may have missed an urgent notification, 201730088Sminshall * so make sure we flush whatever is in the 201830088Sminshall * buffer currently. 201930088Sminshall */ 202030088Sminshall SYNCHing = 1; 202130088Sminshall ttyflush(); 202230088Sminshall SYNCHing = stilloob(net); 202330088Sminshall settimer(gotDM); 202430088Sminshall break; 202530088Sminshall 202630088Sminshall case NOP: 202730088Sminshall case GA: 202830088Sminshall break; 202930088Sminshall 203030088Sminshall case SB: 203130088Sminshall SB_CLEAR(); 203230722Sminshall telrcv_state = TS_SB; 203330088Sminshall continue; 203430088Sminshall 203530088Sminshall # if defined(TN3270) 203630088Sminshall case EOR: 203730088Sminshall if (In3270) { 203830088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 203930088Sminshall if (Ibackp == Ifrontp) { 204030088Sminshall Ibackp = Ifrontp = Ibuf; 204130088Sminshall ISend = 0; /* should have been! */ 204230088Sminshall } else { 204330088Sminshall ISend = 1; 204430088Sminshall } 204530088Sminshall } 204630088Sminshall break; 204730088Sminshall # endif /* defined(TN3270) */ 204830088Sminshall 204930088Sminshall case IAC: 205030088Sminshall # if !defined(TN3270) 205130088Sminshall TTYADD(IAC); 205230088Sminshall # else /* !defined(TN3270) */ 205330088Sminshall if (In3270) { 205430088Sminshall *Ifrontp++ = IAC; 205530088Sminshall } else { 205630088Sminshall TTYADD(IAC); 205730088Sminshall } 205830088Sminshall # endif /* !defined(TN3270) */ 205930088Sminshall break; 206030088Sminshall 206130088Sminshall default: 206230088Sminshall break; 206330088Sminshall } 206430722Sminshall telrcv_state = TS_DATA; 206530088Sminshall continue; 206630088Sminshall 206730088Sminshall case TS_WILL: 206830088Sminshall printoption(">RCVD", will, c, !hisopts[c]); 206930088Sminshall if (c == TELOPT_TM) { 207030088Sminshall if (flushout) { 207130088Sminshall flushout = 0; 207230088Sminshall } 207330088Sminshall } else if (!hisopts[c]) { 207430088Sminshall willoption(c, 1); 207530088Sminshall } 207630088Sminshall SetIn3270(); 207730722Sminshall telrcv_state = TS_DATA; 207830088Sminshall continue; 207930088Sminshall 208030088Sminshall case TS_WONT: 208130088Sminshall printoption(">RCVD", wont, c, hisopts[c]); 208230088Sminshall if (c == TELOPT_TM) { 208330088Sminshall if (flushout) { 208430088Sminshall flushout = 0; 208530088Sminshall } 208630088Sminshall } else if (hisopts[c]) { 208730088Sminshall wontoption(c, 1); 208830088Sminshall } 208930088Sminshall SetIn3270(); 209030722Sminshall telrcv_state = TS_DATA; 209130088Sminshall continue; 209230088Sminshall 209330088Sminshall case TS_DO: 209430088Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 209530088Sminshall if (!myopts[c]) 209630088Sminshall dooption(c); 209730088Sminshall SetIn3270(); 209830722Sminshall telrcv_state = TS_DATA; 209930088Sminshall continue; 210030088Sminshall 210130088Sminshall case TS_DONT: 210230088Sminshall printoption(">RCVD", dont, c, myopts[c]); 210330088Sminshall if (myopts[c]) { 210430088Sminshall myopts[c] = 0; 210530088Sminshall sprintf(nfrontp, wont, c); 210630088Sminshall nfrontp += sizeof (wont) - 2; 210730088Sminshall flushline = 1; 210830088Sminshall setconnmode(); /* set new tty mode (maybe) */ 210930088Sminshall printoption(">SENT", wont, c, 0); 211030088Sminshall } 211130088Sminshall SetIn3270(); 211230722Sminshall telrcv_state = TS_DATA; 211330088Sminshall continue; 211430088Sminshall 211530088Sminshall case TS_SB: 211630088Sminshall if (c == IAC) { 211730722Sminshall telrcv_state = TS_SE; 211830088Sminshall } else { 211930088Sminshall SB_ACCUM(c); 212030088Sminshall } 212130088Sminshall continue; 212230088Sminshall 212330088Sminshall case TS_SE: 212430088Sminshall if (c != SE) { 212530088Sminshall if (c != IAC) { 212630088Sminshall SB_ACCUM(IAC); 212730088Sminshall } 212830088Sminshall SB_ACCUM(c); 212930722Sminshall telrcv_state = TS_SB; 213030088Sminshall } else { 213130088Sminshall SB_TERM(); 213230088Sminshall suboption(); /* handle sub-option */ 213330088Sminshall SetIn3270(); 213430722Sminshall telrcv_state = TS_DATA; 213530088Sminshall } 213630088Sminshall } 213730088Sminshall } 213830088Sminshall } 213930088Sminshall 214030088Sminshall #if defined(TN3270) 214130088Sminshall 214230088Sminshall /* 214330088Sminshall * The following routines are places where the various tn3270 214430088Sminshall * routines make calls into telnet.c. 214530088Sminshall */ 214630088Sminshall 214730088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 214830088Sminshall TtyChars() 214930088Sminshall { 215030088Sminshall return(tfrontp-tbackp); 215130088Sminshall } 215230088Sminshall 215330088Sminshall /* 215430088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 215530088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 215630088Sminshall * don't call us with "done" until you want that done...) 215730088Sminshall * 215830088Sminshall * We actually do send all the data to the network buffer, since our 215930088Sminshall * only client needs for us to do that. 216030088Sminshall */ 216130088Sminshall 216230088Sminshall int 216330088Sminshall DataToNetwork(buffer, count, done) 216430088Sminshall register char *buffer; /* where the data is */ 216530088Sminshall register int count; /* how much to send */ 216630088Sminshall int done; /* is this the last of a logical block */ 216730088Sminshall { 216830088Sminshall register int c; 216930088Sminshall int origCount; 217030088Sminshall fd_set o; 217130088Sminshall 217230088Sminshall origCount = count; 217330088Sminshall FD_ZERO(&o); 217430088Sminshall 217530088Sminshall while (count) { 217630088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 217730088Sminshall netflush(); 217830088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) { 217930088Sminshall FD_SET(net, &o); 218030088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 218130088Sminshall (struct timeval *) 0); 218230088Sminshall netflush(); 218330088Sminshall } 218430088Sminshall } 218530088Sminshall c = *buffer++; 218630088Sminshall count--; 218730088Sminshall if (c == IAC) { 218830088Sminshall *nfrontp++ = IAC; 218930088Sminshall *nfrontp++ = IAC; 219030088Sminshall } else { 219130088Sminshall *nfrontp++ = c; 219230088Sminshall } 219330088Sminshall } 219430088Sminshall 219530088Sminshall if (done && !count) { 219630088Sminshall *nfrontp++ = IAC; 219730088Sminshall *nfrontp++ = EOR; 219830088Sminshall netflush(); /* try to move along as quickly as ... */ 219930088Sminshall } 220030088Sminshall return(origCount - count); 220130088Sminshall } 220230088Sminshall 220330088Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 220430088Sminshall 220530088Sminshall int 220630088Sminshall DataToTerminal(buffer, count) 220730088Sminshall register char *buffer; /* where the data is */ 220830088Sminshall register int count; /* how much to send */ 220930088Sminshall { 221030088Sminshall int origCount; 221131131Sminshall #if defined(unix) 221230088Sminshall fd_set o; 221330088Sminshall 221431131Sminshall FD_ZERO(&o); 221531131Sminshall #endif /* defined(unix) */ 221630088Sminshall origCount = count; 221730088Sminshall 221830088Sminshall while (count) { 221930088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 222030088Sminshall ttyflush(); 222130088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 222231131Sminshall #if defined(unix) 222330088Sminshall FD_SET(tout, &o); 222430088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 222530088Sminshall (struct timeval *) 0); 222631131Sminshall #endif /* defined(unix) */ 222730088Sminshall ttyflush(); 222830088Sminshall } 222930088Sminshall } 223030088Sminshall *tfrontp++ = *buffer++; 223130088Sminshall count--; 223230088Sminshall } 223330088Sminshall return(origCount - count); 223430088Sminshall } 223530088Sminshall 223630088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 223730088Sminshall * Note that we consider the buffer to run all the 223830088Sminshall * way to the kernel (thus the select). 223930088Sminshall */ 224030088Sminshall 224130088Sminshall void 224230088Sminshall EmptyTerminal() 224330088Sminshall { 224431131Sminshall #if defined(unix) 224530088Sminshall fd_set o; 224630088Sminshall 224730088Sminshall FD_ZERO(&o); 224831131Sminshall #endif /* defined(unix) */ 224930088Sminshall 225030088Sminshall if (tfrontp == tbackp) { 225131131Sminshall #if defined(unix) 225230088Sminshall FD_SET(tout, &o); 225330088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 225430088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 225531131Sminshall #endif /* defined(unix) */ 225630088Sminshall } else { 225730088Sminshall while (tfrontp != tbackp) { 225830088Sminshall ttyflush(); 225931131Sminshall #if defined(unix) 226030088Sminshall FD_SET(tout, &o); 226130088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 226230088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 226331131Sminshall #endif /* defined(unix) */ 226430088Sminshall } 226530088Sminshall } 226630088Sminshall } 226730088Sminshall 226830088Sminshall /* 226930088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 227030088Sminshall */ 227130088Sminshall 227230088Sminshall static int 227330088Sminshall Push3270() 227430088Sminshall { 227530088Sminshall int save = scc; 227630088Sminshall 227730088Sminshall if (scc) { 227830088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 227930088Sminshall if (Ibackp != Ibuf) { 228031131Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 228130088Sminshall Ifrontp -= (Ibackp-Ibuf); 228230088Sminshall Ibackp = Ibuf; 228330088Sminshall } 228430088Sminshall } 228530088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 228630088Sminshall telrcv(); 228730088Sminshall } 228830088Sminshall } 228930088Sminshall return save != scc; 229030088Sminshall } 229130088Sminshall 229230088Sminshall 229330088Sminshall /* 229430088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 229530088Sminshall * before quitting. 229630088Sminshall */ 229730088Sminshall 229830088Sminshall static void 229930088Sminshall Finish3270() 230030088Sminshall { 230130088Sminshall while (Push3270() || !DoTerminalOutput()) { 230231589Sminshall #if defined(unix) 230331589Sminshall HaveInput = 0; 230431589Sminshall #endif /* defined(unix) */ 230530088Sminshall ; 230630088Sminshall } 230730088Sminshall } 230830088Sminshall 230930088Sminshall 231030088Sminshall 231130088Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 231230088Sminshall 231330088Sminshall void 231430088Sminshall StringToTerminal(s) 231530088Sminshall char *s; 231630088Sminshall { 231730088Sminshall int count; 231830088Sminshall 231930088Sminshall count = strlen(s); 232030088Sminshall if (count) { 232130088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 232230088Sminshall } 232330088Sminshall } 232430088Sminshall 232530088Sminshall 232630088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) 232730088Sminshall /* _putchar - output a single character to the terminal. This name is so that 232830088Sminshall * curses(3x) can call us to send out data. 232930088Sminshall */ 233030088Sminshall 233130088Sminshall void 233230088Sminshall _putchar(c) 233330088Sminshall char c; 233430088Sminshall { 233530088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 233630088Sminshall (void) DataToTerminal(&c, 1); 233730088Sminshall } else { 233830088Sminshall *tfrontp++ = c; /* optimize if possible. */ 233930088Sminshall } 234030088Sminshall } 234130088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ 234230088Sminshall 234330088Sminshall static void 234430088Sminshall SetForExit() 234530088Sminshall { 234630088Sminshall setconnmode(); 234730088Sminshall if (In3270) { 234830088Sminshall Finish3270(); 234930088Sminshall } 235030088Sminshall setcommandmode(); 235130088Sminshall fflush(stdout); 235230088Sminshall fflush(stderr); 235330088Sminshall if (In3270) { 235430088Sminshall StopScreen(1); 235530088Sminshall } 235630088Sminshall setconnmode(); 235730088Sminshall setcommandmode(); 235830088Sminshall } 235930088Sminshall 236030088Sminshall static void 236130088Sminshall Exit(returnCode) 236230088Sminshall int returnCode; 236330088Sminshall { 236430088Sminshall SetForExit(); 236530088Sminshall exit(returnCode); 236630088Sminshall } 236730088Sminshall 236830088Sminshall void 236930088Sminshall ExitString(file, string, returnCode) 237030088Sminshall FILE *file; 237130088Sminshall char *string; 237230088Sminshall int returnCode; 237330088Sminshall { 237430088Sminshall SetForExit(); 237530088Sminshall fwrite(string, 1, strlen(string), file); 237630088Sminshall exit(returnCode); 237730088Sminshall } 237830088Sminshall 237930088Sminshall void 238030088Sminshall ExitPerror(string, returnCode) 238130088Sminshall char *string; 238230088Sminshall int returnCode; 238330088Sminshall { 238430088Sminshall SetForExit(); 238530088Sminshall perror(string); 238630088Sminshall exit(returnCode); 238730088Sminshall } 238830088Sminshall 238930088Sminshall #endif /* defined(TN3270) */ 239030088Sminshall 239131215Sminshall /* 239231215Sminshall * Scheduler() 239331215Sminshall * 239431215Sminshall * Try to do something. 239531215Sminshall * 239631215Sminshall * If we do something useful, return 1; else return 0. 239731215Sminshall * 239831215Sminshall */ 239931215Sminshall 240031215Sminshall 240131215Sminshall int 240230088Sminshall Scheduler(block) 240330088Sminshall int block; /* should we block in the select ? */ 240430088Sminshall { 240530088Sminshall register int c; 240630088Sminshall /* One wants to be a bit careful about setting returnValue 240730088Sminshall * to one, since a one implies we did some useful work, 240830088Sminshall * and therefore probably won't be called to block next 240930088Sminshall * time (TN3270 mode only). 241030088Sminshall */ 241130088Sminshall int returnValue = 0; 241230088Sminshall static struct timeval TimeValue = { 0 }; 241330088Sminshall 241430088Sminshall if (scc < 0 && tcc < 0) { 241530088Sminshall return -1; 241630088Sminshall } 241730088Sminshall 241830088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 241930088Sminshall FD_SET(net, &obits); 242030088Sminshall } 242131131Sminshall #if !defined(MSDOS) 242230088Sminshall if (TTYBYTES()) { 242330088Sminshall FD_SET(tout, &obits); 242430088Sminshall } 242531215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0)) { 242630088Sminshall FD_SET(tin, &ibits); 242730088Sminshall } 242831131Sminshall #endif /* !defined(MSDOS) */ 242930088Sminshall # if !defined(TN3270) 243030088Sminshall if (TTYROOM()) { 243130088Sminshall FD_SET(net, &ibits); 243230088Sminshall } 243330088Sminshall # else /* !defined(TN3270) */ 243430088Sminshall if (!ISend && TTYROOM()) { 243530088Sminshall FD_SET(net, &ibits); 243630088Sminshall } 243730088Sminshall # endif /* !defined(TN3270) */ 243830088Sminshall if (!SYNCHing) { 243930088Sminshall FD_SET(net, &xbits); 244030088Sminshall } 244130088Sminshall # if defined(TN3270) && defined(unix) 244230088Sminshall if (HaveInput) { 244330088Sminshall HaveInput = 0; 244430088Sminshall signal(SIGIO, inputAvailable); 244530088Sminshall } 244630088Sminshall #endif /* defined(TN3270) && defined(unix) */ 244730088Sminshall if ((c = select(16, &ibits, &obits, &xbits, 244831131Sminshall block? (struct timeval *)0 : &TimeValue)) < 0) { 244930088Sminshall if (c == -1) { 245030088Sminshall /* 245130088Sminshall * we can get EINTR if we are in line mode, 245230088Sminshall * and the user does an escape (TSTP), or 245330088Sminshall * some other signal generator. 245430088Sminshall */ 245530088Sminshall if (errno == EINTR) { 245630088Sminshall return 0; 245730088Sminshall } 245830088Sminshall # if defined(TN3270) 245930088Sminshall /* 246030088Sminshall * we can get EBADF if we were in transparent 246130088Sminshall * mode, and the transcom process died. 246230088Sminshall */ 246330088Sminshall if (errno == EBADF) { 246430088Sminshall /* 246530088Sminshall * zero the bits (even though kernel does it) 246630088Sminshall * to make sure we are selecting on the right 246730088Sminshall * ones. 246830088Sminshall */ 246930088Sminshall FD_ZERO(&ibits); 247030088Sminshall FD_ZERO(&obits); 247130088Sminshall FD_ZERO(&xbits); 247230088Sminshall return 0; 247330088Sminshall } 247430088Sminshall # endif /* defined(TN3270) */ 247530088Sminshall /* I don't like this, does it ever happen? */ 247630088Sminshall printf("sleep(5) from telnet, after select\r\n"); 247730088Sminshall #if defined(unix) 247830088Sminshall sleep(5); 247930088Sminshall #endif /* defined(unix) */ 248030088Sminshall } 248130088Sminshall return 0; 248230088Sminshall } 248330088Sminshall 248430088Sminshall /* 248530088Sminshall * Any urgent data? 248630088Sminshall */ 248730088Sminshall if (FD_ISSET(net, &xbits)) { 248830088Sminshall FD_CLR(net, &xbits); 248930088Sminshall SYNCHing = 1; 249030088Sminshall ttyflush(); /* flush already enqueued data */ 249130088Sminshall } 249230088Sminshall 249330088Sminshall /* 249430088Sminshall * Something to read from the network... 249530088Sminshall */ 249630088Sminshall if (FD_ISSET(net, &ibits)) { 249730088Sminshall int canread; 249830088Sminshall 249930088Sminshall FD_CLR(net, &ibits); 250030088Sminshall if (scc == 0) { 250130088Sminshall sbp = sibuf; 250230088Sminshall } 250330422Sminshall canread = sibuf + sizeof sibuf - (sbp+scc); 250430088Sminshall #if !defined(SO_OOBINLINE) 250530088Sminshall /* 250630088Sminshall * In 4.2 (and some early 4.3) systems, the 250730088Sminshall * OOB indication and data handling in the kernel 250830088Sminshall * is such that if two separate TCP Urgent requests 250930088Sminshall * come in, one byte of TCP data will be overlaid. 251030088Sminshall * This is fatal for Telnet, but we try to live 251130088Sminshall * with it. 251230088Sminshall * 251330088Sminshall * In addition, in 4.2 (and...), a special protocol 251430088Sminshall * is needed to pick up the TCP Urgent data in 251530088Sminshall * the correct sequence. 251630088Sminshall * 251730088Sminshall * What we do is: if we think we are in urgent 251830088Sminshall * mode, we look to see if we are "at the mark". 251930088Sminshall * If we are, we do an OOB receive. If we run 252030088Sminshall * this twice, we will do the OOB receive twice, 252130088Sminshall * but the second will fail, since the second 252230088Sminshall * time we were "at the mark", but there wasn't 252330088Sminshall * any data there (the kernel doesn't reset 252430088Sminshall * "at the mark" until we do a normal read). 252530088Sminshall * Once we've read the OOB data, we go ahead 252630088Sminshall * and do normal reads. 252730088Sminshall * 252830088Sminshall * There is also another problem, which is that 252930088Sminshall * since the OOB byte we read doesn't put us 253030088Sminshall * out of OOB state, and since that byte is most 253130088Sminshall * likely the TELNET DM (data mark), we would 253230088Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 253330088Sminshall * So, clocks to the rescue. If we've "just" 253430088Sminshall * received a DM, then we test for the 253530088Sminshall * presence of OOB data when the receive OOB 253630088Sminshall * fails (and AFTER we did the normal mode read 253730088Sminshall * to clear "at the mark"). 253830088Sminshall */ 253930088Sminshall if (SYNCHing) { 254030088Sminshall int atmark; 254130088Sminshall 254230088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 254330088Sminshall if (atmark) { 254430422Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 254530088Sminshall if ((c == -1) && (errno == EINVAL)) { 254631131Sminshall c = recv(net, sbp+scc, canread, 0); 254730088Sminshall if (clocks.didnetreceive < clocks.gotDM) { 254830088Sminshall SYNCHing = stilloob(net); 254930088Sminshall } 255030088Sminshall } 255130088Sminshall } else { 255231131Sminshall c = recv(net, sbp+scc, canread, 0); 255330088Sminshall } 255430088Sminshall } else { 255531131Sminshall c = recv(net, sbp+scc, canread, 0); 255630088Sminshall } 255730088Sminshall settimer(didnetreceive); 255830088Sminshall #else /* !defined(SO_OOBINLINE) */ 255931131Sminshall c = recv(net, sbp+scc, canread, 0); 256030088Sminshall #endif /* !defined(SO_OOBINLINE) */ 256130088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 256230088Sminshall c = 0; 256330088Sminshall } else if (c <= 0) { 256430088Sminshall return -1; 256530088Sminshall } 256630088Sminshall if (netdata) { 256730422Sminshall Dump('<', sbp+scc, c); 256830088Sminshall } 256930088Sminshall scc += c; 257030088Sminshall returnValue = 1; 257130088Sminshall } 257230088Sminshall 257330088Sminshall /* 257430088Sminshall * Something to read from the tty... 257530088Sminshall */ 257631131Sminshall #if defined(MSDOS) 257731215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead()) 257831131Sminshall #else /* defined(MSDOS) */ 257931131Sminshall if (FD_ISSET(tin, &ibits)) 258031131Sminshall #endif /* defined(MSDOS) */ 258131131Sminshall { 258230088Sminshall FD_CLR(tin, &ibits); 258330088Sminshall if (tcc == 0) { 258430088Sminshall tbp = tibuf; /* nothing left, reset */ 258530088Sminshall } 258631131Sminshall c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp); 258730088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 258830088Sminshall c = 0; 258930088Sminshall } else { 259031124Sminshall #if defined(unix) 259130088Sminshall /* EOF detection for line mode!!!! */ 259230088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 259330088Sminshall /* must be an EOF... */ 259430088Sminshall *tbp = ntc.t_eofc; 259530088Sminshall c = 1; 259630088Sminshall } 259731124Sminshall #endif /* defined(unix) */ 259830088Sminshall if (c <= 0) { 259930088Sminshall tcc = c; 260030088Sminshall return -1; 260130088Sminshall } 260230088Sminshall } 260330088Sminshall tcc += c; 260430088Sminshall returnValue = 1; /* did something useful */ 260530088Sminshall } 260630088Sminshall 260730088Sminshall # if defined(TN3270) 260830088Sminshall if (tcc > 0) { 260930088Sminshall if (In3270) { 261030088Sminshall c = DataFromTerminal(tbp, tcc); 261130088Sminshall if (c) { 261230088Sminshall returnValue = 1; 261330088Sminshall } 261430088Sminshall tcc -= c; 261530088Sminshall tbp += c; 261630088Sminshall } else { 261730320Sminshall # endif /* defined(TN3270) */ 261830088Sminshall returnValue = 1; 261930088Sminshall while (tcc > 0) { 262030088Sminshall register int sc; 262130088Sminshall 262230088Sminshall if (NETROOM() < 2) { 262330088Sminshall flushline = 1; 262430088Sminshall break; 262530088Sminshall } 262630088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 262730088Sminshall if (sc == escape) { 262830088Sminshall command(0); 262930088Sminshall tcc = 0; 263030088Sminshall flushline = 1; 263130088Sminshall break; 263230088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 263330088Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 263430088Sminshall tbp++; 263530088Sminshall tcc--; 263630088Sminshall } else { 263730088Sminshall dontlecho = !dontlecho; 263830088Sminshall settimer(echotoggle); 263930088Sminshall setconnmode(); 264030088Sminshall tcc = 0; 264130088Sminshall flushline = 1; 264230088Sminshall break; 264330088Sminshall } 264430088Sminshall } 264530088Sminshall if (localchars) { 264631131Sminshall if (TerminalSpecialChars(sc) == 0) { 264730088Sminshall break; 264830088Sminshall } 264930088Sminshall } 265030088Sminshall switch (c) { 265130088Sminshall case '\n': 265230088Sminshall /* 265330088Sminshall * If we are in CRMOD mode (\r ==> \n) 265430088Sminshall * on our local machine, then probably 265530088Sminshall * a newline (unix) is CRLF (TELNET). 265630088Sminshall */ 265730088Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 265830088Sminshall NETADD('\r'); 265930088Sminshall } 266030088Sminshall NETADD('\n'); 266130088Sminshall flushline = 1; 266230088Sminshall break; 266330088Sminshall case '\r': 266430088Sminshall NET2ADD('\r', '\0'); 266530088Sminshall flushline = 1; 266630088Sminshall break; 266730088Sminshall case IAC: 266830088Sminshall NET2ADD(IAC, IAC); 266930088Sminshall break; 267030088Sminshall default: 267130088Sminshall NETADD(c); 267230088Sminshall break; 267330088Sminshall } 267430088Sminshall } 267530088Sminshall # if defined(TN3270) 267630088Sminshall } 267730088Sminshall } 267830088Sminshall # endif /* defined(TN3270) */ 267930088Sminshall 268030088Sminshall if ((!MODE_LINE(globalmode) || flushline) && 268130088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 268230088Sminshall FD_CLR(net, &obits); 268330088Sminshall returnValue = netflush(); 268430088Sminshall } 268530088Sminshall if (scc > 0) { 268630088Sminshall # if !defined(TN3270) 268730088Sminshall telrcv(); 268830088Sminshall returnValue = 1; 268930088Sminshall # else /* !defined(TN3270) */ 269030088Sminshall returnValue = Push3270(); 269130088Sminshall # endif /* !defined(TN3270) */ 269230088Sminshall } 269331131Sminshall #if defined(MSDOS) 269431131Sminshall if (TTYBYTES()) 269531131Sminshall #else /* defined(MSDOS) */ 269631131Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 269731131Sminshall #endif /* defined(MSDOS) */ 269831131Sminshall { 269930088Sminshall FD_CLR(tout, &obits); 270030088Sminshall returnValue = ttyflush(); 270130088Sminshall } 270230088Sminshall return returnValue; 270330088Sminshall } 270430088Sminshall 270530088Sminshall /* 270630088Sminshall * Select from tty and network... 270730088Sminshall */ 270830088Sminshall static void 270930088Sminshall telnet() 271030088Sminshall { 271131131Sminshall #if defined(MSDOS) 271231131Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */ 271331131Sminshall #else /* defined(MSDOS) */ 271431131Sminshall #define SCHED_BLOCK 1 271531131Sminshall #endif /* defined(MSDOS) */ 271631131Sminshall 271730088Sminshall #if defined(TN3270) && defined(unix) 271830088Sminshall int myPid; 271930088Sminshall #endif /* defined(TN3270) */ 272030088Sminshall 272130088Sminshall tout = fileno(stdout); 272230088Sminshall tin = fileno(stdin); 272330088Sminshall setconnmode(); 272430088Sminshall scc = 0; 272530088Sminshall tcc = 0; 272630088Sminshall FD_ZERO(&ibits); 272730088Sminshall FD_ZERO(&obits); 272830088Sminshall FD_ZERO(&xbits); 272930088Sminshall 273031124Sminshall NetNonblockingIO(net, 1); 273130088Sminshall 273230088Sminshall #if defined(TN3270) 273331478Sminshall if (noasynch == 0) { /* DBX can't handle! */ 273431478Sminshall NetSigIO(net, 1); 273531478Sminshall } 273631124Sminshall NetSetPgrp(net); 273730088Sminshall #endif /* defined(TN3270) */ 273830088Sminshall 273930088Sminshall 274031124Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 274131124Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 274231124Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 274331124Sminshall 274430320Sminshall # if !defined(TN3270) 274530088Sminshall if (telnetport) { 274630088Sminshall if (!hisopts[TELOPT_SGA]) { 274730088Sminshall willoption(TELOPT_SGA, 0); 274830088Sminshall } 274930088Sminshall if (!myopts[TELOPT_TTYPE]) { 275030088Sminshall dooption(TELOPT_TTYPE, 0); 275130088Sminshall } 275230088Sminshall } 275330320Sminshall # endif /* !defined(TN3270) */ 275430088Sminshall 275530088Sminshall # if !defined(TN3270) 275630088Sminshall for (;;) { 275731131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 275830088Sminshall setcommandmode(); 275930088Sminshall return; 276030088Sminshall } 276130088Sminshall } 276230088Sminshall # else /* !defined(TN3270) */ 276330088Sminshall for (;;) { 276430088Sminshall int schedValue; 276530088Sminshall 2766*31791Sminshall while (!In3270 && !shell_active) { 276731131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 276830088Sminshall setcommandmode(); 276930088Sminshall return; 277030088Sminshall } 277130088Sminshall } 277230088Sminshall 277330088Sminshall while ((schedValue = Scheduler(0)) != 0) { 277430088Sminshall if (schedValue == -1) { 277530088Sminshall setcommandmode(); 277630088Sminshall return; 277730088Sminshall } 277830088Sminshall } 277930088Sminshall /* If there is data waiting to go out to terminal, don't 278030088Sminshall * schedule any more data for the terminal. 278130088Sminshall */ 278230088Sminshall if (tfrontp-tbackp) { 278330088Sminshall schedValue = 1; 278430088Sminshall } else { 278531215Sminshall if (shell_active) { 278631215Sminshall if (shell_continue() == 0) { 278731215Sminshall ConnectScreen(); 278831215Sminshall } 2789*31791Sminshall } else if (In3270) { 279031215Sminshall schedValue = DoTerminalOutput(); 279131215Sminshall } 279230088Sminshall } 279331215Sminshall if (schedValue && (shell_active == 0)) { 279431131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 279530088Sminshall setcommandmode(); 279630088Sminshall return; 279730088Sminshall } 279830088Sminshall } 279930088Sminshall } 280030088Sminshall # endif /* !defined(TN3270) */ 280130088Sminshall } 280230088Sminshall 280330088Sminshall /* 280430088Sminshall * The following are data structures and routines for 280530088Sminshall * the "send" command. 280630088Sminshall * 280730088Sminshall */ 280830088Sminshall 280930088Sminshall struct sendlist { 281030088Sminshall char *name; /* How user refers to it (case independent) */ 281130088Sminshall int what; /* Character to be sent (<0 ==> special) */ 281230088Sminshall char *help; /* Help information (0 ==> no help) */ 281330088Sminshall #if defined(NOT43) 281430088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 281530088Sminshall #else /* defined(NOT43) */ 281630088Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 281730088Sminshall #endif /* defined(NOT43) */ 281830088Sminshall }; 281930088Sminshall 282030088Sminshall #define SENDQUESTION -1 282130088Sminshall #define SENDESCAPE -3 282230088Sminshall 282330088Sminshall static struct sendlist Sendlist[] = { 282430088Sminshall { "ao", AO, "Send Telnet Abort output" }, 282530088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 282630088Sminshall { "brk", BREAK, "Send Telnet Break" }, 282730088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 282830088Sminshall { "el", EL, "Send Telnet Erase Line" }, 282930088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 283030088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 283130088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 283230088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 283330088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 283430088Sminshall { "?", SENDQUESTION, "Display send options" }, 283530088Sminshall { 0 } 283630088Sminshall }; 283730088Sminshall 283830088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 283930088Sminshall { "break", BREAK, 0 }, 284030088Sminshall 284130088Sminshall { "intp", IP, 0 }, 284230088Sminshall { "interrupt", IP, 0 }, 284330088Sminshall { "intr", IP, 0 }, 284430088Sminshall 284530088Sminshall { "help", SENDQUESTION, 0 }, 284630088Sminshall 284730088Sminshall { 0 } 284830088Sminshall }; 284930088Sminshall 285030088Sminshall static char ** 285130088Sminshall getnextsend(name) 285230088Sminshall char *name; 285330088Sminshall { 285430088Sminshall struct sendlist *c = (struct sendlist *) name; 285530088Sminshall 285630088Sminshall return (char **) (c+1); 285730088Sminshall } 285830088Sminshall 285930088Sminshall static struct sendlist * 286030088Sminshall getsend(name) 286130088Sminshall char *name; 286230088Sminshall { 286330088Sminshall struct sendlist *sl; 286430088Sminshall 286530088Sminshall if ((sl = (struct sendlist *) 286630088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 286730088Sminshall return sl; 286830088Sminshall } else { 286930088Sminshall return (struct sendlist *) 287030088Sminshall genget(name, (char **) Sendlist2, getnextsend); 287130088Sminshall } 287230088Sminshall } 287330088Sminshall 287430088Sminshall static 287530088Sminshall sendcmd(argc, argv) 287630088Sminshall int argc; 287730088Sminshall char **argv; 287830088Sminshall { 287930088Sminshall int what; /* what we are sending this time */ 288030088Sminshall int count; /* how many bytes we are going to need to send */ 288130088Sminshall int i; 288230088Sminshall int question = 0; /* was at least one argument a question */ 288330088Sminshall struct sendlist *s; /* pointer to current command */ 288430088Sminshall 288530088Sminshall if (argc < 2) { 288630088Sminshall printf("need at least one argument for 'send' command\n"); 288730088Sminshall printf("'send ?' for help\n"); 288830088Sminshall return 0; 288930088Sminshall } 289030088Sminshall /* 289130088Sminshall * First, validate all the send arguments. 289230088Sminshall * In addition, we see how much space we are going to need, and 289330088Sminshall * whether or not we will be doing a "SYNCH" operation (which 289430088Sminshall * flushes the network queue). 289530088Sminshall */ 289630088Sminshall count = 0; 289730088Sminshall for (i = 1; i < argc; i++) { 289830088Sminshall s = getsend(argv[i]); 289930088Sminshall if (s == 0) { 290030088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 290130088Sminshall argv[i]); 290230088Sminshall return 0; 290330088Sminshall } else if (s == Ambiguous(struct sendlist *)) { 290430088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 290530088Sminshall argv[i]); 290630088Sminshall return 0; 290730088Sminshall } 290830088Sminshall switch (s->what) { 290930088Sminshall case SENDQUESTION: 291030088Sminshall break; 291130088Sminshall case SENDESCAPE: 291230088Sminshall count += 1; 291330088Sminshall break; 291430088Sminshall case SYNCH: 291530088Sminshall count += 2; 291630088Sminshall break; 291730088Sminshall default: 291830088Sminshall count += 2; 291930088Sminshall break; 292030088Sminshall } 292130088Sminshall } 292230088Sminshall /* Now, do we have enough room? */ 292330088Sminshall if (NETROOM() < count) { 292430088Sminshall printf("There is not enough room in the buffer TO the network\n"); 292530088Sminshall printf("to process your request. Nothing will be done.\n"); 292630088Sminshall printf("('send synch' will throw away most data in the network\n"); 292730088Sminshall printf("buffer, if this might help.)\n"); 292830088Sminshall return 0; 292930088Sminshall } 293030088Sminshall /* OK, they are all OK, now go through again and actually send */ 293130088Sminshall for (i = 1; i < argc; i++) { 293230088Sminshall if ((s = getsend(argv[i])) == 0) { 293330088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 293430088Sminshall quit(); 293530088Sminshall /*NOTREACHED*/ 293630088Sminshall } 293730088Sminshall if (s->routine) { 293830088Sminshall (*s->routine)(s); 293930088Sminshall } else { 294030088Sminshall switch (what = s->what) { 294130088Sminshall case SYNCH: 294230088Sminshall dosynch(); 294330088Sminshall break; 294430088Sminshall case SENDQUESTION: 294530088Sminshall for (s = Sendlist; s->name; s++) { 294630088Sminshall if (s->help) { 294730088Sminshall printf(s->name); 294830088Sminshall if (s->help) { 294930088Sminshall printf("\t%s", s->help); 295030088Sminshall } 295130088Sminshall printf("\n"); 295230088Sminshall } 295330088Sminshall } 295430088Sminshall question = 1; 295530088Sminshall break; 295630088Sminshall case SENDESCAPE: 295730088Sminshall NETADD(escape); 295830088Sminshall break; 295930088Sminshall default: 296030088Sminshall NET2ADD(IAC, what); 296130088Sminshall break; 296230088Sminshall } 296330088Sminshall } 296430088Sminshall } 296530088Sminshall return !question; 296630088Sminshall } 296730088Sminshall 296830088Sminshall /* 296930088Sminshall * The following are the routines and data structures referred 297030088Sminshall * to by the arguments to the "toggle" command. 297130088Sminshall */ 297230088Sminshall 297330088Sminshall static 297430088Sminshall lclchars() 297530088Sminshall { 297630088Sminshall donelclchars = 1; 297730088Sminshall return 1; 297830088Sminshall } 297930088Sminshall 298030088Sminshall static 298130088Sminshall togdebug() 298230088Sminshall { 298330088Sminshall #ifndef NOT43 298430088Sminshall if (net > 0 && 298531124Sminshall (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 298630088Sminshall perror("setsockopt (SO_DEBUG)"); 298730088Sminshall } 298830320Sminshall #else /* NOT43 */ 298930088Sminshall if (debug) { 299031124Sminshall if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 299130088Sminshall perror("setsockopt (SO_DEBUG)"); 299230088Sminshall } else 299330088Sminshall printf("Cannot turn off socket debugging\n"); 299430320Sminshall #endif /* NOT43 */ 299530088Sminshall return 1; 299630088Sminshall } 299730088Sminshall 299830088Sminshall 2999*31791Sminshall static int 3000*31791Sminshall togbinary() 3001*31791Sminshall { 3002*31791Sminshall donebinarytoggle = 1; 300330088Sminshall 3004*31791Sminshall if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */ 3005*31791Sminshall NET2ADD(IAC, DO); 3006*31791Sminshall NETADD(TELOPT_BINARY); 3007*31791Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0); 3008*31791Sminshall NET2ADD(IAC, WILL); 3009*31791Sminshall NETADD(TELOPT_BINARY); 3010*31791Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0); 3011*31791Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1; 3012*31791Sminshall printf("Negotiating binary mode with remote host.\n"); 3013*31791Sminshall } else { /* Turn off binary mode */ 3014*31791Sminshall NET2ADD(IAC, DONT); 3015*31791Sminshall NETADD(TELOPT_BINARY); 3016*31791Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0); 3017*31791Sminshall NET2ADD(IAC, DONT); 3018*31791Sminshall NETADD(TELOPT_BINARY); 3019*31791Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0); 3020*31791Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0; 3021*31791Sminshall printf("Negotiating network ascii mode with remote host.\n"); 3022*31791Sminshall } 3023*31791Sminshall return 1; 3024*31791Sminshall } 3025*31791Sminshall 3026*31791Sminshall 3027*31791Sminshall 302830088Sminshall extern int togglehelp(); 302930088Sminshall 303030088Sminshall struct togglelist { 303130088Sminshall char *name; /* name of toggle */ 303230088Sminshall char *help; /* help message */ 303330088Sminshall int (*handler)(); /* routine to do actual setting */ 303430088Sminshall int dohelp; /* should we display help information */ 303530088Sminshall int *variable; 303630088Sminshall char *actionexplanation; 303730088Sminshall }; 303830088Sminshall 303930088Sminshall static struct togglelist Togglelist[] = { 304030088Sminshall { "autoflush", 304130088Sminshall "toggle flushing of output when sending interrupt characters", 304230088Sminshall 0, 304330088Sminshall 1, 304430088Sminshall &autoflush, 304530088Sminshall "flush output when sending interrupt characters" }, 304630088Sminshall { "autosynch", 304730088Sminshall "toggle automatic sending of interrupt characters in urgent mode", 304830088Sminshall 0, 304930088Sminshall 1, 305030088Sminshall &autosynch, 305130088Sminshall "send interrupt characters in urgent mode" }, 3052*31791Sminshall { "binary", 3053*31791Sminshall "toggle sending and receiving of binary data", 3054*31791Sminshall togbinary, 3055*31791Sminshall 1, 3056*31791Sminshall 0, 3057*31791Sminshall "send and receive network data in binary mode" }, 305830088Sminshall { "crmod", 305930088Sminshall "toggle mapping of received carriage returns", 306030088Sminshall 0, 306130088Sminshall 1, 306230088Sminshall &crmod, 306330088Sminshall "map carriage return on output" }, 306430088Sminshall { "localchars", 306530088Sminshall "toggle local recognition of certain control characters", 306630088Sminshall lclchars, 306730088Sminshall 1, 306830088Sminshall &localchars, 306930088Sminshall "recognize certain control characters" }, 307030088Sminshall { " ", "", 0, 1 }, /* empty line */ 307130088Sminshall { "debug", 307230088Sminshall "(debugging) toggle debugging", 307330088Sminshall togdebug, 307430088Sminshall 1, 307530088Sminshall &debug, 307630088Sminshall "turn on socket level debugging" }, 307730088Sminshall { "netdata", 307830088Sminshall "(debugging) toggle printing of hexadecimal network data", 307930088Sminshall 0, 308030088Sminshall 1, 308130088Sminshall &netdata, 308230088Sminshall "print hexadecimal representation of network traffic" }, 308330088Sminshall { "options", 308430088Sminshall "(debugging) toggle viewing of options processing", 308530088Sminshall 0, 308630088Sminshall 1, 308730088Sminshall &showoptions, 308830088Sminshall "show option processing" }, 308930088Sminshall { " ", "", 0, 1 }, /* empty line */ 309030088Sminshall { "?", 309130088Sminshall "display help information", 309230088Sminshall togglehelp, 309330088Sminshall 1 }, 309430088Sminshall { "help", 309530088Sminshall "display help information", 309630088Sminshall togglehelp, 309730088Sminshall 0 }, 309830088Sminshall { 0 } 309930088Sminshall }; 310030088Sminshall 310130088Sminshall static 310230088Sminshall togglehelp() 310330088Sminshall { 310430088Sminshall struct togglelist *c; 310530088Sminshall 310630088Sminshall for (c = Togglelist; c->name; c++) { 310730088Sminshall if (c->dohelp) { 310830088Sminshall printf("%s\t%s\n", c->name, c->help); 310930088Sminshall } 311030088Sminshall } 311130088Sminshall return 0; 311230088Sminshall } 311330088Sminshall 311430088Sminshall static char ** 311530088Sminshall getnexttoggle(name) 311630088Sminshall char *name; 311730088Sminshall { 311830088Sminshall struct togglelist *c = (struct togglelist *) name; 311930088Sminshall 312030088Sminshall return (char **) (c+1); 312130088Sminshall } 312230088Sminshall 312330088Sminshall static struct togglelist * 312430088Sminshall gettoggle(name) 312530088Sminshall char *name; 312630088Sminshall { 312730088Sminshall return (struct togglelist *) 312830088Sminshall genget(name, (char **) Togglelist, getnexttoggle); 312930088Sminshall } 313030088Sminshall 313130088Sminshall static 313230088Sminshall toggle(argc, argv) 313330088Sminshall int argc; 313430088Sminshall char *argv[]; 313530088Sminshall { 313630088Sminshall int retval = 1; 313730088Sminshall char *name; 313830088Sminshall struct togglelist *c; 313930088Sminshall 314030088Sminshall if (argc < 2) { 314130088Sminshall fprintf(stderr, 314230088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 314330088Sminshall return 0; 314430088Sminshall } 314530088Sminshall argc--; 314630088Sminshall argv++; 314730088Sminshall while (argc--) { 314830088Sminshall name = *argv++; 314930088Sminshall c = gettoggle(name); 315030088Sminshall if (c == Ambiguous(struct togglelist *)) { 315130088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 315230088Sminshall name); 315330088Sminshall return 0; 315430088Sminshall } else if (c == 0) { 315530088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 315630088Sminshall name); 315730088Sminshall return 0; 315830088Sminshall } else { 315930088Sminshall if (c->variable) { 316030088Sminshall *c->variable = !*c->variable; /* invert it */ 316130088Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 316230088Sminshall c->actionexplanation); 316330088Sminshall } 316430088Sminshall if (c->handler) { 316530088Sminshall retval &= (*c->handler)(c); 316630088Sminshall } 316730088Sminshall } 316830088Sminshall } 316930088Sminshall return retval; 317030088Sminshall } 317130088Sminshall 317230088Sminshall /* 317330088Sminshall * The following perform the "set" command. 317430088Sminshall */ 317530088Sminshall 317630088Sminshall struct setlist { 317730088Sminshall char *name; /* name */ 317830088Sminshall char *help; /* help information */ 317930088Sminshall char *charp; /* where it is located at */ 318030088Sminshall }; 318130088Sminshall 318230088Sminshall static struct setlist Setlist[] = { 318330088Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 318430088Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 318530088Sminshall { " ", "" }, 318630088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 318731124Sminshall #if defined(unix) 318830088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 318930088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 319030088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 319130088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 319230088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 319330088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 319431124Sminshall #endif /* defined(unix) */ 319531124Sminshall #if defined(MSDOS) 319631124Sminshall { "erase", "character to cause an Erase Character", &termEraseChar }, 319731124Sminshall { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 319831124Sminshall { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 319931124Sminshall { "kill", "character to cause an Erase Line", &termKillChar }, 320031124Sminshall { "quit", "character to cause a Break", &termQuitChar }, 320131124Sminshall { "eof", "character to cause an EOF ", &termEofChar }, 320231124Sminshall #endif /* defined(MSDOS) */ 320330088Sminshall { 0 } 320430088Sminshall }; 320530088Sminshall 320630088Sminshall static char ** 320730088Sminshall getnextset(name) 320830088Sminshall char *name; 320930088Sminshall { 321030088Sminshall struct setlist *c = (struct setlist *)name; 321130088Sminshall 321230088Sminshall return (char **) (c+1); 321330088Sminshall } 321430088Sminshall 321530088Sminshall static struct setlist * 321630088Sminshall getset(name) 321730088Sminshall char *name; 321830088Sminshall { 321930088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 322030088Sminshall } 322130088Sminshall 322230088Sminshall static 322330088Sminshall setcmd(argc, argv) 322430088Sminshall int argc; 322530088Sminshall char *argv[]; 322630088Sminshall { 322730088Sminshall int value; 322830088Sminshall struct setlist *ct; 322930088Sminshall 323030088Sminshall /* XXX back we go... sigh */ 323130088Sminshall if (argc != 3) { 323230088Sminshall if ((argc == 2) && 323330088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 323430088Sminshall for (ct = Setlist; ct->name; ct++) { 323530088Sminshall printf("%s\t%s\n", ct->name, ct->help); 323630088Sminshall } 323730088Sminshall printf("?\tdisplay help information\n"); 323830088Sminshall } else { 323930088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 324030088Sminshall } 324130088Sminshall return 0; 324230088Sminshall } 324330088Sminshall 324430088Sminshall ct = getset(argv[1]); 324530088Sminshall if (ct == 0) { 324630088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 324730088Sminshall argv[1]); 324830088Sminshall return 0; 324930088Sminshall } else if (ct == Ambiguous(struct setlist *)) { 325030088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 325130088Sminshall argv[1]); 325230088Sminshall return 0; 325330088Sminshall } else { 325430088Sminshall if (strcmp("off", argv[2])) { 325530088Sminshall value = special(argv[2]); 325630088Sminshall } else { 325730088Sminshall value = -1; 325830088Sminshall } 325930088Sminshall *(ct->charp) = value; 326030088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 326130088Sminshall } 326230088Sminshall return 1; 326330088Sminshall } 326430088Sminshall 326530088Sminshall /* 326630088Sminshall * The following are the data structures and routines for the 326730088Sminshall * 'mode' command. 326830088Sminshall */ 326930088Sminshall 327030088Sminshall static 327130088Sminshall dolinemode() 327230088Sminshall { 327330088Sminshall if (hisopts[TELOPT_SGA]) { 327430088Sminshall wontoption(TELOPT_SGA, 0); 327530088Sminshall } 327630088Sminshall if (hisopts[TELOPT_ECHO]) { 327730088Sminshall wontoption(TELOPT_ECHO, 0); 327830088Sminshall } 327930088Sminshall return 1; 328030088Sminshall } 328130088Sminshall 328230088Sminshall static 328330088Sminshall docharmode() 328430088Sminshall { 328530088Sminshall if (!hisopts[TELOPT_SGA]) { 328630088Sminshall willoption(TELOPT_SGA, 0); 328730088Sminshall } 328830088Sminshall if (!hisopts[TELOPT_ECHO]) { 328930088Sminshall willoption(TELOPT_ECHO, 0); 329030088Sminshall } 329130088Sminshall return 1; 329230088Sminshall } 329330088Sminshall 329430088Sminshall static struct cmd Modelist[] = { 329530088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 329630088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 329730088Sminshall { 0 }, 329830088Sminshall }; 329930088Sminshall 330030088Sminshall static char ** 330130088Sminshall getnextmode(name) 330230088Sminshall char *name; 330330088Sminshall { 330430088Sminshall struct cmd *c = (struct cmd *) name; 330530088Sminshall 330630088Sminshall return (char **) (c+1); 330730088Sminshall } 330830088Sminshall 330930088Sminshall static struct cmd * 331030088Sminshall getmodecmd(name) 331130088Sminshall char *name; 331230088Sminshall { 331330088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 331430088Sminshall } 331530088Sminshall 331630088Sminshall static 331730088Sminshall modecmd(argc, argv) 331830088Sminshall int argc; 331930088Sminshall char *argv[]; 332030088Sminshall { 332130088Sminshall struct cmd *mt; 332230088Sminshall 332330088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 332430088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 332530088Sminshall for (mt = Modelist; mt->name; mt++) { 332630088Sminshall printf("%s\t%s\n", mt->name, mt->help); 332730088Sminshall } 332830088Sminshall return 0; 332930088Sminshall } 333030088Sminshall mt = getmodecmd(argv[1]); 333130088Sminshall if (mt == 0) { 333230088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 333330088Sminshall return 0; 333430088Sminshall } else if (mt == Ambiguous(struct cmd *)) { 333530088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 333630088Sminshall return 0; 333730088Sminshall } else { 333830088Sminshall (*mt->handler)(); 333930088Sminshall } 334030088Sminshall return 1; 334130088Sminshall } 334230088Sminshall 334330088Sminshall /* 334430088Sminshall * The following data structures and routines implement the 334530088Sminshall * "display" command. 334630088Sminshall */ 334730088Sminshall 334830088Sminshall static 334930088Sminshall display(argc, argv) 335030088Sminshall int argc; 335130088Sminshall char *argv[]; 335230088Sminshall { 335330088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 335430088Sminshall if (*tl->variable) { \ 335530088Sminshall printf("will"); \ 335630088Sminshall } else { \ 335730088Sminshall printf("won't"); \ 335830088Sminshall } \ 335930088Sminshall printf(" %s.\n", tl->actionexplanation); \ 336030088Sminshall } 336130088Sminshall 336230088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 336330088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 336430088Sminshall } 336530088Sminshall 336630088Sminshall struct togglelist *tl; 336730088Sminshall struct setlist *sl; 336830088Sminshall 336930088Sminshall if (argc == 1) { 337030088Sminshall for (tl = Togglelist; tl->name; tl++) { 337130088Sminshall dotog(tl); 337230088Sminshall } 337330088Sminshall printf("\n"); 337430088Sminshall for (sl = Setlist; sl->name; sl++) { 337530088Sminshall doset(sl); 337630088Sminshall } 337730088Sminshall } else { 337830088Sminshall int i; 337930088Sminshall 338030088Sminshall for (i = 1; i < argc; i++) { 338130088Sminshall sl = getset(argv[i]); 338230088Sminshall tl = gettoggle(argv[i]); 338330088Sminshall if ((sl == Ambiguous(struct setlist *)) || 338430088Sminshall (tl == Ambiguous(struct togglelist *))) { 338530088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 338630088Sminshall return 0; 338730088Sminshall } else if (!sl && !tl) { 338830088Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 338930088Sminshall return 0; 339030088Sminshall } else { 339130088Sminshall if (tl) { 339230088Sminshall dotog(tl); 339330088Sminshall } 339430088Sminshall if (sl) { 339530088Sminshall doset(sl); 339630088Sminshall } 339730088Sminshall } 339830088Sminshall } 339930088Sminshall } 340030088Sminshall return 1; 340130088Sminshall #undef doset 340230088Sminshall #undef dotog 340330088Sminshall } 340430088Sminshall 340530088Sminshall /* 340630088Sminshall * The following are the data structures, and many of the routines, 340730088Sminshall * relating to command processing. 340830088Sminshall */ 340930088Sminshall 341030088Sminshall /* 341130088Sminshall * Set the escape character. 341230088Sminshall */ 341330088Sminshall static 341430088Sminshall setescape(argc, argv) 341530088Sminshall int argc; 341630088Sminshall char *argv[]; 341730088Sminshall { 341830088Sminshall register char *arg; 341930088Sminshall char buf[50]; 342030088Sminshall 342130088Sminshall printf( 342230088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 342330088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 342430088Sminshall if (argc > 2) 342530088Sminshall arg = argv[1]; 342630088Sminshall else { 342730088Sminshall printf("new escape character: "); 342830088Sminshall gets(buf); 342930088Sminshall arg = buf; 343030088Sminshall } 343130088Sminshall if (arg[0] != '\0') 343230088Sminshall escape = arg[0]; 343330088Sminshall if (!In3270) { 343430088Sminshall printf("Escape character is '%s'.\n", control(escape)); 343530088Sminshall } 343630088Sminshall fflush(stdout); 343730088Sminshall return 1; 343830088Sminshall } 343930088Sminshall 344030088Sminshall /*VARARGS*/ 344130088Sminshall static 344230088Sminshall togcrmod() 344330088Sminshall { 344430088Sminshall crmod = !crmod; 344530088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 344630088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 344730088Sminshall fflush(stdout); 344830088Sminshall return 1; 344930088Sminshall } 345030088Sminshall 345130088Sminshall /*VARARGS*/ 345230088Sminshall suspend() 345330088Sminshall { 345430088Sminshall setcommandmode(); 345530088Sminshall #if defined(unix) 345630088Sminshall kill(0, SIGTSTP); 345731215Sminshall #endif /* defined(unix) */ 345831124Sminshall /* reget parameters in case they were changed */ 345931124Sminshall TerminalSaveState(); 346031215Sminshall setconnmode(); 346130088Sminshall return 1; 346230088Sminshall } 346330088Sminshall 346430088Sminshall /*VARARGS*/ 346530088Sminshall static 346630326Sminshall bye(argc, argv) 346730326Sminshall int argc; /* Number of arguments */ 346830326Sminshall char *argv[]; /* arguments */ 346930088Sminshall { 347030088Sminshall if (connected) { 347130088Sminshall shutdown(net, 2); 347230088Sminshall printf("Connection closed.\n"); 347331131Sminshall NetClose(net); 347430088Sminshall connected = 0; 347530088Sminshall /* reset options */ 347630326Sminshall tninit(); 347730088Sminshall #if defined(TN3270) 347830326Sminshall SetIn3270(); /* Get out of 3270 mode */ 347930088Sminshall #endif /* defined(TN3270) */ 348030088Sminshall } 348130326Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 348230326Sminshall longjmp(toplevel, 1); 348330326Sminshall /* NOTREACHED */ 348430326Sminshall } 348530326Sminshall return 1; /* Keep lint, etc., happy */ 348630088Sminshall } 348730088Sminshall 348830088Sminshall /*VARARGS*/ 348930088Sminshall quit() 349030088Sminshall { 349130326Sminshall (void) call(bye, "bye", "fromquit", 0); 349230088Sminshall Exit(0); 349330088Sminshall /*NOTREACHED*/ 349430088Sminshall return 1; /* just to keep lint happy */ 349530088Sminshall } 349630088Sminshall 349730088Sminshall /* 349830088Sminshall * Print status about the connection. 349930088Sminshall */ 350030088Sminshall static 350130088Sminshall status(argc, argv) 350230088Sminshall int argc; 350330088Sminshall char *argv[]; 350430088Sminshall { 350530088Sminshall if (connected) { 350630088Sminshall printf("Connected to %s.\n", hostname); 350730088Sminshall if (argc < 2) { 350830088Sminshall printf("Operating in %s.\n", 350930088Sminshall modelist[getconnmode()].modedescriptions); 351030088Sminshall if (localchars) { 351130088Sminshall printf("Catching signals locally.\n"); 351230088Sminshall } 351330088Sminshall } 351430088Sminshall } else { 351530088Sminshall printf("No connection.\n"); 351630088Sminshall } 351730088Sminshall # if !defined(TN3270) 351830088Sminshall printf("Escape character is '%s'.\n", control(escape)); 351930088Sminshall fflush(stdout); 352030088Sminshall # else /* !defined(TN3270) */ 352130088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 352230088Sminshall printf("Escape character is '%s'.\n", control(escape)); 352330088Sminshall } 352430088Sminshall # if defined(unix) 352530088Sminshall if (In3270 && transcom) { 352630088Sminshall printf("Transparent mode command is '%s'.\n", transcom); 352730088Sminshall } 352830088Sminshall # endif /* defined(unix) */ 352930088Sminshall fflush(stdout); 353030088Sminshall if (In3270) { 353130088Sminshall return 0; 353230088Sminshall } 353330088Sminshall # endif /* defined(TN3270) */ 353430088Sminshall return 1; 353530088Sminshall } 353630088Sminshall 353730088Sminshall #if defined(TN3270) && defined(unix) 353830088Sminshall static 353930088Sminshall settranscom(argc, argv) 354030088Sminshall int argc; 354130088Sminshall char *argv[]; 354230088Sminshall { 354330088Sminshall int i, len = 0; 354430088Sminshall char *strcpy(), *strcat(); 354530088Sminshall 354630088Sminshall if (argc == 1 && transcom) { 354730088Sminshall transcom = 0; 354830088Sminshall } 354930088Sminshall if (argc == 1) { 355030088Sminshall return; 355130088Sminshall } 355230088Sminshall for (i = 1; i < argc; ++i) { 355330088Sminshall len += 1 + strlen(argv[1]); 355430088Sminshall } 355530088Sminshall transcom = tline; 355630088Sminshall (void) strcpy(transcom, argv[1]); 355730088Sminshall for (i = 2; i < argc; ++i) { 355830088Sminshall (void) strcat(transcom, " "); 355930088Sminshall (void) strcat(transcom, argv[i]); 356030088Sminshall } 356130088Sminshall } 356230088Sminshall #endif /* defined(TN3270) && defined(unix) */ 356330088Sminshall 356430088Sminshall 356531169Sminshall 356630088Sminshall static 356730088Sminshall tn(argc, argv) 356830088Sminshall int argc; 356930088Sminshall char *argv[]; 357030088Sminshall { 357130088Sminshall register struct hostent *host = 0; 357231131Sminshall #if defined(MSDOS) 357330088Sminshall char *cp; 357431131Sminshall #endif /* defined(MSDOS) */ 357530088Sminshall 357630088Sminshall if (connected) { 357730088Sminshall printf("?Already connected to %s\n", hostname); 357830088Sminshall return 0; 357930088Sminshall } 358030088Sminshall if (argc < 2) { 358130088Sminshall (void) strcpy(line, "Connect "); 358230088Sminshall printf("(to) "); 358330088Sminshall gets(&line[strlen(line)]); 358430088Sminshall makeargv(); 358530088Sminshall argc = margc; 358630088Sminshall argv = margv; 358730088Sminshall } 358830088Sminshall if (argc > 3) { 358930088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 359030088Sminshall return 0; 359130088Sminshall } 359231131Sminshall #if defined(MSDOS) 359330088Sminshall for (cp = argv[1]; *cp; cp++) { 359430088Sminshall if (isupper(*cp)) { 359530088Sminshall *cp = tolower(*cp); 359630088Sminshall } 359730088Sminshall } 359831131Sminshall #endif /* defined(MSDOS) */ 359930088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 360030088Sminshall if (sin.sin_addr.s_addr != -1) { 360130088Sminshall sin.sin_family = AF_INET; 360230088Sminshall (void) strcpy(hnamebuf, argv[1]); 360330088Sminshall hostname = hnamebuf; 360430088Sminshall } else { 360530088Sminshall host = gethostbyname(argv[1]); 360630088Sminshall if (host) { 360730088Sminshall sin.sin_family = host->h_addrtype; 360830088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 360931131Sminshall memcpy((caddr_t)&sin.sin_addr, 361031131Sminshall host->h_addr_list[0], host->h_length); 361130088Sminshall #else /* defined(h_addr) */ 361231131Sminshall memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 361330088Sminshall #endif /* defined(h_addr) */ 361430088Sminshall hostname = host->h_name; 361530088Sminshall } else { 361630088Sminshall printf("%s: unknown host\n", argv[1]); 361730088Sminshall return 0; 361830088Sminshall } 361930088Sminshall } 362030088Sminshall sin.sin_port = sp->s_port; 362130088Sminshall if (argc == 3) { 362230088Sminshall sin.sin_port = atoi(argv[2]); 362330088Sminshall if (sin.sin_port == 0) { 362430088Sminshall sp = getservbyname(argv[2], "tcp"); 362530088Sminshall if (sp) 362630088Sminshall sin.sin_port = sp->s_port; 362730088Sminshall else { 362830088Sminshall printf("%s: bad port number\n", argv[2]); 362930088Sminshall return 0; 363030088Sminshall } 363130088Sminshall } else { 363230088Sminshall sin.sin_port = atoi(argv[2]); 363330088Sminshall sin.sin_port = htons(sin.sin_port); 363430088Sminshall } 363530088Sminshall telnetport = 0; 363630088Sminshall } else { 363730088Sminshall telnetport = 1; 363830088Sminshall } 363930088Sminshall #if defined(unix) 364030088Sminshall signal(SIGINT, intr); 364130088Sminshall signal(SIGQUIT, intr2); 364230088Sminshall signal(SIGPIPE, deadpeer); 364330088Sminshall #endif /* defined(unix) */ 364430088Sminshall printf("Trying...\n"); 364530088Sminshall do { 364630088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 364730088Sminshall if (net < 0) { 364830088Sminshall perror("telnet: socket"); 364930088Sminshall return 0; 365030088Sminshall } 365131124Sminshall if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 365230088Sminshall perror("setsockopt (SO_DEBUG)"); 365331124Sminshall } 365430088Sminshall 365530088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 365630088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 365730088Sminshall if (host && host->h_addr_list[1]) { 365830088Sminshall int oerrno = errno; 365930088Sminshall 366030088Sminshall fprintf(stderr, "telnet: connect to address %s: ", 366130088Sminshall inet_ntoa(sin.sin_addr)); 366230088Sminshall errno = oerrno; 366330088Sminshall perror((char *)0); 366430088Sminshall host->h_addr_list++; 366531131Sminshall memcpy((caddr_t)&sin.sin_addr, 366631131Sminshall host->h_addr_list[0], host->h_length); 366730088Sminshall fprintf(stderr, "Trying %s...\n", 366830088Sminshall inet_ntoa(sin.sin_addr)); 366931131Sminshall (void) NetClose(net); 367030088Sminshall continue; 367130088Sminshall } 367230088Sminshall #endif /* defined(h_addr) */ 367330088Sminshall perror("telnet: Unable to connect to remote host"); 367430088Sminshall #if defined(unix) 367530088Sminshall signal(SIGINT, SIG_DFL); 367630088Sminshall signal(SIGQUIT, SIG_DFL); 367730320Sminshall #endif /* defined(unix) */ 367830088Sminshall return 0; 367930088Sminshall } 368030088Sminshall connected++; 368130088Sminshall } while (connected == 0); 368230088Sminshall call(status, "status", "notmuch", 0); 368330088Sminshall if (setjmp(peerdied) == 0) 368430088Sminshall telnet(); 368531131Sminshall NetClose(net); 368630088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1); 368730088Sminshall /*NOTREACHED*/ 368830088Sminshall } 368930088Sminshall 369030088Sminshall 369130088Sminshall #define HELPINDENT (sizeof ("connect")) 369230088Sminshall 369330088Sminshall static char 369430088Sminshall openhelp[] = "connect to a site", 369530088Sminshall closehelp[] = "close current connection", 369630088Sminshall quithelp[] = "exit telnet", 369730088Sminshall statushelp[] = "print status information", 369830088Sminshall helphelp[] = "print help information", 369930088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 370030088Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 370130088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 370230088Sminshall displayhelp[] = "display operating parameters", 370330088Sminshall #if defined(TN3270) && defined(unix) 370430088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 370530088Sminshall #endif /* defined(TN3270) && defined(unix) */ 370631169Sminshall #if defined(unix) 370731169Sminshall zhelp[] = "suspend telnet", 370831169Sminshall #endif /* defined(unix */ 370931478Sminshall #if defined(TN3270) 371031169Sminshall shellhelp[] = "invoke a subshell", 371131478Sminshall #endif /* defined(TN3270) */ 371230088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 371330088Sminshall 371431169Sminshall extern int help(), shell(); 371530088Sminshall 371630088Sminshall static struct cmd cmdtab[] = { 371730088Sminshall { "close", closehelp, bye, 1, 1 }, 371830088Sminshall { "display", displayhelp, display, 1, 0 }, 371930088Sminshall { "mode", modehelp, modecmd, 1, 1 }, 372030088Sminshall { "open", openhelp, tn, 1, 0 }, 372130088Sminshall { "quit", quithelp, quit, 1, 0 }, 372230088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 372330088Sminshall { "set", sethelp, setcmd, 1, 0 }, 372430088Sminshall { "status", statushelp, status, 1, 0 }, 372530088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 372630088Sminshall #if defined(TN3270) && defined(unix) 372730088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 372830088Sminshall #endif /* defined(TN3270) && defined(unix) */ 372931169Sminshall #if defined(unix) 373030088Sminshall { "z", zhelp, suspend, 1, 0 }, 373131169Sminshall #endif /* defined(unix) */ 373231478Sminshall #if defined(TN3270) 373331478Sminshall { "!", shellhelp, shell, 1, 1 }, 373431478Sminshall #endif /* defined(TN3270) */ 373530088Sminshall { "?", helphelp, help, 1, 0 }, 373630088Sminshall 0 373730088Sminshall }; 373830088Sminshall 373930088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 374030088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 374130088Sminshall 374230088Sminshall static struct cmd cmdtab2[] = { 374330088Sminshall { "help", helphelp, help, 0, 0 }, 374430088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 374530088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 374630088Sminshall 0 374730088Sminshall }; 374830088Sminshall 374930088Sminshall /* 375030088Sminshall * Call routine with argc, argv set from args (terminated by 0). 375130088Sminshall * VARARGS2 375230088Sminshall */ 375330088Sminshall static 375430088Sminshall call(routine, args) 375530088Sminshall int (*routine)(); 375630088Sminshall char *args; 375730088Sminshall { 375830088Sminshall register char **argp; 375930088Sminshall register int argc; 376030088Sminshall 376130088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 376230088Sminshall ; 376330088Sminshall return (*routine)(argc, &args); 376430088Sminshall } 376530088Sminshall 376630088Sminshall static char ** 376730088Sminshall getnextcmd(name) 376830088Sminshall char *name; 376930088Sminshall { 377030088Sminshall struct cmd *c = (struct cmd *) name; 377130088Sminshall 377230088Sminshall return (char **) (c+1); 377330088Sminshall } 377430088Sminshall 377530088Sminshall static struct cmd * 377630088Sminshall getcmd(name) 377730088Sminshall char *name; 377830088Sminshall { 377930088Sminshall struct cmd *cm; 378030088Sminshall 378130088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 378230088Sminshall return cm; 378330088Sminshall } else { 378430088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 378530088Sminshall } 378630088Sminshall } 378730088Sminshall 378830088Sminshall void 378930088Sminshall command(top) 379030088Sminshall int top; 379130088Sminshall { 379231478Sminshall register struct cmd *c; 379330088Sminshall 379431478Sminshall setcommandmode(); 379531478Sminshall if (!top) { 379631478Sminshall putchar('\n'); 379731478Sminshall } else { 379830088Sminshall #if defined(unix) 379931478Sminshall signal(SIGINT, SIG_DFL); 380031478Sminshall signal(SIGQUIT, SIG_DFL); 380130088Sminshall #endif /* defined(unix) */ 380231478Sminshall } 380331478Sminshall for (;;) { 380431478Sminshall printf("%s> ", prompt); 380531478Sminshall if (gets(line) == NULL) { 380631478Sminshall if (feof(stdin) || ferror(stdin)) 380731478Sminshall quit(); 380831478Sminshall break; 380930088Sminshall } 381031478Sminshall if (line[0] == 0) 381131478Sminshall break; 381231478Sminshall makeargv(); 381331478Sminshall c = getcmd(margv[0]); 381431478Sminshall if (c == Ambiguous(struct cmd *)) { 381531478Sminshall printf("?Ambiguous command\n"); 381631478Sminshall continue; 381730088Sminshall } 381831478Sminshall if (c == 0) { 381931478Sminshall printf("?Invalid command\n"); 382031478Sminshall continue; 382130088Sminshall } 382231478Sminshall if (c->needconnect && !connected) { 382331478Sminshall printf("?Need to be connected first.\n"); 382431478Sminshall continue; 382531478Sminshall } 382631478Sminshall if ((*c->handler)(margc, margv)) { 382731478Sminshall break; 382831478Sminshall } 382931478Sminshall } 383031478Sminshall if (!top) { 383131478Sminshall if (!connected) { 383231478Sminshall longjmp(toplevel, 1); 383331478Sminshall /*NOTREACHED*/ 383431478Sminshall } 383531478Sminshall if (shell_active == 0) { 383631478Sminshall setconnmode(); 383731478Sminshall } 383831478Sminshall } 383930088Sminshall } 384030088Sminshall 384130088Sminshall /* 384230088Sminshall * Help command. 384330088Sminshall */ 384430088Sminshall static 384530088Sminshall help(argc, argv) 384630088Sminshall int argc; 384730088Sminshall char *argv[]; 384830088Sminshall { 384930088Sminshall register struct cmd *c; 385030088Sminshall 385130088Sminshall if (argc == 1) { 385230088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 385330088Sminshall for (c = cmdtab; c->name; c++) 385430088Sminshall if (c->dohelp) { 385530088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 385630088Sminshall c->help); 385730088Sminshall } 385830088Sminshall return 0; 385930088Sminshall } 386030088Sminshall while (--argc > 0) { 386130088Sminshall register char *arg; 386230088Sminshall arg = *++argv; 386330088Sminshall c = getcmd(arg); 386430088Sminshall if (c == Ambiguous(struct cmd *)) 386530088Sminshall printf("?Ambiguous help command %s\n", arg); 386630088Sminshall else if (c == (struct cmd *)0) 386730088Sminshall printf("?Invalid help command %s\n", arg); 386830088Sminshall else 386930088Sminshall printf("%s\n", c->help); 387030088Sminshall } 387130088Sminshall return 0; 387230088Sminshall } 387330088Sminshall 387430088Sminshall /* 387530088Sminshall * main. Parse arguments, invoke the protocol or command parser. 387630088Sminshall */ 387730088Sminshall 387830088Sminshall 387930088Sminshall void 388030088Sminshall main(argc, argv) 388130088Sminshall int argc; 388230088Sminshall char *argv[]; 388330088Sminshall { 388430326Sminshall tninit(); /* Clear out things */ 388530326Sminshall 388630088Sminshall NetTrace = stdout; 388731124Sminshall TerminalSaveState(); 388831124Sminshall autoflush = TerminalAutoFlush(); 388931124Sminshall 389030088Sminshall prompt = argv[0]; 389131478Sminshall while ((argc > 1) && (argv[1][0] == '-')) { 389231478Sminshall if (!strcmp(argv[1], "-d")) { 389331478Sminshall debug = 1; 389431478Sminshall } else if (!strcmp(argv[1], "-n")) { 389531510Sminshall if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */ 389631510Sminshall NetTrace = fopen(argv[2], "w"); 389731478Sminshall argv++; 389831478Sminshall argc--; 389931478Sminshall if (NetTrace == NULL) { 390031478Sminshall NetTrace = stdout; 390131478Sminshall } 390230088Sminshall } 390331478Sminshall } else { 390431478Sminshall #if defined(TN3270) && defined(unix) 390531478Sminshall if (!strcmp(argv[1], "-t")) { 390631478Sminshall if ((argc > 1) && (argv[1][0] != '-')) { /* get file name */ 390731478Sminshall transcom = tline; 390831478Sminshall (void) strcpy(transcom, argv[1]); 390931478Sminshall argv++; 391031478Sminshall argc--; 391131478Sminshall } 391231478Sminshall } else if (!strcmp(argv[1], "-noasynch")) { 391331478Sminshall noasynch = 1; 391431478Sminshall } else 391531478Sminshall #endif /* defined(TN3270) && defined(unix) */ 391631478Sminshall if (argv[1][1] != '\0') { 391731478Sminshall fprintf(stderr, "Unknown option *%s*.\n", argv[1]); 391831478Sminshall } 391930088Sminshall } 392031478Sminshall argc--; 392130088Sminshall argv++; 392230088Sminshall } 392330088Sminshall if (argc != 1) { 392430088Sminshall if (setjmp(toplevel) != 0) 392530088Sminshall Exit(0); 392630088Sminshall tn(argc, argv); 392730088Sminshall } 392830088Sminshall setjmp(toplevel); 392931215Sminshall for (;;) { 393031215Sminshall #if !defined(TN3270) 393130088Sminshall command(1); 393231215Sminshall #else /* !defined(TN3270) */ 393331215Sminshall if (!shell_active) { 393431215Sminshall command(1); 393531215Sminshall } else { 393631478Sminshall #if defined(TN3270) 393731215Sminshall shell_continue(); 393831478Sminshall #endif /* defined(TN3270) */ 393931215Sminshall } 394031215Sminshall #endif /* !defined(TN3270) */ 394131215Sminshall } 394230088Sminshall } 3943