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 */ 23431791Sminshall donelclchars, /* the user has set "localchars" */ 23531791Sminshall 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 98431791Sminshall 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 1063*31793Sminshall if (name == 0) { 1064*31793Sminshall return 0; 1065*31793Sminshall } 106630088Sminshall longest = 0; 106730088Sminshall nmatches = 0; 106830088Sminshall found = 0; 106930088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 107030088Sminshall for (q = name; 107130088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 107230088Sminshall if (*q == 0) /* exact match? */ 107330088Sminshall return (c); 107430088Sminshall if (!*q) { /* the name was a prefix */ 107530088Sminshall if (q - name > longest) { 107630088Sminshall longest = q - name; 107730088Sminshall nmatches = 1; 107830088Sminshall found = c; 107930088Sminshall } else if (q - name == longest) 108030088Sminshall nmatches++; 108130088Sminshall } 108230088Sminshall } 108330088Sminshall if (nmatches > 1) 108430088Sminshall return Ambiguous(char **); 108530088Sminshall return (found); 108630088Sminshall } 108730088Sminshall 108830088Sminshall /* 108930088Sminshall * Make a character string into a number. 109030088Sminshall * 109130088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 109230088Sminshall */ 109330088Sminshall 109430088Sminshall static 109530088Sminshall special(s) 109630088Sminshall register char *s; 109730088Sminshall { 109830088Sminshall register char c; 109930088Sminshall char b; 110030088Sminshall 110130088Sminshall switch (*s) { 110230088Sminshall case '^': 110330088Sminshall b = *++s; 110430088Sminshall if (b == '?') { 110530088Sminshall c = b | 0x40; /* DEL */ 110630088Sminshall } else { 110730088Sminshall c = b & 0x1f; 110830088Sminshall } 110930088Sminshall break; 111030088Sminshall default: 111130088Sminshall c = *s; 111230088Sminshall break; 111330088Sminshall } 111430088Sminshall return c; 111530088Sminshall } 111630088Sminshall 111730088Sminshall /* 111830088Sminshall * Construct a control character sequence 111930088Sminshall * for a special character. 112030088Sminshall */ 112130088Sminshall static char * 112230088Sminshall control(c) 112330088Sminshall register int c; 112430088Sminshall { 112530088Sminshall static char buf[3]; 112630088Sminshall 112730088Sminshall if (c == 0x7f) 112830088Sminshall return ("^?"); 112930088Sminshall if (c == '\377') { 113030088Sminshall return "off"; 113130088Sminshall } 113230088Sminshall if (c >= 0x20) { 113330088Sminshall buf[0] = c; 113430088Sminshall buf[1] = 0; 113530088Sminshall } else { 113630088Sminshall buf[0] = '^'; 113730088Sminshall buf[1] = '@'+c; 113830088Sminshall buf[2] = 0; 113930088Sminshall } 114030088Sminshall return (buf); 114130088Sminshall } 114230088Sminshall 114330088Sminshall 114430088Sminshall /* 114530088Sminshall * upcase() 114630088Sminshall * 114730088Sminshall * Upcase (in place) the argument. 114830088Sminshall */ 114930088Sminshall 115030088Sminshall static void 115130088Sminshall upcase(argument) 115230088Sminshall register char *argument; 115330088Sminshall { 115430088Sminshall register int c; 115530088Sminshall 115630088Sminshall while ((c = *argument) != 0) { 115730088Sminshall if (islower(c)) { 115830088Sminshall *argument = toupper(c); 115930088Sminshall } 116030088Sminshall argument++; 116130088Sminshall } 116230088Sminshall } 116331124Sminshall 116431124Sminshall /* 116531124Sminshall * SetSockOpt() 116631124Sminshall * 116731124Sminshall * Compensate for differences in 4.2 and 4.3 systems. 116831124Sminshall */ 116931124Sminshall 117031124Sminshall static int 117131124Sminshall SetSockOpt(fd, level, option, yesno) 117231124Sminshall int 117331124Sminshall fd, 117431124Sminshall level, 117531124Sminshall option, 117631124Sminshall yesno; 117731124Sminshall { 117831124Sminshall #ifndef NOT43 117931124Sminshall return setsockopt(fd, level, option, 118031124Sminshall (char *)&yesno, sizeof yesno); 118131124Sminshall #else /* NOT43 */ 118231124Sminshall if (yesno == 0) { /* Can't do that in 4.2! */ 118331124Sminshall fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", 118431124Sminshall option); 118531124Sminshall return -1; 118631124Sminshall } 118731124Sminshall return setsockopt(fd, level, option, 0, 0); 118831124Sminshall #endif /* NOT43 */ 118931124Sminshall } 119030088Sminshall 119130088Sminshall /* 119230088Sminshall * The following are routines used to print out debugging information. 119330088Sminshall */ 119430088Sminshall 119530088Sminshall 119630088Sminshall static void 119730088Sminshall Dump(direction, buffer, length) 119830088Sminshall char direction; 119930088Sminshall char *buffer; 120030088Sminshall int length; 120130088Sminshall { 120230088Sminshall # define BYTES_PER_LINE 32 120330088Sminshall # define min(x,y) ((x<y)? x:y) 120430088Sminshall char *pThis; 120530088Sminshall int offset; 120630088Sminshall 120730088Sminshall offset = 0; 120830088Sminshall 120930088Sminshall while (length) { 121030088Sminshall /* print one line */ 121130088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 121230088Sminshall pThis = buffer; 121330088Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 121430088Sminshall while (pThis < buffer) { 121530088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 121630088Sminshall pThis++; 121730088Sminshall } 121830088Sminshall fprintf(NetTrace, "\n"); 121930088Sminshall length -= BYTES_PER_LINE; 122030088Sminshall offset += BYTES_PER_LINE; 122130088Sminshall if (length < 0) { 122230088Sminshall return; 122330088Sminshall } 122430088Sminshall /* find next unique line */ 122530088Sminshall } 122630088Sminshall } 122730088Sminshall 122830088Sminshall 122930088Sminshall /*VARARGS*/ 123030088Sminshall static void 123130088Sminshall printoption(direction, fmt, option, what) 123230088Sminshall char *direction, *fmt; 123330088Sminshall int option, what; 123430088Sminshall { 123530088Sminshall if (!showoptions) 123630088Sminshall return; 123730088Sminshall fprintf(NetTrace, "%s ", direction+1); 123830088Sminshall if (fmt == doopt) 123930088Sminshall fmt = "do"; 124030088Sminshall else if (fmt == dont) 124130088Sminshall fmt = "dont"; 124230088Sminshall else if (fmt == will) 124330088Sminshall fmt = "will"; 124430088Sminshall else if (fmt == wont) 124530088Sminshall fmt = "wont"; 124630088Sminshall else 124730088Sminshall fmt = "???"; 124830088Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 124930088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]); 125030088Sminshall else 125130088Sminshall fprintf(NetTrace, "%s %d", fmt, option); 125230088Sminshall if (*direction == '<') { 125330088Sminshall fprintf(NetTrace, "\r\n"); 125430088Sminshall return; 125530088Sminshall } 125630088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); 125730088Sminshall } 125830088Sminshall 125930088Sminshall static void 126030088Sminshall printsub(direction, pointer, length) 126130088Sminshall char *direction, /* "<" or ">" */ 126230088Sminshall *pointer; /* where suboption data sits */ 126330088Sminshall int length; /* length of suboption data */ 126430088Sminshall { 126530088Sminshall if (showoptions) { 126630088Sminshall fprintf(NetTrace, "%s suboption ", 126730088Sminshall (direction[0] == '<')? "Received":"Sent"); 126830088Sminshall switch (pointer[0]) { 126930088Sminshall case TELOPT_TTYPE: 127030088Sminshall fprintf(NetTrace, "Terminal type "); 127130088Sminshall switch (pointer[1]) { 127230088Sminshall case TELQUAL_IS: 127330088Sminshall { 127430088Sminshall char tmpbuf[sizeof subbuffer]; 127530088Sminshall int minlen = min(length, sizeof tmpbuf); 127630088Sminshall 127731131Sminshall memcpy(tmpbuf, pointer+2, minlen); 127830088Sminshall tmpbuf[minlen-1] = 0; 127930088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf); 128030088Sminshall } 128130088Sminshall break; 128230088Sminshall case TELQUAL_SEND: 128330088Sminshall fprintf(NetTrace, "- request to send.\n"); 128430088Sminshall break; 128530088Sminshall default: 128630088Sminshall fprintf(NetTrace, 128730088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]); 128830088Sminshall } 128930088Sminshall break; 129030088Sminshall default: 129130088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n", 129230088Sminshall pointer[0], pointer[0]); 129330088Sminshall } 129430088Sminshall } 129530088Sminshall } 129630088Sminshall 129730088Sminshall /* 129830088Sminshall * Check to see if any out-of-band data exists on a socket (for 129930088Sminshall * Telnet "synch" processing). 130030088Sminshall */ 130130088Sminshall 130230088Sminshall static int 130330088Sminshall stilloob(s) 130430088Sminshall int s; /* socket number */ 130530088Sminshall { 130630088Sminshall static struct timeval timeout = { 0 }; 130730088Sminshall fd_set excepts; 130830088Sminshall int value; 130930088Sminshall 131030088Sminshall do { 131130088Sminshall FD_ZERO(&excepts); 131230088Sminshall FD_SET(s, &excepts); 131330088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 131430088Sminshall } while ((value == -1) && (errno == EINTR)); 131530088Sminshall 131630088Sminshall if (value < 0) { 131730088Sminshall perror("select"); 131830088Sminshall quit(); 131930088Sminshall } 132030088Sminshall if (FD_ISSET(s, &excepts)) { 132130088Sminshall return 1; 132230088Sminshall } else { 132330088Sminshall return 0; 132430088Sminshall } 132530088Sminshall } 132630088Sminshall 132730088Sminshall 132830088Sminshall /* 132930088Sminshall * netflush 133030088Sminshall * Send as much data as possible to the network, 133130088Sminshall * handling requests for urgent data. 133230088Sminshall * 133330088Sminshall * The return value indicates whether we did any 133430088Sminshall * useful work. 133530088Sminshall */ 133630088Sminshall 133730088Sminshall 133830088Sminshall int 133930088Sminshall netflush() 134030088Sminshall { 134130088Sminshall int n; 134230088Sminshall 134330088Sminshall if ((n = nfrontp - nbackp) > 0) { 134430088Sminshall if (!neturg) { 134531131Sminshall n = send(net, nbackp, n, 0); /* normal write */ 134630088Sminshall } else { 134730088Sminshall n = neturg - nbackp; 134830088Sminshall /* 134930088Sminshall * In 4.2 (and 4.3) systems, there is some question about 135030088Sminshall * what byte in a sendOOB operation is the "OOB" data. 135130088Sminshall * To make ourselves compatible, we only send ONE byte 135230088Sminshall * out of band, the one WE THINK should be OOB (though 135330088Sminshall * we really have more the TCP philosophy of urgent data 135430088Sminshall * rather than the Unix philosophy of OOB data). 135530088Sminshall */ 135630088Sminshall if (n > 1) { 135730088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 135830088Sminshall } else { 135930088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 136030088Sminshall } 136130088Sminshall } 136230088Sminshall } 136330088Sminshall if (n < 0) { 136430088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 136530088Sminshall setcommandmode(); 136630088Sminshall perror(hostname); 136731131Sminshall NetClose(net); 136830088Sminshall neturg = 0; 136930088Sminshall longjmp(peerdied, -1); 137030088Sminshall /*NOTREACHED*/ 137130088Sminshall } 137230088Sminshall n = 0; 137330088Sminshall } 137430088Sminshall if (netdata && n) { 137530088Sminshall Dump('>', nbackp, n); 137630088Sminshall } 137730088Sminshall nbackp += n; 137830088Sminshall if (nbackp >= neturg) { 137930088Sminshall neturg = 0; 138030088Sminshall } 138130088Sminshall if (nbackp == nfrontp) { 138230088Sminshall nbackp = nfrontp = netobuf; 138330088Sminshall } 138430088Sminshall return n > 0; 138530088Sminshall } 138630088Sminshall 138730088Sminshall /* 138830088Sminshall * nextitem() 138930088Sminshall * 139030088Sminshall * Return the address of the next "item" in the TELNET data 139130088Sminshall * stream. This will be the address of the next character if 139230088Sminshall * the current address is a user data character, or it will 139330088Sminshall * be the address of the character following the TELNET command 139430088Sminshall * if the current address is a TELNET IAC ("I Am a Command") 139530088Sminshall * character. 139630088Sminshall */ 139730088Sminshall 139830088Sminshall static char * 139930088Sminshall nextitem(current) 140030088Sminshall char *current; 140130088Sminshall { 140230088Sminshall if ((*current&0xff) != IAC) { 140330088Sminshall return current+1; 140430088Sminshall } 140530088Sminshall switch (*(current+1)&0xff) { 140630088Sminshall case DO: 140730088Sminshall case DONT: 140830088Sminshall case WILL: 140930088Sminshall case WONT: 141030088Sminshall return current+3; 141130088Sminshall case SB: /* loop forever looking for the SE */ 141230088Sminshall { 141330088Sminshall register char *look = current+2; 141430088Sminshall 141530088Sminshall for (;;) { 141630088Sminshall if ((*look++&0xff) == IAC) { 141730088Sminshall if ((*look++&0xff) == SE) { 141830088Sminshall return look; 141930088Sminshall } 142030088Sminshall } 142130088Sminshall } 142230088Sminshall } 142330088Sminshall default: 142430088Sminshall return current+2; 142530088Sminshall } 142630088Sminshall } 142730088Sminshall /* 142830088Sminshall * netclear() 142930088Sminshall * 143030088Sminshall * We are about to do a TELNET SYNCH operation. Clear 143130088Sminshall * the path to the network. 143230088Sminshall * 143330088Sminshall * Things are a bit tricky since we may have sent the first 143430088Sminshall * byte or so of a previous TELNET command into the network. 143530088Sminshall * So, we have to scan the network buffer from the beginning 143630088Sminshall * until we are up to where we want to be. 143730088Sminshall * 143830088Sminshall * A side effect of what we do, just to keep things 143930088Sminshall * simple, is to clear the urgent data pointer. The principal 144030088Sminshall * caller should be setting the urgent data pointer AFTER calling 144130088Sminshall * us in any case. 144230088Sminshall */ 144330088Sminshall 144430088Sminshall static void 144530088Sminshall netclear() 144630088Sminshall { 144730088Sminshall register char *thisitem, *next; 144830088Sminshall char *good; 144930088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 145030088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 145130088Sminshall 145230088Sminshall thisitem = netobuf; 145330088Sminshall 145430088Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 145530088Sminshall thisitem = next; 145630088Sminshall } 145730088Sminshall 145830088Sminshall /* Now, thisitem is first before/at boundary. */ 145930088Sminshall 146030088Sminshall good = netobuf; /* where the good bytes go */ 146130088Sminshall 146230088Sminshall while (nfrontp > thisitem) { 146330088Sminshall if (wewant(thisitem)) { 146430088Sminshall int length; 146530088Sminshall 146630088Sminshall next = thisitem; 146730088Sminshall do { 146830088Sminshall next = nextitem(next); 146930088Sminshall } while (wewant(next) && (nfrontp > next)); 147030088Sminshall length = next-thisitem; 147131131Sminshall memcpy(good, thisitem, length); 147230088Sminshall good += length; 147330088Sminshall thisitem = next; 147430088Sminshall } else { 147530088Sminshall thisitem = nextitem(thisitem); 147630088Sminshall } 147730088Sminshall } 147830088Sminshall 147930088Sminshall nbackp = netobuf; 148030088Sminshall nfrontp = good; /* next byte to be sent */ 148130088Sminshall neturg = 0; 148230088Sminshall } 148330088Sminshall 148430088Sminshall /* 148530088Sminshall * These routines add various telnet commands to the data stream. 148630088Sminshall */ 148730088Sminshall 148830088Sminshall #if defined(NOT43) 148930088Sminshall static int 149030088Sminshall #else /* defined(NOT43) */ 149130088Sminshall static void 149230088Sminshall #endif /* defined(NOT43) */ 149330088Sminshall dosynch() 149430088Sminshall { 149530088Sminshall netclear(); /* clear the path to the network */ 149630088Sminshall NET2ADD(IAC, DM); 149730088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 149830088Sminshall 149930088Sminshall #if defined(NOT43) 150030088Sminshall return 0; 150130088Sminshall #endif /* defined(NOT43) */ 150230088Sminshall } 150330088Sminshall 150430088Sminshall static void 150530088Sminshall doflush() 150630088Sminshall { 150730088Sminshall NET2ADD(IAC, DO); 150830088Sminshall NETADD(TELOPT_TM); 150930088Sminshall flushline = 1; 151030088Sminshall flushout = 1; 151130088Sminshall ttyflush(); 151230088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 151330088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 151430088Sminshall } 151530088Sminshall 151630088Sminshall static void 151730088Sminshall intp() 151830088Sminshall { 151930088Sminshall NET2ADD(IAC, IP); 152030088Sminshall if (autoflush) { 152130088Sminshall doflush(); 152230088Sminshall } 152330088Sminshall if (autosynch) { 152430088Sminshall dosynch(); 152530088Sminshall } 152630088Sminshall } 152730088Sminshall 152830088Sminshall static void 152930088Sminshall sendbrk() 153030088Sminshall { 153130088Sminshall NET2ADD(IAC, BREAK); 153230088Sminshall if (autoflush) { 153330088Sminshall doflush(); 153430088Sminshall } 153530088Sminshall if (autosynch) { 153630088Sminshall dosynch(); 153730088Sminshall } 153830088Sminshall } 153930088Sminshall 154030088Sminshall /* 154130088Sminshall * Send as much data as possible to the terminal. 154230088Sminshall * 154330088Sminshall * The return value indicates whether we did any 154430088Sminshall * useful work. 154530088Sminshall */ 154630088Sminshall 154730088Sminshall 154830088Sminshall static int 154930088Sminshall ttyflush() 155030088Sminshall { 155130088Sminshall int n; 155230088Sminshall 155330088Sminshall if ((n = tfrontp - tbackp) > 0) { 155430088Sminshall if (!(SYNCHing||flushout)) { 155531131Sminshall n = TerminalWrite(tout, tbackp, n); 155630088Sminshall } else { 155731124Sminshall TerminalFlushOutput(); 155830088Sminshall /* we leave 'n' alone! */ 155930088Sminshall } 156030088Sminshall } 156130088Sminshall if (n >= 0) { 156230088Sminshall tbackp += n; 156330088Sminshall if (tbackp == tfrontp) { 156430088Sminshall tbackp = tfrontp = ttyobuf; 156530088Sminshall } 156630088Sminshall } 156730088Sminshall return n > 0; 156830088Sminshall } 156930088Sminshall 157030088Sminshall #if defined(TN3270) 157130088Sminshall 157230088Sminshall #if defined(unix) 157330088Sminshall static void 157430088Sminshall inputAvailable() 157530088Sminshall { 157630088Sminshall HaveInput = 1; 157730088Sminshall } 157830088Sminshall #endif /* defined(unix) */ 157930088Sminshall 158030088Sminshall void 158130088Sminshall outputPurge() 158230088Sminshall { 158330088Sminshall int tmp = flushout; 158430088Sminshall 158530088Sminshall flushout = 1; 158630088Sminshall 158730088Sminshall ttyflush(); 158830088Sminshall 158930088Sminshall flushout = tmp; 159030088Sminshall } 159130088Sminshall 159230088Sminshall #endif /* defined(TN3270) */ 159330088Sminshall 159430088Sminshall #if defined(unix) 159530088Sminshall /* 159630088Sminshall * Various signal handling routines. 159730088Sminshall */ 159830088Sminshall 159930088Sminshall static void 160030088Sminshall deadpeer() 160130088Sminshall { 160230088Sminshall setcommandmode(); 160330088Sminshall longjmp(peerdied, -1); 160430088Sminshall } 160530088Sminshall 160630088Sminshall static void 160730088Sminshall intr() 160830088Sminshall { 160930088Sminshall if (localchars) { 161030088Sminshall intp(); 161130088Sminshall return; 161230088Sminshall } 161330088Sminshall setcommandmode(); 161430088Sminshall longjmp(toplevel, -1); 161530088Sminshall } 161630088Sminshall 161730088Sminshall static void 161830088Sminshall intr2() 161930088Sminshall { 162030088Sminshall if (localchars) { 162130088Sminshall sendbrk(); 162230088Sminshall return; 162330088Sminshall } 162430088Sminshall } 162530088Sminshall 162630088Sminshall static void 162730088Sminshall doescape() 162830088Sminshall { 162930088Sminshall command(0); 163030088Sminshall } 163130088Sminshall #endif /* defined(unix) */ 163230088Sminshall 163330088Sminshall /* 163430088Sminshall * These routines decides on what the mode should be (based on the values 163530088Sminshall * of various global variables). 163630088Sminshall */ 163730088Sminshall 163830088Sminshall 163930088Sminshall static 164030088Sminshall getconnmode() 164130088Sminshall { 164230088Sminshall static char newmode[16] = 164330088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; 164430088Sminshall int modeindex = 0; 164530088Sminshall 164630088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 164730088Sminshall modeindex += 1; 164830088Sminshall } 164930088Sminshall if (hisopts[TELOPT_ECHO]) { 165030088Sminshall modeindex += 2; 165130088Sminshall } 165230088Sminshall if (hisopts[TELOPT_SGA]) { 165330088Sminshall modeindex += 4; 165430088Sminshall } 165530088Sminshall if (In3270) { 165630088Sminshall modeindex += 8; 165730088Sminshall } 165830088Sminshall return newmode[modeindex]; 165930088Sminshall } 166030088Sminshall 166130088Sminshall void 166230088Sminshall setconnmode() 166330088Sminshall { 166431124Sminshall TerminalNewMode(getconnmode()); 166530088Sminshall } 166630088Sminshall 166730088Sminshall 166830088Sminshall void 166930088Sminshall setcommandmode() 167030088Sminshall { 167131124Sminshall TerminalNewMode(0); 167230088Sminshall } 167330088Sminshall 167430088Sminshall static void 167530088Sminshall willoption(option, reply) 167630088Sminshall int option, reply; 167730088Sminshall { 167830088Sminshall char *fmt; 167930088Sminshall 168030088Sminshall switch (option) { 168130088Sminshall 168230368Sminshall case TELOPT_ECHO: 168330088Sminshall # if defined(TN3270) 168430368Sminshall /* 168530368Sminshall * The following is a pain in the rear-end. 168630368Sminshall * Various IBM servers (some versions of Wiscnet, 168730368Sminshall * possibly Fibronics/Spartacus, and who knows who 168830368Sminshall * else) will NOT allow us to send "DO SGA" too early 168930368Sminshall * in the setup proceedings. On the other hand, 169030368Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 169130368Sminshall * So, we are stuck. Empirically (but, based on 169230368Sminshall * a VERY small sample), the IBM servers don't send 169330368Sminshall * out anything about ECHO, so we postpone our sending 169430368Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 169530368Sminshall * DO send). 169630368Sminshall */ 169730368Sminshall { 169830368Sminshall if (askedSGA == 0) { 169930368Sminshall askedSGA = 1; 170030368Sminshall if (!hisopts[TELOPT_SGA]) { 170130368Sminshall willoption(TELOPT_SGA, 0); 170230368Sminshall } 170330368Sminshall } 170430368Sminshall } 170530368Sminshall /* Fall through */ 170630088Sminshall case TELOPT_EOR: 170730088Sminshall case TELOPT_BINARY: 170830088Sminshall #endif /* defined(TN3270) */ 170930088Sminshall case TELOPT_SGA: 171030088Sminshall settimer(modenegotiated); 171130088Sminshall hisopts[option] = 1; 171230088Sminshall fmt = doopt; 171330088Sminshall setconnmode(); /* possibly set new tty mode */ 171430088Sminshall break; 171530088Sminshall 171630088Sminshall case TELOPT_TM: 171730088Sminshall return; /* Never reply to TM will's/wont's */ 171830088Sminshall 171930088Sminshall default: 172030088Sminshall fmt = dont; 172130088Sminshall break; 172230088Sminshall } 172330088Sminshall sprintf(nfrontp, fmt, option); 172430088Sminshall nfrontp += sizeof (dont) - 2; 172530088Sminshall if (reply) 172630088Sminshall printoption(">SENT", fmt, option, reply); 172730088Sminshall else 172830088Sminshall printoption("<SENT", fmt, option, reply); 172930088Sminshall } 173030088Sminshall 173130088Sminshall static void 173230088Sminshall wontoption(option, reply) 173330088Sminshall int option, reply; 173430088Sminshall { 173530088Sminshall char *fmt; 173630088Sminshall 173730088Sminshall switch (option) { 173830088Sminshall 173930088Sminshall case TELOPT_ECHO: 174030088Sminshall case TELOPT_SGA: 174130088Sminshall settimer(modenegotiated); 174230088Sminshall hisopts[option] = 0; 174330088Sminshall fmt = dont; 174430088Sminshall setconnmode(); /* Set new tty mode */ 174530088Sminshall break; 174630088Sminshall 174730088Sminshall case TELOPT_TM: 174830088Sminshall return; /* Never reply to TM will's/wont's */ 174930088Sminshall 175030088Sminshall default: 175130088Sminshall fmt = dont; 175230088Sminshall } 175330088Sminshall sprintf(nfrontp, fmt, option); 175430088Sminshall nfrontp += sizeof (doopt) - 2; 175530088Sminshall if (reply) 175630088Sminshall printoption(">SENT", fmt, option, reply); 175730088Sminshall else 175830088Sminshall printoption("<SENT", fmt, option, reply); 175930088Sminshall } 176030088Sminshall 176130088Sminshall static void 176230088Sminshall dooption(option) 176330088Sminshall int option; 176430088Sminshall { 176530088Sminshall char *fmt; 176630088Sminshall 176730088Sminshall switch (option) { 176830088Sminshall 176930088Sminshall case TELOPT_TM: 177030088Sminshall fmt = will; 177130088Sminshall break; 177230088Sminshall 177330088Sminshall # if defined(TN3270) 177430088Sminshall case TELOPT_EOR: 177530088Sminshall case TELOPT_BINARY: 177630088Sminshall # endif /* defined(TN3270) */ 177730088Sminshall case TELOPT_TTYPE: /* terminal type option */ 177830088Sminshall case TELOPT_SGA: /* no big deal */ 177930088Sminshall fmt = will; 178030088Sminshall myopts[option] = 1; 178130088Sminshall break; 178230088Sminshall 178330088Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 178430088Sminshall default: 178530088Sminshall fmt = wont; 178630088Sminshall break; 178730088Sminshall } 178830088Sminshall sprintf(nfrontp, fmt, option); 178930088Sminshall nfrontp += sizeof (doopt) - 2; 179030088Sminshall printoption(">SENT", fmt, option, 0); 179130088Sminshall } 179230088Sminshall 179330088Sminshall /* 179430088Sminshall * suboption() 179530088Sminshall * 179630088Sminshall * Look at the sub-option buffer, and try to be helpful to the other 179730088Sminshall * side. 179830088Sminshall * 179930088Sminshall * Currently we recognize: 180030088Sminshall * 180130088Sminshall * Terminal type, send request. 180230088Sminshall */ 180330088Sminshall 180430088Sminshall static void 180530088Sminshall suboption() 180630088Sminshall { 180730088Sminshall printsub("<", subbuffer, subend-subbuffer+1); 180830088Sminshall switch (subbuffer[0]&0xff) { 180930088Sminshall case TELOPT_TTYPE: 181030088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 181130088Sminshall ; 181230088Sminshall } else { 181330088Sminshall char *name; 181430088Sminshall char namebuf[41]; 181530088Sminshall extern char *getenv(); 181630088Sminshall int len; 181730088Sminshall 181830088Sminshall #if defined(TN3270) 181930088Sminshall /* 182030326Sminshall * Try to send a 3270 type terminal name. Decide which one based 182130088Sminshall * on the format of our screen, and (in the future) color 182230088Sminshall * capaiblities. 182330088Sminshall */ 182431124Sminshall #if defined(unix) 182531131Sminshall if (initscr() != ERR) { /* Initialize curses to get line size */ 182631131Sminshall MaxNumberLines = LINES; 182731131Sminshall MaxNumberColumns = COLS; 182831131Sminshall } 182931131Sminshall #else /* defined(unix) */ 183031131Sminshall InitTerminal(); 183131131Sminshall #endif /* defined(unix) */ 183231131Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 183330088Sminshall Sent3270TerminalType = 1; 183431131Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 183530088Sminshall MaxNumberLines = 27; 183630088Sminshall MaxNumberColumns = 132; 183730088Sminshall sb_terminal[SBTERMMODEL] = '5'; 183831131Sminshall } else if (MaxNumberLines >= 43) { 183930088Sminshall MaxNumberLines = 43; 184030088Sminshall MaxNumberColumns = 80; 184130088Sminshall sb_terminal[SBTERMMODEL] = '4'; 184231131Sminshall } else if (MaxNumberLines >= 32) { 184330088Sminshall MaxNumberLines = 32; 184430088Sminshall MaxNumberColumns = 80; 184530088Sminshall sb_terminal[SBTERMMODEL] = '3'; 184630088Sminshall } else { 184730088Sminshall MaxNumberLines = 24; 184830088Sminshall MaxNumberColumns = 80; 184930088Sminshall sb_terminal[SBTERMMODEL] = '2'; 185030088Sminshall } 185130088Sminshall NumberLines = 24; /* before we start out... */ 185230088Sminshall NumberColumns = 80; 185330088Sminshall ScreenSize = NumberLines*NumberColumns; 185430088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 185530088Sminshall ExitString(stderr, 185630088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 185730088Sminshall /*NOTREACHED*/ 185830088Sminshall } 185931131Sminshall memcpy(nfrontp, sb_terminal, sizeof sb_terminal); 186030088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 186130088Sminshall nfrontp += sizeof sb_terminal; 186230088Sminshall return; 186330088Sminshall } 186430088Sminshall #endif /* defined(TN3270) */ 186530088Sminshall 186630088Sminshall name = getenv("TERM"); 186730088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 186830088Sminshall name = "UNKNOWN"; 186930088Sminshall } 187030088Sminshall if ((len + 4+2) < NETROOM()) { 187130088Sminshall strcpy(namebuf, name); 187230088Sminshall upcase(namebuf); 187330088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 187430088Sminshall TELQUAL_IS, namebuf, IAC, SE); 187530088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 187630088Sminshall nfrontp += 4+strlen(namebuf)+2; 187730088Sminshall } else { 187830088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 187930088Sminshall 1); 188030088Sminshall /*NOTREACHED*/ 188130088Sminshall } 188230088Sminshall } 188330088Sminshall 188430088Sminshall default: 188530088Sminshall break; 188630088Sminshall } 188730088Sminshall } 188830088Sminshall 188930088Sminshall #if defined(TN3270) 189030088Sminshall static void 189130088Sminshall SetIn3270() 189230088Sminshall { 189330088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 189431791Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 189530088Sminshall if (!In3270) { 189630088Sminshall In3270 = 1; 189730326Sminshall Init3270(); /* Initialize 3270 functions */ 189830088Sminshall /* initialize terminal key mapping */ 189930326Sminshall InitTerminal(); /* Start terminal going */ 190030088Sminshall setconnmode(); 190130088Sminshall } 190230088Sminshall } else { 190330088Sminshall if (In3270) { 190430088Sminshall StopScreen(1); 190530088Sminshall In3270 = 0; 190631215Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 190730088Sminshall setconnmode(); 190830088Sminshall } 190930088Sminshall } 191030088Sminshall } 191130088Sminshall #endif /* defined(TN3270) */ 191230088Sminshall 191330088Sminshall 191430088Sminshall static void 191530088Sminshall telrcv() 191630088Sminshall { 191730088Sminshall register int c; 191830722Sminshall static int telrcv_state = TS_DATA; 191930088Sminshall # if defined(TN3270) 192030088Sminshall register int Scc; 192130088Sminshall register char *Sbp; 192230088Sminshall # endif /* defined(TN3270) */ 192330088Sminshall 192430088Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 192530088Sminshall c = *sbp++ & 0xff, scc--; 192630722Sminshall switch (telrcv_state) { 192730088Sminshall 192830088Sminshall case TS_CR: 192930722Sminshall telrcv_state = TS_DATA; 193030088Sminshall if (c == '\0') { 193130088Sminshall break; /* Ignore \0 after CR */ 193230088Sminshall } else if (c == '\n') { 193330088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 193430088Sminshall TTYADD(c); 193530088Sminshall } 193630088Sminshall break; 193730088Sminshall } 193830088Sminshall /* Else, fall through */ 193930088Sminshall 194030088Sminshall case TS_DATA: 194130088Sminshall if (c == IAC) { 194230722Sminshall telrcv_state = TS_IAC; 194330088Sminshall continue; 194430088Sminshall } 194530088Sminshall # if defined(TN3270) 194630088Sminshall if (In3270) { 194730088Sminshall *Ifrontp++ = c; 194830088Sminshall Sbp = sbp; 194930088Sminshall Scc = scc; 195030088Sminshall while (Scc > 0) { 195130088Sminshall c = *Sbp++ & 0377, Scc--; 195230088Sminshall if (c == IAC) { 195330722Sminshall telrcv_state = TS_IAC; 195430088Sminshall break; 195530088Sminshall } 195630088Sminshall *Ifrontp++ = c; 195730088Sminshall } 195830088Sminshall sbp = Sbp; 195930088Sminshall scc = Scc; 196030088Sminshall } else 196130088Sminshall # endif /* defined(TN3270) */ 196230088Sminshall /* 196330088Sminshall * The 'crmod' hack (see following) is needed 196430088Sminshall * since we can't * set CRMOD on output only. 196530088Sminshall * Machines like MULTICS like to send \r without 196630088Sminshall * \n; since we must turn off CRMOD to get proper 196730088Sminshall * input, the mapping is done here (sigh). 196830088Sminshall */ 196930088Sminshall if (c == '\r') { 197030088Sminshall if (scc > 0) { 197130088Sminshall c = *sbp&0xff; 197230088Sminshall if (c == 0) { 197330088Sminshall sbp++, scc--; 197430088Sminshall /* a "true" CR */ 197530088Sminshall TTYADD('\r'); 197630088Sminshall } else if (!hisopts[TELOPT_ECHO] && 197730088Sminshall (c == '\n')) { 197830088Sminshall sbp++, scc--; 197930088Sminshall TTYADD('\n'); 198030088Sminshall } else { 198130088Sminshall TTYADD('\r'); 198230088Sminshall if (crmod) { 198330088Sminshall TTYADD('\n'); 198430088Sminshall } 198530088Sminshall } 198630088Sminshall } else { 198730722Sminshall telrcv_state = TS_CR; 198830088Sminshall TTYADD('\r'); 198930088Sminshall if (crmod) { 199030088Sminshall TTYADD('\n'); 199130088Sminshall } 199230088Sminshall } 199330088Sminshall } else { 199430088Sminshall TTYADD(c); 199530088Sminshall } 199630088Sminshall continue; 199730088Sminshall 199830088Sminshall case TS_IAC: 199930088Sminshall switch (c) { 200030088Sminshall 200130088Sminshall case WILL: 200230722Sminshall telrcv_state = TS_WILL; 200330088Sminshall continue; 200430088Sminshall 200530088Sminshall case WONT: 200630722Sminshall telrcv_state = TS_WONT; 200730088Sminshall continue; 200830088Sminshall 200930088Sminshall case DO: 201030722Sminshall telrcv_state = TS_DO; 201130088Sminshall continue; 201230088Sminshall 201330088Sminshall case DONT: 201430722Sminshall telrcv_state = TS_DONT; 201530088Sminshall continue; 201630088Sminshall 201730088Sminshall case DM: 201830088Sminshall /* 201930088Sminshall * We may have missed an urgent notification, 202030088Sminshall * so make sure we flush whatever is in the 202130088Sminshall * buffer currently. 202230088Sminshall */ 202330088Sminshall SYNCHing = 1; 202430088Sminshall ttyflush(); 202530088Sminshall SYNCHing = stilloob(net); 202630088Sminshall settimer(gotDM); 202730088Sminshall break; 202830088Sminshall 202930088Sminshall case NOP: 203030088Sminshall case GA: 203130088Sminshall break; 203230088Sminshall 203330088Sminshall case SB: 203430088Sminshall SB_CLEAR(); 203530722Sminshall telrcv_state = TS_SB; 203630088Sminshall continue; 203730088Sminshall 203830088Sminshall # if defined(TN3270) 203930088Sminshall case EOR: 204030088Sminshall if (In3270) { 204130088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 204230088Sminshall if (Ibackp == Ifrontp) { 204330088Sminshall Ibackp = Ifrontp = Ibuf; 204430088Sminshall ISend = 0; /* should have been! */ 204530088Sminshall } else { 204630088Sminshall ISend = 1; 204730088Sminshall } 204830088Sminshall } 204930088Sminshall break; 205030088Sminshall # endif /* defined(TN3270) */ 205130088Sminshall 205230088Sminshall case IAC: 205330088Sminshall # if !defined(TN3270) 205430088Sminshall TTYADD(IAC); 205530088Sminshall # else /* !defined(TN3270) */ 205630088Sminshall if (In3270) { 205730088Sminshall *Ifrontp++ = IAC; 205830088Sminshall } else { 205930088Sminshall TTYADD(IAC); 206030088Sminshall } 206130088Sminshall # endif /* !defined(TN3270) */ 206230088Sminshall break; 206330088Sminshall 206430088Sminshall default: 206530088Sminshall break; 206630088Sminshall } 206730722Sminshall telrcv_state = TS_DATA; 206830088Sminshall continue; 206930088Sminshall 207030088Sminshall case TS_WILL: 207130088Sminshall printoption(">RCVD", will, c, !hisopts[c]); 207230088Sminshall if (c == TELOPT_TM) { 207330088Sminshall if (flushout) { 207430088Sminshall flushout = 0; 207530088Sminshall } 207630088Sminshall } else if (!hisopts[c]) { 207730088Sminshall willoption(c, 1); 207830088Sminshall } 207930088Sminshall SetIn3270(); 208030722Sminshall telrcv_state = TS_DATA; 208130088Sminshall continue; 208230088Sminshall 208330088Sminshall case TS_WONT: 208430088Sminshall printoption(">RCVD", wont, c, hisopts[c]); 208530088Sminshall if (c == TELOPT_TM) { 208630088Sminshall if (flushout) { 208730088Sminshall flushout = 0; 208830088Sminshall } 208930088Sminshall } else if (hisopts[c]) { 209030088Sminshall wontoption(c, 1); 209130088Sminshall } 209230088Sminshall SetIn3270(); 209330722Sminshall telrcv_state = TS_DATA; 209430088Sminshall continue; 209530088Sminshall 209630088Sminshall case TS_DO: 209730088Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 209830088Sminshall if (!myopts[c]) 209930088Sminshall dooption(c); 210030088Sminshall SetIn3270(); 210130722Sminshall telrcv_state = TS_DATA; 210230088Sminshall continue; 210330088Sminshall 210430088Sminshall case TS_DONT: 210530088Sminshall printoption(">RCVD", dont, c, myopts[c]); 210630088Sminshall if (myopts[c]) { 210730088Sminshall myopts[c] = 0; 210830088Sminshall sprintf(nfrontp, wont, c); 210930088Sminshall nfrontp += sizeof (wont) - 2; 211030088Sminshall flushline = 1; 211130088Sminshall setconnmode(); /* set new tty mode (maybe) */ 211230088Sminshall printoption(">SENT", wont, c, 0); 211330088Sminshall } 211430088Sminshall SetIn3270(); 211530722Sminshall telrcv_state = TS_DATA; 211630088Sminshall continue; 211730088Sminshall 211830088Sminshall case TS_SB: 211930088Sminshall if (c == IAC) { 212030722Sminshall telrcv_state = TS_SE; 212130088Sminshall } else { 212230088Sminshall SB_ACCUM(c); 212330088Sminshall } 212430088Sminshall continue; 212530088Sminshall 212630088Sminshall case TS_SE: 212730088Sminshall if (c != SE) { 212830088Sminshall if (c != IAC) { 212930088Sminshall SB_ACCUM(IAC); 213030088Sminshall } 213130088Sminshall SB_ACCUM(c); 213230722Sminshall telrcv_state = TS_SB; 213330088Sminshall } else { 213430088Sminshall SB_TERM(); 213530088Sminshall suboption(); /* handle sub-option */ 213630088Sminshall SetIn3270(); 213730722Sminshall telrcv_state = TS_DATA; 213830088Sminshall } 213930088Sminshall } 214030088Sminshall } 214130088Sminshall } 214230088Sminshall 214330088Sminshall #if defined(TN3270) 214430088Sminshall 214530088Sminshall /* 214630088Sminshall * The following routines are places where the various tn3270 214730088Sminshall * routines make calls into telnet.c. 214830088Sminshall */ 214930088Sminshall 215030088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 215130088Sminshall TtyChars() 215230088Sminshall { 215330088Sminshall return(tfrontp-tbackp); 215430088Sminshall } 215530088Sminshall 215630088Sminshall /* 215730088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 215830088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 215930088Sminshall * don't call us with "done" until you want that done...) 216030088Sminshall * 216130088Sminshall * We actually do send all the data to the network buffer, since our 216230088Sminshall * only client needs for us to do that. 216330088Sminshall */ 216430088Sminshall 216530088Sminshall int 216630088Sminshall DataToNetwork(buffer, count, done) 216730088Sminshall register char *buffer; /* where the data is */ 216830088Sminshall register int count; /* how much to send */ 216930088Sminshall int done; /* is this the last of a logical block */ 217030088Sminshall { 217130088Sminshall register int c; 217230088Sminshall int origCount; 217330088Sminshall fd_set o; 217430088Sminshall 217530088Sminshall origCount = count; 217630088Sminshall FD_ZERO(&o); 217730088Sminshall 217830088Sminshall while (count) { 217930088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 218030088Sminshall netflush(); 218130088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) { 218230088Sminshall FD_SET(net, &o); 218330088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 218430088Sminshall (struct timeval *) 0); 218530088Sminshall netflush(); 218630088Sminshall } 218730088Sminshall } 218830088Sminshall c = *buffer++; 218930088Sminshall count--; 219030088Sminshall if (c == IAC) { 219130088Sminshall *nfrontp++ = IAC; 219230088Sminshall *nfrontp++ = IAC; 219330088Sminshall } else { 219430088Sminshall *nfrontp++ = c; 219530088Sminshall } 219630088Sminshall } 219730088Sminshall 219830088Sminshall if (done && !count) { 219930088Sminshall *nfrontp++ = IAC; 220030088Sminshall *nfrontp++ = EOR; 220130088Sminshall netflush(); /* try to move along as quickly as ... */ 220230088Sminshall } 220330088Sminshall return(origCount - count); 220430088Sminshall } 220530088Sminshall 220630088Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 220730088Sminshall 220830088Sminshall int 220930088Sminshall DataToTerminal(buffer, count) 221030088Sminshall register char *buffer; /* where the data is */ 221130088Sminshall register int count; /* how much to send */ 221230088Sminshall { 221330088Sminshall int origCount; 221431131Sminshall #if defined(unix) 221530088Sminshall fd_set o; 221630088Sminshall 221731131Sminshall FD_ZERO(&o); 221831131Sminshall #endif /* defined(unix) */ 221930088Sminshall origCount = count; 222030088Sminshall 222130088Sminshall while (count) { 222230088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 222330088Sminshall ttyflush(); 222430088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 222531131Sminshall #if defined(unix) 222630088Sminshall FD_SET(tout, &o); 222730088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 222830088Sminshall (struct timeval *) 0); 222931131Sminshall #endif /* defined(unix) */ 223030088Sminshall ttyflush(); 223130088Sminshall } 223230088Sminshall } 223330088Sminshall *tfrontp++ = *buffer++; 223430088Sminshall count--; 223530088Sminshall } 223630088Sminshall return(origCount - count); 223730088Sminshall } 223830088Sminshall 223930088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 224030088Sminshall * Note that we consider the buffer to run all the 224130088Sminshall * way to the kernel (thus the select). 224230088Sminshall */ 224330088Sminshall 224430088Sminshall void 224530088Sminshall EmptyTerminal() 224630088Sminshall { 224731131Sminshall #if defined(unix) 224830088Sminshall fd_set o; 224930088Sminshall 225030088Sminshall FD_ZERO(&o); 225131131Sminshall #endif /* defined(unix) */ 225230088Sminshall 225330088Sminshall if (tfrontp == tbackp) { 225431131Sminshall #if defined(unix) 225530088Sminshall FD_SET(tout, &o); 225630088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 225730088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 225831131Sminshall #endif /* defined(unix) */ 225930088Sminshall } else { 226030088Sminshall while (tfrontp != tbackp) { 226130088Sminshall ttyflush(); 226231131Sminshall #if defined(unix) 226330088Sminshall FD_SET(tout, &o); 226430088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 226530088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 226631131Sminshall #endif /* defined(unix) */ 226730088Sminshall } 226830088Sminshall } 226930088Sminshall } 227030088Sminshall 227130088Sminshall /* 227230088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 227330088Sminshall */ 227430088Sminshall 227530088Sminshall static int 227630088Sminshall Push3270() 227730088Sminshall { 227830088Sminshall int save = scc; 227930088Sminshall 228030088Sminshall if (scc) { 228130088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 228230088Sminshall if (Ibackp != Ibuf) { 228331131Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 228430088Sminshall Ifrontp -= (Ibackp-Ibuf); 228530088Sminshall Ibackp = Ibuf; 228630088Sminshall } 228730088Sminshall } 228830088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 228930088Sminshall telrcv(); 229030088Sminshall } 229130088Sminshall } 229230088Sminshall return save != scc; 229330088Sminshall } 229430088Sminshall 229530088Sminshall 229630088Sminshall /* 229730088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 229830088Sminshall * before quitting. 229930088Sminshall */ 230030088Sminshall 230130088Sminshall static void 230230088Sminshall Finish3270() 230330088Sminshall { 230430088Sminshall while (Push3270() || !DoTerminalOutput()) { 230531589Sminshall #if defined(unix) 230631589Sminshall HaveInput = 0; 230731589Sminshall #endif /* defined(unix) */ 230830088Sminshall ; 230930088Sminshall } 231030088Sminshall } 231130088Sminshall 231230088Sminshall 231330088Sminshall 231430088Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 231530088Sminshall 231630088Sminshall void 231730088Sminshall StringToTerminal(s) 231830088Sminshall char *s; 231930088Sminshall { 232030088Sminshall int count; 232130088Sminshall 232230088Sminshall count = strlen(s); 232330088Sminshall if (count) { 232430088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 232530088Sminshall } 232630088Sminshall } 232730088Sminshall 232830088Sminshall 232930088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) 233030088Sminshall /* _putchar - output a single character to the terminal. This name is so that 233130088Sminshall * curses(3x) can call us to send out data. 233230088Sminshall */ 233330088Sminshall 233430088Sminshall void 233530088Sminshall _putchar(c) 233630088Sminshall char c; 233730088Sminshall { 233830088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 233930088Sminshall (void) DataToTerminal(&c, 1); 234030088Sminshall } else { 234130088Sminshall *tfrontp++ = c; /* optimize if possible. */ 234230088Sminshall } 234330088Sminshall } 234430088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ 234530088Sminshall 234630088Sminshall static void 234730088Sminshall SetForExit() 234830088Sminshall { 234930088Sminshall setconnmode(); 235030088Sminshall if (In3270) { 235130088Sminshall Finish3270(); 235230088Sminshall } 235330088Sminshall setcommandmode(); 235430088Sminshall fflush(stdout); 235530088Sminshall fflush(stderr); 235630088Sminshall if (In3270) { 235730088Sminshall StopScreen(1); 235830088Sminshall } 235930088Sminshall setconnmode(); 236030088Sminshall setcommandmode(); 236130088Sminshall } 236230088Sminshall 236330088Sminshall static void 236430088Sminshall Exit(returnCode) 236530088Sminshall int returnCode; 236630088Sminshall { 236730088Sminshall SetForExit(); 236830088Sminshall exit(returnCode); 236930088Sminshall } 237030088Sminshall 237130088Sminshall void 237230088Sminshall ExitString(file, string, returnCode) 237330088Sminshall FILE *file; 237430088Sminshall char *string; 237530088Sminshall int returnCode; 237630088Sminshall { 237730088Sminshall SetForExit(); 237830088Sminshall fwrite(string, 1, strlen(string), file); 237930088Sminshall exit(returnCode); 238030088Sminshall } 238130088Sminshall 238230088Sminshall void 238330088Sminshall ExitPerror(string, returnCode) 238430088Sminshall char *string; 238530088Sminshall int returnCode; 238630088Sminshall { 238730088Sminshall SetForExit(); 238830088Sminshall perror(string); 238930088Sminshall exit(returnCode); 239030088Sminshall } 239130088Sminshall 239230088Sminshall #endif /* defined(TN3270) */ 239330088Sminshall 239431215Sminshall /* 239531215Sminshall * Scheduler() 239631215Sminshall * 239731215Sminshall * Try to do something. 239831215Sminshall * 239931215Sminshall * If we do something useful, return 1; else return 0. 240031215Sminshall * 240131215Sminshall */ 240231215Sminshall 240331215Sminshall 240431215Sminshall int 240530088Sminshall Scheduler(block) 240630088Sminshall int block; /* should we block in the select ? */ 240730088Sminshall { 240830088Sminshall register int c; 240930088Sminshall /* One wants to be a bit careful about setting returnValue 241030088Sminshall * to one, since a one implies we did some useful work, 241130088Sminshall * and therefore probably won't be called to block next 241230088Sminshall * time (TN3270 mode only). 241330088Sminshall */ 241430088Sminshall int returnValue = 0; 241530088Sminshall static struct timeval TimeValue = { 0 }; 241630088Sminshall 241730088Sminshall if (scc < 0 && tcc < 0) { 241830088Sminshall return -1; 241930088Sminshall } 242030088Sminshall 242130088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 242230088Sminshall FD_SET(net, &obits); 242330088Sminshall } 242431131Sminshall #if !defined(MSDOS) 242530088Sminshall if (TTYBYTES()) { 242630088Sminshall FD_SET(tout, &obits); 242730088Sminshall } 242831215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0)) { 242930088Sminshall FD_SET(tin, &ibits); 243030088Sminshall } 243131131Sminshall #endif /* !defined(MSDOS) */ 243230088Sminshall # if !defined(TN3270) 243330088Sminshall if (TTYROOM()) { 243430088Sminshall FD_SET(net, &ibits); 243530088Sminshall } 243630088Sminshall # else /* !defined(TN3270) */ 243730088Sminshall if (!ISend && TTYROOM()) { 243830088Sminshall FD_SET(net, &ibits); 243930088Sminshall } 244030088Sminshall # endif /* !defined(TN3270) */ 244130088Sminshall if (!SYNCHing) { 244230088Sminshall FD_SET(net, &xbits); 244330088Sminshall } 244430088Sminshall # if defined(TN3270) && defined(unix) 244530088Sminshall if (HaveInput) { 244630088Sminshall HaveInput = 0; 244730088Sminshall signal(SIGIO, inputAvailable); 244830088Sminshall } 244930088Sminshall #endif /* defined(TN3270) && defined(unix) */ 245030088Sminshall if ((c = select(16, &ibits, &obits, &xbits, 245131131Sminshall block? (struct timeval *)0 : &TimeValue)) < 0) { 245230088Sminshall if (c == -1) { 245330088Sminshall /* 245430088Sminshall * we can get EINTR if we are in line mode, 245530088Sminshall * and the user does an escape (TSTP), or 245630088Sminshall * some other signal generator. 245730088Sminshall */ 245830088Sminshall if (errno == EINTR) { 245930088Sminshall return 0; 246030088Sminshall } 246130088Sminshall # if defined(TN3270) 246230088Sminshall /* 246330088Sminshall * we can get EBADF if we were in transparent 246430088Sminshall * mode, and the transcom process died. 246530088Sminshall */ 246630088Sminshall if (errno == EBADF) { 246730088Sminshall /* 246830088Sminshall * zero the bits (even though kernel does it) 246930088Sminshall * to make sure we are selecting on the right 247030088Sminshall * ones. 247130088Sminshall */ 247230088Sminshall FD_ZERO(&ibits); 247330088Sminshall FD_ZERO(&obits); 247430088Sminshall FD_ZERO(&xbits); 247530088Sminshall return 0; 247630088Sminshall } 247730088Sminshall # endif /* defined(TN3270) */ 247830088Sminshall /* I don't like this, does it ever happen? */ 247930088Sminshall printf("sleep(5) from telnet, after select\r\n"); 248030088Sminshall #if defined(unix) 248130088Sminshall sleep(5); 248230088Sminshall #endif /* defined(unix) */ 248330088Sminshall } 248430088Sminshall return 0; 248530088Sminshall } 248630088Sminshall 248730088Sminshall /* 248830088Sminshall * Any urgent data? 248930088Sminshall */ 249030088Sminshall if (FD_ISSET(net, &xbits)) { 249130088Sminshall FD_CLR(net, &xbits); 249230088Sminshall SYNCHing = 1; 249330088Sminshall ttyflush(); /* flush already enqueued data */ 249430088Sminshall } 249530088Sminshall 249630088Sminshall /* 249730088Sminshall * Something to read from the network... 249830088Sminshall */ 249930088Sminshall if (FD_ISSET(net, &ibits)) { 250030088Sminshall int canread; 250130088Sminshall 250230088Sminshall FD_CLR(net, &ibits); 250330088Sminshall if (scc == 0) { 250430088Sminshall sbp = sibuf; 250530088Sminshall } 250630422Sminshall canread = sibuf + sizeof sibuf - (sbp+scc); 250730088Sminshall #if !defined(SO_OOBINLINE) 250830088Sminshall /* 250930088Sminshall * In 4.2 (and some early 4.3) systems, the 251030088Sminshall * OOB indication and data handling in the kernel 251130088Sminshall * is such that if two separate TCP Urgent requests 251230088Sminshall * come in, one byte of TCP data will be overlaid. 251330088Sminshall * This is fatal for Telnet, but we try to live 251430088Sminshall * with it. 251530088Sminshall * 251630088Sminshall * In addition, in 4.2 (and...), a special protocol 251730088Sminshall * is needed to pick up the TCP Urgent data in 251830088Sminshall * the correct sequence. 251930088Sminshall * 252030088Sminshall * What we do is: if we think we are in urgent 252130088Sminshall * mode, we look to see if we are "at the mark". 252230088Sminshall * If we are, we do an OOB receive. If we run 252330088Sminshall * this twice, we will do the OOB receive twice, 252430088Sminshall * but the second will fail, since the second 252530088Sminshall * time we were "at the mark", but there wasn't 252630088Sminshall * any data there (the kernel doesn't reset 252730088Sminshall * "at the mark" until we do a normal read). 252830088Sminshall * Once we've read the OOB data, we go ahead 252930088Sminshall * and do normal reads. 253030088Sminshall * 253130088Sminshall * There is also another problem, which is that 253230088Sminshall * since the OOB byte we read doesn't put us 253330088Sminshall * out of OOB state, and since that byte is most 253430088Sminshall * likely the TELNET DM (data mark), we would 253530088Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 253630088Sminshall * So, clocks to the rescue. If we've "just" 253730088Sminshall * received a DM, then we test for the 253830088Sminshall * presence of OOB data when the receive OOB 253930088Sminshall * fails (and AFTER we did the normal mode read 254030088Sminshall * to clear "at the mark"). 254130088Sminshall */ 254230088Sminshall if (SYNCHing) { 254330088Sminshall int atmark; 254430088Sminshall 254530088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 254630088Sminshall if (atmark) { 254730422Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 254830088Sminshall if ((c == -1) && (errno == EINVAL)) { 254931131Sminshall c = recv(net, sbp+scc, canread, 0); 255030088Sminshall if (clocks.didnetreceive < clocks.gotDM) { 255130088Sminshall SYNCHing = stilloob(net); 255230088Sminshall } 255330088Sminshall } 255430088Sminshall } else { 255531131Sminshall c = recv(net, sbp+scc, canread, 0); 255630088Sminshall } 255730088Sminshall } else { 255831131Sminshall c = recv(net, sbp+scc, canread, 0); 255930088Sminshall } 256030088Sminshall settimer(didnetreceive); 256130088Sminshall #else /* !defined(SO_OOBINLINE) */ 256231131Sminshall c = recv(net, sbp+scc, canread, 0); 256330088Sminshall #endif /* !defined(SO_OOBINLINE) */ 256430088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 256530088Sminshall c = 0; 256630088Sminshall } else if (c <= 0) { 256730088Sminshall return -1; 256830088Sminshall } 256930088Sminshall if (netdata) { 257030422Sminshall Dump('<', sbp+scc, c); 257130088Sminshall } 257230088Sminshall scc += c; 257330088Sminshall returnValue = 1; 257430088Sminshall } 257530088Sminshall 257630088Sminshall /* 257730088Sminshall * Something to read from the tty... 257830088Sminshall */ 257931131Sminshall #if defined(MSDOS) 258031215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead()) 258131131Sminshall #else /* defined(MSDOS) */ 258231131Sminshall if (FD_ISSET(tin, &ibits)) 258331131Sminshall #endif /* defined(MSDOS) */ 258431131Sminshall { 258530088Sminshall FD_CLR(tin, &ibits); 258630088Sminshall if (tcc == 0) { 258730088Sminshall tbp = tibuf; /* nothing left, reset */ 258830088Sminshall } 258931131Sminshall c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp); 259030088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 259130088Sminshall c = 0; 259230088Sminshall } else { 259331124Sminshall #if defined(unix) 259430088Sminshall /* EOF detection for line mode!!!! */ 259530088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 259630088Sminshall /* must be an EOF... */ 259730088Sminshall *tbp = ntc.t_eofc; 259830088Sminshall c = 1; 259930088Sminshall } 260031124Sminshall #endif /* defined(unix) */ 260130088Sminshall if (c <= 0) { 260230088Sminshall tcc = c; 260330088Sminshall return -1; 260430088Sminshall } 260530088Sminshall } 260630088Sminshall tcc += c; 260730088Sminshall returnValue = 1; /* did something useful */ 260830088Sminshall } 260930088Sminshall 261030088Sminshall # if defined(TN3270) 261130088Sminshall if (tcc > 0) { 261230088Sminshall if (In3270) { 261330088Sminshall c = DataFromTerminal(tbp, tcc); 261430088Sminshall if (c) { 261530088Sminshall returnValue = 1; 261630088Sminshall } 261730088Sminshall tcc -= c; 261830088Sminshall tbp += c; 261930088Sminshall } else { 262030320Sminshall # endif /* defined(TN3270) */ 262130088Sminshall returnValue = 1; 262230088Sminshall while (tcc > 0) { 262330088Sminshall register int sc; 262430088Sminshall 262530088Sminshall if (NETROOM() < 2) { 262630088Sminshall flushline = 1; 262730088Sminshall break; 262830088Sminshall } 262930088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 263030088Sminshall if (sc == escape) { 263130088Sminshall command(0); 263230088Sminshall tcc = 0; 263330088Sminshall flushline = 1; 263430088Sminshall break; 263530088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 263630088Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 263730088Sminshall tbp++; 263830088Sminshall tcc--; 263930088Sminshall } else { 264030088Sminshall dontlecho = !dontlecho; 264130088Sminshall settimer(echotoggle); 264230088Sminshall setconnmode(); 264330088Sminshall tcc = 0; 264430088Sminshall flushline = 1; 264530088Sminshall break; 264630088Sminshall } 264730088Sminshall } 264830088Sminshall if (localchars) { 264931131Sminshall if (TerminalSpecialChars(sc) == 0) { 265030088Sminshall break; 265130088Sminshall } 265230088Sminshall } 265330088Sminshall switch (c) { 265430088Sminshall case '\n': 265530088Sminshall /* 265630088Sminshall * If we are in CRMOD mode (\r ==> \n) 265730088Sminshall * on our local machine, then probably 265830088Sminshall * a newline (unix) is CRLF (TELNET). 265930088Sminshall */ 266030088Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 266130088Sminshall NETADD('\r'); 266230088Sminshall } 266330088Sminshall NETADD('\n'); 266430088Sminshall flushline = 1; 266530088Sminshall break; 266630088Sminshall case '\r': 266730088Sminshall NET2ADD('\r', '\0'); 266830088Sminshall flushline = 1; 266930088Sminshall break; 267030088Sminshall case IAC: 267130088Sminshall NET2ADD(IAC, IAC); 267230088Sminshall break; 267330088Sminshall default: 267430088Sminshall NETADD(c); 267530088Sminshall break; 267630088Sminshall } 267730088Sminshall } 267830088Sminshall # if defined(TN3270) 267930088Sminshall } 268030088Sminshall } 268130088Sminshall # endif /* defined(TN3270) */ 268230088Sminshall 268330088Sminshall if ((!MODE_LINE(globalmode) || flushline) && 268430088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 268530088Sminshall FD_CLR(net, &obits); 268630088Sminshall returnValue = netflush(); 268730088Sminshall } 268830088Sminshall if (scc > 0) { 268930088Sminshall # if !defined(TN3270) 269030088Sminshall telrcv(); 269130088Sminshall returnValue = 1; 269230088Sminshall # else /* !defined(TN3270) */ 269330088Sminshall returnValue = Push3270(); 269430088Sminshall # endif /* !defined(TN3270) */ 269530088Sminshall } 269631131Sminshall #if defined(MSDOS) 269731131Sminshall if (TTYBYTES()) 269831131Sminshall #else /* defined(MSDOS) */ 269931131Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 270031131Sminshall #endif /* defined(MSDOS) */ 270131131Sminshall { 270230088Sminshall FD_CLR(tout, &obits); 270330088Sminshall returnValue = ttyflush(); 270430088Sminshall } 270530088Sminshall return returnValue; 270630088Sminshall } 270730088Sminshall 270830088Sminshall /* 270930088Sminshall * Select from tty and network... 271030088Sminshall */ 271130088Sminshall static void 271230088Sminshall telnet() 271330088Sminshall { 271431131Sminshall #if defined(MSDOS) 271531131Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */ 271631131Sminshall #else /* defined(MSDOS) */ 271731131Sminshall #define SCHED_BLOCK 1 271831131Sminshall #endif /* defined(MSDOS) */ 271931131Sminshall 272030088Sminshall #if defined(TN3270) && defined(unix) 272130088Sminshall int myPid; 272230088Sminshall #endif /* defined(TN3270) */ 272330088Sminshall 272430088Sminshall tout = fileno(stdout); 272530088Sminshall tin = fileno(stdin); 272630088Sminshall setconnmode(); 272730088Sminshall scc = 0; 272830088Sminshall tcc = 0; 272930088Sminshall FD_ZERO(&ibits); 273030088Sminshall FD_ZERO(&obits); 273130088Sminshall FD_ZERO(&xbits); 273230088Sminshall 273331124Sminshall NetNonblockingIO(net, 1); 273430088Sminshall 273530088Sminshall #if defined(TN3270) 273631478Sminshall if (noasynch == 0) { /* DBX can't handle! */ 273731478Sminshall NetSigIO(net, 1); 273831478Sminshall } 273931124Sminshall NetSetPgrp(net); 274030088Sminshall #endif /* defined(TN3270) */ 274130088Sminshall 274230088Sminshall 274331124Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 274431124Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 274531124Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 274631124Sminshall 274730320Sminshall # if !defined(TN3270) 274830088Sminshall if (telnetport) { 274930088Sminshall if (!hisopts[TELOPT_SGA]) { 275030088Sminshall willoption(TELOPT_SGA, 0); 275130088Sminshall } 275230088Sminshall if (!myopts[TELOPT_TTYPE]) { 275330088Sminshall dooption(TELOPT_TTYPE, 0); 275430088Sminshall } 275530088Sminshall } 275630320Sminshall # endif /* !defined(TN3270) */ 275730088Sminshall 275830088Sminshall # if !defined(TN3270) 275930088Sminshall for (;;) { 276031131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 276130088Sminshall setcommandmode(); 276230088Sminshall return; 276330088Sminshall } 276430088Sminshall } 276530088Sminshall # else /* !defined(TN3270) */ 276630088Sminshall for (;;) { 276730088Sminshall int schedValue; 276830088Sminshall 276931791Sminshall while (!In3270 && !shell_active) { 277031131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 277130088Sminshall setcommandmode(); 277230088Sminshall return; 277330088Sminshall } 277430088Sminshall } 277530088Sminshall 277630088Sminshall while ((schedValue = Scheduler(0)) != 0) { 277730088Sminshall if (schedValue == -1) { 277830088Sminshall setcommandmode(); 277930088Sminshall return; 278030088Sminshall } 278130088Sminshall } 278230088Sminshall /* If there is data waiting to go out to terminal, don't 278330088Sminshall * schedule any more data for the terminal. 278430088Sminshall */ 278530088Sminshall if (tfrontp-tbackp) { 278630088Sminshall schedValue = 1; 278730088Sminshall } else { 278831215Sminshall if (shell_active) { 278931215Sminshall if (shell_continue() == 0) { 279031215Sminshall ConnectScreen(); 279131215Sminshall } 279231791Sminshall } else if (In3270) { 279331215Sminshall schedValue = DoTerminalOutput(); 279431215Sminshall } 279530088Sminshall } 279631215Sminshall if (schedValue && (shell_active == 0)) { 279731131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 279830088Sminshall setcommandmode(); 279930088Sminshall return; 280030088Sminshall } 280130088Sminshall } 280230088Sminshall } 280330088Sminshall # endif /* !defined(TN3270) */ 280430088Sminshall } 280530088Sminshall 280630088Sminshall /* 280730088Sminshall * The following are data structures and routines for 280830088Sminshall * the "send" command. 280930088Sminshall * 281030088Sminshall */ 281130088Sminshall 281230088Sminshall struct sendlist { 281330088Sminshall char *name; /* How user refers to it (case independent) */ 281430088Sminshall int what; /* Character to be sent (<0 ==> special) */ 281530088Sminshall char *help; /* Help information (0 ==> no help) */ 281630088Sminshall #if defined(NOT43) 281730088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 281830088Sminshall #else /* defined(NOT43) */ 281930088Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 282030088Sminshall #endif /* defined(NOT43) */ 282130088Sminshall }; 282230088Sminshall 282330088Sminshall #define SENDQUESTION -1 282430088Sminshall #define SENDESCAPE -3 282530088Sminshall 282630088Sminshall static struct sendlist Sendlist[] = { 282730088Sminshall { "ao", AO, "Send Telnet Abort output" }, 282830088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 282930088Sminshall { "brk", BREAK, "Send Telnet Break" }, 283030088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 283130088Sminshall { "el", EL, "Send Telnet Erase Line" }, 283230088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 283330088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 283430088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 283530088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 283630088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 283730088Sminshall { "?", SENDQUESTION, "Display send options" }, 283830088Sminshall { 0 } 283930088Sminshall }; 284030088Sminshall 284130088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 284230088Sminshall { "break", BREAK, 0 }, 284330088Sminshall 284430088Sminshall { "intp", IP, 0 }, 284530088Sminshall { "interrupt", IP, 0 }, 284630088Sminshall { "intr", IP, 0 }, 284730088Sminshall 284830088Sminshall { "help", SENDQUESTION, 0 }, 284930088Sminshall 285030088Sminshall { 0 } 285130088Sminshall }; 285230088Sminshall 285330088Sminshall static char ** 285430088Sminshall getnextsend(name) 285530088Sminshall char *name; 285630088Sminshall { 285730088Sminshall struct sendlist *c = (struct sendlist *) name; 285830088Sminshall 285930088Sminshall return (char **) (c+1); 286030088Sminshall } 286130088Sminshall 286230088Sminshall static struct sendlist * 286330088Sminshall getsend(name) 286430088Sminshall char *name; 286530088Sminshall { 286630088Sminshall struct sendlist *sl; 286730088Sminshall 286830088Sminshall if ((sl = (struct sendlist *) 286930088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 287030088Sminshall return sl; 287130088Sminshall } else { 287230088Sminshall return (struct sendlist *) 287330088Sminshall genget(name, (char **) Sendlist2, getnextsend); 287430088Sminshall } 287530088Sminshall } 287630088Sminshall 287730088Sminshall static 287830088Sminshall sendcmd(argc, argv) 287930088Sminshall int argc; 288030088Sminshall char **argv; 288130088Sminshall { 288230088Sminshall int what; /* what we are sending this time */ 288330088Sminshall int count; /* how many bytes we are going to need to send */ 288430088Sminshall int i; 288530088Sminshall int question = 0; /* was at least one argument a question */ 288630088Sminshall struct sendlist *s; /* pointer to current command */ 288730088Sminshall 288830088Sminshall if (argc < 2) { 288930088Sminshall printf("need at least one argument for 'send' command\n"); 289030088Sminshall printf("'send ?' for help\n"); 289130088Sminshall return 0; 289230088Sminshall } 289330088Sminshall /* 289430088Sminshall * First, validate all the send arguments. 289530088Sminshall * In addition, we see how much space we are going to need, and 289630088Sminshall * whether or not we will be doing a "SYNCH" operation (which 289730088Sminshall * flushes the network queue). 289830088Sminshall */ 289930088Sminshall count = 0; 290030088Sminshall for (i = 1; i < argc; i++) { 290130088Sminshall s = getsend(argv[i]); 290230088Sminshall if (s == 0) { 290330088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 290430088Sminshall argv[i]); 290530088Sminshall return 0; 290630088Sminshall } else if (s == Ambiguous(struct sendlist *)) { 290730088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 290830088Sminshall argv[i]); 290930088Sminshall return 0; 291030088Sminshall } 291130088Sminshall switch (s->what) { 291230088Sminshall case SENDQUESTION: 291330088Sminshall break; 291430088Sminshall case SENDESCAPE: 291530088Sminshall count += 1; 291630088Sminshall break; 291730088Sminshall case SYNCH: 291830088Sminshall count += 2; 291930088Sminshall break; 292030088Sminshall default: 292130088Sminshall count += 2; 292230088Sminshall break; 292330088Sminshall } 292430088Sminshall } 292530088Sminshall /* Now, do we have enough room? */ 292630088Sminshall if (NETROOM() < count) { 292730088Sminshall printf("There is not enough room in the buffer TO the network\n"); 292830088Sminshall printf("to process your request. Nothing will be done.\n"); 292930088Sminshall printf("('send synch' will throw away most data in the network\n"); 293030088Sminshall printf("buffer, if this might help.)\n"); 293130088Sminshall return 0; 293230088Sminshall } 293330088Sminshall /* OK, they are all OK, now go through again and actually send */ 293430088Sminshall for (i = 1; i < argc; i++) { 293530088Sminshall if ((s = getsend(argv[i])) == 0) { 293630088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 293730088Sminshall quit(); 293830088Sminshall /*NOTREACHED*/ 293930088Sminshall } 294030088Sminshall if (s->routine) { 294130088Sminshall (*s->routine)(s); 294230088Sminshall } else { 294330088Sminshall switch (what = s->what) { 294430088Sminshall case SYNCH: 294530088Sminshall dosynch(); 294630088Sminshall break; 294730088Sminshall case SENDQUESTION: 294830088Sminshall for (s = Sendlist; s->name; s++) { 294930088Sminshall if (s->help) { 295030088Sminshall printf(s->name); 295130088Sminshall if (s->help) { 295230088Sminshall printf("\t%s", s->help); 295330088Sminshall } 295430088Sminshall printf("\n"); 295530088Sminshall } 295630088Sminshall } 295730088Sminshall question = 1; 295830088Sminshall break; 295930088Sminshall case SENDESCAPE: 296030088Sminshall NETADD(escape); 296130088Sminshall break; 296230088Sminshall default: 296330088Sminshall NET2ADD(IAC, what); 296430088Sminshall break; 296530088Sminshall } 296630088Sminshall } 296730088Sminshall } 296830088Sminshall return !question; 296930088Sminshall } 297030088Sminshall 297130088Sminshall /* 297230088Sminshall * The following are the routines and data structures referred 297330088Sminshall * to by the arguments to the "toggle" command. 297430088Sminshall */ 297530088Sminshall 297630088Sminshall static 297730088Sminshall lclchars() 297830088Sminshall { 297930088Sminshall donelclchars = 1; 298030088Sminshall return 1; 298130088Sminshall } 298230088Sminshall 298330088Sminshall static 298430088Sminshall togdebug() 298530088Sminshall { 298630088Sminshall #ifndef NOT43 298730088Sminshall if (net > 0 && 298831124Sminshall (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 298930088Sminshall perror("setsockopt (SO_DEBUG)"); 299030088Sminshall } 299130320Sminshall #else /* NOT43 */ 299230088Sminshall if (debug) { 299331124Sminshall if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 299430088Sminshall perror("setsockopt (SO_DEBUG)"); 299530088Sminshall } else 299630088Sminshall printf("Cannot turn off socket debugging\n"); 299730320Sminshall #endif /* NOT43 */ 299830088Sminshall return 1; 299930088Sminshall } 300030088Sminshall 300130088Sminshall 300231791Sminshall static int 300331791Sminshall togbinary() 300431791Sminshall { 300531791Sminshall donebinarytoggle = 1; 300630088Sminshall 300731791Sminshall if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */ 300831791Sminshall NET2ADD(IAC, DO); 300931791Sminshall NETADD(TELOPT_BINARY); 301031791Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0); 301131791Sminshall NET2ADD(IAC, WILL); 301231791Sminshall NETADD(TELOPT_BINARY); 301331791Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0); 301431791Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1; 301531791Sminshall printf("Negotiating binary mode with remote host.\n"); 301631791Sminshall } else { /* Turn off binary mode */ 301731791Sminshall NET2ADD(IAC, DONT); 301831791Sminshall NETADD(TELOPT_BINARY); 301931791Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0); 302031791Sminshall NET2ADD(IAC, DONT); 302131791Sminshall NETADD(TELOPT_BINARY); 302231791Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0); 302331791Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0; 302431791Sminshall printf("Negotiating network ascii mode with remote host.\n"); 302531791Sminshall } 302631791Sminshall return 1; 302731791Sminshall } 302831791Sminshall 302931791Sminshall 303031791Sminshall 303130088Sminshall extern int togglehelp(); 303230088Sminshall 303330088Sminshall struct togglelist { 303430088Sminshall char *name; /* name of toggle */ 303530088Sminshall char *help; /* help message */ 303630088Sminshall int (*handler)(); /* routine to do actual setting */ 303730088Sminshall int dohelp; /* should we display help information */ 303830088Sminshall int *variable; 303930088Sminshall char *actionexplanation; 304030088Sminshall }; 304130088Sminshall 304230088Sminshall static struct togglelist Togglelist[] = { 304330088Sminshall { "autoflush", 304430088Sminshall "toggle flushing of output when sending interrupt characters", 304530088Sminshall 0, 304630088Sminshall 1, 304730088Sminshall &autoflush, 304830088Sminshall "flush output when sending interrupt characters" }, 304930088Sminshall { "autosynch", 305030088Sminshall "toggle automatic sending of interrupt characters in urgent mode", 305130088Sminshall 0, 305230088Sminshall 1, 305330088Sminshall &autosynch, 305430088Sminshall "send interrupt characters in urgent mode" }, 305531791Sminshall { "binary", 305631791Sminshall "toggle sending and receiving of binary data", 305731791Sminshall togbinary, 305831791Sminshall 1, 305931791Sminshall 0, 306031791Sminshall "send and receive network data in binary mode" }, 306130088Sminshall { "crmod", 306230088Sminshall "toggle mapping of received carriage returns", 306330088Sminshall 0, 306430088Sminshall 1, 306530088Sminshall &crmod, 306630088Sminshall "map carriage return on output" }, 306730088Sminshall { "localchars", 306830088Sminshall "toggle local recognition of certain control characters", 306930088Sminshall lclchars, 307030088Sminshall 1, 307130088Sminshall &localchars, 307230088Sminshall "recognize certain control characters" }, 307330088Sminshall { " ", "", 0, 1 }, /* empty line */ 307430088Sminshall { "debug", 307530088Sminshall "(debugging) toggle debugging", 307630088Sminshall togdebug, 307730088Sminshall 1, 307830088Sminshall &debug, 307930088Sminshall "turn on socket level debugging" }, 308030088Sminshall { "netdata", 308130088Sminshall "(debugging) toggle printing of hexadecimal network data", 308230088Sminshall 0, 308330088Sminshall 1, 308430088Sminshall &netdata, 308530088Sminshall "print hexadecimal representation of network traffic" }, 308630088Sminshall { "options", 308730088Sminshall "(debugging) toggle viewing of options processing", 308830088Sminshall 0, 308930088Sminshall 1, 309030088Sminshall &showoptions, 309130088Sminshall "show option processing" }, 309230088Sminshall { " ", "", 0, 1 }, /* empty line */ 309330088Sminshall { "?", 309430088Sminshall "display help information", 309530088Sminshall togglehelp, 309630088Sminshall 1 }, 309730088Sminshall { "help", 309830088Sminshall "display help information", 309930088Sminshall togglehelp, 310030088Sminshall 0 }, 310130088Sminshall { 0 } 310230088Sminshall }; 310330088Sminshall 310430088Sminshall static 310530088Sminshall togglehelp() 310630088Sminshall { 310730088Sminshall struct togglelist *c; 310830088Sminshall 310930088Sminshall for (c = Togglelist; c->name; c++) { 311030088Sminshall if (c->dohelp) { 311130088Sminshall printf("%s\t%s\n", c->name, c->help); 311230088Sminshall } 311330088Sminshall } 311430088Sminshall return 0; 311530088Sminshall } 311630088Sminshall 311730088Sminshall static char ** 311830088Sminshall getnexttoggle(name) 311930088Sminshall char *name; 312030088Sminshall { 312130088Sminshall struct togglelist *c = (struct togglelist *) name; 312230088Sminshall 312330088Sminshall return (char **) (c+1); 312430088Sminshall } 312530088Sminshall 312630088Sminshall static struct togglelist * 312730088Sminshall gettoggle(name) 312830088Sminshall char *name; 312930088Sminshall { 313030088Sminshall return (struct togglelist *) 313130088Sminshall genget(name, (char **) Togglelist, getnexttoggle); 313230088Sminshall } 313330088Sminshall 313430088Sminshall static 313530088Sminshall toggle(argc, argv) 313630088Sminshall int argc; 313730088Sminshall char *argv[]; 313830088Sminshall { 313930088Sminshall int retval = 1; 314030088Sminshall char *name; 314130088Sminshall struct togglelist *c; 314230088Sminshall 314330088Sminshall if (argc < 2) { 314430088Sminshall fprintf(stderr, 314530088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 314630088Sminshall return 0; 314730088Sminshall } 314830088Sminshall argc--; 314930088Sminshall argv++; 315030088Sminshall while (argc--) { 315130088Sminshall name = *argv++; 315230088Sminshall c = gettoggle(name); 315330088Sminshall if (c == Ambiguous(struct togglelist *)) { 315430088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 315530088Sminshall name); 315630088Sminshall return 0; 315730088Sminshall } else if (c == 0) { 315830088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 315930088Sminshall name); 316030088Sminshall return 0; 316130088Sminshall } else { 316230088Sminshall if (c->variable) { 316330088Sminshall *c->variable = !*c->variable; /* invert it */ 316430088Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 316530088Sminshall c->actionexplanation); 316630088Sminshall } 316730088Sminshall if (c->handler) { 316830088Sminshall retval &= (*c->handler)(c); 316930088Sminshall } 317030088Sminshall } 317130088Sminshall } 317230088Sminshall return retval; 317330088Sminshall } 317430088Sminshall 317530088Sminshall /* 317630088Sminshall * The following perform the "set" command. 317730088Sminshall */ 317830088Sminshall 317930088Sminshall struct setlist { 318030088Sminshall char *name; /* name */ 318130088Sminshall char *help; /* help information */ 318230088Sminshall char *charp; /* where it is located at */ 318330088Sminshall }; 318430088Sminshall 318530088Sminshall static struct setlist Setlist[] = { 318630088Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 318730088Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 318830088Sminshall { " ", "" }, 318930088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 319031124Sminshall #if defined(unix) 319130088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 319230088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 319330088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 319430088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 319530088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 319630088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 319731124Sminshall #endif /* defined(unix) */ 319831124Sminshall #if defined(MSDOS) 319931124Sminshall { "erase", "character to cause an Erase Character", &termEraseChar }, 320031124Sminshall { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 320131124Sminshall { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 320231124Sminshall { "kill", "character to cause an Erase Line", &termKillChar }, 320331124Sminshall { "quit", "character to cause a Break", &termQuitChar }, 320431124Sminshall { "eof", "character to cause an EOF ", &termEofChar }, 320531124Sminshall #endif /* defined(MSDOS) */ 320630088Sminshall { 0 } 320730088Sminshall }; 320830088Sminshall 320930088Sminshall static char ** 321030088Sminshall getnextset(name) 321130088Sminshall char *name; 321230088Sminshall { 321330088Sminshall struct setlist *c = (struct setlist *)name; 321430088Sminshall 321530088Sminshall return (char **) (c+1); 321630088Sminshall } 321730088Sminshall 321830088Sminshall static struct setlist * 321930088Sminshall getset(name) 322030088Sminshall char *name; 322130088Sminshall { 322230088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 322330088Sminshall } 322430088Sminshall 322530088Sminshall static 322630088Sminshall setcmd(argc, argv) 322730088Sminshall int argc; 322830088Sminshall char *argv[]; 322930088Sminshall { 323030088Sminshall int value; 323130088Sminshall struct setlist *ct; 323230088Sminshall 323330088Sminshall /* XXX back we go... sigh */ 323430088Sminshall if (argc != 3) { 323530088Sminshall if ((argc == 2) && 323630088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 323730088Sminshall for (ct = Setlist; ct->name; ct++) { 323830088Sminshall printf("%s\t%s\n", ct->name, ct->help); 323930088Sminshall } 324030088Sminshall printf("?\tdisplay help information\n"); 324130088Sminshall } else { 324230088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 324330088Sminshall } 324430088Sminshall return 0; 324530088Sminshall } 324630088Sminshall 324730088Sminshall ct = getset(argv[1]); 324830088Sminshall if (ct == 0) { 324930088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 325030088Sminshall argv[1]); 325130088Sminshall return 0; 325230088Sminshall } else if (ct == Ambiguous(struct setlist *)) { 325330088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 325430088Sminshall argv[1]); 325530088Sminshall return 0; 325630088Sminshall } else { 325730088Sminshall if (strcmp("off", argv[2])) { 325830088Sminshall value = special(argv[2]); 325930088Sminshall } else { 326030088Sminshall value = -1; 326130088Sminshall } 326230088Sminshall *(ct->charp) = value; 326330088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 326430088Sminshall } 326530088Sminshall return 1; 326630088Sminshall } 326730088Sminshall 326830088Sminshall /* 326930088Sminshall * The following are the data structures and routines for the 327030088Sminshall * 'mode' command. 327130088Sminshall */ 327230088Sminshall 327330088Sminshall static 327430088Sminshall dolinemode() 327530088Sminshall { 327630088Sminshall if (hisopts[TELOPT_SGA]) { 327730088Sminshall wontoption(TELOPT_SGA, 0); 327830088Sminshall } 327930088Sminshall if (hisopts[TELOPT_ECHO]) { 328030088Sminshall wontoption(TELOPT_ECHO, 0); 328130088Sminshall } 328230088Sminshall return 1; 328330088Sminshall } 328430088Sminshall 328530088Sminshall static 328630088Sminshall docharmode() 328730088Sminshall { 328830088Sminshall if (!hisopts[TELOPT_SGA]) { 328930088Sminshall willoption(TELOPT_SGA, 0); 329030088Sminshall } 329130088Sminshall if (!hisopts[TELOPT_ECHO]) { 329230088Sminshall willoption(TELOPT_ECHO, 0); 329330088Sminshall } 329430088Sminshall return 1; 329530088Sminshall } 329630088Sminshall 329730088Sminshall static struct cmd Modelist[] = { 329830088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 329930088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 330030088Sminshall { 0 }, 330130088Sminshall }; 330230088Sminshall 330330088Sminshall static char ** 330430088Sminshall getnextmode(name) 330530088Sminshall char *name; 330630088Sminshall { 330730088Sminshall struct cmd *c = (struct cmd *) name; 330830088Sminshall 330930088Sminshall return (char **) (c+1); 331030088Sminshall } 331130088Sminshall 331230088Sminshall static struct cmd * 331330088Sminshall getmodecmd(name) 331430088Sminshall char *name; 331530088Sminshall { 331630088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 331730088Sminshall } 331830088Sminshall 331930088Sminshall static 332030088Sminshall modecmd(argc, argv) 332130088Sminshall int argc; 332230088Sminshall char *argv[]; 332330088Sminshall { 332430088Sminshall struct cmd *mt; 332530088Sminshall 332630088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 332730088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 332830088Sminshall for (mt = Modelist; mt->name; mt++) { 332930088Sminshall printf("%s\t%s\n", mt->name, mt->help); 333030088Sminshall } 333130088Sminshall return 0; 333230088Sminshall } 333330088Sminshall mt = getmodecmd(argv[1]); 333430088Sminshall if (mt == 0) { 333530088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 333630088Sminshall return 0; 333730088Sminshall } else if (mt == Ambiguous(struct cmd *)) { 333830088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 333930088Sminshall return 0; 334030088Sminshall } else { 334130088Sminshall (*mt->handler)(); 334230088Sminshall } 334330088Sminshall return 1; 334430088Sminshall } 334530088Sminshall 334630088Sminshall /* 334730088Sminshall * The following data structures and routines implement the 334830088Sminshall * "display" command. 334930088Sminshall */ 335030088Sminshall 335130088Sminshall static 335230088Sminshall display(argc, argv) 335330088Sminshall int argc; 335430088Sminshall char *argv[]; 335530088Sminshall { 335630088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 335730088Sminshall if (*tl->variable) { \ 335830088Sminshall printf("will"); \ 335930088Sminshall } else { \ 336030088Sminshall printf("won't"); \ 336130088Sminshall } \ 336230088Sminshall printf(" %s.\n", tl->actionexplanation); \ 336330088Sminshall } 336430088Sminshall 336530088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 336630088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 336730088Sminshall } 336830088Sminshall 336930088Sminshall struct togglelist *tl; 337030088Sminshall struct setlist *sl; 337130088Sminshall 337230088Sminshall if (argc == 1) { 337330088Sminshall for (tl = Togglelist; tl->name; tl++) { 337430088Sminshall dotog(tl); 337530088Sminshall } 337630088Sminshall printf("\n"); 337730088Sminshall for (sl = Setlist; sl->name; sl++) { 337830088Sminshall doset(sl); 337930088Sminshall } 338030088Sminshall } else { 338130088Sminshall int i; 338230088Sminshall 338330088Sminshall for (i = 1; i < argc; i++) { 338430088Sminshall sl = getset(argv[i]); 338530088Sminshall tl = gettoggle(argv[i]); 338630088Sminshall if ((sl == Ambiguous(struct setlist *)) || 338730088Sminshall (tl == Ambiguous(struct togglelist *))) { 338830088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 338930088Sminshall return 0; 339030088Sminshall } else if (!sl && !tl) { 339130088Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 339230088Sminshall return 0; 339330088Sminshall } else { 339430088Sminshall if (tl) { 339530088Sminshall dotog(tl); 339630088Sminshall } 339730088Sminshall if (sl) { 339830088Sminshall doset(sl); 339930088Sminshall } 340030088Sminshall } 340130088Sminshall } 340230088Sminshall } 340330088Sminshall return 1; 340430088Sminshall #undef doset 340530088Sminshall #undef dotog 340630088Sminshall } 340730088Sminshall 340830088Sminshall /* 340930088Sminshall * The following are the data structures, and many of the routines, 341030088Sminshall * relating to command processing. 341130088Sminshall */ 341230088Sminshall 341330088Sminshall /* 341430088Sminshall * Set the escape character. 341530088Sminshall */ 341630088Sminshall static 341730088Sminshall setescape(argc, argv) 341830088Sminshall int argc; 341930088Sminshall char *argv[]; 342030088Sminshall { 342130088Sminshall register char *arg; 342230088Sminshall char buf[50]; 342330088Sminshall 342430088Sminshall printf( 342530088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 342630088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 342730088Sminshall if (argc > 2) 342830088Sminshall arg = argv[1]; 342930088Sminshall else { 343030088Sminshall printf("new escape character: "); 343130088Sminshall gets(buf); 343230088Sminshall arg = buf; 343330088Sminshall } 343430088Sminshall if (arg[0] != '\0') 343530088Sminshall escape = arg[0]; 343630088Sminshall if (!In3270) { 343730088Sminshall printf("Escape character is '%s'.\n", control(escape)); 343830088Sminshall } 343930088Sminshall fflush(stdout); 344030088Sminshall return 1; 344130088Sminshall } 344230088Sminshall 344330088Sminshall /*VARARGS*/ 344430088Sminshall static 344530088Sminshall togcrmod() 344630088Sminshall { 344730088Sminshall crmod = !crmod; 344830088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 344930088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 345030088Sminshall fflush(stdout); 345130088Sminshall return 1; 345230088Sminshall } 345330088Sminshall 345430088Sminshall /*VARARGS*/ 345530088Sminshall suspend() 345630088Sminshall { 345730088Sminshall setcommandmode(); 345830088Sminshall #if defined(unix) 345930088Sminshall kill(0, SIGTSTP); 346031215Sminshall #endif /* defined(unix) */ 346131124Sminshall /* reget parameters in case they were changed */ 346231124Sminshall TerminalSaveState(); 346331215Sminshall setconnmode(); 346430088Sminshall return 1; 346530088Sminshall } 346630088Sminshall 346730088Sminshall /*VARARGS*/ 346830088Sminshall static 346930326Sminshall bye(argc, argv) 347030326Sminshall int argc; /* Number of arguments */ 347130326Sminshall char *argv[]; /* arguments */ 347230088Sminshall { 347330088Sminshall if (connected) { 347430088Sminshall shutdown(net, 2); 347530088Sminshall printf("Connection closed.\n"); 347631131Sminshall NetClose(net); 347730088Sminshall connected = 0; 347830088Sminshall /* reset options */ 347930326Sminshall tninit(); 348030088Sminshall #if defined(TN3270) 348130326Sminshall SetIn3270(); /* Get out of 3270 mode */ 348230088Sminshall #endif /* defined(TN3270) */ 348330088Sminshall } 348430326Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 348530326Sminshall longjmp(toplevel, 1); 348630326Sminshall /* NOTREACHED */ 348730326Sminshall } 348830326Sminshall return 1; /* Keep lint, etc., happy */ 348930088Sminshall } 349030088Sminshall 349130088Sminshall /*VARARGS*/ 349230088Sminshall quit() 349330088Sminshall { 349430326Sminshall (void) call(bye, "bye", "fromquit", 0); 349530088Sminshall Exit(0); 349630088Sminshall /*NOTREACHED*/ 349730088Sminshall return 1; /* just to keep lint happy */ 349830088Sminshall } 349930088Sminshall 350030088Sminshall /* 350130088Sminshall * Print status about the connection. 350230088Sminshall */ 350330088Sminshall static 350430088Sminshall status(argc, argv) 350530088Sminshall int argc; 350630088Sminshall char *argv[]; 350730088Sminshall { 350830088Sminshall if (connected) { 350930088Sminshall printf("Connected to %s.\n", hostname); 351030088Sminshall if (argc < 2) { 351130088Sminshall printf("Operating in %s.\n", 351230088Sminshall modelist[getconnmode()].modedescriptions); 351330088Sminshall if (localchars) { 351430088Sminshall printf("Catching signals locally.\n"); 351530088Sminshall } 351630088Sminshall } 351730088Sminshall } else { 351830088Sminshall printf("No connection.\n"); 351930088Sminshall } 352030088Sminshall # if !defined(TN3270) 352130088Sminshall printf("Escape character is '%s'.\n", control(escape)); 352230088Sminshall fflush(stdout); 352330088Sminshall # else /* !defined(TN3270) */ 352430088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 352530088Sminshall printf("Escape character is '%s'.\n", control(escape)); 352630088Sminshall } 352730088Sminshall # if defined(unix) 352830088Sminshall if (In3270 && transcom) { 352930088Sminshall printf("Transparent mode command is '%s'.\n", transcom); 353030088Sminshall } 353130088Sminshall # endif /* defined(unix) */ 353230088Sminshall fflush(stdout); 353330088Sminshall if (In3270) { 353430088Sminshall return 0; 353530088Sminshall } 353630088Sminshall # endif /* defined(TN3270) */ 353730088Sminshall return 1; 353830088Sminshall } 353930088Sminshall 354030088Sminshall #if defined(TN3270) && defined(unix) 354130088Sminshall static 354230088Sminshall settranscom(argc, argv) 354330088Sminshall int argc; 354430088Sminshall char *argv[]; 354530088Sminshall { 354630088Sminshall int i, len = 0; 354730088Sminshall char *strcpy(), *strcat(); 354830088Sminshall 354930088Sminshall if (argc == 1 && transcom) { 355030088Sminshall transcom = 0; 355130088Sminshall } 355230088Sminshall if (argc == 1) { 355330088Sminshall return; 355430088Sminshall } 355530088Sminshall for (i = 1; i < argc; ++i) { 355630088Sminshall len += 1 + strlen(argv[1]); 355730088Sminshall } 355830088Sminshall transcom = tline; 355930088Sminshall (void) strcpy(transcom, argv[1]); 356030088Sminshall for (i = 2; i < argc; ++i) { 356130088Sminshall (void) strcat(transcom, " "); 356230088Sminshall (void) strcat(transcom, argv[i]); 356330088Sminshall } 356430088Sminshall } 356530088Sminshall #endif /* defined(TN3270) && defined(unix) */ 356630088Sminshall 356730088Sminshall 356831169Sminshall 356930088Sminshall static 357030088Sminshall tn(argc, argv) 357130088Sminshall int argc; 357230088Sminshall char *argv[]; 357330088Sminshall { 357430088Sminshall register struct hostent *host = 0; 357531131Sminshall #if defined(MSDOS) 357630088Sminshall char *cp; 357731131Sminshall #endif /* defined(MSDOS) */ 357830088Sminshall 357930088Sminshall if (connected) { 358030088Sminshall printf("?Already connected to %s\n", hostname); 358130088Sminshall return 0; 358230088Sminshall } 358330088Sminshall if (argc < 2) { 358430088Sminshall (void) strcpy(line, "Connect "); 358530088Sminshall printf("(to) "); 358630088Sminshall gets(&line[strlen(line)]); 358730088Sminshall makeargv(); 358830088Sminshall argc = margc; 358930088Sminshall argv = margv; 359030088Sminshall } 3591*31793Sminshall if ((argc < 2) || (argc > 3)) { 359230088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 359330088Sminshall return 0; 359430088Sminshall } 359531131Sminshall #if defined(MSDOS) 359630088Sminshall for (cp = argv[1]; *cp; cp++) { 359730088Sminshall if (isupper(*cp)) { 359830088Sminshall *cp = tolower(*cp); 359930088Sminshall } 360030088Sminshall } 360131131Sminshall #endif /* defined(MSDOS) */ 360230088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 360330088Sminshall if (sin.sin_addr.s_addr != -1) { 360430088Sminshall sin.sin_family = AF_INET; 360530088Sminshall (void) strcpy(hnamebuf, argv[1]); 360630088Sminshall hostname = hnamebuf; 360730088Sminshall } else { 360830088Sminshall host = gethostbyname(argv[1]); 360930088Sminshall if (host) { 361030088Sminshall sin.sin_family = host->h_addrtype; 361130088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 361231131Sminshall memcpy((caddr_t)&sin.sin_addr, 361331131Sminshall host->h_addr_list[0], host->h_length); 361430088Sminshall #else /* defined(h_addr) */ 361531131Sminshall memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 361630088Sminshall #endif /* defined(h_addr) */ 361730088Sminshall hostname = host->h_name; 361830088Sminshall } else { 361930088Sminshall printf("%s: unknown host\n", argv[1]); 362030088Sminshall return 0; 362130088Sminshall } 362230088Sminshall } 362330088Sminshall sin.sin_port = sp->s_port; 362430088Sminshall if (argc == 3) { 362530088Sminshall sin.sin_port = atoi(argv[2]); 362630088Sminshall if (sin.sin_port == 0) { 362730088Sminshall sp = getservbyname(argv[2], "tcp"); 362830088Sminshall if (sp) 362930088Sminshall sin.sin_port = sp->s_port; 363030088Sminshall else { 363130088Sminshall printf("%s: bad port number\n", argv[2]); 363230088Sminshall return 0; 363330088Sminshall } 363430088Sminshall } else { 363530088Sminshall sin.sin_port = atoi(argv[2]); 363630088Sminshall sin.sin_port = htons(sin.sin_port); 363730088Sminshall } 363830088Sminshall telnetport = 0; 363930088Sminshall } else { 364030088Sminshall telnetport = 1; 364130088Sminshall } 364230088Sminshall #if defined(unix) 364330088Sminshall signal(SIGINT, intr); 364430088Sminshall signal(SIGQUIT, intr2); 364530088Sminshall signal(SIGPIPE, deadpeer); 364630088Sminshall #endif /* defined(unix) */ 364730088Sminshall printf("Trying...\n"); 364830088Sminshall do { 364930088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 365030088Sminshall if (net < 0) { 365130088Sminshall perror("telnet: socket"); 365230088Sminshall return 0; 365330088Sminshall } 365431124Sminshall if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 365530088Sminshall perror("setsockopt (SO_DEBUG)"); 365631124Sminshall } 365730088Sminshall 365830088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 365930088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 366030088Sminshall if (host && host->h_addr_list[1]) { 366130088Sminshall int oerrno = errno; 366230088Sminshall 366330088Sminshall fprintf(stderr, "telnet: connect to address %s: ", 366430088Sminshall inet_ntoa(sin.sin_addr)); 366530088Sminshall errno = oerrno; 366630088Sminshall perror((char *)0); 366730088Sminshall host->h_addr_list++; 366831131Sminshall memcpy((caddr_t)&sin.sin_addr, 366931131Sminshall host->h_addr_list[0], host->h_length); 367030088Sminshall fprintf(stderr, "Trying %s...\n", 367130088Sminshall inet_ntoa(sin.sin_addr)); 367231131Sminshall (void) NetClose(net); 367330088Sminshall continue; 367430088Sminshall } 367530088Sminshall #endif /* defined(h_addr) */ 367630088Sminshall perror("telnet: Unable to connect to remote host"); 367730088Sminshall #if defined(unix) 367830088Sminshall signal(SIGINT, SIG_DFL); 367930088Sminshall signal(SIGQUIT, SIG_DFL); 368030320Sminshall #endif /* defined(unix) */ 368130088Sminshall return 0; 368230088Sminshall } 368330088Sminshall connected++; 368430088Sminshall } while (connected == 0); 368530088Sminshall call(status, "status", "notmuch", 0); 368630088Sminshall if (setjmp(peerdied) == 0) 368730088Sminshall telnet(); 368831131Sminshall NetClose(net); 368930088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1); 369030088Sminshall /*NOTREACHED*/ 369130088Sminshall } 369230088Sminshall 369330088Sminshall 369430088Sminshall #define HELPINDENT (sizeof ("connect")) 369530088Sminshall 369630088Sminshall static char 369730088Sminshall openhelp[] = "connect to a site", 369830088Sminshall closehelp[] = "close current connection", 369930088Sminshall quithelp[] = "exit telnet", 370030088Sminshall statushelp[] = "print status information", 370130088Sminshall helphelp[] = "print help information", 370230088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 370330088Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 370430088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 370530088Sminshall displayhelp[] = "display operating parameters", 370630088Sminshall #if defined(TN3270) && defined(unix) 370730088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 370830088Sminshall #endif /* defined(TN3270) && defined(unix) */ 370931169Sminshall #if defined(unix) 371031169Sminshall zhelp[] = "suspend telnet", 371131169Sminshall #endif /* defined(unix */ 371231478Sminshall #if defined(TN3270) 371331169Sminshall shellhelp[] = "invoke a subshell", 371431478Sminshall #endif /* defined(TN3270) */ 371530088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 371630088Sminshall 371731169Sminshall extern int help(), shell(); 371830088Sminshall 371930088Sminshall static struct cmd cmdtab[] = { 372030088Sminshall { "close", closehelp, bye, 1, 1 }, 372130088Sminshall { "display", displayhelp, display, 1, 0 }, 372230088Sminshall { "mode", modehelp, modecmd, 1, 1 }, 372330088Sminshall { "open", openhelp, tn, 1, 0 }, 372430088Sminshall { "quit", quithelp, quit, 1, 0 }, 372530088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 372630088Sminshall { "set", sethelp, setcmd, 1, 0 }, 372730088Sminshall { "status", statushelp, status, 1, 0 }, 372830088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 372930088Sminshall #if defined(TN3270) && defined(unix) 373030088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 373130088Sminshall #endif /* defined(TN3270) && defined(unix) */ 373231169Sminshall #if defined(unix) 373330088Sminshall { "z", zhelp, suspend, 1, 0 }, 373431169Sminshall #endif /* defined(unix) */ 373531478Sminshall #if defined(TN3270) 373631478Sminshall { "!", shellhelp, shell, 1, 1 }, 373731478Sminshall #endif /* defined(TN3270) */ 373830088Sminshall { "?", helphelp, help, 1, 0 }, 373930088Sminshall 0 374030088Sminshall }; 374130088Sminshall 374230088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 374330088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 374430088Sminshall 374530088Sminshall static struct cmd cmdtab2[] = { 374630088Sminshall { "help", helphelp, help, 0, 0 }, 374730088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 374830088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 374930088Sminshall 0 375030088Sminshall }; 375130088Sminshall 375230088Sminshall /* 375330088Sminshall * Call routine with argc, argv set from args (terminated by 0). 375430088Sminshall * VARARGS2 375530088Sminshall */ 375630088Sminshall static 375730088Sminshall call(routine, args) 375830088Sminshall int (*routine)(); 375930088Sminshall char *args; 376030088Sminshall { 376130088Sminshall register char **argp; 376230088Sminshall register int argc; 376330088Sminshall 376430088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 376530088Sminshall ; 376630088Sminshall return (*routine)(argc, &args); 376730088Sminshall } 376830088Sminshall 376930088Sminshall static char ** 377030088Sminshall getnextcmd(name) 377130088Sminshall char *name; 377230088Sminshall { 377330088Sminshall struct cmd *c = (struct cmd *) name; 377430088Sminshall 377530088Sminshall return (char **) (c+1); 377630088Sminshall } 377730088Sminshall 377830088Sminshall static struct cmd * 377930088Sminshall getcmd(name) 378030088Sminshall char *name; 378130088Sminshall { 378230088Sminshall struct cmd *cm; 378330088Sminshall 378430088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 378530088Sminshall return cm; 378630088Sminshall } else { 378730088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 378830088Sminshall } 378930088Sminshall } 379030088Sminshall 379130088Sminshall void 379230088Sminshall command(top) 379330088Sminshall int top; 379430088Sminshall { 379531478Sminshall register struct cmd *c; 379630088Sminshall 379731478Sminshall setcommandmode(); 379831478Sminshall if (!top) { 379931478Sminshall putchar('\n'); 380031478Sminshall } else { 380130088Sminshall #if defined(unix) 380231478Sminshall signal(SIGINT, SIG_DFL); 380331478Sminshall signal(SIGQUIT, SIG_DFL); 380430088Sminshall #endif /* defined(unix) */ 380531478Sminshall } 380631478Sminshall for (;;) { 380731478Sminshall printf("%s> ", prompt); 380831478Sminshall if (gets(line) == NULL) { 380931478Sminshall if (feof(stdin) || ferror(stdin)) 381031478Sminshall quit(); 381131478Sminshall break; 381230088Sminshall } 381331478Sminshall if (line[0] == 0) 381431478Sminshall break; 381531478Sminshall makeargv(); 381631478Sminshall c = getcmd(margv[0]); 381731478Sminshall if (c == Ambiguous(struct cmd *)) { 381831478Sminshall printf("?Ambiguous command\n"); 381931478Sminshall continue; 382030088Sminshall } 382131478Sminshall if (c == 0) { 382231478Sminshall printf("?Invalid command\n"); 382331478Sminshall continue; 382430088Sminshall } 382531478Sminshall if (c->needconnect && !connected) { 382631478Sminshall printf("?Need to be connected first.\n"); 382731478Sminshall continue; 382831478Sminshall } 382931478Sminshall if ((*c->handler)(margc, margv)) { 383031478Sminshall break; 383131478Sminshall } 383231478Sminshall } 383331478Sminshall if (!top) { 383431478Sminshall if (!connected) { 383531478Sminshall longjmp(toplevel, 1); 383631478Sminshall /*NOTREACHED*/ 383731478Sminshall } 383831478Sminshall if (shell_active == 0) { 383931478Sminshall setconnmode(); 384031478Sminshall } 384131478Sminshall } 384230088Sminshall } 384330088Sminshall 384430088Sminshall /* 384530088Sminshall * Help command. 384630088Sminshall */ 384730088Sminshall static 384830088Sminshall help(argc, argv) 384930088Sminshall int argc; 385030088Sminshall char *argv[]; 385130088Sminshall { 385230088Sminshall register struct cmd *c; 385330088Sminshall 385430088Sminshall if (argc == 1) { 385530088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 385630088Sminshall for (c = cmdtab; c->name; c++) 385730088Sminshall if (c->dohelp) { 385830088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 385930088Sminshall c->help); 386030088Sminshall } 386130088Sminshall return 0; 386230088Sminshall } 386330088Sminshall while (--argc > 0) { 386430088Sminshall register char *arg; 386530088Sminshall arg = *++argv; 386630088Sminshall c = getcmd(arg); 386730088Sminshall if (c == Ambiguous(struct cmd *)) 386830088Sminshall printf("?Ambiguous help command %s\n", arg); 386930088Sminshall else if (c == (struct cmd *)0) 387030088Sminshall printf("?Invalid help command %s\n", arg); 387130088Sminshall else 387230088Sminshall printf("%s\n", c->help); 387330088Sminshall } 387430088Sminshall return 0; 387530088Sminshall } 387630088Sminshall 387730088Sminshall /* 387830088Sminshall * main. Parse arguments, invoke the protocol or command parser. 387930088Sminshall */ 388030088Sminshall 388130088Sminshall 388230088Sminshall void 388330088Sminshall main(argc, argv) 388430088Sminshall int argc; 388530088Sminshall char *argv[]; 388630088Sminshall { 388730326Sminshall tninit(); /* Clear out things */ 388830326Sminshall 388930088Sminshall NetTrace = stdout; 389031124Sminshall TerminalSaveState(); 389131124Sminshall autoflush = TerminalAutoFlush(); 389231124Sminshall 389330088Sminshall prompt = argv[0]; 389431478Sminshall while ((argc > 1) && (argv[1][0] == '-')) { 389531478Sminshall if (!strcmp(argv[1], "-d")) { 389631478Sminshall debug = 1; 389731478Sminshall } else if (!strcmp(argv[1], "-n")) { 389831510Sminshall if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */ 389931510Sminshall NetTrace = fopen(argv[2], "w"); 390031478Sminshall argv++; 390131478Sminshall argc--; 390231478Sminshall if (NetTrace == NULL) { 390331478Sminshall NetTrace = stdout; 390431478Sminshall } 390530088Sminshall } 390631478Sminshall } else { 390731478Sminshall #if defined(TN3270) && defined(unix) 390831478Sminshall if (!strcmp(argv[1], "-t")) { 390931478Sminshall if ((argc > 1) && (argv[1][0] != '-')) { /* get file name */ 391031478Sminshall transcom = tline; 391131478Sminshall (void) strcpy(transcom, argv[1]); 391231478Sminshall argv++; 391331478Sminshall argc--; 391431478Sminshall } 391531478Sminshall } else if (!strcmp(argv[1], "-noasynch")) { 391631478Sminshall noasynch = 1; 391731478Sminshall } else 391831478Sminshall #endif /* defined(TN3270) && defined(unix) */ 391931478Sminshall if (argv[1][1] != '\0') { 392031478Sminshall fprintf(stderr, "Unknown option *%s*.\n", argv[1]); 392131478Sminshall } 392230088Sminshall } 392331478Sminshall argc--; 392430088Sminshall argv++; 392530088Sminshall } 392630088Sminshall if (argc != 1) { 392730088Sminshall if (setjmp(toplevel) != 0) 392830088Sminshall Exit(0); 392930088Sminshall tn(argc, argv); 393030088Sminshall } 393130088Sminshall setjmp(toplevel); 393231215Sminshall for (;;) { 393331215Sminshall #if !defined(TN3270) 393430088Sminshall command(1); 393531215Sminshall #else /* !defined(TN3270) */ 393631215Sminshall if (!shell_active) { 393731215Sminshall command(1); 393831215Sminshall } else { 393931478Sminshall #if defined(TN3270) 394031215Sminshall shell_continue(); 394131478Sminshall #endif /* defined(TN3270) */ 394231215Sminshall } 394331215Sminshall #endif /* !defined(TN3270) */ 394431215Sminshall } 394530088Sminshall } 3946