130088Sminshall /* 231978Sminshall * Copyright (c) 1984-1987 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[] = 2431978Sminshall "@(#) Copyright (c) 1984-1987 Regents of the University of California.\n\ 2530088Sminshall All rights reserved.\n"; 2630320Sminshall #endif /* not lint */ 2730088Sminshall 2830088Sminshall #ifndef lint 29*31980Sminshall static char sccsid[] = "@(#)telnet.c 1.18 (Berkeley) 07/31/87"; 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> 618*31980Sminshall #include <fcntl.h> 619*31980Sminshall #include <io.h> 62031978Sminshall #include <dos.h> 62131978Sminshall 62231124Sminshall #if !defined(SO_OOBINLINE) 62331124Sminshall #define SO_OOBINLINE 62431124Sminshall #endif /* !defined(SO_OOBINLINE) */ 62531124Sminshall 62631124Sminshall 62731124Sminshall static char 62831131Sminshall termEofChar, 62931124Sminshall termEraseChar, 63031124Sminshall termFlushChar, 63131124Sminshall termIntChar, 63231124Sminshall termKillChar, 63331131Sminshall termLiteralNextChar, 63431131Sminshall termQuitChar; 63531124Sminshall 63631131Sminshall 63731131Sminshall /* 63831131Sminshall * MSDOS doesn't have anyway of deciding whether a full-edited line 63931131Sminshall * is ready to be read in, so we need to do character-by-character 64031131Sminshall * reads, and then do the editing in the program (in the case where 64131131Sminshall * we are supporting line-by-line mode). 64231131Sminshall * 64331131Sminshall * The following routines, which are internal to the MSDOS-specific 64431131Sminshall * code, accomplish this miracle. 64531131Sminshall */ 64631124Sminshall 64731131Sminshall #define Hex(c) HEX[(c)&0xff] 64831131Sminshall 64931131Sminshall static survivorSetup = 0; /* Do we have ^C hooks in? */ 65031131Sminshall 65131131Sminshall static int 65231131Sminshall lineend = 0, /* There is a line terminator */ 65331131Sminshall ctrlCCount = 0; 65431131Sminshall 65531131Sminshall static char linein[200], /* Where input line is assembled */ 65631131Sminshall *nextin = linein, /* Next input character */ 65731131Sminshall *nextout = linein; /* Next character to be consumed */ 65831131Sminshall 65931131Sminshall #define consumechar() \ 66031131Sminshall if ((++nextout) >= nextin) { \ 66131131Sminshall nextout = nextin = linein; \ 66231131Sminshall lineend = 0; \ 66331131Sminshall } 66431131Sminshall 66531131Sminshall #define characteratatime() (!MODE_LINE(globalmode)) /* one by one */ 66631131Sminshall 66731131Sminshall 66831124Sminshall /* 66931131Sminshall * killone() 67031131Sminshall * 67131131Sminshall * Erase the last character on the line. 67231131Sminshall */ 67331131Sminshall 67431131Sminshall static void 67531131Sminshall killone() 67631131Sminshall { 67731131Sminshall if (lineend) { 67831131Sminshall return; /* ??? XXX */ 67931131Sminshall } 68031131Sminshall if (nextin == linein) { 68131131Sminshall return; /* Nothing to do */ 68231131Sminshall } 68331131Sminshall nextin--; 68431131Sminshall if (!(isspace(*nextin) || isprint(*nextin))) { 68531131Sminshall putchar('\b'); 68631131Sminshall putchar(' '); 68731131Sminshall putchar('\b'); 68831131Sminshall } 68931131Sminshall putchar('\b'); 69031131Sminshall putchar(' '); 69131131Sminshall putchar('\b'); 69231131Sminshall } 69331131Sminshall 69431131Sminshall 69531131Sminshall /* 69631131Sminshall * setlineend() 69731131Sminshall * 69831131Sminshall * Decide if it's time to send the current line up to the user 69931131Sminshall * process. 70031131Sminshall */ 70131131Sminshall 70231131Sminshall static void 70331131Sminshall setlineend() 70431131Sminshall { 70531131Sminshall if (nextin == nextout) { 70631131Sminshall return; 70731131Sminshall } 70831131Sminshall if (characteratatime()) { 70931131Sminshall lineend = 1; 71031131Sminshall } else if (nextin >= (linein+sizeof linein)) { 71131131Sminshall lineend = 1; 71231131Sminshall } else { 71331131Sminshall int c = *(nextin-1); 71431131Sminshall if ((c == termIntChar) 71531131Sminshall || (c == termQuitChar) 71631131Sminshall || (c == termEofChar)) { 71731131Sminshall lineend = 1; 71831131Sminshall } else if (c == termFlushChar) { 71931131Sminshall lineend = 1; 72031131Sminshall } else if ((c == '\n') || (c == '\r')) { 72131131Sminshall lineend = 1; 72231131Sminshall } 72331131Sminshall } 72431131Sminshall /* Otherwise, leave it alone (reset by 'consumechar') */ 72531131Sminshall } 72631131Sminshall 72731131Sminshall /* 72831131Sminshall * OK, what we do here is: 72931131Sminshall * 73031131Sminshall * o If we are echoing, then 73131131Sminshall * o Look for character erase, line kill characters 73231131Sminshall * o Echo the character (using '^' if a control character) 73331131Sminshall * o Put the character in the input buffer 73431131Sminshall * o Set 'lineend' as necessary 73531131Sminshall */ 73631131Sminshall 73731131Sminshall static void 73831131Sminshall DoNextChar(c) 73931131Sminshall int c; /* Character to process */ 74031131Sminshall { 74131131Sminshall static char literalnextcharacter = 0; 74231131Sminshall 74331131Sminshall if (nextin >= (linein+sizeof linein)) { 74431131Sminshall putchar('\7'); /* Ring bell */ 74531131Sminshall setlineend(); 74631131Sminshall return; 74731131Sminshall } 74831131Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 74931131Sminshall /* Look for some special character */ 75031131Sminshall if (!literalnextcharacter) { 75131131Sminshall if (c == termEraseChar) { 75231131Sminshall killone(); 75331131Sminshall setlineend(); 75431131Sminshall return; 75531131Sminshall } else if (c == termKillChar) { 75631131Sminshall while (nextin != linein) { 75731131Sminshall killone(); 75831131Sminshall } 75931131Sminshall setlineend(); 76031131Sminshall return; 76131131Sminshall } else if (c == termLiteralNextChar) { 76231131Sminshall literalnextcharacter = 1; 76331131Sminshall return; 76431131Sminshall } 76531131Sminshall } 76631131Sminshall 76731131Sminshall if (MODE_LOCAL_ECHO(globalmode)) { 76831131Sminshall if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) { 76931131Sminshall putchar('\r'); 77031131Sminshall putchar('\n'); 77131131Sminshall c = '\n'; 77231131Sminshall } else if (!isprint(c) && !isspace(c)) { 77331131Sminshall putchar('^'); 77431131Sminshall putchar(c^0x40); 77531131Sminshall } else { 77631131Sminshall putchar(c); 77731131Sminshall } 77831131Sminshall } 77931131Sminshall literalnextcharacter = 0; 78031131Sminshall } 78131131Sminshall *nextin++ = c; 78231131Sminshall setlineend(); 78331131Sminshall } 78431131Sminshall 78531131Sminshall static int 78631131Sminshall inputExists() 78731131Sminshall { 78831131Sminshall int input; 78931131Sminshall static state = 0; 79031131Sminshall 79131131Sminshall while (ctrlCCount) { 79231131Sminshall DoNextChar(0x03); 79331131Sminshall ctrlCCount--; 79431131Sminshall } 79531131Sminshall if (lineend) { 79631131Sminshall return 1; 79731131Sminshall } 79831169Sminshall #if 1 /* For BIOS variety of calls */ 79931169Sminshall if (kbhit() == 0) { 80031131Sminshall return lineend; 80131131Sminshall } 80231131Sminshall input = getch(); /* MSC - get console character */ 80331131Sminshall if ((input&0xff) == 0) { 80431169Sminshall DoNextChar(0x01); /* ^A */ 80531169Sminshall } else { 80631169Sminshall DoNextChar(input&0xff); 80731169Sminshall } 80831169Sminshall #else /* 0 */ 80931169Sminshall if ((input = dirconio()) == -1) { 81031169Sminshall return lineend; 81131169Sminshall } 81231169Sminshall if ((input&0xff) == 0) { 81331131Sminshall if ((input&0xff00) == 0x0300) { /* Null */ 81431131Sminshall DoNextChar(0); 81531131Sminshall } else { 81631131Sminshall DoNextChar(0x01); 81731131Sminshall if (input&0x8000) { 81831131Sminshall DoNextChar(0x01); 81931131Sminshall DoNextChar((input>>8)&0x7f); 82031131Sminshall } else { 82131131Sminshall DoNextChar((input>>8)&0xff); 82231131Sminshall } 82331131Sminshall } 82431131Sminshall } else { 82531131Sminshall DoNextChar(input&0xff); 82631131Sminshall } 82731131Sminshall #endif /* 0 */ 82831131Sminshall return lineend; 82931131Sminshall } 83031131Sminshall 83131131Sminshall 83231131Sminshall void 83331131Sminshall CtrlCInterrupt() 83431131Sminshall { 83531131Sminshall if (!MODE_COMMAND_LINE(globalmode)) { 83631131Sminshall ctrlCCount++; /* XXX */ 83731131Sminshall signal(SIGINT, CtrlCInterrupt); 83831131Sminshall } else { 83931131Sminshall closeallsockets(); 84031169Sminshall exit(1); 84131131Sminshall } 84231131Sminshall } 84331131Sminshall 84431131Sminshall /* 84531131Sminshall * The MSDOS routines, called from elsewhere. 84631131Sminshall */ 84731131Sminshall 84831131Sminshall 84931131Sminshall static int 85031131Sminshall TerminalAutoFlush() /* MSDOS */ 85131131Sminshall { 85231131Sminshall return 1; 85331131Sminshall } 85431131Sminshall 85531131Sminshall static int 85631131Sminshall TerminalCanRead() 85731131Sminshall { 85831131Sminshall return inputExists(); 85931131Sminshall } 86031131Sminshall 86131131Sminshall 86231131Sminshall /* 86331124Sminshall * Flush output to the terminal 86431124Sminshall */ 86531124Sminshall 86631124Sminshall static void 86731124Sminshall TerminalFlushOutput() /* MSDOS */ 86831124Sminshall { 86931124Sminshall } 87031124Sminshall 87131131Sminshall 87231124Sminshall static void 87331131Sminshall TerminalNewMode(f) /* MSDOS */ 87431131Sminshall register int f; 87531131Sminshall { 87631978Sminshall union REGS inregs; 87731978Sminshall struct SREGS segregs; 87831978Sminshall static old_1b_offset = 0, old_1b_segment = 0; 87931978Sminshall 88031131Sminshall globalmode = f; 88131978Sminshall if (MODE_COMMAND_LINE(f)) { 882*31980Sminshall signal(SIGINT, SIG_DFL); 88331978Sminshall if (old_1b_segment|old_1b_offset) { 88431978Sminshall inregs.h.ah = 0x25; 88531978Sminshall inregs.h.al = 0x1b; 88631978Sminshall inregs.x.dx = old_1b_offset; 88731978Sminshall segregs.ds = old_1b_segment; 88831978Sminshall intdosx(&inregs, &inregs, &segregs); 88931978Sminshall old_1b_segment = old_1b_offset = 0; 89031978Sminshall } 891*31980Sminshall if (setmode(fileno(stdout), O_TEXT) == -1) { 892*31980Sminshall ExitPerror("setmode (text)", 1); 893*31980Sminshall } 894*31980Sminshall if (setmode(fileno(stdin), O_TEXT) == -1) { 895*31980Sminshall ExitPerror("setmode (text)", 1); 896*31980Sminshall } 89731978Sminshall } else { 898*31980Sminshall signal(SIGINT, CtrlCInterrupt); 89931978Sminshall if ((old_1b_segment|old_1b_offset) == 0) { 90031978Sminshall extern void iret_subr(); 90131978Sminshall void (far *foo_subr)() = iret_subr; 90231978Sminshall 90331978Sminshall inregs.h.ah = 0x35; 90431978Sminshall inregs.h.al = 0x1b; 90531978Sminshall intdosx(&inregs, &inregs, &segregs); 90631978Sminshall old_1b_segment = segregs.es; 90731978Sminshall old_1b_offset = inregs.x.bx; 90831978Sminshall inregs.h.ah = 0x25; 90931978Sminshall inregs.h.al = 0x1b; 91031978Sminshall inregs.x.dx = FP_OFF(foo_subr); 91131978Sminshall segregs.ds = FP_SEG(foo_subr); 91231978Sminshall intdosx(&inregs, &inregs, &segregs); 91331978Sminshall } 914*31980Sminshall if (setmode(fileno(stdout), O_BINARY) == -1) { 915*31980Sminshall ExitPerror("setmode (binary)", 1); 916*31980Sminshall } 917*31980Sminshall if (setmode(fileno(stdin), O_BINARY) == -1) { 918*31980Sminshall ExitPerror("setmode (binary)", 1); 919*31980Sminshall } 92031978Sminshall } 92131131Sminshall } 92231131Sminshall 92331131Sminshall 92431131Sminshall int 92531131Sminshall TerminalRead(fd, buffer, count) 92631131Sminshall int fd; 92731131Sminshall char *buffer; 92831131Sminshall int count; 92931131Sminshall { 93031131Sminshall int done = 0; 93131131Sminshall 93231131Sminshall for (;;) { 93331131Sminshall while (inputExists() && (done < count)) { 93431131Sminshall *buffer++ = *nextout; 93531131Sminshall consumechar(); 93631131Sminshall done++; 93731131Sminshall } 93831131Sminshall if (done) { 93931131Sminshall return(done); 94031131Sminshall } else { 94131131Sminshall return 0; 94231131Sminshall } 94331131Sminshall } 94431131Sminshall } 94531131Sminshall 94631131Sminshall 94731131Sminshall static void 94831124Sminshall TerminalSaveState() /* MSDOS */ 94931124Sminshall { 95031124Sminshall } 95131124Sminshall 95231131Sminshall int 95331131Sminshall TerminalSpecialChars(c) /* MSDOS */ 95431131Sminshall { 95531131Sminshall return 1; 95631131Sminshall } 95731131Sminshall 95831131Sminshall 95931124Sminshall static void 96031124Sminshall TerminalRestoreState() /* MSDOS */ 96131124Sminshall { 96231124Sminshall } 96331124Sminshall 96431131Sminshall 96531131Sminshall static int 96631131Sminshall TerminalWrite(fd, buffer, count) /* MSDOS */ 96731131Sminshall int fd; 96831131Sminshall char *buffer; 96931131Sminshall int count; 97031131Sminshall { 97131131Sminshall return fwrite(buffer, sizeof (char), count, stdout); 97231131Sminshall } 97331131Sminshall 97431131Sminshall 97531131Sminshall static int 97631131Sminshall NetClose(fd) 97731131Sminshall { 97831131Sminshall return closesocket(fd); 97931131Sminshall } 98031131Sminshall 98131124Sminshall static void 98231124Sminshall NetNonblockingIO(fd, onoff) /* MSDOS */ 98331124Sminshall int 98431124Sminshall fd, 98531124Sminshall onoff; 98631124Sminshall { 98731124Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) { 98831124Sminshall perror("setsockop (SO_NONBLOCKING) "); 98931131Sminshall ExitString(stderr, "exiting\n", 1); 99031124Sminshall } 99131124Sminshall } 99231124Sminshall 99331124Sminshall static void 99431124Sminshall NetSigIO(fd) /* MSDOS */ 99531124Sminshall int fd; 99631124Sminshall { 99731124Sminshall } 99831124Sminshall 99931124Sminshall static void 100031124Sminshall NetSetPgrp(fd) /* MSDOS */ 100131124Sminshall int fd; 100231124Sminshall { 100331124Sminshall } 100431124Sminshall 100531124Sminshall 100631124Sminshall #endif /* defined(MSDOS) */ 100731124Sminshall 100831124Sminshall /* 100930326Sminshall * Initialize variables. 101030326Sminshall */ 101130326Sminshall 101230326Sminshall static void 101330326Sminshall tninit() 101430326Sminshall { 101531131Sminshall #if defined(TN3270) 101631131Sminshall Sent3270TerminalType = 0; 101730326Sminshall Ifrontp = Ibackp = Ibuf; 101831131Sminshall #endif /* defined(TN3270) */ 101931131Sminshall 102030326Sminshall tfrontp = tbackp = ttyobuf; 102130326Sminshall nfrontp = nbackp = netobuf; 102230326Sminshall 102330326Sminshall /* Don't change telnetport */ 102430722Sminshall SB_CLEAR(); 102530722Sminshall ClearArray(hisopts); 102630722Sminshall ClearArray(myopts); 102730722Sminshall sbp = sibuf; 102830722Sminshall tbp = tibuf; 102930326Sminshall 103031791Sminshall connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0; 103130722Sminshall telnetport = 0; 103231124Sminshall #if defined(unix) 103331124Sminshall HaveInput = 0; 103431124Sminshall #endif /* defined(unix) */ 103530722Sminshall 103630722Sminshall SYNCHing = 0; 103730722Sminshall 103830722Sminshall errno = 0; 103930722Sminshall 104030722Sminshall flushline = 0; 104130722Sminshall 104230326Sminshall /* Don't change NetTrace */ 104330326Sminshall 104430326Sminshall escape = CONTROL(']'); 104530326Sminshall echoc = CONTROL('E'); 104630326Sminshall 104730326Sminshall flushline = 1; 104830326Sminshall sp = getservbyname("telnet", "tcp"); 104930326Sminshall if (sp == 0) { 105030326Sminshall ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1); 105130326Sminshall /*NOTREACHED*/ 105230326Sminshall } 105330326Sminshall 105430326Sminshall #if defined(TN3270) 105530722Sminshall init_ctlr(); /* Initialize some things */ 105630722Sminshall init_keyboard(); 105730722Sminshall init_screen(); 105830722Sminshall init_system(); 105930326Sminshall #endif /* defined(TN3270) */ 106030326Sminshall } 106130326Sminshall 106230326Sminshall /* 106330088Sminshall * Various utility routines. 106430088Sminshall */ 106530088Sminshall 106630088Sminshall static void 106730088Sminshall makeargv() 106830088Sminshall { 106931215Sminshall register char *cp; 107031215Sminshall register char **argp = margv; 107130088Sminshall 107231215Sminshall margc = 0; 107331215Sminshall cp = line; 107431215Sminshall if (*cp == '!') { /* Special case shell escape */ 107531215Sminshall *argp++ = "!"; /* No room in string to get this */ 107631215Sminshall margc++; 107731215Sminshall cp++; 107831215Sminshall } 107931215Sminshall while (*cp) { 108031215Sminshall while (isspace(*cp)) 108131215Sminshall cp++; 108231215Sminshall if (*cp == '\0') 108331215Sminshall break; 108431215Sminshall *argp++ = cp; 108531215Sminshall margc += 1; 108631215Sminshall while (*cp != '\0' && !isspace(*cp)) 108731215Sminshall cp++; 108831215Sminshall if (*cp == '\0') 108931215Sminshall break; 109031215Sminshall *cp++ = '\0'; 109131215Sminshall } 109231215Sminshall *argp++ = 0; 109330088Sminshall } 109430088Sminshall 109530088Sminshall static char *ambiguous; /* special return value */ 109630088Sminshall #define Ambiguous(t) ((t)&ambiguous) 109730088Sminshall 109830088Sminshall 109930088Sminshall static char ** 110030088Sminshall genget(name, table, next) 110130088Sminshall char *name; /* name to match */ 110230088Sminshall char **table; /* name entry in table */ 110330088Sminshall char **(*next)(); /* routine to return next entry in table */ 110430088Sminshall { 110530088Sminshall register char *p, *q; 110630088Sminshall register char **c, **found; 110730088Sminshall register int nmatches, longest; 110830088Sminshall 110931793Sminshall if (name == 0) { 111031793Sminshall return 0; 111131793Sminshall } 111230088Sminshall longest = 0; 111330088Sminshall nmatches = 0; 111430088Sminshall found = 0; 111530088Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 111630088Sminshall for (q = name; 111730088Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 111830088Sminshall if (*q == 0) /* exact match? */ 111930088Sminshall return (c); 112030088Sminshall if (!*q) { /* the name was a prefix */ 112130088Sminshall if (q - name > longest) { 112230088Sminshall longest = q - name; 112330088Sminshall nmatches = 1; 112430088Sminshall found = c; 112530088Sminshall } else if (q - name == longest) 112630088Sminshall nmatches++; 112730088Sminshall } 112830088Sminshall } 112930088Sminshall if (nmatches > 1) 113030088Sminshall return Ambiguous(char **); 113130088Sminshall return (found); 113230088Sminshall } 113330088Sminshall 113430088Sminshall /* 113530088Sminshall * Make a character string into a number. 113630088Sminshall * 113730088Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 113830088Sminshall */ 113930088Sminshall 114030088Sminshall static 114130088Sminshall special(s) 114230088Sminshall register char *s; 114330088Sminshall { 114430088Sminshall register char c; 114530088Sminshall char b; 114630088Sminshall 114730088Sminshall switch (*s) { 114830088Sminshall case '^': 114930088Sminshall b = *++s; 115030088Sminshall if (b == '?') { 115130088Sminshall c = b | 0x40; /* DEL */ 115230088Sminshall } else { 115330088Sminshall c = b & 0x1f; 115430088Sminshall } 115530088Sminshall break; 115630088Sminshall default: 115730088Sminshall c = *s; 115830088Sminshall break; 115930088Sminshall } 116030088Sminshall return c; 116130088Sminshall } 116230088Sminshall 116330088Sminshall /* 116430088Sminshall * Construct a control character sequence 116530088Sminshall * for a special character. 116630088Sminshall */ 116730088Sminshall static char * 116830088Sminshall control(c) 116930088Sminshall register int c; 117030088Sminshall { 117130088Sminshall static char buf[3]; 117230088Sminshall 117330088Sminshall if (c == 0x7f) 117430088Sminshall return ("^?"); 117530088Sminshall if (c == '\377') { 117630088Sminshall return "off"; 117730088Sminshall } 117830088Sminshall if (c >= 0x20) { 117930088Sminshall buf[0] = c; 118030088Sminshall buf[1] = 0; 118130088Sminshall } else { 118230088Sminshall buf[0] = '^'; 118330088Sminshall buf[1] = '@'+c; 118430088Sminshall buf[2] = 0; 118530088Sminshall } 118630088Sminshall return (buf); 118730088Sminshall } 118830088Sminshall 118930088Sminshall 119030088Sminshall /* 119130088Sminshall * upcase() 119230088Sminshall * 119330088Sminshall * Upcase (in place) the argument. 119430088Sminshall */ 119530088Sminshall 119630088Sminshall static void 119730088Sminshall upcase(argument) 119830088Sminshall register char *argument; 119930088Sminshall { 120030088Sminshall register int c; 120130088Sminshall 120230088Sminshall while ((c = *argument) != 0) { 120330088Sminshall if (islower(c)) { 120430088Sminshall *argument = toupper(c); 120530088Sminshall } 120630088Sminshall argument++; 120730088Sminshall } 120830088Sminshall } 120931124Sminshall 121031124Sminshall /* 121131124Sminshall * SetSockOpt() 121231124Sminshall * 121331124Sminshall * Compensate for differences in 4.2 and 4.3 systems. 121431124Sminshall */ 121531124Sminshall 121631124Sminshall static int 121731124Sminshall SetSockOpt(fd, level, option, yesno) 121831124Sminshall int 121931124Sminshall fd, 122031124Sminshall level, 122131124Sminshall option, 122231124Sminshall yesno; 122331124Sminshall { 122431124Sminshall #ifndef NOT43 122531124Sminshall return setsockopt(fd, level, option, 122631124Sminshall (char *)&yesno, sizeof yesno); 122731124Sminshall #else /* NOT43 */ 122831124Sminshall if (yesno == 0) { /* Can't do that in 4.2! */ 122931124Sminshall fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", 123031124Sminshall option); 123131124Sminshall return -1; 123231124Sminshall } 123331124Sminshall return setsockopt(fd, level, option, 0, 0); 123431124Sminshall #endif /* NOT43 */ 123531124Sminshall } 123630088Sminshall 123730088Sminshall /* 123830088Sminshall * The following are routines used to print out debugging information. 123930088Sminshall */ 124030088Sminshall 124130088Sminshall 124230088Sminshall static void 124330088Sminshall Dump(direction, buffer, length) 124430088Sminshall char direction; 124530088Sminshall char *buffer; 124630088Sminshall int length; 124730088Sminshall { 124830088Sminshall # define BYTES_PER_LINE 32 124930088Sminshall # define min(x,y) ((x<y)? x:y) 125030088Sminshall char *pThis; 125130088Sminshall int offset; 125230088Sminshall 125330088Sminshall offset = 0; 125430088Sminshall 125530088Sminshall while (length) { 125630088Sminshall /* print one line */ 125730088Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 125830088Sminshall pThis = buffer; 125930088Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 126030088Sminshall while (pThis < buffer) { 126130088Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 126230088Sminshall pThis++; 126330088Sminshall } 126430088Sminshall fprintf(NetTrace, "\n"); 126530088Sminshall length -= BYTES_PER_LINE; 126630088Sminshall offset += BYTES_PER_LINE; 126730088Sminshall if (length < 0) { 126830088Sminshall return; 126930088Sminshall } 127030088Sminshall /* find next unique line */ 127130088Sminshall } 127230088Sminshall } 127330088Sminshall 127430088Sminshall 127530088Sminshall /*VARARGS*/ 127630088Sminshall static void 127730088Sminshall printoption(direction, fmt, option, what) 127830088Sminshall char *direction, *fmt; 127930088Sminshall int option, what; 128030088Sminshall { 128130088Sminshall if (!showoptions) 128230088Sminshall return; 128330088Sminshall fprintf(NetTrace, "%s ", direction+1); 128430088Sminshall if (fmt == doopt) 128530088Sminshall fmt = "do"; 128630088Sminshall else if (fmt == dont) 128730088Sminshall fmt = "dont"; 128830088Sminshall else if (fmt == will) 128930088Sminshall fmt = "will"; 129030088Sminshall else if (fmt == wont) 129130088Sminshall fmt = "wont"; 129230088Sminshall else 129330088Sminshall fmt = "???"; 129430088Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 129530088Sminshall fprintf(NetTrace, "%s %s", fmt, telopts[option]); 129630088Sminshall else 129730088Sminshall fprintf(NetTrace, "%s %d", fmt, option); 129830088Sminshall if (*direction == '<') { 129930088Sminshall fprintf(NetTrace, "\r\n"); 130030088Sminshall return; 130130088Sminshall } 130230088Sminshall fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply"); 130330088Sminshall } 130430088Sminshall 130530088Sminshall static void 130630088Sminshall printsub(direction, pointer, length) 130730088Sminshall char *direction, /* "<" or ">" */ 130830088Sminshall *pointer; /* where suboption data sits */ 130930088Sminshall int length; /* length of suboption data */ 131030088Sminshall { 131130088Sminshall if (showoptions) { 131230088Sminshall fprintf(NetTrace, "%s suboption ", 131330088Sminshall (direction[0] == '<')? "Received":"Sent"); 131430088Sminshall switch (pointer[0]) { 131530088Sminshall case TELOPT_TTYPE: 131630088Sminshall fprintf(NetTrace, "Terminal type "); 131730088Sminshall switch (pointer[1]) { 131830088Sminshall case TELQUAL_IS: 131930088Sminshall { 132030088Sminshall char tmpbuf[sizeof subbuffer]; 132130088Sminshall int minlen = min(length, sizeof tmpbuf); 132230088Sminshall 132331131Sminshall memcpy(tmpbuf, pointer+2, minlen); 132430088Sminshall tmpbuf[minlen-1] = 0; 132530088Sminshall fprintf(NetTrace, "is %s.\n", tmpbuf); 132630088Sminshall } 132730088Sminshall break; 132830088Sminshall case TELQUAL_SEND: 132930088Sminshall fprintf(NetTrace, "- request to send.\n"); 133030088Sminshall break; 133130088Sminshall default: 133230088Sminshall fprintf(NetTrace, 133330088Sminshall "- unknown qualifier %d (0x%x).\n", pointer[1]); 133430088Sminshall } 133530088Sminshall break; 133630088Sminshall default: 133730088Sminshall fprintf(NetTrace, "Unknown option %d (0x%x)\n", 133830088Sminshall pointer[0], pointer[0]); 133930088Sminshall } 134030088Sminshall } 134130088Sminshall } 134230088Sminshall 134330088Sminshall /* 134430088Sminshall * Check to see if any out-of-band data exists on a socket (for 134530088Sminshall * Telnet "synch" processing). 134630088Sminshall */ 134730088Sminshall 134830088Sminshall static int 134930088Sminshall stilloob(s) 135030088Sminshall int s; /* socket number */ 135130088Sminshall { 135230088Sminshall static struct timeval timeout = { 0 }; 135330088Sminshall fd_set excepts; 135430088Sminshall int value; 135530088Sminshall 135630088Sminshall do { 135730088Sminshall FD_ZERO(&excepts); 135830088Sminshall FD_SET(s, &excepts); 135930088Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 136030088Sminshall } while ((value == -1) && (errno == EINTR)); 136130088Sminshall 136230088Sminshall if (value < 0) { 136330088Sminshall perror("select"); 136430088Sminshall quit(); 136530088Sminshall } 136630088Sminshall if (FD_ISSET(s, &excepts)) { 136730088Sminshall return 1; 136830088Sminshall } else { 136930088Sminshall return 0; 137030088Sminshall } 137130088Sminshall } 137230088Sminshall 137330088Sminshall 137430088Sminshall /* 137530088Sminshall * netflush 137630088Sminshall * Send as much data as possible to the network, 137730088Sminshall * handling requests for urgent data. 137830088Sminshall * 137930088Sminshall * The return value indicates whether we did any 138030088Sminshall * useful work. 138130088Sminshall */ 138230088Sminshall 138330088Sminshall 138430088Sminshall int 138530088Sminshall netflush() 138630088Sminshall { 138730088Sminshall int n; 138830088Sminshall 138930088Sminshall if ((n = nfrontp - nbackp) > 0) { 139030088Sminshall if (!neturg) { 139131131Sminshall n = send(net, nbackp, n, 0); /* normal write */ 139230088Sminshall } else { 139330088Sminshall n = neturg - nbackp; 139430088Sminshall /* 139530088Sminshall * In 4.2 (and 4.3) systems, there is some question about 139630088Sminshall * what byte in a sendOOB operation is the "OOB" data. 139730088Sminshall * To make ourselves compatible, we only send ONE byte 139830088Sminshall * out of band, the one WE THINK should be OOB (though 139930088Sminshall * we really have more the TCP philosophy of urgent data 140030088Sminshall * rather than the Unix philosophy of OOB data). 140130088Sminshall */ 140230088Sminshall if (n > 1) { 140330088Sminshall n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 140430088Sminshall } else { 140530088Sminshall n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 140630088Sminshall } 140730088Sminshall } 140830088Sminshall } 140930088Sminshall if (n < 0) { 141030088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 141130088Sminshall setcommandmode(); 141230088Sminshall perror(hostname); 141331131Sminshall NetClose(net); 141430088Sminshall neturg = 0; 141530088Sminshall longjmp(peerdied, -1); 141630088Sminshall /*NOTREACHED*/ 141730088Sminshall } 141830088Sminshall n = 0; 141930088Sminshall } 142030088Sminshall if (netdata && n) { 142130088Sminshall Dump('>', nbackp, n); 142230088Sminshall } 142330088Sminshall nbackp += n; 142430088Sminshall if (nbackp >= neturg) { 142530088Sminshall neturg = 0; 142630088Sminshall } 142730088Sminshall if (nbackp == nfrontp) { 142830088Sminshall nbackp = nfrontp = netobuf; 142930088Sminshall } 143030088Sminshall return n > 0; 143130088Sminshall } 143230088Sminshall 143330088Sminshall /* 143430088Sminshall * nextitem() 143530088Sminshall * 143630088Sminshall * Return the address of the next "item" in the TELNET data 143730088Sminshall * stream. This will be the address of the next character if 143830088Sminshall * the current address is a user data character, or it will 143930088Sminshall * be the address of the character following the TELNET command 144030088Sminshall * if the current address is a TELNET IAC ("I Am a Command") 144130088Sminshall * character. 144230088Sminshall */ 144330088Sminshall 144430088Sminshall static char * 144530088Sminshall nextitem(current) 144630088Sminshall char *current; 144730088Sminshall { 144830088Sminshall if ((*current&0xff) != IAC) { 144930088Sminshall return current+1; 145030088Sminshall } 145130088Sminshall switch (*(current+1)&0xff) { 145230088Sminshall case DO: 145330088Sminshall case DONT: 145430088Sminshall case WILL: 145530088Sminshall case WONT: 145630088Sminshall return current+3; 145730088Sminshall case SB: /* loop forever looking for the SE */ 145830088Sminshall { 145930088Sminshall register char *look = current+2; 146030088Sminshall 146130088Sminshall for (;;) { 146230088Sminshall if ((*look++&0xff) == IAC) { 146330088Sminshall if ((*look++&0xff) == SE) { 146430088Sminshall return look; 146530088Sminshall } 146630088Sminshall } 146730088Sminshall } 146830088Sminshall } 146930088Sminshall default: 147030088Sminshall return current+2; 147130088Sminshall } 147230088Sminshall } 147330088Sminshall /* 147430088Sminshall * netclear() 147530088Sminshall * 147630088Sminshall * We are about to do a TELNET SYNCH operation. Clear 147730088Sminshall * the path to the network. 147830088Sminshall * 147930088Sminshall * Things are a bit tricky since we may have sent the first 148030088Sminshall * byte or so of a previous TELNET command into the network. 148130088Sminshall * So, we have to scan the network buffer from the beginning 148230088Sminshall * until we are up to where we want to be. 148330088Sminshall * 148430088Sminshall * A side effect of what we do, just to keep things 148530088Sminshall * simple, is to clear the urgent data pointer. The principal 148630088Sminshall * caller should be setting the urgent data pointer AFTER calling 148730088Sminshall * us in any case. 148830088Sminshall */ 148930088Sminshall 149030088Sminshall static void 149130088Sminshall netclear() 149230088Sminshall { 149330088Sminshall register char *thisitem, *next; 149430088Sminshall char *good; 149530088Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 149630088Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 149730088Sminshall 149830088Sminshall thisitem = netobuf; 149930088Sminshall 150030088Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 150130088Sminshall thisitem = next; 150230088Sminshall } 150330088Sminshall 150430088Sminshall /* Now, thisitem is first before/at boundary. */ 150530088Sminshall 150630088Sminshall good = netobuf; /* where the good bytes go */ 150730088Sminshall 150830088Sminshall while (nfrontp > thisitem) { 150930088Sminshall if (wewant(thisitem)) { 151030088Sminshall int length; 151130088Sminshall 151230088Sminshall next = thisitem; 151330088Sminshall do { 151430088Sminshall next = nextitem(next); 151530088Sminshall } while (wewant(next) && (nfrontp > next)); 151630088Sminshall length = next-thisitem; 151731131Sminshall memcpy(good, thisitem, length); 151830088Sminshall good += length; 151930088Sminshall thisitem = next; 152030088Sminshall } else { 152130088Sminshall thisitem = nextitem(thisitem); 152230088Sminshall } 152330088Sminshall } 152430088Sminshall 152530088Sminshall nbackp = netobuf; 152630088Sminshall nfrontp = good; /* next byte to be sent */ 152730088Sminshall neturg = 0; 152830088Sminshall } 152930088Sminshall 153030088Sminshall /* 153130088Sminshall * These routines add various telnet commands to the data stream. 153230088Sminshall */ 153330088Sminshall 153430088Sminshall #if defined(NOT43) 153530088Sminshall static int 153630088Sminshall #else /* defined(NOT43) */ 153730088Sminshall static void 153830088Sminshall #endif /* defined(NOT43) */ 153930088Sminshall dosynch() 154030088Sminshall { 154130088Sminshall netclear(); /* clear the path to the network */ 154230088Sminshall NET2ADD(IAC, DM); 154330088Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 154430088Sminshall 154530088Sminshall #if defined(NOT43) 154630088Sminshall return 0; 154730088Sminshall #endif /* defined(NOT43) */ 154830088Sminshall } 154930088Sminshall 155030088Sminshall static void 155130088Sminshall doflush() 155230088Sminshall { 155330088Sminshall NET2ADD(IAC, DO); 155430088Sminshall NETADD(TELOPT_TM); 155530088Sminshall flushline = 1; 155630088Sminshall flushout = 1; 155730088Sminshall ttyflush(); 155830088Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 155930088Sminshall printoption("<SENT", doopt, TELOPT_TM, 0); 156030088Sminshall } 156130088Sminshall 156230088Sminshall static void 156330088Sminshall intp() 156430088Sminshall { 156530088Sminshall NET2ADD(IAC, IP); 156630088Sminshall if (autoflush) { 156730088Sminshall doflush(); 156830088Sminshall } 156930088Sminshall if (autosynch) { 157030088Sminshall dosynch(); 157130088Sminshall } 157230088Sminshall } 157330088Sminshall 157430088Sminshall static void 157530088Sminshall sendbrk() 157630088Sminshall { 157730088Sminshall NET2ADD(IAC, BREAK); 157830088Sminshall if (autoflush) { 157930088Sminshall doflush(); 158030088Sminshall } 158130088Sminshall if (autosynch) { 158230088Sminshall dosynch(); 158330088Sminshall } 158430088Sminshall } 158530088Sminshall 158630088Sminshall /* 158730088Sminshall * Send as much data as possible to the terminal. 158830088Sminshall * 158930088Sminshall * The return value indicates whether we did any 159030088Sminshall * useful work. 159130088Sminshall */ 159230088Sminshall 159330088Sminshall 159430088Sminshall static int 159530088Sminshall ttyflush() 159630088Sminshall { 159730088Sminshall int n; 159830088Sminshall 159930088Sminshall if ((n = tfrontp - tbackp) > 0) { 160030088Sminshall if (!(SYNCHing||flushout)) { 160131131Sminshall n = TerminalWrite(tout, tbackp, n); 160230088Sminshall } else { 160331124Sminshall TerminalFlushOutput(); 160430088Sminshall /* we leave 'n' alone! */ 160530088Sminshall } 160630088Sminshall } 160730088Sminshall if (n >= 0) { 160830088Sminshall tbackp += n; 160930088Sminshall if (tbackp == tfrontp) { 161030088Sminshall tbackp = tfrontp = ttyobuf; 161130088Sminshall } 161230088Sminshall } 161330088Sminshall return n > 0; 161430088Sminshall } 161530088Sminshall 161630088Sminshall #if defined(TN3270) 161730088Sminshall 161830088Sminshall #if defined(unix) 161930088Sminshall static void 162030088Sminshall inputAvailable() 162130088Sminshall { 162230088Sminshall HaveInput = 1; 162330088Sminshall } 162430088Sminshall #endif /* defined(unix) */ 162530088Sminshall 162630088Sminshall void 162730088Sminshall outputPurge() 162830088Sminshall { 162930088Sminshall int tmp = flushout; 163030088Sminshall 163130088Sminshall flushout = 1; 163230088Sminshall 163330088Sminshall ttyflush(); 163430088Sminshall 163530088Sminshall flushout = tmp; 163630088Sminshall } 163730088Sminshall 163830088Sminshall #endif /* defined(TN3270) */ 163930088Sminshall 164030088Sminshall #if defined(unix) 164130088Sminshall /* 164230088Sminshall * Various signal handling routines. 164330088Sminshall */ 164430088Sminshall 164530088Sminshall static void 164630088Sminshall deadpeer() 164730088Sminshall { 164830088Sminshall setcommandmode(); 164930088Sminshall longjmp(peerdied, -1); 165030088Sminshall } 165130088Sminshall 165230088Sminshall static void 165330088Sminshall intr() 165430088Sminshall { 165530088Sminshall if (localchars) { 165630088Sminshall intp(); 165730088Sminshall return; 165830088Sminshall } 165930088Sminshall setcommandmode(); 166030088Sminshall longjmp(toplevel, -1); 166130088Sminshall } 166230088Sminshall 166330088Sminshall static void 166430088Sminshall intr2() 166530088Sminshall { 166630088Sminshall if (localchars) { 166730088Sminshall sendbrk(); 166830088Sminshall return; 166930088Sminshall } 167030088Sminshall } 167130088Sminshall 167230088Sminshall static void 167330088Sminshall doescape() 167430088Sminshall { 167530088Sminshall command(0); 167630088Sminshall } 167730088Sminshall #endif /* defined(unix) */ 167830088Sminshall 167930088Sminshall /* 168030088Sminshall * These routines decides on what the mode should be (based on the values 168130088Sminshall * of various global variables). 168230088Sminshall */ 168330088Sminshall 168430088Sminshall 168530088Sminshall static 168630088Sminshall getconnmode() 168730088Sminshall { 168830088Sminshall static char newmode[16] = 168930088Sminshall { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 }; 169030088Sminshall int modeindex = 0; 169130088Sminshall 169230088Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 169330088Sminshall modeindex += 1; 169430088Sminshall } 169530088Sminshall if (hisopts[TELOPT_ECHO]) { 169630088Sminshall modeindex += 2; 169730088Sminshall } 169830088Sminshall if (hisopts[TELOPT_SGA]) { 169930088Sminshall modeindex += 4; 170030088Sminshall } 170130088Sminshall if (In3270) { 170230088Sminshall modeindex += 8; 170330088Sminshall } 170430088Sminshall return newmode[modeindex]; 170530088Sminshall } 170630088Sminshall 170730088Sminshall void 170830088Sminshall setconnmode() 170930088Sminshall { 171031124Sminshall TerminalNewMode(getconnmode()); 171130088Sminshall } 171230088Sminshall 171330088Sminshall 171430088Sminshall void 171530088Sminshall setcommandmode() 171630088Sminshall { 171731124Sminshall TerminalNewMode(0); 171830088Sminshall } 171930088Sminshall 172030088Sminshall static void 172130088Sminshall willoption(option, reply) 172230088Sminshall int option, reply; 172330088Sminshall { 172430088Sminshall char *fmt; 172530088Sminshall 172630088Sminshall switch (option) { 172730088Sminshall 172830368Sminshall case TELOPT_ECHO: 172930088Sminshall # if defined(TN3270) 173030368Sminshall /* 173130368Sminshall * The following is a pain in the rear-end. 173230368Sminshall * Various IBM servers (some versions of Wiscnet, 173330368Sminshall * possibly Fibronics/Spartacus, and who knows who 173430368Sminshall * else) will NOT allow us to send "DO SGA" too early 173530368Sminshall * in the setup proceedings. On the other hand, 173630368Sminshall * 4.2 servers (telnetd) won't set SGA correctly. 173730368Sminshall * So, we are stuck. Empirically (but, based on 173830368Sminshall * a VERY small sample), the IBM servers don't send 173930368Sminshall * out anything about ECHO, so we postpone our sending 174030368Sminshall * "DO SGA" until we see "WILL ECHO" (which 4.2 servers 174130368Sminshall * DO send). 174230368Sminshall */ 174330368Sminshall { 174430368Sminshall if (askedSGA == 0) { 174530368Sminshall askedSGA = 1; 174630368Sminshall if (!hisopts[TELOPT_SGA]) { 174730368Sminshall willoption(TELOPT_SGA, 0); 174830368Sminshall } 174930368Sminshall } 175030368Sminshall } 175130368Sminshall /* Fall through */ 175230088Sminshall case TELOPT_EOR: 175330088Sminshall case TELOPT_BINARY: 175430088Sminshall #endif /* defined(TN3270) */ 175530088Sminshall case TELOPT_SGA: 175630088Sminshall settimer(modenegotiated); 175730088Sminshall hisopts[option] = 1; 175830088Sminshall fmt = doopt; 175930088Sminshall setconnmode(); /* possibly set new tty mode */ 176030088Sminshall break; 176130088Sminshall 176230088Sminshall case TELOPT_TM: 176330088Sminshall return; /* Never reply to TM will's/wont's */ 176430088Sminshall 176530088Sminshall default: 176630088Sminshall fmt = dont; 176730088Sminshall break; 176830088Sminshall } 176930088Sminshall sprintf(nfrontp, fmt, option); 177030088Sminshall nfrontp += sizeof (dont) - 2; 177130088Sminshall if (reply) 177230088Sminshall printoption(">SENT", fmt, option, reply); 177330088Sminshall else 177430088Sminshall printoption("<SENT", fmt, option, reply); 177530088Sminshall } 177630088Sminshall 177730088Sminshall static void 177830088Sminshall wontoption(option, reply) 177930088Sminshall int option, reply; 178030088Sminshall { 178130088Sminshall char *fmt; 178230088Sminshall 178330088Sminshall switch (option) { 178430088Sminshall 178530088Sminshall case TELOPT_ECHO: 178630088Sminshall case TELOPT_SGA: 178730088Sminshall settimer(modenegotiated); 178830088Sminshall hisopts[option] = 0; 178930088Sminshall fmt = dont; 179030088Sminshall setconnmode(); /* Set new tty mode */ 179130088Sminshall break; 179230088Sminshall 179330088Sminshall case TELOPT_TM: 179430088Sminshall return; /* Never reply to TM will's/wont's */ 179530088Sminshall 179630088Sminshall default: 179730088Sminshall fmt = dont; 179830088Sminshall } 179930088Sminshall sprintf(nfrontp, fmt, option); 180030088Sminshall nfrontp += sizeof (doopt) - 2; 180130088Sminshall if (reply) 180230088Sminshall printoption(">SENT", fmt, option, reply); 180330088Sminshall else 180430088Sminshall printoption("<SENT", fmt, option, reply); 180530088Sminshall } 180630088Sminshall 180730088Sminshall static void 180830088Sminshall dooption(option) 180930088Sminshall int option; 181030088Sminshall { 181130088Sminshall char *fmt; 181230088Sminshall 181330088Sminshall switch (option) { 181430088Sminshall 181530088Sminshall case TELOPT_TM: 181630088Sminshall fmt = will; 181730088Sminshall break; 181830088Sminshall 181930088Sminshall # if defined(TN3270) 182030088Sminshall case TELOPT_EOR: 182130088Sminshall case TELOPT_BINARY: 182230088Sminshall # endif /* defined(TN3270) */ 182330088Sminshall case TELOPT_TTYPE: /* terminal type option */ 182430088Sminshall case TELOPT_SGA: /* no big deal */ 182530088Sminshall fmt = will; 182630088Sminshall myopts[option] = 1; 182730088Sminshall break; 182830088Sminshall 182930088Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 183030088Sminshall default: 183130088Sminshall fmt = wont; 183230088Sminshall break; 183330088Sminshall } 183430088Sminshall sprintf(nfrontp, fmt, option); 183530088Sminshall nfrontp += sizeof (doopt) - 2; 183630088Sminshall printoption(">SENT", fmt, option, 0); 183730088Sminshall } 183830088Sminshall 183930088Sminshall /* 184030088Sminshall * suboption() 184130088Sminshall * 184230088Sminshall * Look at the sub-option buffer, and try to be helpful to the other 184330088Sminshall * side. 184430088Sminshall * 184530088Sminshall * Currently we recognize: 184630088Sminshall * 184730088Sminshall * Terminal type, send request. 184830088Sminshall */ 184930088Sminshall 185030088Sminshall static void 185130088Sminshall suboption() 185230088Sminshall { 185330088Sminshall printsub("<", subbuffer, subend-subbuffer+1); 185430088Sminshall switch (subbuffer[0]&0xff) { 185530088Sminshall case TELOPT_TTYPE: 185630088Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 185730088Sminshall ; 185830088Sminshall } else { 185930088Sminshall char *name; 186030088Sminshall char namebuf[41]; 186130088Sminshall extern char *getenv(); 186230088Sminshall int len; 186330088Sminshall 186430088Sminshall #if defined(TN3270) 186530088Sminshall /* 186630326Sminshall * Try to send a 3270 type terminal name. Decide which one based 186730088Sminshall * on the format of our screen, and (in the future) color 186830088Sminshall * capaiblities. 186930088Sminshall */ 187031124Sminshall #if defined(unix) 187131131Sminshall if (initscr() != ERR) { /* Initialize curses to get line size */ 187231131Sminshall MaxNumberLines = LINES; 187331131Sminshall MaxNumberColumns = COLS; 187431131Sminshall } 187531131Sminshall #else /* defined(unix) */ 187631131Sminshall InitTerminal(); 187731131Sminshall #endif /* defined(unix) */ 187831131Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 187930088Sminshall Sent3270TerminalType = 1; 188031131Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 188130088Sminshall MaxNumberLines = 27; 188230088Sminshall MaxNumberColumns = 132; 188330088Sminshall sb_terminal[SBTERMMODEL] = '5'; 188431131Sminshall } else if (MaxNumberLines >= 43) { 188530088Sminshall MaxNumberLines = 43; 188630088Sminshall MaxNumberColumns = 80; 188730088Sminshall sb_terminal[SBTERMMODEL] = '4'; 188831131Sminshall } else if (MaxNumberLines >= 32) { 188930088Sminshall MaxNumberLines = 32; 189030088Sminshall MaxNumberColumns = 80; 189130088Sminshall sb_terminal[SBTERMMODEL] = '3'; 189230088Sminshall } else { 189330088Sminshall MaxNumberLines = 24; 189430088Sminshall MaxNumberColumns = 80; 189530088Sminshall sb_terminal[SBTERMMODEL] = '2'; 189630088Sminshall } 189730088Sminshall NumberLines = 24; /* before we start out... */ 189830088Sminshall NumberColumns = 80; 189930088Sminshall ScreenSize = NumberLines*NumberColumns; 190030088Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 190130088Sminshall ExitString(stderr, 190230088Sminshall "Programming error: MAXSCREENSIZE too small.\n", 1); 190330088Sminshall /*NOTREACHED*/ 190430088Sminshall } 190531131Sminshall memcpy(nfrontp, sb_terminal, sizeof sb_terminal); 190630088Sminshall printsub(">", nfrontp+2, sizeof sb_terminal-2); 190730088Sminshall nfrontp += sizeof sb_terminal; 190830088Sminshall return; 190930088Sminshall } 191030088Sminshall #endif /* defined(TN3270) */ 191130088Sminshall 191230088Sminshall name = getenv("TERM"); 191330088Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 191430088Sminshall name = "UNKNOWN"; 191530088Sminshall } 191630088Sminshall if ((len + 4+2) < NETROOM()) { 191730088Sminshall strcpy(namebuf, name); 191830088Sminshall upcase(namebuf); 191930088Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 192030088Sminshall TELQUAL_IS, namebuf, IAC, SE); 192130088Sminshall printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); 192230088Sminshall nfrontp += 4+strlen(namebuf)+2; 192330088Sminshall } else { 192430088Sminshall ExitString(stderr, "No room in buffer for terminal type.\n", 192530088Sminshall 1); 192630088Sminshall /*NOTREACHED*/ 192730088Sminshall } 192830088Sminshall } 192930088Sminshall 193030088Sminshall default: 193130088Sminshall break; 193230088Sminshall } 193330088Sminshall } 193430088Sminshall 193530088Sminshall #if defined(TN3270) 193630088Sminshall static void 193730088Sminshall SetIn3270() 193830088Sminshall { 193930088Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 194031791Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 194130088Sminshall if (!In3270) { 194230088Sminshall In3270 = 1; 194330326Sminshall Init3270(); /* Initialize 3270 functions */ 194430088Sminshall /* initialize terminal key mapping */ 194530326Sminshall InitTerminal(); /* Start terminal going */ 194630088Sminshall setconnmode(); 194730088Sminshall } 194830088Sminshall } else { 194930088Sminshall if (In3270) { 195030088Sminshall StopScreen(1); 195130088Sminshall In3270 = 0; 195231215Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 195330088Sminshall setconnmode(); 195430088Sminshall } 195530088Sminshall } 195630088Sminshall } 195730088Sminshall #endif /* defined(TN3270) */ 195830088Sminshall 195930088Sminshall 196030088Sminshall static void 196130088Sminshall telrcv() 196230088Sminshall { 196330088Sminshall register int c; 196430722Sminshall static int telrcv_state = TS_DATA; 196530088Sminshall # if defined(TN3270) 196630088Sminshall register int Scc; 196730088Sminshall register char *Sbp; 196830088Sminshall # endif /* defined(TN3270) */ 196930088Sminshall 197030088Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 197130088Sminshall c = *sbp++ & 0xff, scc--; 197230722Sminshall switch (telrcv_state) { 197330088Sminshall 197430088Sminshall case TS_CR: 197530722Sminshall telrcv_state = TS_DATA; 197630088Sminshall if (c == '\0') { 197730088Sminshall break; /* Ignore \0 after CR */ 197830088Sminshall } else if (c == '\n') { 197930088Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 198030088Sminshall TTYADD(c); 198130088Sminshall } 198230088Sminshall break; 198330088Sminshall } 198430088Sminshall /* Else, fall through */ 198530088Sminshall 198630088Sminshall case TS_DATA: 198730088Sminshall if (c == IAC) { 198830722Sminshall telrcv_state = TS_IAC; 198930088Sminshall continue; 199030088Sminshall } 199130088Sminshall # if defined(TN3270) 199230088Sminshall if (In3270) { 199330088Sminshall *Ifrontp++ = c; 199430088Sminshall Sbp = sbp; 199530088Sminshall Scc = scc; 199630088Sminshall while (Scc > 0) { 199730088Sminshall c = *Sbp++ & 0377, Scc--; 199830088Sminshall if (c == IAC) { 199930722Sminshall telrcv_state = TS_IAC; 200030088Sminshall break; 200130088Sminshall } 200230088Sminshall *Ifrontp++ = c; 200330088Sminshall } 200430088Sminshall sbp = Sbp; 200530088Sminshall scc = Scc; 200630088Sminshall } else 200730088Sminshall # endif /* defined(TN3270) */ 200830088Sminshall /* 200930088Sminshall * The 'crmod' hack (see following) is needed 201030088Sminshall * since we can't * set CRMOD on output only. 201130088Sminshall * Machines like MULTICS like to send \r without 201230088Sminshall * \n; since we must turn off CRMOD to get proper 201330088Sminshall * input, the mapping is done here (sigh). 201430088Sminshall */ 201530088Sminshall if (c == '\r') { 201630088Sminshall if (scc > 0) { 201730088Sminshall c = *sbp&0xff; 201830088Sminshall if (c == 0) { 201930088Sminshall sbp++, scc--; 202030088Sminshall /* a "true" CR */ 202130088Sminshall TTYADD('\r'); 202230088Sminshall } else if (!hisopts[TELOPT_ECHO] && 202330088Sminshall (c == '\n')) { 202430088Sminshall sbp++, scc--; 202530088Sminshall TTYADD('\n'); 202630088Sminshall } else { 202730088Sminshall TTYADD('\r'); 202830088Sminshall if (crmod) { 202930088Sminshall TTYADD('\n'); 203030088Sminshall } 203130088Sminshall } 203230088Sminshall } else { 203330722Sminshall telrcv_state = TS_CR; 203430088Sminshall TTYADD('\r'); 203530088Sminshall if (crmod) { 203630088Sminshall TTYADD('\n'); 203730088Sminshall } 203830088Sminshall } 203930088Sminshall } else { 204030088Sminshall TTYADD(c); 204130088Sminshall } 204230088Sminshall continue; 204330088Sminshall 204430088Sminshall case TS_IAC: 204530088Sminshall switch (c) { 204630088Sminshall 204730088Sminshall case WILL: 204830722Sminshall telrcv_state = TS_WILL; 204930088Sminshall continue; 205030088Sminshall 205130088Sminshall case WONT: 205230722Sminshall telrcv_state = TS_WONT; 205330088Sminshall continue; 205430088Sminshall 205530088Sminshall case DO: 205630722Sminshall telrcv_state = TS_DO; 205730088Sminshall continue; 205830088Sminshall 205930088Sminshall case DONT: 206030722Sminshall telrcv_state = TS_DONT; 206130088Sminshall continue; 206230088Sminshall 206330088Sminshall case DM: 206430088Sminshall /* 206530088Sminshall * We may have missed an urgent notification, 206630088Sminshall * so make sure we flush whatever is in the 206730088Sminshall * buffer currently. 206830088Sminshall */ 206930088Sminshall SYNCHing = 1; 207030088Sminshall ttyflush(); 207130088Sminshall SYNCHing = stilloob(net); 207230088Sminshall settimer(gotDM); 207330088Sminshall break; 207430088Sminshall 207530088Sminshall case NOP: 207630088Sminshall case GA: 207730088Sminshall break; 207830088Sminshall 207930088Sminshall case SB: 208030088Sminshall SB_CLEAR(); 208130722Sminshall telrcv_state = TS_SB; 208230088Sminshall continue; 208330088Sminshall 208430088Sminshall # if defined(TN3270) 208530088Sminshall case EOR: 208630088Sminshall if (In3270) { 208730088Sminshall Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); 208830088Sminshall if (Ibackp == Ifrontp) { 208930088Sminshall Ibackp = Ifrontp = Ibuf; 209030088Sminshall ISend = 0; /* should have been! */ 209130088Sminshall } else { 209230088Sminshall ISend = 1; 209330088Sminshall } 209430088Sminshall } 209530088Sminshall break; 209630088Sminshall # endif /* defined(TN3270) */ 209730088Sminshall 209830088Sminshall case IAC: 209930088Sminshall # if !defined(TN3270) 210030088Sminshall TTYADD(IAC); 210130088Sminshall # else /* !defined(TN3270) */ 210230088Sminshall if (In3270) { 210330088Sminshall *Ifrontp++ = IAC; 210430088Sminshall } else { 210530088Sminshall TTYADD(IAC); 210630088Sminshall } 210730088Sminshall # endif /* !defined(TN3270) */ 210830088Sminshall break; 210930088Sminshall 211030088Sminshall default: 211130088Sminshall break; 211230088Sminshall } 211330722Sminshall telrcv_state = TS_DATA; 211430088Sminshall continue; 211530088Sminshall 211630088Sminshall case TS_WILL: 211730088Sminshall printoption(">RCVD", will, c, !hisopts[c]); 211830088Sminshall if (c == TELOPT_TM) { 211930088Sminshall if (flushout) { 212030088Sminshall flushout = 0; 212130088Sminshall } 212230088Sminshall } else if (!hisopts[c]) { 212330088Sminshall willoption(c, 1); 212430088Sminshall } 212530088Sminshall SetIn3270(); 212630722Sminshall telrcv_state = TS_DATA; 212730088Sminshall continue; 212830088Sminshall 212930088Sminshall case TS_WONT: 213030088Sminshall printoption(">RCVD", wont, c, hisopts[c]); 213130088Sminshall if (c == TELOPT_TM) { 213230088Sminshall if (flushout) { 213330088Sminshall flushout = 0; 213430088Sminshall } 213530088Sminshall } else if (hisopts[c]) { 213630088Sminshall wontoption(c, 1); 213730088Sminshall } 213830088Sminshall SetIn3270(); 213930722Sminshall telrcv_state = TS_DATA; 214030088Sminshall continue; 214130088Sminshall 214230088Sminshall case TS_DO: 214330088Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 214430088Sminshall if (!myopts[c]) 214530088Sminshall dooption(c); 214630088Sminshall SetIn3270(); 214730722Sminshall telrcv_state = TS_DATA; 214830088Sminshall continue; 214930088Sminshall 215030088Sminshall case TS_DONT: 215130088Sminshall printoption(">RCVD", dont, c, myopts[c]); 215230088Sminshall if (myopts[c]) { 215330088Sminshall myopts[c] = 0; 215430088Sminshall sprintf(nfrontp, wont, c); 215530088Sminshall nfrontp += sizeof (wont) - 2; 215630088Sminshall flushline = 1; 215730088Sminshall setconnmode(); /* set new tty mode (maybe) */ 215830088Sminshall printoption(">SENT", wont, c, 0); 215930088Sminshall } 216030088Sminshall SetIn3270(); 216130722Sminshall telrcv_state = TS_DATA; 216230088Sminshall continue; 216330088Sminshall 216430088Sminshall case TS_SB: 216530088Sminshall if (c == IAC) { 216630722Sminshall telrcv_state = TS_SE; 216730088Sminshall } else { 216830088Sminshall SB_ACCUM(c); 216930088Sminshall } 217030088Sminshall continue; 217130088Sminshall 217230088Sminshall case TS_SE: 217330088Sminshall if (c != SE) { 217430088Sminshall if (c != IAC) { 217530088Sminshall SB_ACCUM(IAC); 217630088Sminshall } 217730088Sminshall SB_ACCUM(c); 217830722Sminshall telrcv_state = TS_SB; 217930088Sminshall } else { 218030088Sminshall SB_TERM(); 218130088Sminshall suboption(); /* handle sub-option */ 218230088Sminshall SetIn3270(); 218330722Sminshall telrcv_state = TS_DATA; 218430088Sminshall } 218530088Sminshall } 218630088Sminshall } 218730088Sminshall } 218830088Sminshall 218930088Sminshall #if defined(TN3270) 219030088Sminshall 219130088Sminshall /* 219230088Sminshall * The following routines are places where the various tn3270 219330088Sminshall * routines make calls into telnet.c. 219430088Sminshall */ 219530088Sminshall 219630088Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 219730088Sminshall TtyChars() 219830088Sminshall { 219930088Sminshall return(tfrontp-tbackp); 220030088Sminshall } 220130088Sminshall 220230088Sminshall /* 220330088Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 220430088Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 220530088Sminshall * don't call us with "done" until you want that done...) 220630088Sminshall * 220730088Sminshall * We actually do send all the data to the network buffer, since our 220830088Sminshall * only client needs for us to do that. 220930088Sminshall */ 221030088Sminshall 221130088Sminshall int 221230088Sminshall DataToNetwork(buffer, count, done) 221330088Sminshall register char *buffer; /* where the data is */ 221430088Sminshall register int count; /* how much to send */ 221530088Sminshall int done; /* is this the last of a logical block */ 221630088Sminshall { 221730088Sminshall register int c; 221830088Sminshall int origCount; 221930088Sminshall fd_set o; 222030088Sminshall 222130088Sminshall origCount = count; 222230088Sminshall FD_ZERO(&o); 222330088Sminshall 222430088Sminshall while (count) { 222530088Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 222630088Sminshall netflush(); 222730088Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 6) { 222830088Sminshall FD_SET(net, &o); 222930088Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 223030088Sminshall (struct timeval *) 0); 223130088Sminshall netflush(); 223230088Sminshall } 223330088Sminshall } 223430088Sminshall c = *buffer++; 223530088Sminshall count--; 223630088Sminshall if (c == IAC) { 223730088Sminshall *nfrontp++ = IAC; 223830088Sminshall *nfrontp++ = IAC; 223930088Sminshall } else { 224030088Sminshall *nfrontp++ = c; 224130088Sminshall } 224230088Sminshall } 224330088Sminshall 224430088Sminshall if (done && !count) { 224530088Sminshall *nfrontp++ = IAC; 224630088Sminshall *nfrontp++ = EOR; 224730088Sminshall netflush(); /* try to move along as quickly as ... */ 224830088Sminshall } 224930088Sminshall return(origCount - count); 225030088Sminshall } 225130088Sminshall 225230088Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 225330088Sminshall 225430088Sminshall int 225530088Sminshall DataToTerminal(buffer, count) 225630088Sminshall register char *buffer; /* where the data is */ 225730088Sminshall register int count; /* how much to send */ 225830088Sminshall { 225930088Sminshall int origCount; 226031131Sminshall #if defined(unix) 226130088Sminshall fd_set o; 226230088Sminshall 226331131Sminshall FD_ZERO(&o); 226431131Sminshall #endif /* defined(unix) */ 226530088Sminshall origCount = count; 226630088Sminshall 226730088Sminshall while (count) { 226830088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 226930088Sminshall ttyflush(); 227030088Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 227131131Sminshall #if defined(unix) 227230088Sminshall FD_SET(tout, &o); 227330088Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 227430088Sminshall (struct timeval *) 0); 227531131Sminshall #endif /* defined(unix) */ 227630088Sminshall ttyflush(); 227730088Sminshall } 227830088Sminshall } 227930088Sminshall *tfrontp++ = *buffer++; 228030088Sminshall count--; 228130088Sminshall } 228230088Sminshall return(origCount - count); 228330088Sminshall } 228430088Sminshall 228530088Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 228630088Sminshall * Note that we consider the buffer to run all the 228730088Sminshall * way to the kernel (thus the select). 228830088Sminshall */ 228930088Sminshall 229030088Sminshall void 229130088Sminshall EmptyTerminal() 229230088Sminshall { 229331131Sminshall #if defined(unix) 229430088Sminshall fd_set o; 229530088Sminshall 229630088Sminshall FD_ZERO(&o); 229731131Sminshall #endif /* defined(unix) */ 229830088Sminshall 229930088Sminshall if (tfrontp == tbackp) { 230031131Sminshall #if defined(unix) 230130088Sminshall FD_SET(tout, &o); 230230088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 230330088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 230431131Sminshall #endif /* defined(unix) */ 230530088Sminshall } else { 230630088Sminshall while (tfrontp != tbackp) { 230730088Sminshall ttyflush(); 230831131Sminshall #if defined(unix) 230930088Sminshall FD_SET(tout, &o); 231030088Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 231130088Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 231231131Sminshall #endif /* defined(unix) */ 231330088Sminshall } 231430088Sminshall } 231530088Sminshall } 231630088Sminshall 231730088Sminshall /* 231830088Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 231930088Sminshall */ 232030088Sminshall 232130088Sminshall static int 232230088Sminshall Push3270() 232330088Sminshall { 232430088Sminshall int save = scc; 232530088Sminshall 232630088Sminshall if (scc) { 232730088Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 232830088Sminshall if (Ibackp != Ibuf) { 232931131Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 233030088Sminshall Ifrontp -= (Ibackp-Ibuf); 233130088Sminshall Ibackp = Ibuf; 233230088Sminshall } 233330088Sminshall } 233430088Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 233530088Sminshall telrcv(); 233630088Sminshall } 233730088Sminshall } 233830088Sminshall return save != scc; 233930088Sminshall } 234030088Sminshall 234130088Sminshall 234230088Sminshall /* 234330088Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 234430088Sminshall * before quitting. 234530088Sminshall */ 234630088Sminshall 234730088Sminshall static void 234830088Sminshall Finish3270() 234930088Sminshall { 235030088Sminshall while (Push3270() || !DoTerminalOutput()) { 235131589Sminshall #if defined(unix) 235231589Sminshall HaveInput = 0; 235331589Sminshall #endif /* defined(unix) */ 235430088Sminshall ; 235530088Sminshall } 235630088Sminshall } 235730088Sminshall 235830088Sminshall 235930088Sminshall 236030088Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 236130088Sminshall 236230088Sminshall void 236330088Sminshall StringToTerminal(s) 236430088Sminshall char *s; 236530088Sminshall { 236630088Sminshall int count; 236730088Sminshall 236830088Sminshall count = strlen(s); 236930088Sminshall if (count) { 237030088Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 237130088Sminshall } 237230088Sminshall } 237330088Sminshall 237430088Sminshall 237530088Sminshall #if defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) 237630088Sminshall /* _putchar - output a single character to the terminal. This name is so that 237730088Sminshall * curses(3x) can call us to send out data. 237830088Sminshall */ 237930088Sminshall 238030088Sminshall void 238130088Sminshall _putchar(c) 238230088Sminshall char c; 238330088Sminshall { 238430088Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 238530088Sminshall (void) DataToTerminal(&c, 1); 238630088Sminshall } else { 238730088Sminshall *tfrontp++ = c; /* optimize if possible. */ 238830088Sminshall } 238930088Sminshall } 239030088Sminshall #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */ 239130088Sminshall 239230088Sminshall static void 239330088Sminshall SetForExit() 239430088Sminshall { 239530088Sminshall setconnmode(); 239630088Sminshall if (In3270) { 239730088Sminshall Finish3270(); 239830088Sminshall } 239930088Sminshall setcommandmode(); 240030088Sminshall fflush(stdout); 240130088Sminshall fflush(stderr); 240230088Sminshall if (In3270) { 240330088Sminshall StopScreen(1); 240430088Sminshall } 240530088Sminshall setconnmode(); 240630088Sminshall setcommandmode(); 240730088Sminshall } 240830088Sminshall 240930088Sminshall static void 241030088Sminshall Exit(returnCode) 241130088Sminshall int returnCode; 241230088Sminshall { 241330088Sminshall SetForExit(); 241430088Sminshall exit(returnCode); 241530088Sminshall } 241630088Sminshall 241730088Sminshall void 241830088Sminshall ExitString(file, string, returnCode) 241930088Sminshall FILE *file; 242030088Sminshall char *string; 242130088Sminshall int returnCode; 242230088Sminshall { 242330088Sminshall SetForExit(); 242430088Sminshall fwrite(string, 1, strlen(string), file); 242530088Sminshall exit(returnCode); 242630088Sminshall } 242730088Sminshall 242830088Sminshall void 242930088Sminshall ExitPerror(string, returnCode) 243030088Sminshall char *string; 243130088Sminshall int returnCode; 243230088Sminshall { 243330088Sminshall SetForExit(); 243430088Sminshall perror(string); 243530088Sminshall exit(returnCode); 243630088Sminshall } 243730088Sminshall 243830088Sminshall #endif /* defined(TN3270) */ 243930088Sminshall 244031215Sminshall /* 244131215Sminshall * Scheduler() 244231215Sminshall * 244331215Sminshall * Try to do something. 244431215Sminshall * 244531215Sminshall * If we do something useful, return 1; else return 0. 244631215Sminshall * 244731215Sminshall */ 244831215Sminshall 244931215Sminshall 245031215Sminshall int 245130088Sminshall Scheduler(block) 245230088Sminshall int block; /* should we block in the select ? */ 245330088Sminshall { 245430088Sminshall register int c; 245530088Sminshall /* One wants to be a bit careful about setting returnValue 245630088Sminshall * to one, since a one implies we did some useful work, 245730088Sminshall * and therefore probably won't be called to block next 245830088Sminshall * time (TN3270 mode only). 245930088Sminshall */ 246030088Sminshall int returnValue = 0; 246130088Sminshall static struct timeval TimeValue = { 0 }; 246230088Sminshall 246330088Sminshall if (scc < 0 && tcc < 0) { 246430088Sminshall return -1; 246530088Sminshall } 246630088Sminshall 246730088Sminshall if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) { 246830088Sminshall FD_SET(net, &obits); 246930088Sminshall } 247031131Sminshall #if !defined(MSDOS) 247130088Sminshall if (TTYBYTES()) { 247230088Sminshall FD_SET(tout, &obits); 247330088Sminshall } 247431215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0)) { 247530088Sminshall FD_SET(tin, &ibits); 247630088Sminshall } 247731131Sminshall #endif /* !defined(MSDOS) */ 247830088Sminshall # if !defined(TN3270) 247930088Sminshall if (TTYROOM()) { 248030088Sminshall FD_SET(net, &ibits); 248130088Sminshall } 248230088Sminshall # else /* !defined(TN3270) */ 248330088Sminshall if (!ISend && TTYROOM()) { 248430088Sminshall FD_SET(net, &ibits); 248530088Sminshall } 248630088Sminshall # endif /* !defined(TN3270) */ 248730088Sminshall if (!SYNCHing) { 248830088Sminshall FD_SET(net, &xbits); 248930088Sminshall } 249030088Sminshall # if defined(TN3270) && defined(unix) 249130088Sminshall if (HaveInput) { 249230088Sminshall HaveInput = 0; 249330088Sminshall signal(SIGIO, inputAvailable); 249430088Sminshall } 249530088Sminshall #endif /* defined(TN3270) && defined(unix) */ 249630088Sminshall if ((c = select(16, &ibits, &obits, &xbits, 249731131Sminshall block? (struct timeval *)0 : &TimeValue)) < 0) { 249830088Sminshall if (c == -1) { 249930088Sminshall /* 250030088Sminshall * we can get EINTR if we are in line mode, 250130088Sminshall * and the user does an escape (TSTP), or 250230088Sminshall * some other signal generator. 250330088Sminshall */ 250430088Sminshall if (errno == EINTR) { 250530088Sminshall return 0; 250630088Sminshall } 250730088Sminshall # if defined(TN3270) 250830088Sminshall /* 250930088Sminshall * we can get EBADF if we were in transparent 251030088Sminshall * mode, and the transcom process died. 251130088Sminshall */ 251230088Sminshall if (errno == EBADF) { 251330088Sminshall /* 251430088Sminshall * zero the bits (even though kernel does it) 251530088Sminshall * to make sure we are selecting on the right 251630088Sminshall * ones. 251730088Sminshall */ 251830088Sminshall FD_ZERO(&ibits); 251930088Sminshall FD_ZERO(&obits); 252030088Sminshall FD_ZERO(&xbits); 252130088Sminshall return 0; 252230088Sminshall } 252330088Sminshall # endif /* defined(TN3270) */ 252430088Sminshall /* I don't like this, does it ever happen? */ 252530088Sminshall printf("sleep(5) from telnet, after select\r\n"); 252630088Sminshall #if defined(unix) 252730088Sminshall sleep(5); 252830088Sminshall #endif /* defined(unix) */ 252930088Sminshall } 253030088Sminshall return 0; 253130088Sminshall } 253230088Sminshall 253330088Sminshall /* 253430088Sminshall * Any urgent data? 253530088Sminshall */ 253630088Sminshall if (FD_ISSET(net, &xbits)) { 253730088Sminshall FD_CLR(net, &xbits); 253830088Sminshall SYNCHing = 1; 253930088Sminshall ttyflush(); /* flush already enqueued data */ 254030088Sminshall } 254130088Sminshall 254230088Sminshall /* 254330088Sminshall * Something to read from the network... 254430088Sminshall */ 254530088Sminshall if (FD_ISSET(net, &ibits)) { 254630088Sminshall int canread; 254730088Sminshall 254830088Sminshall FD_CLR(net, &ibits); 254930088Sminshall if (scc == 0) { 255030088Sminshall sbp = sibuf; 255130088Sminshall } 255230422Sminshall canread = sibuf + sizeof sibuf - (sbp+scc); 255330088Sminshall #if !defined(SO_OOBINLINE) 255430088Sminshall /* 255530088Sminshall * In 4.2 (and some early 4.3) systems, the 255630088Sminshall * OOB indication and data handling in the kernel 255730088Sminshall * is such that if two separate TCP Urgent requests 255830088Sminshall * come in, one byte of TCP data will be overlaid. 255930088Sminshall * This is fatal for Telnet, but we try to live 256030088Sminshall * with it. 256130088Sminshall * 256230088Sminshall * In addition, in 4.2 (and...), a special protocol 256330088Sminshall * is needed to pick up the TCP Urgent data in 256430088Sminshall * the correct sequence. 256530088Sminshall * 256630088Sminshall * What we do is: if we think we are in urgent 256730088Sminshall * mode, we look to see if we are "at the mark". 256830088Sminshall * If we are, we do an OOB receive. If we run 256930088Sminshall * this twice, we will do the OOB receive twice, 257030088Sminshall * but the second will fail, since the second 257130088Sminshall * time we were "at the mark", but there wasn't 257230088Sminshall * any data there (the kernel doesn't reset 257330088Sminshall * "at the mark" until we do a normal read). 257430088Sminshall * Once we've read the OOB data, we go ahead 257530088Sminshall * and do normal reads. 257630088Sminshall * 257730088Sminshall * There is also another problem, which is that 257830088Sminshall * since the OOB byte we read doesn't put us 257930088Sminshall * out of OOB state, and since that byte is most 258030088Sminshall * likely the TELNET DM (data mark), we would 258130088Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 258230088Sminshall * So, clocks to the rescue. If we've "just" 258330088Sminshall * received a DM, then we test for the 258430088Sminshall * presence of OOB data when the receive OOB 258530088Sminshall * fails (and AFTER we did the normal mode read 258630088Sminshall * to clear "at the mark"). 258730088Sminshall */ 258830088Sminshall if (SYNCHing) { 258930088Sminshall int atmark; 259030088Sminshall 259130088Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 259230088Sminshall if (atmark) { 259330422Sminshall c = recv(net, sbp+scc, canread, MSG_OOB); 259430088Sminshall if ((c == -1) && (errno == EINVAL)) { 259531131Sminshall c = recv(net, sbp+scc, canread, 0); 259630088Sminshall if (clocks.didnetreceive < clocks.gotDM) { 259730088Sminshall SYNCHing = stilloob(net); 259830088Sminshall } 259930088Sminshall } 260030088Sminshall } else { 260131131Sminshall c = recv(net, sbp+scc, canread, 0); 260230088Sminshall } 260330088Sminshall } else { 260431131Sminshall c = recv(net, sbp+scc, canread, 0); 260530088Sminshall } 260630088Sminshall settimer(didnetreceive); 260730088Sminshall #else /* !defined(SO_OOBINLINE) */ 260831131Sminshall c = recv(net, sbp+scc, canread, 0); 260930088Sminshall #endif /* !defined(SO_OOBINLINE) */ 261030088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 261130088Sminshall c = 0; 261230088Sminshall } else if (c <= 0) { 261330088Sminshall return -1; 261430088Sminshall } 261530088Sminshall if (netdata) { 261630422Sminshall Dump('<', sbp+scc, c); 261730088Sminshall } 261830088Sminshall scc += c; 261930088Sminshall returnValue = 1; 262030088Sminshall } 262130088Sminshall 262230088Sminshall /* 262330088Sminshall * Something to read from the tty... 262430088Sminshall */ 262531131Sminshall #if defined(MSDOS) 262631215Sminshall if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead()) 262731131Sminshall #else /* defined(MSDOS) */ 262831131Sminshall if (FD_ISSET(tin, &ibits)) 262931131Sminshall #endif /* defined(MSDOS) */ 263031131Sminshall { 263130088Sminshall FD_CLR(tin, &ibits); 263230088Sminshall if (tcc == 0) { 263330088Sminshall tbp = tibuf; /* nothing left, reset */ 263430088Sminshall } 263531131Sminshall c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp); 263630088Sminshall if (c < 0 && errno == EWOULDBLOCK) { 263730088Sminshall c = 0; 263830088Sminshall } else { 263931124Sminshall #if defined(unix) 264030088Sminshall /* EOF detection for line mode!!!! */ 264130088Sminshall if (c == 0 && MODE_LOCAL_CHARS(globalmode)) { 264230088Sminshall /* must be an EOF... */ 264330088Sminshall *tbp = ntc.t_eofc; 264430088Sminshall c = 1; 264530088Sminshall } 264631124Sminshall #endif /* defined(unix) */ 264730088Sminshall if (c <= 0) { 264830088Sminshall tcc = c; 264930088Sminshall return -1; 265030088Sminshall } 265130088Sminshall } 265230088Sminshall tcc += c; 265330088Sminshall returnValue = 1; /* did something useful */ 265430088Sminshall } 265530088Sminshall 265630088Sminshall # if defined(TN3270) 265730088Sminshall if (tcc > 0) { 265830088Sminshall if (In3270) { 265930088Sminshall c = DataFromTerminal(tbp, tcc); 266030088Sminshall if (c) { 266130088Sminshall returnValue = 1; 266230088Sminshall } 266330088Sminshall tcc -= c; 266430088Sminshall tbp += c; 266530088Sminshall } else { 266630320Sminshall # endif /* defined(TN3270) */ 266730088Sminshall returnValue = 1; 266830088Sminshall while (tcc > 0) { 266930088Sminshall register int sc; 267030088Sminshall 267130088Sminshall if (NETROOM() < 2) { 267230088Sminshall flushline = 1; 267330088Sminshall break; 267430088Sminshall } 267530088Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 267630088Sminshall if (sc == escape) { 267730088Sminshall command(0); 267830088Sminshall tcc = 0; 267930088Sminshall flushline = 1; 268030088Sminshall break; 268130088Sminshall } else if (MODE_LINE(globalmode) && (sc == echoc)) { 268230088Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 268330088Sminshall tbp++; 268430088Sminshall tcc--; 268530088Sminshall } else { 268630088Sminshall dontlecho = !dontlecho; 268730088Sminshall settimer(echotoggle); 268830088Sminshall setconnmode(); 268930088Sminshall tcc = 0; 269030088Sminshall flushline = 1; 269130088Sminshall break; 269230088Sminshall } 269330088Sminshall } 269430088Sminshall if (localchars) { 269531131Sminshall if (TerminalSpecialChars(sc) == 0) { 269630088Sminshall break; 269730088Sminshall } 269830088Sminshall } 269930088Sminshall switch (c) { 270030088Sminshall case '\n': 270130088Sminshall /* 270230088Sminshall * If we are in CRMOD mode (\r ==> \n) 270330088Sminshall * on our local machine, then probably 270430088Sminshall * a newline (unix) is CRLF (TELNET). 270530088Sminshall */ 270630088Sminshall if (MODE_LOCAL_CHARS(globalmode)) { 270730088Sminshall NETADD('\r'); 270830088Sminshall } 270930088Sminshall NETADD('\n'); 271030088Sminshall flushline = 1; 271130088Sminshall break; 271230088Sminshall case '\r': 271330088Sminshall NET2ADD('\r', '\0'); 271430088Sminshall flushline = 1; 271530088Sminshall break; 271630088Sminshall case IAC: 271730088Sminshall NET2ADD(IAC, IAC); 271830088Sminshall break; 271930088Sminshall default: 272030088Sminshall NETADD(c); 272130088Sminshall break; 272230088Sminshall } 272330088Sminshall } 272430088Sminshall # if defined(TN3270) 272530088Sminshall } 272630088Sminshall } 272730088Sminshall # endif /* defined(TN3270) */ 272830088Sminshall 272930088Sminshall if ((!MODE_LINE(globalmode) || flushline) && 273030088Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 273130088Sminshall FD_CLR(net, &obits); 273230088Sminshall returnValue = netflush(); 273330088Sminshall } 273430088Sminshall if (scc > 0) { 273530088Sminshall # if !defined(TN3270) 273630088Sminshall telrcv(); 273730088Sminshall returnValue = 1; 273830088Sminshall # else /* !defined(TN3270) */ 273930088Sminshall returnValue = Push3270(); 274030088Sminshall # endif /* !defined(TN3270) */ 274130088Sminshall } 274231131Sminshall #if defined(MSDOS) 274331131Sminshall if (TTYBYTES()) 274431131Sminshall #else /* defined(MSDOS) */ 274531131Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 274631131Sminshall #endif /* defined(MSDOS) */ 274731131Sminshall { 274830088Sminshall FD_CLR(tout, &obits); 274930088Sminshall returnValue = ttyflush(); 275030088Sminshall } 275130088Sminshall return returnValue; 275230088Sminshall } 275330088Sminshall 275430088Sminshall /* 275530088Sminshall * Select from tty and network... 275630088Sminshall */ 275730088Sminshall static void 275830088Sminshall telnet() 275930088Sminshall { 276031131Sminshall #if defined(MSDOS) 276131131Sminshall #define SCHED_BLOCK 0 /* Don't block in MSDOS */ 276231131Sminshall #else /* defined(MSDOS) */ 276331131Sminshall #define SCHED_BLOCK 1 276431131Sminshall #endif /* defined(MSDOS) */ 276531131Sminshall 276630088Sminshall #if defined(TN3270) && defined(unix) 276730088Sminshall int myPid; 276830088Sminshall #endif /* defined(TN3270) */ 276930088Sminshall 277030088Sminshall tout = fileno(stdout); 277130088Sminshall tin = fileno(stdin); 277230088Sminshall setconnmode(); 277330088Sminshall scc = 0; 277430088Sminshall tcc = 0; 277530088Sminshall FD_ZERO(&ibits); 277630088Sminshall FD_ZERO(&obits); 277730088Sminshall FD_ZERO(&xbits); 277830088Sminshall 277931124Sminshall NetNonblockingIO(net, 1); 278030088Sminshall 278130088Sminshall #if defined(TN3270) 278231478Sminshall if (noasynch == 0) { /* DBX can't handle! */ 278331478Sminshall NetSigIO(net, 1); 278431478Sminshall } 278531124Sminshall NetSetPgrp(net); 278630088Sminshall #endif /* defined(TN3270) */ 278730088Sminshall 278830088Sminshall 278931124Sminshall #if defined(SO_OOBINLINE) && !defined(MSDOS) 279031124Sminshall SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1); 279131124Sminshall #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */ 279231124Sminshall 279330320Sminshall # if !defined(TN3270) 279430088Sminshall if (telnetport) { 279530088Sminshall if (!hisopts[TELOPT_SGA]) { 279630088Sminshall willoption(TELOPT_SGA, 0); 279730088Sminshall } 279830088Sminshall if (!myopts[TELOPT_TTYPE]) { 279930088Sminshall dooption(TELOPT_TTYPE, 0); 280030088Sminshall } 280130088Sminshall } 280230320Sminshall # endif /* !defined(TN3270) */ 280330088Sminshall 280430088Sminshall # if !defined(TN3270) 280530088Sminshall for (;;) { 280631131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 280730088Sminshall setcommandmode(); 280830088Sminshall return; 280930088Sminshall } 281030088Sminshall } 281130088Sminshall # else /* !defined(TN3270) */ 281230088Sminshall for (;;) { 281330088Sminshall int schedValue; 281430088Sminshall 281531791Sminshall while (!In3270 && !shell_active) { 281631131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 281730088Sminshall setcommandmode(); 281830088Sminshall return; 281930088Sminshall } 282030088Sminshall } 282130088Sminshall 282230088Sminshall while ((schedValue = Scheduler(0)) != 0) { 282330088Sminshall if (schedValue == -1) { 282430088Sminshall setcommandmode(); 282530088Sminshall return; 282630088Sminshall } 282730088Sminshall } 282830088Sminshall /* If there is data waiting to go out to terminal, don't 282930088Sminshall * schedule any more data for the terminal. 283030088Sminshall */ 283130088Sminshall if (tfrontp-tbackp) { 283230088Sminshall schedValue = 1; 283330088Sminshall } else { 283431215Sminshall if (shell_active) { 283531215Sminshall if (shell_continue() == 0) { 283631215Sminshall ConnectScreen(); 283731215Sminshall } 283831791Sminshall } else if (In3270) { 283931215Sminshall schedValue = DoTerminalOutput(); 284031215Sminshall } 284130088Sminshall } 284231215Sminshall if (schedValue && (shell_active == 0)) { 284331131Sminshall if (Scheduler(SCHED_BLOCK) == -1) { 284430088Sminshall setcommandmode(); 284530088Sminshall return; 284630088Sminshall } 284730088Sminshall } 284830088Sminshall } 284930088Sminshall # endif /* !defined(TN3270) */ 285030088Sminshall } 285130088Sminshall 285230088Sminshall /* 285330088Sminshall * The following are data structures and routines for 285430088Sminshall * the "send" command. 285530088Sminshall * 285630088Sminshall */ 285730088Sminshall 285830088Sminshall struct sendlist { 285930088Sminshall char *name; /* How user refers to it (case independent) */ 286030088Sminshall int what; /* Character to be sent (<0 ==> special) */ 286130088Sminshall char *help; /* Help information (0 ==> no help) */ 286230088Sminshall #if defined(NOT43) 286330088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 286430088Sminshall #else /* defined(NOT43) */ 286530088Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 286630088Sminshall #endif /* defined(NOT43) */ 286730088Sminshall }; 286830088Sminshall 286930088Sminshall #define SENDQUESTION -1 287030088Sminshall #define SENDESCAPE -3 287130088Sminshall 287230088Sminshall static struct sendlist Sendlist[] = { 287330088Sminshall { "ao", AO, "Send Telnet Abort output" }, 287430088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 287530088Sminshall { "brk", BREAK, "Send Telnet Break" }, 287630088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 287730088Sminshall { "el", EL, "Send Telnet Erase Line" }, 287830088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 287930088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 288030088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 288130088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 288230088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 288330088Sminshall { "?", SENDQUESTION, "Display send options" }, 288430088Sminshall { 0 } 288530088Sminshall }; 288630088Sminshall 288730088Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 288830088Sminshall { "break", BREAK, 0 }, 288930088Sminshall 289030088Sminshall { "intp", IP, 0 }, 289130088Sminshall { "interrupt", IP, 0 }, 289230088Sminshall { "intr", IP, 0 }, 289330088Sminshall 289430088Sminshall { "help", SENDQUESTION, 0 }, 289530088Sminshall 289630088Sminshall { 0 } 289730088Sminshall }; 289830088Sminshall 289930088Sminshall static char ** 290030088Sminshall getnextsend(name) 290130088Sminshall char *name; 290230088Sminshall { 290330088Sminshall struct sendlist *c = (struct sendlist *) name; 290430088Sminshall 290530088Sminshall return (char **) (c+1); 290630088Sminshall } 290730088Sminshall 290830088Sminshall static struct sendlist * 290930088Sminshall getsend(name) 291030088Sminshall char *name; 291130088Sminshall { 291230088Sminshall struct sendlist *sl; 291330088Sminshall 291430088Sminshall if ((sl = (struct sendlist *) 291530088Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 291630088Sminshall return sl; 291730088Sminshall } else { 291830088Sminshall return (struct sendlist *) 291930088Sminshall genget(name, (char **) Sendlist2, getnextsend); 292030088Sminshall } 292130088Sminshall } 292230088Sminshall 292330088Sminshall static 292430088Sminshall sendcmd(argc, argv) 292530088Sminshall int argc; 292630088Sminshall char **argv; 292730088Sminshall { 292830088Sminshall int what; /* what we are sending this time */ 292930088Sminshall int count; /* how many bytes we are going to need to send */ 293030088Sminshall int i; 293130088Sminshall int question = 0; /* was at least one argument a question */ 293230088Sminshall struct sendlist *s; /* pointer to current command */ 293330088Sminshall 293430088Sminshall if (argc < 2) { 293530088Sminshall printf("need at least one argument for 'send' command\n"); 293630088Sminshall printf("'send ?' for help\n"); 293730088Sminshall return 0; 293830088Sminshall } 293930088Sminshall /* 294030088Sminshall * First, validate all the send arguments. 294130088Sminshall * In addition, we see how much space we are going to need, and 294230088Sminshall * whether or not we will be doing a "SYNCH" operation (which 294330088Sminshall * flushes the network queue). 294430088Sminshall */ 294530088Sminshall count = 0; 294630088Sminshall for (i = 1; i < argc; i++) { 294730088Sminshall s = getsend(argv[i]); 294830088Sminshall if (s == 0) { 294930088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 295030088Sminshall argv[i]); 295130088Sminshall return 0; 295230088Sminshall } else if (s == Ambiguous(struct sendlist *)) { 295330088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 295430088Sminshall argv[i]); 295530088Sminshall return 0; 295630088Sminshall } 295730088Sminshall switch (s->what) { 295830088Sminshall case SENDQUESTION: 295930088Sminshall break; 296030088Sminshall case SENDESCAPE: 296130088Sminshall count += 1; 296230088Sminshall break; 296330088Sminshall case SYNCH: 296430088Sminshall count += 2; 296530088Sminshall break; 296630088Sminshall default: 296730088Sminshall count += 2; 296830088Sminshall break; 296930088Sminshall } 297030088Sminshall } 297130088Sminshall /* Now, do we have enough room? */ 297230088Sminshall if (NETROOM() < count) { 297330088Sminshall printf("There is not enough room in the buffer TO the network\n"); 297430088Sminshall printf("to process your request. Nothing will be done.\n"); 297530088Sminshall printf("('send synch' will throw away most data in the network\n"); 297630088Sminshall printf("buffer, if this might help.)\n"); 297730088Sminshall return 0; 297830088Sminshall } 297930088Sminshall /* OK, they are all OK, now go through again and actually send */ 298030088Sminshall for (i = 1; i < argc; i++) { 298130088Sminshall if ((s = getsend(argv[i])) == 0) { 298230088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 298330088Sminshall quit(); 298430088Sminshall /*NOTREACHED*/ 298530088Sminshall } 298630088Sminshall if (s->routine) { 298730088Sminshall (*s->routine)(s); 298830088Sminshall } else { 298930088Sminshall switch (what = s->what) { 299030088Sminshall case SYNCH: 299130088Sminshall dosynch(); 299230088Sminshall break; 299330088Sminshall case SENDQUESTION: 299430088Sminshall for (s = Sendlist; s->name; s++) { 299530088Sminshall if (s->help) { 299630088Sminshall printf(s->name); 299730088Sminshall if (s->help) { 299830088Sminshall printf("\t%s", s->help); 299930088Sminshall } 300030088Sminshall printf("\n"); 300130088Sminshall } 300230088Sminshall } 300330088Sminshall question = 1; 300430088Sminshall break; 300530088Sminshall case SENDESCAPE: 300630088Sminshall NETADD(escape); 300730088Sminshall break; 300830088Sminshall default: 300930088Sminshall NET2ADD(IAC, what); 301030088Sminshall break; 301130088Sminshall } 301230088Sminshall } 301330088Sminshall } 301430088Sminshall return !question; 301530088Sminshall } 301630088Sminshall 301730088Sminshall /* 301830088Sminshall * The following are the routines and data structures referred 301930088Sminshall * to by the arguments to the "toggle" command. 302030088Sminshall */ 302130088Sminshall 302230088Sminshall static 302330088Sminshall lclchars() 302430088Sminshall { 302530088Sminshall donelclchars = 1; 302630088Sminshall return 1; 302730088Sminshall } 302830088Sminshall 302930088Sminshall static 303030088Sminshall togdebug() 303130088Sminshall { 303230088Sminshall #ifndef NOT43 303330088Sminshall if (net > 0 && 303431124Sminshall (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 303530088Sminshall perror("setsockopt (SO_DEBUG)"); 303630088Sminshall } 303730320Sminshall #else /* NOT43 */ 303830088Sminshall if (debug) { 303931124Sminshall if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 304030088Sminshall perror("setsockopt (SO_DEBUG)"); 304130088Sminshall } else 304230088Sminshall printf("Cannot turn off socket debugging\n"); 304330320Sminshall #endif /* NOT43 */ 304430088Sminshall return 1; 304530088Sminshall } 304630088Sminshall 304730088Sminshall 304831791Sminshall static int 304931791Sminshall togbinary() 305031791Sminshall { 305131791Sminshall donebinarytoggle = 1; 305230088Sminshall 305331791Sminshall if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */ 305431791Sminshall NET2ADD(IAC, DO); 305531791Sminshall NETADD(TELOPT_BINARY); 305631791Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0); 305731791Sminshall NET2ADD(IAC, WILL); 305831791Sminshall NETADD(TELOPT_BINARY); 305931791Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0); 306031791Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1; 306131791Sminshall printf("Negotiating binary mode with remote host.\n"); 306231791Sminshall } else { /* Turn off binary mode */ 306331791Sminshall NET2ADD(IAC, DONT); 306431791Sminshall NETADD(TELOPT_BINARY); 306531791Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0); 306631791Sminshall NET2ADD(IAC, DONT); 306731791Sminshall NETADD(TELOPT_BINARY); 306831791Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0); 306931791Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0; 307031791Sminshall printf("Negotiating network ascii mode with remote host.\n"); 307131791Sminshall } 307231791Sminshall return 1; 307331791Sminshall } 307431791Sminshall 307531791Sminshall 307631791Sminshall 307730088Sminshall extern int togglehelp(); 307830088Sminshall 307930088Sminshall struct togglelist { 308030088Sminshall char *name; /* name of toggle */ 308130088Sminshall char *help; /* help message */ 308230088Sminshall int (*handler)(); /* routine to do actual setting */ 308330088Sminshall int dohelp; /* should we display help information */ 308430088Sminshall int *variable; 308530088Sminshall char *actionexplanation; 308630088Sminshall }; 308730088Sminshall 308830088Sminshall static struct togglelist Togglelist[] = { 308930088Sminshall { "autoflush", 309030088Sminshall "toggle flushing of output when sending interrupt characters", 309130088Sminshall 0, 309230088Sminshall 1, 309330088Sminshall &autoflush, 309430088Sminshall "flush output when sending interrupt characters" }, 309530088Sminshall { "autosynch", 309630088Sminshall "toggle automatic sending of interrupt characters in urgent mode", 309730088Sminshall 0, 309830088Sminshall 1, 309930088Sminshall &autosynch, 310030088Sminshall "send interrupt characters in urgent mode" }, 310131791Sminshall { "binary", 310231791Sminshall "toggle sending and receiving of binary data", 310331791Sminshall togbinary, 310431791Sminshall 1, 310531791Sminshall 0, 310631791Sminshall "send and receive network data in binary mode" }, 310730088Sminshall { "crmod", 310830088Sminshall "toggle mapping of received carriage returns", 310930088Sminshall 0, 311030088Sminshall 1, 311130088Sminshall &crmod, 311230088Sminshall "map carriage return on output" }, 311330088Sminshall { "localchars", 311430088Sminshall "toggle local recognition of certain control characters", 311530088Sminshall lclchars, 311630088Sminshall 1, 311730088Sminshall &localchars, 311830088Sminshall "recognize certain control characters" }, 311930088Sminshall { " ", "", 0, 1 }, /* empty line */ 312030088Sminshall { "debug", 312130088Sminshall "(debugging) toggle debugging", 312230088Sminshall togdebug, 312330088Sminshall 1, 312430088Sminshall &debug, 312530088Sminshall "turn on socket level debugging" }, 312630088Sminshall { "netdata", 312730088Sminshall "(debugging) toggle printing of hexadecimal network data", 312830088Sminshall 0, 312930088Sminshall 1, 313030088Sminshall &netdata, 313130088Sminshall "print hexadecimal representation of network traffic" }, 313230088Sminshall { "options", 313330088Sminshall "(debugging) toggle viewing of options processing", 313430088Sminshall 0, 313530088Sminshall 1, 313630088Sminshall &showoptions, 313730088Sminshall "show option processing" }, 313830088Sminshall { " ", "", 0, 1 }, /* empty line */ 313930088Sminshall { "?", 314030088Sminshall "display help information", 314130088Sminshall togglehelp, 314230088Sminshall 1 }, 314330088Sminshall { "help", 314430088Sminshall "display help information", 314530088Sminshall togglehelp, 314630088Sminshall 0 }, 314730088Sminshall { 0 } 314830088Sminshall }; 314930088Sminshall 315030088Sminshall static 315130088Sminshall togglehelp() 315230088Sminshall { 315330088Sminshall struct togglelist *c; 315430088Sminshall 315530088Sminshall for (c = Togglelist; c->name; c++) { 315630088Sminshall if (c->dohelp) { 315730088Sminshall printf("%s\t%s\n", c->name, c->help); 315830088Sminshall } 315930088Sminshall } 316030088Sminshall return 0; 316130088Sminshall } 316230088Sminshall 316330088Sminshall static char ** 316430088Sminshall getnexttoggle(name) 316530088Sminshall char *name; 316630088Sminshall { 316730088Sminshall struct togglelist *c = (struct togglelist *) name; 316830088Sminshall 316930088Sminshall return (char **) (c+1); 317030088Sminshall } 317130088Sminshall 317230088Sminshall static struct togglelist * 317330088Sminshall gettoggle(name) 317430088Sminshall char *name; 317530088Sminshall { 317630088Sminshall return (struct togglelist *) 317730088Sminshall genget(name, (char **) Togglelist, getnexttoggle); 317830088Sminshall } 317930088Sminshall 318030088Sminshall static 318130088Sminshall toggle(argc, argv) 318230088Sminshall int argc; 318330088Sminshall char *argv[]; 318430088Sminshall { 318530088Sminshall int retval = 1; 318630088Sminshall char *name; 318730088Sminshall struct togglelist *c; 318830088Sminshall 318930088Sminshall if (argc < 2) { 319030088Sminshall fprintf(stderr, 319130088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 319230088Sminshall return 0; 319330088Sminshall } 319430088Sminshall argc--; 319530088Sminshall argv++; 319630088Sminshall while (argc--) { 319730088Sminshall name = *argv++; 319830088Sminshall c = gettoggle(name); 319930088Sminshall if (c == Ambiguous(struct togglelist *)) { 320030088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 320130088Sminshall name); 320230088Sminshall return 0; 320330088Sminshall } else if (c == 0) { 320430088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 320530088Sminshall name); 320630088Sminshall return 0; 320730088Sminshall } else { 320830088Sminshall if (c->variable) { 320930088Sminshall *c->variable = !*c->variable; /* invert it */ 321030088Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 321130088Sminshall c->actionexplanation); 321230088Sminshall } 321330088Sminshall if (c->handler) { 321430088Sminshall retval &= (*c->handler)(c); 321530088Sminshall } 321630088Sminshall } 321730088Sminshall } 321830088Sminshall return retval; 321930088Sminshall } 322030088Sminshall 322130088Sminshall /* 322230088Sminshall * The following perform the "set" command. 322330088Sminshall */ 322430088Sminshall 322530088Sminshall struct setlist { 322630088Sminshall char *name; /* name */ 322730088Sminshall char *help; /* help information */ 322830088Sminshall char *charp; /* where it is located at */ 322930088Sminshall }; 323030088Sminshall 323130088Sminshall static struct setlist Setlist[] = { 323230088Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 323330088Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 323430088Sminshall { " ", "" }, 323530088Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 323631124Sminshall #if defined(unix) 323730088Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 323830088Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 323930088Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 324030088Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 324130088Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 324230088Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 324331124Sminshall #endif /* defined(unix) */ 324431124Sminshall #if defined(MSDOS) 324531124Sminshall { "erase", "character to cause an Erase Character", &termEraseChar }, 324631124Sminshall { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 324731124Sminshall { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 324831124Sminshall { "kill", "character to cause an Erase Line", &termKillChar }, 324931124Sminshall { "quit", "character to cause a Break", &termQuitChar }, 325031124Sminshall { "eof", "character to cause an EOF ", &termEofChar }, 325131124Sminshall #endif /* defined(MSDOS) */ 325230088Sminshall { 0 } 325330088Sminshall }; 325430088Sminshall 325530088Sminshall static char ** 325630088Sminshall getnextset(name) 325730088Sminshall char *name; 325830088Sminshall { 325930088Sminshall struct setlist *c = (struct setlist *)name; 326030088Sminshall 326130088Sminshall return (char **) (c+1); 326230088Sminshall } 326330088Sminshall 326430088Sminshall static struct setlist * 326530088Sminshall getset(name) 326630088Sminshall char *name; 326730088Sminshall { 326830088Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 326930088Sminshall } 327030088Sminshall 327130088Sminshall static 327230088Sminshall setcmd(argc, argv) 327330088Sminshall int argc; 327430088Sminshall char *argv[]; 327530088Sminshall { 327630088Sminshall int value; 327730088Sminshall struct setlist *ct; 327830088Sminshall 327930088Sminshall /* XXX back we go... sigh */ 328030088Sminshall if (argc != 3) { 328130088Sminshall if ((argc == 2) && 328230088Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 328330088Sminshall for (ct = Setlist; ct->name; ct++) { 328430088Sminshall printf("%s\t%s\n", ct->name, ct->help); 328530088Sminshall } 328630088Sminshall printf("?\tdisplay help information\n"); 328730088Sminshall } else { 328830088Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 328930088Sminshall } 329030088Sminshall return 0; 329130088Sminshall } 329230088Sminshall 329330088Sminshall ct = getset(argv[1]); 329430088Sminshall if (ct == 0) { 329530088Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 329630088Sminshall argv[1]); 329730088Sminshall return 0; 329830088Sminshall } else if (ct == Ambiguous(struct setlist *)) { 329930088Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 330030088Sminshall argv[1]); 330130088Sminshall return 0; 330230088Sminshall } else { 330330088Sminshall if (strcmp("off", argv[2])) { 330430088Sminshall value = special(argv[2]); 330530088Sminshall } else { 330630088Sminshall value = -1; 330730088Sminshall } 330830088Sminshall *(ct->charp) = value; 330930088Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 331030088Sminshall } 331130088Sminshall return 1; 331230088Sminshall } 331330088Sminshall 331430088Sminshall /* 331530088Sminshall * The following are the data structures and routines for the 331630088Sminshall * 'mode' command. 331730088Sminshall */ 331830088Sminshall 331930088Sminshall static 332030088Sminshall dolinemode() 332130088Sminshall { 332230088Sminshall if (hisopts[TELOPT_SGA]) { 332330088Sminshall wontoption(TELOPT_SGA, 0); 332430088Sminshall } 332530088Sminshall if (hisopts[TELOPT_ECHO]) { 332630088Sminshall wontoption(TELOPT_ECHO, 0); 332730088Sminshall } 332830088Sminshall return 1; 332930088Sminshall } 333030088Sminshall 333130088Sminshall static 333230088Sminshall docharmode() 333330088Sminshall { 333430088Sminshall if (!hisopts[TELOPT_SGA]) { 333530088Sminshall willoption(TELOPT_SGA, 0); 333630088Sminshall } 333730088Sminshall if (!hisopts[TELOPT_ECHO]) { 333830088Sminshall willoption(TELOPT_ECHO, 0); 333930088Sminshall } 334030088Sminshall return 1; 334130088Sminshall } 334230088Sminshall 334330088Sminshall static struct cmd Modelist[] = { 334430088Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 334530088Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 334630088Sminshall { 0 }, 334730088Sminshall }; 334830088Sminshall 334930088Sminshall static char ** 335030088Sminshall getnextmode(name) 335130088Sminshall char *name; 335230088Sminshall { 335330088Sminshall struct cmd *c = (struct cmd *) name; 335430088Sminshall 335530088Sminshall return (char **) (c+1); 335630088Sminshall } 335730088Sminshall 335830088Sminshall static struct cmd * 335930088Sminshall getmodecmd(name) 336030088Sminshall char *name; 336130088Sminshall { 336230088Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 336330088Sminshall } 336430088Sminshall 336530088Sminshall static 336630088Sminshall modecmd(argc, argv) 336730088Sminshall int argc; 336830088Sminshall char *argv[]; 336930088Sminshall { 337030088Sminshall struct cmd *mt; 337130088Sminshall 337230088Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 337330088Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 337430088Sminshall for (mt = Modelist; mt->name; mt++) { 337530088Sminshall printf("%s\t%s\n", mt->name, mt->help); 337630088Sminshall } 337730088Sminshall return 0; 337830088Sminshall } 337930088Sminshall mt = getmodecmd(argv[1]); 338030088Sminshall if (mt == 0) { 338130088Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 338230088Sminshall return 0; 338330088Sminshall } else if (mt == Ambiguous(struct cmd *)) { 338430088Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 338530088Sminshall return 0; 338630088Sminshall } else { 338730088Sminshall (*mt->handler)(); 338830088Sminshall } 338930088Sminshall return 1; 339030088Sminshall } 339130088Sminshall 339230088Sminshall /* 339330088Sminshall * The following data structures and routines implement the 339430088Sminshall * "display" command. 339530088Sminshall */ 339630088Sminshall 339730088Sminshall static 339830088Sminshall display(argc, argv) 339930088Sminshall int argc; 340030088Sminshall char *argv[]; 340130088Sminshall { 340230088Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 340330088Sminshall if (*tl->variable) { \ 340430088Sminshall printf("will"); \ 340530088Sminshall } else { \ 340630088Sminshall printf("won't"); \ 340730088Sminshall } \ 340830088Sminshall printf(" %s.\n", tl->actionexplanation); \ 340930088Sminshall } 341030088Sminshall 341130088Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 341230088Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 341330088Sminshall } 341430088Sminshall 341530088Sminshall struct togglelist *tl; 341630088Sminshall struct setlist *sl; 341730088Sminshall 341830088Sminshall if (argc == 1) { 341930088Sminshall for (tl = Togglelist; tl->name; tl++) { 342030088Sminshall dotog(tl); 342130088Sminshall } 342230088Sminshall printf("\n"); 342330088Sminshall for (sl = Setlist; sl->name; sl++) { 342430088Sminshall doset(sl); 342530088Sminshall } 342630088Sminshall } else { 342730088Sminshall int i; 342830088Sminshall 342930088Sminshall for (i = 1; i < argc; i++) { 343030088Sminshall sl = getset(argv[i]); 343130088Sminshall tl = gettoggle(argv[i]); 343230088Sminshall if ((sl == Ambiguous(struct setlist *)) || 343330088Sminshall (tl == Ambiguous(struct togglelist *))) { 343430088Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 343530088Sminshall return 0; 343630088Sminshall } else if (!sl && !tl) { 343730088Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 343830088Sminshall return 0; 343930088Sminshall } else { 344030088Sminshall if (tl) { 344130088Sminshall dotog(tl); 344230088Sminshall } 344330088Sminshall if (sl) { 344430088Sminshall doset(sl); 344530088Sminshall } 344630088Sminshall } 344730088Sminshall } 344830088Sminshall } 344930088Sminshall return 1; 345030088Sminshall #undef doset 345130088Sminshall #undef dotog 345230088Sminshall } 345330088Sminshall 345430088Sminshall /* 345530088Sminshall * The following are the data structures, and many of the routines, 345630088Sminshall * relating to command processing. 345730088Sminshall */ 345830088Sminshall 345930088Sminshall /* 346030088Sminshall * Set the escape character. 346130088Sminshall */ 346230088Sminshall static 346330088Sminshall setescape(argc, argv) 346430088Sminshall int argc; 346530088Sminshall char *argv[]; 346630088Sminshall { 346730088Sminshall register char *arg; 346830088Sminshall char buf[50]; 346930088Sminshall 347030088Sminshall printf( 347130088Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 347230088Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 347330088Sminshall if (argc > 2) 347430088Sminshall arg = argv[1]; 347530088Sminshall else { 347630088Sminshall printf("new escape character: "); 347730088Sminshall gets(buf); 347830088Sminshall arg = buf; 347930088Sminshall } 348030088Sminshall if (arg[0] != '\0') 348130088Sminshall escape = arg[0]; 348230088Sminshall if (!In3270) { 348330088Sminshall printf("Escape character is '%s'.\n", control(escape)); 348430088Sminshall } 348530088Sminshall fflush(stdout); 348630088Sminshall return 1; 348730088Sminshall } 348830088Sminshall 348930088Sminshall /*VARARGS*/ 349030088Sminshall static 349130088Sminshall togcrmod() 349230088Sminshall { 349330088Sminshall crmod = !crmod; 349430088Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 349530088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 349630088Sminshall fflush(stdout); 349730088Sminshall return 1; 349830088Sminshall } 349930088Sminshall 350030088Sminshall /*VARARGS*/ 350130088Sminshall suspend() 350230088Sminshall { 350330088Sminshall setcommandmode(); 350430088Sminshall #if defined(unix) 350530088Sminshall kill(0, SIGTSTP); 350631215Sminshall #endif /* defined(unix) */ 350731124Sminshall /* reget parameters in case they were changed */ 350831124Sminshall TerminalSaveState(); 350931215Sminshall setconnmode(); 351030088Sminshall return 1; 351130088Sminshall } 351230088Sminshall 351330088Sminshall /*VARARGS*/ 351430088Sminshall static 351530326Sminshall bye(argc, argv) 351630326Sminshall int argc; /* Number of arguments */ 351730326Sminshall char *argv[]; /* arguments */ 351830088Sminshall { 351930088Sminshall if (connected) { 352030088Sminshall shutdown(net, 2); 352130088Sminshall printf("Connection closed.\n"); 352231131Sminshall NetClose(net); 352330088Sminshall connected = 0; 352430088Sminshall /* reset options */ 352530326Sminshall tninit(); 352630088Sminshall #if defined(TN3270) 352730326Sminshall SetIn3270(); /* Get out of 3270 mode */ 352830088Sminshall #endif /* defined(TN3270) */ 352930088Sminshall } 353030326Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 353130326Sminshall longjmp(toplevel, 1); 353230326Sminshall /* NOTREACHED */ 353330326Sminshall } 353430326Sminshall return 1; /* Keep lint, etc., happy */ 353530088Sminshall } 353630088Sminshall 353730088Sminshall /*VARARGS*/ 353830088Sminshall quit() 353930088Sminshall { 354030326Sminshall (void) call(bye, "bye", "fromquit", 0); 354130088Sminshall Exit(0); 354230088Sminshall /*NOTREACHED*/ 354330088Sminshall return 1; /* just to keep lint happy */ 354430088Sminshall } 354530088Sminshall 354630088Sminshall /* 354730088Sminshall * Print status about the connection. 354830088Sminshall */ 354930088Sminshall static 355030088Sminshall status(argc, argv) 355130088Sminshall int argc; 355230088Sminshall char *argv[]; 355330088Sminshall { 355430088Sminshall if (connected) { 355530088Sminshall printf("Connected to %s.\n", hostname); 355630088Sminshall if (argc < 2) { 355730088Sminshall printf("Operating in %s.\n", 355830088Sminshall modelist[getconnmode()].modedescriptions); 355930088Sminshall if (localchars) { 356030088Sminshall printf("Catching signals locally.\n"); 356130088Sminshall } 356230088Sminshall } 356330088Sminshall } else { 356430088Sminshall printf("No connection.\n"); 356530088Sminshall } 356630088Sminshall # if !defined(TN3270) 356730088Sminshall printf("Escape character is '%s'.\n", control(escape)); 356830088Sminshall fflush(stdout); 356930088Sminshall # else /* !defined(TN3270) */ 357030088Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 357130088Sminshall printf("Escape character is '%s'.\n", control(escape)); 357230088Sminshall } 357330088Sminshall # if defined(unix) 357430088Sminshall if (In3270 && transcom) { 357530088Sminshall printf("Transparent mode command is '%s'.\n", transcom); 357630088Sminshall } 357730088Sminshall # endif /* defined(unix) */ 357830088Sminshall fflush(stdout); 357930088Sminshall if (In3270) { 358030088Sminshall return 0; 358130088Sminshall } 358230088Sminshall # endif /* defined(TN3270) */ 358330088Sminshall return 1; 358430088Sminshall } 358530088Sminshall 358630088Sminshall #if defined(TN3270) && defined(unix) 358730088Sminshall static 358830088Sminshall settranscom(argc, argv) 358930088Sminshall int argc; 359030088Sminshall char *argv[]; 359130088Sminshall { 359230088Sminshall int i, len = 0; 359330088Sminshall char *strcpy(), *strcat(); 359430088Sminshall 359530088Sminshall if (argc == 1 && transcom) { 359630088Sminshall transcom = 0; 359730088Sminshall } 359830088Sminshall if (argc == 1) { 359930088Sminshall return; 360030088Sminshall } 360130088Sminshall for (i = 1; i < argc; ++i) { 360230088Sminshall len += 1 + strlen(argv[1]); 360330088Sminshall } 360430088Sminshall transcom = tline; 360530088Sminshall (void) strcpy(transcom, argv[1]); 360630088Sminshall for (i = 2; i < argc; ++i) { 360730088Sminshall (void) strcat(transcom, " "); 360830088Sminshall (void) strcat(transcom, argv[i]); 360930088Sminshall } 361030088Sminshall } 361130088Sminshall #endif /* defined(TN3270) && defined(unix) */ 361230088Sminshall 361330088Sminshall 361431169Sminshall 361530088Sminshall static 361630088Sminshall tn(argc, argv) 361730088Sminshall int argc; 361830088Sminshall char *argv[]; 361930088Sminshall { 362030088Sminshall register struct hostent *host = 0; 362131131Sminshall #if defined(MSDOS) 362230088Sminshall char *cp; 362331131Sminshall #endif /* defined(MSDOS) */ 362430088Sminshall 362530088Sminshall if (connected) { 362630088Sminshall printf("?Already connected to %s\n", hostname); 362730088Sminshall return 0; 362830088Sminshall } 362930088Sminshall if (argc < 2) { 363030088Sminshall (void) strcpy(line, "Connect "); 363130088Sminshall printf("(to) "); 363230088Sminshall gets(&line[strlen(line)]); 363330088Sminshall makeargv(); 363430088Sminshall argc = margc; 363530088Sminshall argv = margv; 363630088Sminshall } 363731793Sminshall if ((argc < 2) || (argc > 3)) { 363830088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 363930088Sminshall return 0; 364030088Sminshall } 364131131Sminshall #if defined(MSDOS) 364230088Sminshall for (cp = argv[1]; *cp; cp++) { 364330088Sminshall if (isupper(*cp)) { 364430088Sminshall *cp = tolower(*cp); 364530088Sminshall } 364630088Sminshall } 364731131Sminshall #endif /* defined(MSDOS) */ 364830088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 364930088Sminshall if (sin.sin_addr.s_addr != -1) { 365030088Sminshall sin.sin_family = AF_INET; 365130088Sminshall (void) strcpy(hnamebuf, argv[1]); 365230088Sminshall hostname = hnamebuf; 365330088Sminshall } else { 365430088Sminshall host = gethostbyname(argv[1]); 365530088Sminshall if (host) { 365630088Sminshall sin.sin_family = host->h_addrtype; 365730088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 365831131Sminshall memcpy((caddr_t)&sin.sin_addr, 365931131Sminshall host->h_addr_list[0], host->h_length); 366030088Sminshall #else /* defined(h_addr) */ 366131131Sminshall memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 366230088Sminshall #endif /* defined(h_addr) */ 366330088Sminshall hostname = host->h_name; 366430088Sminshall } else { 366530088Sminshall printf("%s: unknown host\n", argv[1]); 366630088Sminshall return 0; 366730088Sminshall } 366830088Sminshall } 366930088Sminshall sin.sin_port = sp->s_port; 367030088Sminshall if (argc == 3) { 367130088Sminshall sin.sin_port = atoi(argv[2]); 367230088Sminshall if (sin.sin_port == 0) { 367330088Sminshall sp = getservbyname(argv[2], "tcp"); 367430088Sminshall if (sp) 367530088Sminshall sin.sin_port = sp->s_port; 367630088Sminshall else { 367730088Sminshall printf("%s: bad port number\n", argv[2]); 367830088Sminshall return 0; 367930088Sminshall } 368030088Sminshall } else { 368130088Sminshall sin.sin_port = atoi(argv[2]); 368230088Sminshall sin.sin_port = htons(sin.sin_port); 368330088Sminshall } 368430088Sminshall telnetport = 0; 368530088Sminshall } else { 368630088Sminshall telnetport = 1; 368730088Sminshall } 368830088Sminshall #if defined(unix) 368930088Sminshall signal(SIGINT, intr); 369030088Sminshall signal(SIGQUIT, intr2); 369130088Sminshall signal(SIGPIPE, deadpeer); 369230088Sminshall #endif /* defined(unix) */ 369330088Sminshall printf("Trying...\n"); 369430088Sminshall do { 369530088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 369630088Sminshall if (net < 0) { 369730088Sminshall perror("telnet: socket"); 369830088Sminshall return 0; 369930088Sminshall } 370031124Sminshall if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 370130088Sminshall perror("setsockopt (SO_DEBUG)"); 370231124Sminshall } 370330088Sminshall 370430088Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 370530088Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 370630088Sminshall if (host && host->h_addr_list[1]) { 370730088Sminshall int oerrno = errno; 370830088Sminshall 370930088Sminshall fprintf(stderr, "telnet: connect to address %s: ", 371030088Sminshall inet_ntoa(sin.sin_addr)); 371130088Sminshall errno = oerrno; 371230088Sminshall perror((char *)0); 371330088Sminshall host->h_addr_list++; 371431131Sminshall memcpy((caddr_t)&sin.sin_addr, 371531131Sminshall host->h_addr_list[0], host->h_length); 371630088Sminshall fprintf(stderr, "Trying %s...\n", 371730088Sminshall inet_ntoa(sin.sin_addr)); 371831131Sminshall (void) NetClose(net); 371930088Sminshall continue; 372030088Sminshall } 372130088Sminshall #endif /* defined(h_addr) */ 372230088Sminshall perror("telnet: Unable to connect to remote host"); 372330088Sminshall #if defined(unix) 372430088Sminshall signal(SIGINT, SIG_DFL); 372530088Sminshall signal(SIGQUIT, SIG_DFL); 372630320Sminshall #endif /* defined(unix) */ 372730088Sminshall return 0; 372830088Sminshall } 372930088Sminshall connected++; 373030088Sminshall } while (connected == 0); 373130088Sminshall call(status, "status", "notmuch", 0); 373230088Sminshall if (setjmp(peerdied) == 0) 373330088Sminshall telnet(); 373431131Sminshall NetClose(net); 373530088Sminshall ExitString(stderr, "Connection closed by foreign host.\n",1); 373630088Sminshall /*NOTREACHED*/ 373730088Sminshall } 373830088Sminshall 373930088Sminshall 374030088Sminshall #define HELPINDENT (sizeof ("connect")) 374130088Sminshall 374230088Sminshall static char 374330088Sminshall openhelp[] = "connect to a site", 374430088Sminshall closehelp[] = "close current connection", 374530088Sminshall quithelp[] = "exit telnet", 374630088Sminshall statushelp[] = "print status information", 374730088Sminshall helphelp[] = "print help information", 374830088Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 374930088Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 375030088Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 375130088Sminshall displayhelp[] = "display operating parameters", 375230088Sminshall #if defined(TN3270) && defined(unix) 375330088Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 375430088Sminshall #endif /* defined(TN3270) && defined(unix) */ 375531169Sminshall #if defined(unix) 375631169Sminshall zhelp[] = "suspend telnet", 375731169Sminshall #endif /* defined(unix */ 375831478Sminshall #if defined(TN3270) 375931169Sminshall shellhelp[] = "invoke a subshell", 376031478Sminshall #endif /* defined(TN3270) */ 376130088Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 376230088Sminshall 376331169Sminshall extern int help(), shell(); 376430088Sminshall 376530088Sminshall static struct cmd cmdtab[] = { 376630088Sminshall { "close", closehelp, bye, 1, 1 }, 376730088Sminshall { "display", displayhelp, display, 1, 0 }, 376830088Sminshall { "mode", modehelp, modecmd, 1, 1 }, 376930088Sminshall { "open", openhelp, tn, 1, 0 }, 377030088Sminshall { "quit", quithelp, quit, 1, 0 }, 377130088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 377230088Sminshall { "set", sethelp, setcmd, 1, 0 }, 377330088Sminshall { "status", statushelp, status, 1, 0 }, 377430088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 377530088Sminshall #if defined(TN3270) && defined(unix) 377630088Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 377730088Sminshall #endif /* defined(TN3270) && defined(unix) */ 377831169Sminshall #if defined(unix) 377930088Sminshall { "z", zhelp, suspend, 1, 0 }, 378031169Sminshall #endif /* defined(unix) */ 378131478Sminshall #if defined(TN3270) 378231478Sminshall { "!", shellhelp, shell, 1, 1 }, 378331478Sminshall #endif /* defined(TN3270) */ 378430088Sminshall { "?", helphelp, help, 1, 0 }, 378530088Sminshall 0 378630088Sminshall }; 378730088Sminshall 378830088Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 378930088Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 379030088Sminshall 379130088Sminshall static struct cmd cmdtab2[] = { 379230088Sminshall { "help", helphelp, help, 0, 0 }, 379330088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 379430088Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 379530088Sminshall 0 379630088Sminshall }; 379730088Sminshall 379830088Sminshall /* 379930088Sminshall * Call routine with argc, argv set from args (terminated by 0). 380030088Sminshall * VARARGS2 380130088Sminshall */ 380230088Sminshall static 380330088Sminshall call(routine, args) 380430088Sminshall int (*routine)(); 380530088Sminshall char *args; 380630088Sminshall { 380730088Sminshall register char **argp; 380830088Sminshall register int argc; 380930088Sminshall 381030088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 381130088Sminshall ; 381230088Sminshall return (*routine)(argc, &args); 381330088Sminshall } 381430088Sminshall 381530088Sminshall static char ** 381630088Sminshall getnextcmd(name) 381730088Sminshall char *name; 381830088Sminshall { 381930088Sminshall struct cmd *c = (struct cmd *) name; 382030088Sminshall 382130088Sminshall return (char **) (c+1); 382230088Sminshall } 382330088Sminshall 382430088Sminshall static struct cmd * 382530088Sminshall getcmd(name) 382630088Sminshall char *name; 382730088Sminshall { 382830088Sminshall struct cmd *cm; 382930088Sminshall 383030088Sminshall if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 383130088Sminshall return cm; 383230088Sminshall } else { 383330088Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 383430088Sminshall } 383530088Sminshall } 383630088Sminshall 383730088Sminshall void 383830088Sminshall command(top) 383930088Sminshall int top; 384030088Sminshall { 384131478Sminshall register struct cmd *c; 384230088Sminshall 384331478Sminshall setcommandmode(); 384431478Sminshall if (!top) { 384531478Sminshall putchar('\n'); 384631478Sminshall } else { 384730088Sminshall #if defined(unix) 384831478Sminshall signal(SIGINT, SIG_DFL); 384931478Sminshall signal(SIGQUIT, SIG_DFL); 385030088Sminshall #endif /* defined(unix) */ 385131478Sminshall } 385231478Sminshall for (;;) { 385331478Sminshall printf("%s> ", prompt); 385431478Sminshall if (gets(line) == NULL) { 385531478Sminshall if (feof(stdin) || ferror(stdin)) 385631478Sminshall quit(); 385731478Sminshall break; 385830088Sminshall } 385931478Sminshall if (line[0] == 0) 386031478Sminshall break; 386131478Sminshall makeargv(); 386231478Sminshall c = getcmd(margv[0]); 386331478Sminshall if (c == Ambiguous(struct cmd *)) { 386431478Sminshall printf("?Ambiguous command\n"); 386531478Sminshall continue; 386630088Sminshall } 386731478Sminshall if (c == 0) { 386831478Sminshall printf("?Invalid command\n"); 386931478Sminshall continue; 387030088Sminshall } 387131478Sminshall if (c->needconnect && !connected) { 387231478Sminshall printf("?Need to be connected first.\n"); 387331478Sminshall continue; 387431478Sminshall } 387531478Sminshall if ((*c->handler)(margc, margv)) { 387631478Sminshall break; 387731478Sminshall } 387831478Sminshall } 387931478Sminshall if (!top) { 388031478Sminshall if (!connected) { 388131478Sminshall longjmp(toplevel, 1); 388231478Sminshall /*NOTREACHED*/ 388331478Sminshall } 388431478Sminshall if (shell_active == 0) { 388531478Sminshall setconnmode(); 388631478Sminshall } 388731478Sminshall } 388830088Sminshall } 388930088Sminshall 389030088Sminshall /* 389130088Sminshall * Help command. 389230088Sminshall */ 389330088Sminshall static 389430088Sminshall help(argc, argv) 389530088Sminshall int argc; 389630088Sminshall char *argv[]; 389730088Sminshall { 389830088Sminshall register struct cmd *c; 389930088Sminshall 390030088Sminshall if (argc == 1) { 390130088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 390230088Sminshall for (c = cmdtab; c->name; c++) 390330088Sminshall if (c->dohelp) { 390430088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 390530088Sminshall c->help); 390630088Sminshall } 390730088Sminshall return 0; 390830088Sminshall } 390930088Sminshall while (--argc > 0) { 391030088Sminshall register char *arg; 391130088Sminshall arg = *++argv; 391230088Sminshall c = getcmd(arg); 391330088Sminshall if (c == Ambiguous(struct cmd *)) 391430088Sminshall printf("?Ambiguous help command %s\n", arg); 391530088Sminshall else if (c == (struct cmd *)0) 391630088Sminshall printf("?Invalid help command %s\n", arg); 391730088Sminshall else 391830088Sminshall printf("%s\n", c->help); 391930088Sminshall } 392030088Sminshall return 0; 392130088Sminshall } 392230088Sminshall 392330088Sminshall /* 392430088Sminshall * main. Parse arguments, invoke the protocol or command parser. 392530088Sminshall */ 392630088Sminshall 392730088Sminshall 392830088Sminshall void 392930088Sminshall main(argc, argv) 393030088Sminshall int argc; 393130088Sminshall char *argv[]; 393230088Sminshall { 393330326Sminshall tninit(); /* Clear out things */ 393430326Sminshall 393530088Sminshall NetTrace = stdout; 393631124Sminshall TerminalSaveState(); 393731124Sminshall autoflush = TerminalAutoFlush(); 393831124Sminshall 393930088Sminshall prompt = argv[0]; 394031478Sminshall while ((argc > 1) && (argv[1][0] == '-')) { 394131478Sminshall if (!strcmp(argv[1], "-d")) { 394231478Sminshall debug = 1; 394331478Sminshall } else if (!strcmp(argv[1], "-n")) { 394431510Sminshall if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */ 394531510Sminshall NetTrace = fopen(argv[2], "w"); 394631478Sminshall argv++; 394731478Sminshall argc--; 394831478Sminshall if (NetTrace == NULL) { 394931478Sminshall NetTrace = stdout; 395031478Sminshall } 395130088Sminshall } 395231478Sminshall } else { 395331478Sminshall #if defined(TN3270) && defined(unix) 395431478Sminshall if (!strcmp(argv[1], "-t")) { 395531978Sminshall if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */ 395631478Sminshall transcom = tline; 395731478Sminshall (void) strcpy(transcom, argv[1]); 395831478Sminshall argv++; 395931478Sminshall argc--; 396031478Sminshall } 396131478Sminshall } else if (!strcmp(argv[1], "-noasynch")) { 396231478Sminshall noasynch = 1; 396331478Sminshall } else 396431478Sminshall #endif /* defined(TN3270) && defined(unix) */ 396531478Sminshall if (argv[1][1] != '\0') { 396631478Sminshall fprintf(stderr, "Unknown option *%s*.\n", argv[1]); 396731478Sminshall } 396830088Sminshall } 396931478Sminshall argc--; 397030088Sminshall argv++; 397130088Sminshall } 397230088Sminshall if (argc != 1) { 397330088Sminshall if (setjmp(toplevel) != 0) 397430088Sminshall Exit(0); 397530088Sminshall tn(argc, argv); 397630088Sminshall } 397730088Sminshall setjmp(toplevel); 397831215Sminshall for (;;) { 397931215Sminshall #if !defined(TN3270) 398030088Sminshall command(1); 398131215Sminshall #else /* !defined(TN3270) */ 398231215Sminshall if (!shell_active) { 398331215Sminshall command(1); 398431215Sminshall } else { 398531478Sminshall #if defined(TN3270) 398631215Sminshall shell_continue(); 398731478Sminshall #endif /* defined(TN3270) */ 398831215Sminshall } 398931215Sminshall #endif /* !defined(TN3270) */ 399031215Sminshall } 399130088Sminshall } 3992