121580Sdist /* 221580Sdist * Copyright (c) 1983 Regents of the University of California. 321580Sdist * All rights reserved. The Berkeley software License Agreement 421580Sdist * specifies the terms and conditions for redistribution. 521580Sdist */ 621580Sdist 711758Ssam #ifndef lint 821580Sdist char copyright[] = 921580Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021580Sdist All rights reserved.\n"; 1121580Sdist #endif not lint 1211758Ssam 1321580Sdist #ifndef lint 14*27186Sminshall static char sccsid[] = "@(#)telnet.c 5.10 (Berkeley) 04/19/86"; 1521580Sdist #endif not lint 1621580Sdist 176000Sroot /* 186000Sroot * User telnet program. 196000Sroot */ 209217Ssam #include <sys/types.h> 219217Ssam #include <sys/socket.h> 229972Ssam #include <sys/ioctl.h> 2327178Sminshall #include <sys/time.h> 249217Ssam 259217Ssam #include <netinet/in.h> 269217Ssam 2712212Ssam #define TELOPTS 2812212Ssam #include <arpa/telnet.h> 29*27186Sminshall #include <arpa/inet.h> 3012212Ssam 316000Sroot #include <stdio.h> 326000Sroot #include <ctype.h> 336000Sroot #include <errno.h> 346000Sroot #include <signal.h> 356000Sroot #include <setjmp.h> 368345Ssam #include <netdb.h> 37*27186Sminshall #include <strings.h> 389217Ssam 3927178Sminshall 4027178Sminshall 4127178Sminshall /* 4227178Sminshall * The following is defined just in case someone should want to run 4327178Sminshall * this telnet on a 4.2 system. 4427178Sminshall * 4527178Sminshall * This has never been tested, so good luck... 4627178Sminshall */ 4727178Sminshall #ifndef FD_SETSIZE 4827178Sminshall 4927178Sminshall typedef long fd_set; 5027178Sminshall 5127178Sminshall #define FD_SET(n, p) (*(p) |= (1<<(n))) 5227178Sminshall #define FD_CLR(n, p) (*(p) &= ~(1<<(n))) 5327178Sminshall #define FD_ISSET(n, p) (*(p) & (1<<(n))) 5427178Sminshall #define FD_ZERO(p) (*(p) = 0) 5527178Sminshall 5627178Sminshall #endif 5727178Sminshall 58*27186Sminshall #define strip(x) ((x)&0x3f) 596000Sroot 606000Sroot char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 61*27186Sminshall #define TTYADD(c) { if (!SYNCHing) { *tfrontp++ = c; } } 6227088Sminshall 638378Ssam char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 6427088Sminshall #define NETADD(c) { *nfrontp++ = c; } 6527088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 6627088Sminshall #define NETLOC() (nfrontp) 6727088Sminshall char *neturg = 0; /* one past last byte of urgent data */ 686000Sroot 696000Sroot char hisopts[256]; 706000Sroot char myopts[256]; 716000Sroot 726000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 736000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 746000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 756000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 766000Sroot 7727088Sminshall struct cmd { 7827088Sminshall char *name; /* command name */ 7927088Sminshall char *help; /* help string */ 8027088Sminshall int (*handler)(); /* routine which executes command */ 8127088Sminshall int dohelp; /* Should we give general help information? */ 8227088Sminshall int needconnect; /* Do we need to be connected to execute? */ 8327088Sminshall }; 8427088Sminshall 856000Sroot int connected; 866000Sroot int net; 8727088Sminshall int tout; 889972Ssam int showoptions = 0; 8910339Ssam int debug = 0; 909972Ssam int crmod = 0; 9127088Sminshall int netdata = 0; 9227021Sminshall static FILE *NetTrace; 9325289Skarels int telnetport = 1; 9427088Sminshall 9527088Sminshall 966000Sroot char *prompt; 979972Ssam char escape = CTRL(]); 9827110Sminshall char echoc = CTRL(E); 996000Sroot 100*27186Sminshall int SYNCHing = 0; /* we are in TELNET SYNCH mode */ 101*27186Sminshall int flushout = 0; /* flush output */ 102*27186Sminshall int autosynch = 0; /* send interrupt characters with SYNCH? */ 103*27186Sminshall int localsigs = 0; /* we recognize interrupt/quit */ 104*27186Sminshall int donelclsigs = 0; /* the user has set "localsigs" */ 105*27186Sminshall int doechocharrecognition = 1; /* in line mode recognize echo toggle */ 106*27186Sminshall int dontlecho = 0; /* do we suppress local echoing right now? */ 107*27186Sminshall 1086000Sroot char line[200]; 1096000Sroot int margc; 1106000Sroot char *margv[20]; 1116000Sroot 1126000Sroot jmp_buf toplevel; 1136000Sroot jmp_buf peerdied; 1146000Sroot 1156000Sroot extern int errno; 1166000Sroot 1176000Sroot 1189972Ssam struct sockaddr_in sin; 1196000Sroot 1206000Sroot struct cmd *getcmd(); 1218345Ssam struct servent *sp; 1226000Sroot 12327110Sminshall struct tchars otc, ntc; 12413076Ssam struct ltchars oltc; 12527110Sminshall struct sgttyb ottyb, nttyb; 12627110Sminshall int globalmode = 0; 12727110Sminshall int flushline = 1; 1288378Ssam 12927110Sminshall char *hostname; 13027110Sminshall char hnamebuf[32]; 13127110Sminshall 13227110Sminshall /* 13327110Sminshall * The following are some clocks used to decide how to interpret 13427178Sminshall * the relationship between various variables. 13527110Sminshall */ 13627110Sminshall 13727110Sminshall struct { 13827110Sminshall int 13927110Sminshall system, /* what the current time is */ 14027110Sminshall echotoggle, /* last time user entered echo character */ 14127178Sminshall modenegotiated, /* last time operating mode negotiated */ 14227178Sminshall didnetreceive, /* last time we read data from network */ 14327178Sminshall gotDM; /* when did we last see a data mark */ 144*27186Sminshall } clocks; 14527110Sminshall 146*27186Sminshall #define settimer(x) clocks.x = clocks.system++ 14727110Sminshall 14827110Sminshall /* 14927110Sminshall * Various utility routines. 15027110Sminshall */ 1516000Sroot 152*27186Sminshall char *ambiguous; /* special return value */ 153*27186Sminshall #define Ambiguous(t) ((t)&ambiguous) 154*27186Sminshall 155*27186Sminshall 15627088Sminshall char ** 15727088Sminshall genget(name, table, next) 15827088Sminshall char *name; /* name to match */ 15927088Sminshall char **table; /* name entry in table */ 16027088Sminshall char **(*next)(); /* routine to return next entry in table */ 1616000Sroot { 16227088Sminshall register char *p, *q; 16327088Sminshall register char **c, **found; 16427088Sminshall register int nmatches, longest; 1656000Sroot 16627088Sminshall longest = 0; 16727088Sminshall nmatches = 0; 16827088Sminshall found = 0; 16927088Sminshall for (c = table; p = *c; c = (*next)(c)) { 17027088Sminshall for (q = name; *q == *p++; q++) 17127088Sminshall if (*q == 0) /* exact match? */ 17227088Sminshall return (c); 17327088Sminshall if (!*q) { /* the name was a prefix */ 17427088Sminshall if (q - name > longest) { 17527088Sminshall longest = q - name; 17627088Sminshall nmatches = 1; 17727088Sminshall found = c; 17827088Sminshall } else if (q - name == longest) 17927088Sminshall nmatches++; 1808377Ssam } 1816000Sroot } 18227088Sminshall if (nmatches > 1) 183*27186Sminshall return Ambiguous(char **); 18427088Sminshall return (found); 1856000Sroot } 1866000Sroot 18727110Sminshall /* 18827110Sminshall * Make a character string into a number. 18927110Sminshall * 190*27186Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 19127110Sminshall */ 1926000Sroot 19327110Sminshall special(s) 19427110Sminshall register char *s; 19527110Sminshall { 19627110Sminshall register char c; 19727110Sminshall char b; 19827110Sminshall 19927110Sminshall switch (*s) { 20027110Sminshall case '^': 20127110Sminshall b = *++s; 20227110Sminshall if (b == '?') { 20327110Sminshall c = b | 0x80; /* DEL */ 20427110Sminshall } else { 20527110Sminshall c = b & 0x1f; 20627110Sminshall } 20727110Sminshall break; 20827110Sminshall default: 20927110Sminshall c = *s; 21027110Sminshall break; 21127110Sminshall } 21227110Sminshall return c; 21327110Sminshall } 214*27186Sminshall 215*27186Sminshall /* 216*27186Sminshall * Construct a control character sequence 217*27186Sminshall * for a special character. 218*27186Sminshall */ 219*27186Sminshall char * 220*27186Sminshall control(c) 221*27186Sminshall register int c; 222*27186Sminshall { 223*27186Sminshall static char buf[3]; 224*27186Sminshall 225*27186Sminshall if (c == 0x3f) 226*27186Sminshall return ("^?"); 227*27186Sminshall if (c == '\377') { 228*27186Sminshall return "off"; 229*27186Sminshall } 230*27186Sminshall if (c >= 0x20) { 231*27186Sminshall buf[0] = c; 232*27186Sminshall buf[1] = 0; 233*27186Sminshall } else { 234*27186Sminshall buf[0] = '^'; 235*27186Sminshall buf[1] = '@'+c; 236*27186Sminshall buf[2] = 0; 237*27186Sminshall } 238*27186Sminshall return (buf); 239*27186Sminshall } 24027110Sminshall 24127110Sminshall /* 242*27186Sminshall * Check to see if any out-of-band data exists on a socket (for 243*27186Sminshall * Telnet "synch" processing). 244*27186Sminshall */ 245*27186Sminshall 246*27186Sminshall int 247*27186Sminshall stilloob(s) 248*27186Sminshall int s; /* socket number */ 249*27186Sminshall { 250*27186Sminshall static struct timeval timeout = { 0 }; 251*27186Sminshall fd_set excepts; 252*27186Sminshall int value; 253*27186Sminshall 254*27186Sminshall do { 255*27186Sminshall FD_ZERO(&excepts); 256*27186Sminshall FD_SET(s, &excepts); 257*27186Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 258*27186Sminshall } while ((value == -1) && (errno = EINTR)); 259*27186Sminshall 260*27186Sminshall if (value < 0) { 261*27186Sminshall perror("select"); 262*27186Sminshall quit(); 263*27186Sminshall } 264*27186Sminshall if (FD_ISSET(s, &excepts)) { 265*27186Sminshall return 1; 266*27186Sminshall } else { 267*27186Sminshall return 0; 268*27186Sminshall } 269*27186Sminshall } 270*27186Sminshall 271*27186Sminshall 272*27186Sminshall /* 273*27186Sminshall * netflush 274*27186Sminshall * Send as much data as possible to the network, 275*27186Sminshall * handling requests for urgent data. 276*27186Sminshall */ 277*27186Sminshall 278*27186Sminshall 279*27186Sminshall netflush(fd) 280*27186Sminshall { 281*27186Sminshall int n; 282*27186Sminshall 283*27186Sminshall if ((n = nfrontp - nbackp) > 0) { 284*27186Sminshall if (!neturg) { 285*27186Sminshall n = write(fd, nbackp, n); /* normal write */ 286*27186Sminshall } else { 287*27186Sminshall n = neturg - nbackp; 288*27186Sminshall /* 289*27186Sminshall * In 4.2 (and 4.3) systems, there is some question about 290*27186Sminshall * what byte in a sendOOB operation is the "OOB" data. 291*27186Sminshall * To make ourselves compatible, we only send ONE byte 292*27186Sminshall * out of band, the one WE THINK should be OOB (though 293*27186Sminshall * we really have more the TCP philosophy of urgent data 294*27186Sminshall * rather than the Unix philosophy of OOB data). 295*27186Sminshall */ 296*27186Sminshall if (n > 1) { 297*27186Sminshall n = send(fd, nbackp, n-1, 0); /* send URGENT all by itself */ 298*27186Sminshall } else { 299*27186Sminshall n = send(fd, nbackp, n, MSG_OOB); /* URGENT data */ 300*27186Sminshall } 301*27186Sminshall } 302*27186Sminshall } 303*27186Sminshall if (n < 0) { 304*27186Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 305*27186Sminshall setcommandmode(); 306*27186Sminshall perror(hostname); 307*27186Sminshall close(fd); 308*27186Sminshall neturg = 0; 309*27186Sminshall longjmp(peerdied, -1); 310*27186Sminshall /*NOTREACHED*/ 311*27186Sminshall } 312*27186Sminshall n = 0; 313*27186Sminshall } 314*27186Sminshall if (netdata && n) { 315*27186Sminshall Dump('>', nbackp, n); 316*27186Sminshall } 317*27186Sminshall nbackp += n; 318*27186Sminshall if (nbackp >= neturg) { 319*27186Sminshall neturg = 0; 320*27186Sminshall } 321*27186Sminshall if (nbackp == nfrontp) { 322*27186Sminshall nbackp = nfrontp = netobuf; 323*27186Sminshall } 324*27186Sminshall } 325*27186Sminshall 326*27186Sminshall /* 327*27186Sminshall * Send as much data as possible to the terminal. 328*27186Sminshall */ 329*27186Sminshall 330*27186Sminshall 331*27186Sminshall ttyflush() 332*27186Sminshall { 333*27186Sminshall int n; 334*27186Sminshall 335*27186Sminshall if ((n = tfrontp - tbackp) > 0) { 336*27186Sminshall if (!SYNCHing) { 337*27186Sminshall n = write(tout, tbackp, n); 338*27186Sminshall } else { 339*27186Sminshall ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 340*27186Sminshall } 341*27186Sminshall } 342*27186Sminshall if (n < 0) { 343*27186Sminshall return; 344*27186Sminshall } 345*27186Sminshall tbackp += n; 346*27186Sminshall if (tbackp == tfrontp) { 347*27186Sminshall tbackp = tfrontp = ttyobuf; 348*27186Sminshall } 349*27186Sminshall } 350*27186Sminshall 351*27186Sminshall /* 35227110Sminshall * Various signal handling routines. 35327110Sminshall */ 35427110Sminshall 35527110Sminshall deadpeer() 35627110Sminshall { 35727110Sminshall setcommandmode(); 35827110Sminshall longjmp(peerdied, -1); 35927110Sminshall } 36027110Sminshall 36127110Sminshall intr() 36227110Sminshall { 36327110Sminshall if (localsigs) { 36427110Sminshall intp(); 365*27186Sminshall if (autosynch) { 366*27186Sminshall dosynch(); 367*27186Sminshall } 36827110Sminshall return; 36927110Sminshall } 37027110Sminshall setcommandmode(); 37127110Sminshall longjmp(toplevel, -1); 37227110Sminshall } 37327110Sminshall 37427110Sminshall intr2() 37527110Sminshall { 37627110Sminshall if (localsigs) { 37727110Sminshall sendbrk(); 378*27186Sminshall if (autosynch) { 379*27186Sminshall dosynch(); 380*27186Sminshall } 38127110Sminshall return; 38227110Sminshall } 38327110Sminshall } 38427110Sminshall 38527110Sminshall doescape() 38627110Sminshall { 38727110Sminshall command(0); 38827110Sminshall } 38927110Sminshall 39027110Sminshall /* 391*27186Sminshall * The following are routines used to print out debugging information. 392*27186Sminshall */ 393*27186Sminshall 394*27186Sminshall 395*27186Sminshall static 396*27186Sminshall Dump(direction, buffer, length) 397*27186Sminshall char direction; 398*27186Sminshall char *buffer; 399*27186Sminshall int length; 400*27186Sminshall { 401*27186Sminshall # define BYTES_PER_LINE 32 402*27186Sminshall # define min(x,y) ((x<y)? x:y) 403*27186Sminshall char *pThis; 404*27186Sminshall int offset; 405*27186Sminshall 406*27186Sminshall offset = 0; 407*27186Sminshall 408*27186Sminshall while (length) { 409*27186Sminshall /* print one line */ 410*27186Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 411*27186Sminshall pThis = buffer; 412*27186Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 413*27186Sminshall while (pThis < buffer) { 414*27186Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 415*27186Sminshall pThis++; 416*27186Sminshall } 417*27186Sminshall fprintf(NetTrace, "\n"); 418*27186Sminshall length -= BYTES_PER_LINE; 419*27186Sminshall offset += BYTES_PER_LINE; 420*27186Sminshall if (length < 0) { 421*27186Sminshall return; 422*27186Sminshall } 423*27186Sminshall /* find next unique line */ 424*27186Sminshall } 425*27186Sminshall } 426*27186Sminshall 427*27186Sminshall 428*27186Sminshall /*VARARGS*/ 429*27186Sminshall printoption(direction, fmt, option, what) 430*27186Sminshall char *direction, *fmt; 431*27186Sminshall int option, what; 432*27186Sminshall { 433*27186Sminshall if (!showoptions) 434*27186Sminshall return; 435*27186Sminshall printf("%s ", direction); 436*27186Sminshall if (fmt == doopt) 437*27186Sminshall fmt = "do"; 438*27186Sminshall else if (fmt == dont) 439*27186Sminshall fmt = "dont"; 440*27186Sminshall else if (fmt == will) 441*27186Sminshall fmt = "will"; 442*27186Sminshall else if (fmt == wont) 443*27186Sminshall fmt = "wont"; 444*27186Sminshall else 445*27186Sminshall fmt = "???"; 446*27186Sminshall if (option < TELOPT_SUPDUP) 447*27186Sminshall printf("%s %s", fmt, telopts[option]); 448*27186Sminshall else 449*27186Sminshall printf("%s %d", fmt, option); 450*27186Sminshall if (*direction == '<') { 451*27186Sminshall printf("\r\n"); 452*27186Sminshall return; 453*27186Sminshall } 454*27186Sminshall printf(" (%s)\r\n", what ? "reply" : "don't reply"); 455*27186Sminshall } 456*27186Sminshall 457*27186Sminshall /* 45827110Sminshall * Mode - set up terminal to a specific mode. 45927110Sminshall */ 46027110Sminshall 46113076Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 46227110Sminshall struct tchars notc2; 46313076Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 46427110Sminshall struct ltchars noltc2; 4659972Ssam 4666000Sroot mode(f) 4676000Sroot register int f; 4686000Sroot { 4698378Ssam static int prevmode = 0; 47013076Ssam struct tchars *tc; 47113076Ssam struct ltchars *ltc; 47213076Ssam struct sgttyb sb; 47313076Ssam int onoff, old; 4746000Sroot 47527110Sminshall globalmode = f; 4768378Ssam if (prevmode == f) 477*27186Sminshall return; 4788378Ssam old = prevmode; 4798378Ssam prevmode = f; 48027110Sminshall sb = nttyb; 4816000Sroot switch (f) { 4828378Ssam 4836000Sroot case 0: 4846000Sroot onoff = 0; 4859972Ssam tc = &otc; 48613076Ssam ltc = &oltc; 4876000Sroot break; 4886000Sroot 48927110Sminshall case 1: /* remote character processing, remote echo */ 49027110Sminshall case 2: /* remote character processing, local echo */ 49113076Ssam sb.sg_flags |= CBREAK; 4928378Ssam if (f == 1) 49313076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 4948378Ssam else 49513076Ssam sb.sg_flags |= ECHO|CRMOD; 49613076Ssam sb.sg_erase = sb.sg_kill = -1; 4979972Ssam tc = ¬c; 49827110Sminshall /* 49927110Sminshall * If user hasn't specified one way or the other, 50027110Sminshall * then default to not trapping signals. 50127110Sminshall */ 50227110Sminshall if (!donelclsigs) 50327110Sminshall localsigs = 0; 50427110Sminshall if (localsigs) { 50527110Sminshall notc2 = notc; 50627110Sminshall notc2.t_intrc = ntc.t_intrc; 50727110Sminshall notc2.t_quitc = ntc.t_quitc; 50827110Sminshall notc2.t_eofc = ntc.t_eofc; 50927110Sminshall tc = ¬c2; 51027110Sminshall } else 51127110Sminshall tc = ¬c; 51213076Ssam ltc = &noltc; 5136000Sroot onoff = 1; 5149972Ssam break; 51527110Sminshall case 3: /* local character processing, remote echo */ 51627110Sminshall case 4: /* local character processing, local echo */ 51727110Sminshall case 5: /* local character processing, no echo */ 51827110Sminshall sb.sg_flags &= ~CBREAK; 51927110Sminshall sb.sg_flags |= CRMOD; 52027110Sminshall if (f == 4) 52127110Sminshall sb.sg_flags |= ECHO; 52227110Sminshall else 52327110Sminshall sb.sg_flags &= ~ECHO; 52427110Sminshall /* 52527110Sminshall * If user hasn't specified one way or the other, 52627110Sminshall * then default to trapping signals. 52727110Sminshall */ 52827110Sminshall if (!donelclsigs) 52927110Sminshall localsigs = 1; 53027110Sminshall if (localsigs) 53127110Sminshall tc = &ntc; 53227110Sminshall else { 53327110Sminshall notc2 = ntc; 53427110Sminshall notc2.t_intrc = notc2.t_quitc = -1; 53527110Sminshall tc = ¬c2; 53627110Sminshall } 53727110Sminshall noltc2 = oltc; 53827110Sminshall noltc2.t_suspc = escape; 53927110Sminshall noltc2.t_dsuspc = -1; 54027110Sminshall ltc = &noltc2; 54127110Sminshall onoff = 1; 54227110Sminshall break; 5439972Ssam 5449972Ssam default: 5459972Ssam return; 5466000Sroot } 54713076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 54813076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 54913076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 550*27186Sminshall ioctl(fileno(stdin), FIONBIO, (char *)&onoff); 551*27186Sminshall ioctl(fileno(stdout), FIONBIO, (char *)&onoff); 55227110Sminshall if (f >= 3) 55327110Sminshall signal(SIGTSTP, doescape); 55427110Sminshall else if (old >= 3) { 55527110Sminshall signal(SIGTSTP, SIG_DFL); 55627110Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 55727110Sminshall } 5586000Sroot } 559*27186Sminshall 56027110Sminshall /* 56127110Sminshall * These routines decides on what the mode should be (based on the values 56227110Sminshall * of various global variables). 56327110Sminshall */ 56427110Sminshall 56527178Sminshall char *modedescriptions[] = { 56627178Sminshall "telnet command mode", /* 0 */ 56727178Sminshall "character-at-a-time mode", /* 1 */ 56827178Sminshall "character-at-a-time mode (local echo)", /* 2 */ 56927178Sminshall "line-by-line mode (remote echo)", /* 3 */ 57027178Sminshall "line-by-line mode", /* 4 */ 57127178Sminshall "line-by-line mode (local echoing suppressed)", /* 5 */ 57227178Sminshall }; 57327178Sminshall 57427178Sminshall getconnmode() 57527110Sminshall { 57627110Sminshall static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 }; 577*27186Sminshall int modeindex = 0; 57827110Sminshall 57927110Sminshall if (hisopts[TELOPT_ECHO]) { 580*27186Sminshall modeindex += 2; 58127110Sminshall } 58227110Sminshall if (hisopts[TELOPT_SGA]) { 583*27186Sminshall modeindex += 4; 58427110Sminshall } 585*27186Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 586*27186Sminshall modeindex += 1; 58727110Sminshall } 588*27186Sminshall return newmode[modeindex]; 58927110Sminshall } 59027110Sminshall 59127178Sminshall setconnmode() 59227178Sminshall { 59327178Sminshall mode(getconnmode()); 59427178Sminshall } 59527110Sminshall 59627178Sminshall 59727110Sminshall setcommandmode() 59827110Sminshall { 59927110Sminshall mode(0); 60027110Sminshall } 60127110Sminshall 6026000Sroot char sibuf[BUFSIZ], *sbp; 6036000Sroot char tibuf[BUFSIZ], *tbp; 6046000Sroot int scc, tcc; 6056000Sroot 6066000Sroot /* 6076000Sroot * Select from tty and network... 6086000Sroot */ 60927088Sminshall telnet() 6106000Sroot { 6116000Sroot register int c; 61227088Sminshall int tin = fileno(stdin); 6136000Sroot int on = 1; 6146000Sroot 61527088Sminshall tout = fileno(stdout); 61627110Sminshall setconnmode(); 617*27186Sminshall ioctl(net, FIONBIO, (char *)&on); 61827178Sminshall #if defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) 61927178Sminshall ioctl(net, asdf, asdf); /* handle urgent data in band */ 62027178Sminshall #endif /* defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */ 62127088Sminshall if (telnetport && !hisopts[TELOPT_SGA]) { 62217922Sralph willoption(TELOPT_SGA); 62327088Sminshall } 6246000Sroot for (;;) { 62527110Sminshall fd_set ibits, obits, xbits; 6266000Sroot 62727110Sminshall if (scc < 0 && tcc < 0) { 6286000Sroot break; 62927110Sminshall } 63027110Sminshall 63127110Sminshall FD_ZERO(&ibits); 63227110Sminshall FD_ZERO(&obits); 63327110Sminshall FD_ZERO(&xbits); 63427110Sminshall 63527110Sminshall if (((globalmode < 4) || flushline) && (nfrontp - nbackp)) { 63627110Sminshall FD_SET(net, &obits); 63727088Sminshall } else { 63827110Sminshall FD_SET(tin, &ibits); 63927088Sminshall } 64027110Sminshall if (tfrontp - tbackp) { 64127110Sminshall FD_SET(tout, &obits); 64227110Sminshall } else { 64327110Sminshall FD_SET(net, &ibits); 64427110Sminshall } 645*27186Sminshall if (!SYNCHing) { 64627110Sminshall FD_SET(net, &xbits); 64727110Sminshall } 648*27186Sminshall if ((c = select(16, &ibits, &obits, &xbits, 649*27186Sminshall (struct timeval *)0)) < 1) { 65027110Sminshall if (c == -1) { 65127110Sminshall /* 65227110Sminshall * we can get EINTR if we are in line mode, 65327110Sminshall * and the user does an escape (TSTP), or 65427110Sminshall * some other signal generator. 65527110Sminshall */ 65627110Sminshall if (errno == EINTR) { 65727110Sminshall continue; 65827110Sminshall } 65927110Sminshall } 6606000Sroot sleep(5); 6616000Sroot continue; 6626000Sroot } 6636000Sroot 6646000Sroot /* 66527088Sminshall * Any urgent data? 66627088Sminshall */ 66727110Sminshall if (FD_ISSET(net, &xbits)) { 668*27186Sminshall SYNCHing = 1; 66927088Sminshall ttyflush(); /* flush already enqueued data */ 67027088Sminshall } 67127088Sminshall 67227088Sminshall /* 6736000Sroot * Something to read from the network... 6746000Sroot */ 67527110Sminshall if (FD_ISSET(net, &ibits)) { 67627178Sminshall #if !defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) 67727178Sminshall /* 67827178Sminshall * In 4.2 (and some early 4.3) systems, the 67927178Sminshall * OOB indication and data handling in the kernel 68027178Sminshall * is such that if two separate TCP Urgent requests 68127178Sminshall * come in, one byte of TCP data will be overlaid. 68227178Sminshall * This is fatal for Telnet, but we try to live 68327178Sminshall * with it. 68427178Sminshall * 68527178Sminshall * In addition, in 4.2 (and...), a special protocol 68627178Sminshall * is needed to pick up the TCP Urgent data in 68727178Sminshall * the correct sequence. 68827178Sminshall * 68927178Sminshall * What we do is: if we think we are in urgent 69027178Sminshall * mode, we look to see if we are "at the mark". 69127178Sminshall * If we are, we do an OOB receive. If we run 69227178Sminshall * this twice, we will do the OOB receive twice, 69327178Sminshall * but the second will fail, since the second 69427178Sminshall * time we were "at the mark", but there wasn't 69527178Sminshall * any data there (the kernel doesn't reset 69627178Sminshall * "at the mark" until we do a normal read). 69727178Sminshall * Once we've read the OOB data, we go ahead 69827178Sminshall * and do normal reads. 69927178Sminshall * 70027178Sminshall * There is also another problem, which is that 70127178Sminshall * since the OOB byte we read doesn't put us 70227178Sminshall * out of OOB state, and since that byte is most 70327178Sminshall * likely the TELNET DM (data mark), we would 704*27186Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 70527178Sminshall * So, clocks to the rescue. If we've "just" 70627178Sminshall * received a DM, then we test for the 70727178Sminshall * presence of OOB data when the receive OOB 70827178Sminshall * fails (and AFTER we did the normal mode read 70927178Sminshall * to clear "at the mark"). 71027178Sminshall */ 711*27186Sminshall if (SYNCHing) { 71227178Sminshall int atmark; 71327178Sminshall 714*27186Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 71527178Sminshall if (atmark) { 71627178Sminshall scc = recv(net, sibuf, sizeof (sibuf), MSG_OOB); 71727178Sminshall if ((scc == -1) && (errno == EINVAL)) { 71827178Sminshall scc = read(net, sibuf, sizeof (sibuf)); 719*27186Sminshall if (clocks.didnetreceive < clocks.gotDM) { 720*27186Sminshall SYNCHing = stilloob(net); 72127021Sminshall } 72227178Sminshall } 72327178Sminshall } else { 72427178Sminshall scc = read(net, sibuf, sizeof (sibuf)); 7256000Sroot } 72627178Sminshall } else { 72727178Sminshall scc = read(net, sibuf, sizeof (sibuf)); 72827178Sminshall } 72927178Sminshall settimer(didnetreceive); 73027178Sminshall #else /* !defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */ 73127178Sminshall scc = read(net, sibuf, sizeof (sibuf)); 73227178Sminshall #endif /* !defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */ 73327178Sminshall if (scc < 0 && errno == EWOULDBLOCK) 73427178Sminshall scc = 0; 73527178Sminshall else { 73627178Sminshall if (scc <= 0) { 73727178Sminshall break; 73827178Sminshall } 73927178Sminshall sbp = sibuf; 74027178Sminshall if (netdata) { 74127178Sminshall Dump('<', sbp, scc); 74227178Sminshall } 74327178Sminshall } 7446000Sroot } 7456000Sroot 7466000Sroot /* 7476000Sroot * Something to read from the tty... 7486000Sroot */ 74927110Sminshall if (FD_ISSET(tin, &ibits)) { 7508378Ssam tcc = read(tin, tibuf, sizeof (tibuf)); 7516000Sroot if (tcc < 0 && errno == EWOULDBLOCK) 7526000Sroot tcc = 0; 7536000Sroot else { 7546000Sroot if (tcc <= 0) 7556000Sroot break; 7566000Sroot tbp = tibuf; 7576000Sroot } 7586000Sroot } 7596000Sroot 7606000Sroot while (tcc > 0) { 761*27186Sminshall register int sc; 7626000Sroot 76327110Sminshall if ((&netobuf[BUFSIZ] - nfrontp) < 2) { 76427110Sminshall flushline = 1; 7656000Sroot break; 76627110Sminshall } 767*27186Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 768*27186Sminshall if (sc == escape) { 7696000Sroot command(0); 7706000Sroot tcc = 0; 77127110Sminshall flushline = 1; 7726000Sroot break; 77327110Sminshall } else if ((globalmode >= 4) && doechocharrecognition && 774*27186Sminshall (sc == echoc)) { 77527110Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 77627110Sminshall tbp++; 77727110Sminshall tcc--; 77827110Sminshall } else { 77927110Sminshall dontlecho = !dontlecho; 78027110Sminshall settimer(echotoggle); 78127110Sminshall setconnmode(); 78227110Sminshall tcc = 0; 78327110Sminshall flushline = 1; 78427110Sminshall break; 78527110Sminshall } 7866000Sroot } 78727110Sminshall if (localsigs) { 788*27186Sminshall if (sc == ntc.t_intrc) { 78927110Sminshall intp(); 79027110Sminshall break; 791*27186Sminshall } else if (sc == ntc.t_quitc) { 79227110Sminshall sendbrk(); 79327110Sminshall break; 79427110Sminshall } else if (globalmode > 2) { 79527110Sminshall ; 796*27186Sminshall } else if (sc == nttyb.sg_kill) { 79727110Sminshall NET2ADD(IAC, EL); 79827110Sminshall break; 799*27186Sminshall } else if (sc == nttyb.sg_erase) { 80027110Sminshall NET2ADD(IAC, EC); 80127110Sminshall break; 80227110Sminshall } 80327110Sminshall } 80417922Sralph switch (c) { 80517922Sralph case '\n': 80627021Sminshall /* 80727021Sminshall * If echoing is happening locally, 80827021Sminshall * then a newline (unix) is CRLF (TELNET). 80927021Sminshall */ 81027088Sminshall if (!hisopts[TELOPT_ECHO]) { 81127088Sminshall NETADD('\r'); 81227088Sminshall } 81327088Sminshall NETADD('\n'); 81427110Sminshall flushline = 1; 81517922Sralph break; 81617922Sralph case '\r': 81727088Sminshall NET2ADD('\r', '\0'); 81827110Sminshall flushline = 1; 81917922Sralph break; 82017922Sralph case IAC: 82127088Sminshall NET2ADD(IAC, IAC); 82227021Sminshall break; 82317922Sralph default: 82427088Sminshall NETADD(c); 82517922Sralph break; 82617922Sralph } 8276000Sroot } 82827110Sminshall if (((globalmode < 4) || flushline) && 82927110Sminshall (FD_ISSET(net, &obits) && (nfrontp - nbackp) > 0)) { 83027088Sminshall netflush(net); 83127110Sminshall } 8326000Sroot if (scc > 0) 8336000Sroot telrcv(); 83427110Sminshall if (FD_ISSET(tout, &obits) && (tfrontp - tbackp) > 0) 83527088Sminshall ttyflush(); 8366000Sroot } 83727110Sminshall setcommandmode(); 8386000Sroot } 83927110Sminshall 8406000Sroot /* 8416000Sroot * Telnet receiver states for fsm 8426000Sroot */ 8436000Sroot #define TS_DATA 0 8446000Sroot #define TS_IAC 1 8456000Sroot #define TS_WILL 2 8466000Sroot #define TS_WONT 3 8476000Sroot #define TS_DO 4 8486000Sroot #define TS_DONT 5 84927021Sminshall #define TS_CR 6 8506000Sroot 8516000Sroot telrcv() 8526000Sroot { 8536000Sroot register int c; 8546000Sroot static int state = TS_DATA; 8556000Sroot 8566000Sroot while (scc > 0) { 857*27186Sminshall c = *sbp++ & 0xff, scc--; 8586000Sroot switch (state) { 8596000Sroot 86027021Sminshall case TS_CR: 86127021Sminshall state = TS_DATA; 86227021Sminshall if ((c == '\0') || (c == '\n')) { 86327021Sminshall break; /* by now, we ignore \n */ 86427021Sminshall } 86527021Sminshall 8666000Sroot case TS_DATA: 8679972Ssam if (c == IAC) { 8686000Sroot state = TS_IAC; 8699972Ssam continue; 8709972Ssam } 87127021Sminshall if (c == '\r') { 87227021Sminshall if (scc > 0) { 873*27186Sminshall c = *sbp&0xff; 87427021Sminshall if (c == 0) { 87527021Sminshall sbp++, scc--; 87627088Sminshall TTYADD('\r'); 87727021Sminshall /* 87827021Sminshall * The following hack is needed since we can't 87927021Sminshall * set CRMOD on output only. Machines like 88027021Sminshall * MULTICS like to send \r without \n; since 88127021Sminshall * we must turn off CRMOD to get proper input, 88227021Sminshall * the mapping is done here (sigh). 88327021Sminshall */ 88427021Sminshall if (crmod) { 88527088Sminshall TTYADD('\n'); 88627021Sminshall } 88727021Sminshall } else if (!hisopts[TELOPT_ECHO] && 88827021Sminshall (c == '\n')) { 88927021Sminshall sbp++, scc--; 89027088Sminshall TTYADD('\n'); 89127021Sminshall } else { 89227088Sminshall TTYADD('\r'); 89327021Sminshall } 89427021Sminshall } else { 89527021Sminshall state = TS_CR; 89627088Sminshall TTYADD('\r'); 89727021Sminshall } 89827021Sminshall } else { 89927088Sminshall TTYADD(c); 90027021Sminshall } 9016000Sroot continue; 9026000Sroot 9036000Sroot case TS_IAC: 9046000Sroot switch (c) { 9056000Sroot 9066000Sroot case WILL: 9076000Sroot state = TS_WILL; 9086000Sroot continue; 9096000Sroot 9106000Sroot case WONT: 9116000Sroot state = TS_WONT; 9126000Sroot continue; 9136000Sroot 9146000Sroot case DO: 9156000Sroot state = TS_DO; 9166000Sroot continue; 9176000Sroot 9186000Sroot case DONT: 9196000Sroot state = TS_DONT; 9206000Sroot continue; 9216000Sroot 9226000Sroot case DM: 92327088Sminshall /* 92427088Sminshall * We may have missed an urgent notification, 92527088Sminshall * so make sure we flush whatever is in the 92627088Sminshall * buffer currently. 92727088Sminshall */ 928*27186Sminshall SYNCHing = 1; 92927088Sminshall ttyflush(); 930*27186Sminshall SYNCHing = stilloob(net); 93127178Sminshall settimer(gotDM); 9326000Sroot break; 9336000Sroot 9346000Sroot case NOP: 9356000Sroot case GA: 9366000Sroot break; 9376000Sroot 9386000Sroot default: 9396000Sroot break; 9406000Sroot } 9416000Sroot state = TS_DATA; 9426000Sroot continue; 9436000Sroot 9446000Sroot case TS_WILL: 9458345Ssam printoption("RCVD", will, c, !hisopts[c]); 94627110Sminshall if (c == TELOPT_TM) { 94727110Sminshall if (flushout) { 948*27186Sminshall flushout = 0; 94927110Sminshall } 95027110Sminshall } else if (!hisopts[c]) { 9516000Sroot willoption(c); 95227110Sminshall } 9536000Sroot state = TS_DATA; 9546000Sroot continue; 9556000Sroot 9566000Sroot case TS_WONT: 9578345Ssam printoption("RCVD", wont, c, hisopts[c]); 95827110Sminshall if (c == TELOPT_TM) { 95927110Sminshall if (flushout) { 960*27186Sminshall flushout = 0; 96127110Sminshall } 96227110Sminshall } else if (hisopts[c]) { 9636000Sroot wontoption(c); 96427110Sminshall } 9656000Sroot state = TS_DATA; 9666000Sroot continue; 9676000Sroot 9686000Sroot case TS_DO: 9698345Ssam printoption("RCVD", doopt, c, !myopts[c]); 9706000Sroot if (!myopts[c]) 9716000Sroot dooption(c); 9726000Sroot state = TS_DATA; 9736000Sroot continue; 9746000Sroot 9756000Sroot case TS_DONT: 9768345Ssam printoption("RCVD", dont, c, myopts[c]); 9776000Sroot if (myopts[c]) { 9786000Sroot myopts[c] = 0; 9796000Sroot sprintf(nfrontp, wont, c); 9808378Ssam nfrontp += sizeof (wont) - 2; 98127110Sminshall flushline = 1; 98227110Sminshall setconnmode(); /* set new tty mode (maybe) */ 9838345Ssam printoption("SENT", wont, c); 9846000Sroot } 9856000Sroot state = TS_DATA; 9866000Sroot continue; 9876000Sroot } 9886000Sroot } 9896000Sroot } 99027110Sminshall 9916000Sroot willoption(option) 9926000Sroot int option; 9936000Sroot { 9946000Sroot char *fmt; 9956000Sroot 9966000Sroot switch (option) { 9976000Sroot 9986000Sroot case TELOPT_ECHO: 9996000Sroot case TELOPT_SGA: 100027110Sminshall settimer(modenegotiated); 10016000Sroot hisopts[option] = 1; 10026000Sroot fmt = doopt; 100327110Sminshall setconnmode(); /* possibly set new tty mode */ 10046000Sroot break; 10056000Sroot 10066000Sroot case TELOPT_TM: 100727110Sminshall return; /* Never reply to TM will's/wont's */ 10086000Sroot 10096000Sroot default: 10106000Sroot fmt = dont; 10116000Sroot break; 10126000Sroot } 10136024Ssam sprintf(nfrontp, fmt, option); 10148378Ssam nfrontp += sizeof (dont) - 2; 10158345Ssam printoption("SENT", fmt, option); 10166000Sroot } 10176000Sroot 10186000Sroot wontoption(option) 10196000Sroot int option; 10206000Sroot { 10216000Sroot char *fmt; 10226000Sroot 10236000Sroot switch (option) { 10246000Sroot 10256000Sroot case TELOPT_ECHO: 10266000Sroot case TELOPT_SGA: 102727110Sminshall settimer(modenegotiated); 10286000Sroot hisopts[option] = 0; 10296000Sroot fmt = dont; 103027110Sminshall setconnmode(); /* Set new tty mode */ 10316000Sroot break; 10326000Sroot 103327110Sminshall case TELOPT_TM: 103427110Sminshall return; /* Never reply to TM will's/wont's */ 103527110Sminshall 10366000Sroot default: 10376000Sroot fmt = dont; 10386000Sroot } 10396000Sroot sprintf(nfrontp, fmt, option); 10408378Ssam nfrontp += sizeof (doopt) - 2; 10418345Ssam printoption("SENT", fmt, option); 10426000Sroot } 10436000Sroot 10446000Sroot dooption(option) 10456000Sroot int option; 10466000Sroot { 10476000Sroot char *fmt; 10486000Sroot 10496000Sroot switch (option) { 10506000Sroot 10516000Sroot case TELOPT_TM: 105213231Ssam fmt = will; 105313231Ssam break; 105413231Ssam 105527110Sminshall case TELOPT_SGA: /* no big deal */ 10566000Sroot fmt = will; 105727110Sminshall myopts[option] = 1; 10586000Sroot break; 10596000Sroot 106027110Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 10616000Sroot default: 10626000Sroot fmt = wont; 10636000Sroot break; 10646000Sroot } 10656000Sroot sprintf(nfrontp, fmt, option); 10668378Ssam nfrontp += sizeof (doopt) - 2; 10678345Ssam printoption("SENT", fmt, option); 10686000Sroot } 106927110Sminshall 10706000Sroot /* 107127088Sminshall * The following are data structures and routines for 107227088Sminshall * the "send" command. 107327088Sminshall * 107427088Sminshall */ 107527088Sminshall 107627088Sminshall struct sendlist { 107727088Sminshall char *name; /* How user refers to it (case independent) */ 107827088Sminshall int what; /* Character to be sent (<0 ==> special) */ 107927088Sminshall char *help; /* Help information (0 ==> no help) */ 108027088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 108127088Sminshall }; 108227088Sminshall 1083*27186Sminshall /*ARGSUSED*/ 108427088Sminshall dosynch(s) 108527088Sminshall struct sendlist *s; 108627088Sminshall { 108727088Sminshall /* XXX We really should purge the buffer to the network */ 108827088Sminshall NET2ADD(IAC, DM); 1089*27186Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 109027088Sminshall } 109127088Sminshall 109227088Sminshall intp() 109327088Sminshall { 109427110Sminshall NET2ADD(IAC, IP); 109527088Sminshall } 109627088Sminshall 109727110Sminshall sendbrk() 109827110Sminshall { 1099*27186Sminshall #if 0 1100*27186Sminshall /* 1101*27186Sminshall * There is a question here. Should we send a TM to flush the stream? 1102*27186Sminshall * Should we also send a TELNET SYNCH also? 1103*27186Sminshall */ 110427110Sminshall *nfrontp++ = IAC; 110527110Sminshall *nfrontp++ = DO; 110627110Sminshall *nfrontp++ = TELOPT_TM; 110727110Sminshall flushout = 1; 1108*27186Sminshall printoption("SENT", doopt, TELOPT_TM); 1109*27186Sminshall #endif /* 0 */ 1110*27186Sminshall NET2ADD(IAC, BREAK); 111127110Sminshall flushline = 1; 111227110Sminshall } 111327088Sminshall 111427110Sminshall 111527088Sminshall #define SENDQUESTION -1 111627088Sminshall #define SEND2QUESTION -2 111727088Sminshall #define SENDESCAPE -3 111827088Sminshall 111927088Sminshall struct sendlist Sendlist[] = { 112027088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 112127088Sminshall { "brk", BREAK, "Send Telnet Break" }, 112227088Sminshall { "break", BREAK, 0 }, 112327088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 112427088Sminshall { "intp", IP, 0 }, 112527088Sminshall { "interrupt", IP, 0 }, 112627088Sminshall { "intr", IP, 0 }, 112727088Sminshall { "ao", AO, "Send Telnet Abort output" }, 112827088Sminshall { "abort", AO, 0 }, 112927088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 113027088Sminshall { "are", AYT, 0 }, 113127088Sminshall { "hello", AYT, 0 }, 113227088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 113327088Sminshall { "el", EL, "Send Telnet Erase Line" }, 113427088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 113527088Sminshall { "go", GA, 0 }, 113627088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 113727088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 113827088Sminshall { "?", SENDQUESTION, "Display send options" }, 113927088Sminshall { "help", SENDQUESTION, 0 }, 114027088Sminshall { "??", SEND2QUESTION, "Display all send options (including aliases)" }, 114127088Sminshall { 0 } 114227088Sminshall }; 114327088Sminshall 114427088Sminshall char ** 114527088Sminshall getnextsend(name) 114627088Sminshall char *name; 114727088Sminshall { 114827088Sminshall struct sendlist *c = (struct sendlist *) name; 114927088Sminshall 115027088Sminshall return (char **) (c+1); 115127088Sminshall } 115227088Sminshall 115327088Sminshall struct sendlist * 115427088Sminshall getsend(name) 115527088Sminshall char *name; 115627088Sminshall { 115727088Sminshall return (struct sendlist *) genget(name, (char **) Sendlist, getnextsend); 115827088Sminshall } 115927088Sminshall 116027088Sminshall sendcmd(argc, argv) 116127088Sminshall int argc; 116227088Sminshall char **argv; 116327088Sminshall { 116427088Sminshall int what; /* what we are sending this time */ 116527088Sminshall int count; /* how many bytes we are going to need to send */ 116627088Sminshall int hadsynch; /* are we going to process a "synch"? */ 116727088Sminshall int i; 116827088Sminshall struct sendlist *s; /* pointer to current command */ 116927088Sminshall 117027088Sminshall if (argc < 2) { 117127088Sminshall printf("need at least one argument for 'send' command\n"); 117227088Sminshall printf("'send ?' for help\n"); 117327088Sminshall return; 117427088Sminshall } 117527088Sminshall /* 117627088Sminshall * First, validate all the send arguments. 117727088Sminshall * In addition, we see how much space we are going to need, and 117827088Sminshall * whether or not we will be doing a "SYNCH" operation (which 117927088Sminshall * flushes the network queue). 118027088Sminshall */ 118127088Sminshall count = 0; 118227088Sminshall hadsynch = 0; 118327088Sminshall for (i = 1; i < argc; i++) { 118427088Sminshall s = getsend(argv[i]); 118527088Sminshall if (s == 0) { 118627088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 118727088Sminshall argv[i]); 118827088Sminshall return; 1189*27186Sminshall } else if (s == Ambiguous(struct sendlist *)) { 119027088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 119127088Sminshall argv[i]); 119227088Sminshall return; 119327088Sminshall } 119427088Sminshall switch (s->what) { 119527088Sminshall case SENDQUESTION: 119627088Sminshall case SEND2QUESTION: 119727088Sminshall break; 119827088Sminshall case SENDESCAPE: 119927088Sminshall count += 1; 120027088Sminshall break; 120127088Sminshall case SYNCH: 120227088Sminshall hadsynch = 1; 120327088Sminshall count += 2; 120427088Sminshall break; 120527088Sminshall default: 120627088Sminshall count += 2; 120727088Sminshall break; 120827088Sminshall } 120927088Sminshall } 121027088Sminshall /* Now, do we have enough room? */ 121127088Sminshall if (netobuf+sizeof netobuf-nfrontp-1 < count) { 121227088Sminshall printf("There is not enough room in the buffer TO the network\n"); 121327088Sminshall printf("to process your request. Nothing will be done.\n"); 121427088Sminshall printf("('send synch' will throw away most data in the network\n"); 121527088Sminshall printf("buffer, if this might help.)\n"); 121627088Sminshall return; 121727088Sminshall } 121827088Sminshall /* OK, they are all OK, now go through again and actually send */ 121927088Sminshall for (i = 1; i < argc; i++) { 122027088Sminshall if (!(s = getsend(argv[i]))) { 122127088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 122227088Sminshall quit(); 122327088Sminshall /*NOTREACHED*/ 122427088Sminshall } 122527088Sminshall if (s->routine) { 122627088Sminshall (*s->routine)(s); 122727088Sminshall } else { 122827088Sminshall switch (what = s->what) { 122927088Sminshall case SENDQUESTION: 123027088Sminshall case SEND2QUESTION: 123127088Sminshall for (s = Sendlist; s->name; s++) { 123227088Sminshall if (s->help || (what == SEND2QUESTION)) { 123327088Sminshall printf(s->name); 123427088Sminshall if (s->help) { 123527088Sminshall printf("\t%s", s->help); 123627088Sminshall } 123727088Sminshall printf("\n"); 123827088Sminshall } 123927088Sminshall } 124027088Sminshall break; 124127088Sminshall case SENDESCAPE: 124227088Sminshall NETADD(escape); 124327088Sminshall break; 124427088Sminshall default: 124527088Sminshall NET2ADD(IAC, what); 124627088Sminshall break; 124727088Sminshall } 124827088Sminshall } 124927088Sminshall } 125027088Sminshall } 125127088Sminshall 125227088Sminshall /* 125327088Sminshall * The following are the routines and data structures referred 125427088Sminshall * to by the arguments to the "toggle" command. 125527088Sminshall */ 125627088Sminshall 125727110Sminshall lclsigs() 125827110Sminshall { 125927110Sminshall donelclsigs = 1; 126027110Sminshall } 126127110Sminshall 126227110Sminshall /*VARARGS*/ 126327178Sminshall togcrmod() 126427110Sminshall { 126527110Sminshall crmod = !crmod; 1266*27186Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 126727110Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 126827110Sminshall fflush(stdout); 126927110Sminshall } 127027110Sminshall 127127178Sminshall togdebug() 127227088Sminshall { 127327110Sminshall if (net > 0 && 1274*27186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug)) 1275*27186Sminshall < 0) { 127627110Sminshall perror("setsockopt (SO_DEBUG)"); 1277*27186Sminshall } 127827088Sminshall } 127927088Sminshall 128027088Sminshall 128127088Sminshall 128227088Sminshall int togglehelp(); 128327088Sminshall 128427110Sminshall char crmodhelp[] = "toggle mapping of received carriage returns"; 128527110Sminshall 128627178Sminshall struct togglelist { 128727178Sminshall char *name; /* name of toggle */ 128827178Sminshall char *help; /* help message */ 1289*27186Sminshall int (*handler)(); /* routine to do actual setting */ 129027178Sminshall int dohelp; /* should we display help information */ 129127178Sminshall int *variable; 129227178Sminshall char *actionexplanation; 129327178Sminshall }; 129427178Sminshall 129527178Sminshall struct togglelist Togglelist[] = { 129627178Sminshall { "localchars", 129727178Sminshall "toggle local recognition of control characters", 129827178Sminshall lclsigs, 129927178Sminshall 1, 130027178Sminshall &localsigs, 130127178Sminshall "recognize interrupt/quit characters" }, 130227178Sminshall { "echochar", 130327178Sminshall "toggle recognition of echo toggle character", 1304*27186Sminshall 0, 130527178Sminshall 1, 130627178Sminshall &doechocharrecognition, 130727178Sminshall "recognize echo toggle character" }, 1308*27186Sminshall { "autosynch", 1309*27186Sminshall "toggle automatic sending of interrupt characters in urgent mode", 1310*27186Sminshall 0, 1311*27186Sminshall 1, 1312*27186Sminshall &autosynch, 1313*27186Sminshall "send interrupt characters in urgent mode" }, 131427178Sminshall { "crmod", 131527178Sminshall crmodhelp, 1316*27186Sminshall 0, 131727178Sminshall 1, 131827178Sminshall &crmod, 131927178Sminshall "map carriage return on output" }, 132027110Sminshall { " ", "", 0, 1 }, /* empty line */ 132127178Sminshall { "debug", 132227178Sminshall "(debugging) toggle debugging", 132327178Sminshall togdebug, 132427178Sminshall 1, 132527178Sminshall &debug, 132627178Sminshall "turn on socket level debugging" }, 132727178Sminshall { "options", 132827178Sminshall "(debugging) toggle viewing of options processing", 1329*27186Sminshall 0, 133027178Sminshall 1, 133127178Sminshall &showoptions, 133227178Sminshall "show option processing" }, 133327178Sminshall { "netdata", 133427178Sminshall "(debugging) toggle printing of hexadecimal network data", 1335*27186Sminshall 0, 133627178Sminshall 1, 133727178Sminshall &netdata, 133827178Sminshall "print hexadecimal representation of network traffic" }, 133927178Sminshall { "?", 134027178Sminshall "display help information", 134127178Sminshall togglehelp, 134227178Sminshall 1 }, 134327178Sminshall { "help", 134427178Sminshall "display help information", 134527178Sminshall togglehelp, 134627178Sminshall 0 }, 134727088Sminshall { 0 } 134827088Sminshall }; 134927088Sminshall 135027088Sminshall togglehelp() 135127088Sminshall { 135227178Sminshall struct togglelist *c; 135327088Sminshall 135427178Sminshall for (c = Togglelist; c->name; c++) { 135527088Sminshall if (c->dohelp) { 135627088Sminshall printf("%s\t%s\n", c->name, c->help); 135727088Sminshall } 135827088Sminshall } 135927088Sminshall } 136027088Sminshall 136127088Sminshall char ** 136227088Sminshall getnexttoggle(name) 136327088Sminshall char *name; 136427088Sminshall { 136527178Sminshall struct togglelist *c = (struct togglelist *) name; 136627088Sminshall 136727088Sminshall return (char **) (c+1); 136827088Sminshall } 136927088Sminshall 137027178Sminshall struct togglelist * 137127088Sminshall gettoggle(name) 137227088Sminshall char *name; 137327088Sminshall { 137427178Sminshall return (struct togglelist *) 137527178Sminshall genget(name, (char **) Togglelist, getnexttoggle); 137627088Sminshall } 137727088Sminshall 137827088Sminshall toggle(argc, argv) 137927088Sminshall int argc; 138027088Sminshall char *argv[]; 138127088Sminshall { 138227088Sminshall char *name; 138327178Sminshall struct togglelist *c; 138427088Sminshall 138527088Sminshall if (argc < 2) { 138627088Sminshall fprintf(stderr, 138727088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 138827088Sminshall return; 138927088Sminshall } 139027088Sminshall argc--; 139127088Sminshall argv++; 139227088Sminshall while (argc--) { 139327088Sminshall name = *argv++; 139427088Sminshall c = gettoggle(name); 1395*27186Sminshall if (c == Ambiguous(struct togglelist *)) { 139627088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 139727088Sminshall name); 139827088Sminshall } else if (c == 0) { 139927088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 140027088Sminshall name); 140127088Sminshall } else { 1402*27186Sminshall if (c->variable) { 1403*27186Sminshall *c->variable = !*c->variable; /* invert it */ 1404*27186Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 1405*27186Sminshall c->actionexplanation); 1406*27186Sminshall } 1407*27186Sminshall if (c->handler) { 1408*27186Sminshall (*c->handler)(c); 1409*27186Sminshall } 141027088Sminshall } 141127088Sminshall } 141227088Sminshall } 141327088Sminshall 141427088Sminshall /* 141527110Sminshall * The following perform the "set" command. 141627110Sminshall */ 141727110Sminshall 141827178Sminshall struct setlist { 141927178Sminshall char *name; /* name */ 142027110Sminshall char *help; /* help information */ 142127110Sminshall char *charp; /* where it is located at */ 142227110Sminshall }; 142327110Sminshall 142427178Sminshall struct setlist Setlist[] = { 142527110Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 142627110Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 142727110Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 142827110Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 142927110Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 143027110Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 143127110Sminshall { 0 } 143227110Sminshall }; 143327110Sminshall 143427110Sminshall char ** 143527178Sminshall getnextset(name) 143627110Sminshall char *name; 143727110Sminshall { 143827178Sminshall struct setlist *c = (struct setlist *)name; 143927110Sminshall 144027110Sminshall return (char **) (c+1); 144127110Sminshall } 144227110Sminshall 144327178Sminshall struct setlist * 144427178Sminshall getset(name) 144527110Sminshall char *name; 144627110Sminshall { 144727178Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 144827110Sminshall } 144927110Sminshall 145027110Sminshall setcmd(argc, argv) 145127110Sminshall int argc; 145227110Sminshall char *argv[]; 145327110Sminshall { 145427110Sminshall int value; 145527178Sminshall struct setlist *ct; 145627110Sminshall 145727110Sminshall /* XXX back we go... sigh */ 145827110Sminshall if (argc != 3) { 145927110Sminshall printf("Format is 'set Name Value', where 'Name' is one of:\n\n"); 146027178Sminshall for (ct = Setlist; ct->name; ct++) { 146127178Sminshall printf("%s\t%s\n", ct->name, ct->help); 146227110Sminshall } 146327110Sminshall return; 146427110Sminshall } 146527110Sminshall 146627178Sminshall ct = getset(argv[1]); 146727110Sminshall if (ct == 0) { 146827110Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 146927110Sminshall argv[1]); 1470*27186Sminshall } else if (ct == Ambiguous(struct setlist *)) { 147127110Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 147227110Sminshall argv[1]); 147327110Sminshall } else { 147427110Sminshall if (strcmp("off", argv[2])) { 147527110Sminshall value = special(argv[2]); 147627110Sminshall } else { 147727110Sminshall value = -1; 147827110Sminshall } 147927110Sminshall *(ct->charp) = value; 148027178Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 148127110Sminshall } 148227110Sminshall } 148327110Sminshall 148427110Sminshall /* 148527110Sminshall * The following are the data structures and routines for the 148627110Sminshall * 'mode' command. 148727110Sminshall */ 148827110Sminshall 148927110Sminshall dolinemode() 149027110Sminshall { 149127110Sminshall if (hisopts[TELOPT_SGA]) { 1492*27186Sminshall wontoption(TELOPT_SGA); 149327110Sminshall } 149427110Sminshall if (hisopts[TELOPT_ECHO]) { 1495*27186Sminshall wontoption(TELOPT_ECHO); 149627110Sminshall } 149727110Sminshall } 149827110Sminshall 149927110Sminshall docharmode() 150027110Sminshall { 150127110Sminshall if (!hisopts[TELOPT_SGA]) { 1502*27186Sminshall willoption(TELOPT_SGA); 150327110Sminshall } 150427110Sminshall if (!hisopts[TELOPT_ECHO]) { 1505*27186Sminshall willoption(TELOPT_ECHO); 150627110Sminshall } 150727110Sminshall } 150827110Sminshall 150927110Sminshall struct cmd Modelist[] = { 151027110Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 151127110Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 151227110Sminshall { 0 }, 151327110Sminshall }; 151427110Sminshall 151527110Sminshall char ** 151627110Sminshall getnextmode(name) 151727110Sminshall char *name; 151827110Sminshall { 151927110Sminshall struct cmd *c = (struct cmd *) name; 152027110Sminshall 152127110Sminshall return (char **) (c+1); 152227110Sminshall } 152327110Sminshall 152427110Sminshall struct cmd * 152527110Sminshall getmodecmd(name) 152627110Sminshall char *name; 152727110Sminshall { 152827110Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 152927110Sminshall } 153027110Sminshall 153127110Sminshall modecmd(argc, argv) 153227110Sminshall int argc; 153327110Sminshall char *argv[]; 153427110Sminshall { 153527110Sminshall struct cmd *mt; 153627110Sminshall 153727110Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 153827110Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 153927110Sminshall for (mt = Modelist; mt->name; mt++) { 154027110Sminshall printf("%s\t%s\n", mt->name, mt->help); 154127110Sminshall } 154227110Sminshall return; 154327110Sminshall } 154427110Sminshall mt = getmodecmd(argv[1]); 154527110Sminshall if (mt == 0) { 154627110Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 1547*27186Sminshall } else if (mt == Ambiguous(struct cmd *)) { 154827110Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 154927110Sminshall } else { 155027110Sminshall (*mt->handler)(); 155127110Sminshall } 155227110Sminshall } 155327110Sminshall 155427110Sminshall /* 155527178Sminshall * The following data structures and routines implement the 155627178Sminshall * "display" command. 155727178Sminshall */ 155827178Sminshall 155927178Sminshall display(argc, argv) 156027178Sminshall int argc; 156127178Sminshall char *argv[]; 156227178Sminshall { 156327178Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 156427178Sminshall if (*tl->variable) { \ 156527178Sminshall printf("will"); \ 156627178Sminshall } else { \ 156727178Sminshall printf("won't"); \ 156827178Sminshall } \ 156927178Sminshall printf(" %s.\n", tl->actionexplanation); \ 157027178Sminshall } 157127178Sminshall 157227178Sminshall #define doset(sl) printf("[%s]\t%s.\n", control(*sl->charp), sl->name); 157327178Sminshall 157427178Sminshall struct togglelist *tl; 157527178Sminshall struct setlist *sl; 157627178Sminshall 157727178Sminshall if (argc == 1) { 157827178Sminshall for (tl = Togglelist; tl->name; tl++) { 157927178Sminshall dotog(tl); 158027178Sminshall } 158127178Sminshall for (sl = Setlist; sl->name; sl++) { 158227178Sminshall doset(sl); 158327178Sminshall } 158427178Sminshall } else { 158527178Sminshall int i; 158627178Sminshall 158727178Sminshall for (i = 1; i < argc; i++) { 158827178Sminshall sl = getset(argv[i]); 158927178Sminshall tl = gettoggle(argv[i]); 1590*27186Sminshall if ((sl == Ambiguous(struct setlist *)) || 1591*27186Sminshall (tl == Ambiguous(struct togglelist *))) { 159227178Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 159327178Sminshall } else if (!sl && !tl) { 159427178Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 159527178Sminshall } else { 1596*27186Sminshall if (tl) { 1597*27186Sminshall dotog(tl); 1598*27186Sminshall } 1599*27186Sminshall if (sl) { 1600*27186Sminshall doset(sl); 1601*27186Sminshall } 160227178Sminshall } 160327178Sminshall } 160427178Sminshall } 160527178Sminshall #undef doset(sl) 160627178Sminshall #undef dotog(tl) 160727178Sminshall } 160827178Sminshall 160927178Sminshall /* 161027088Sminshall * The following are the data structures, and many of the routines, 161127088Sminshall * relating to command processing. 161227088Sminshall */ 161327088Sminshall 161427088Sminshall /* 161527088Sminshall * Set the escape character. 161627088Sminshall */ 161727088Sminshall setescape(argc, argv) 161827088Sminshall int argc; 161927088Sminshall char *argv[]; 162027088Sminshall { 162127088Sminshall register char *arg; 162227088Sminshall char buf[50]; 162327088Sminshall 1624*27186Sminshall printf( 1625*27186Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 1626*27186Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 162727088Sminshall if (argc > 2) 162827088Sminshall arg = argv[1]; 162927088Sminshall else { 163027088Sminshall printf("new escape character: "); 163127088Sminshall gets(buf); 163227088Sminshall arg = buf; 163327088Sminshall } 163427088Sminshall if (arg[0] != '\0') 163527088Sminshall escape = arg[0]; 163627088Sminshall printf("Escape character is '%s'.\n", control(escape)); 163727088Sminshall fflush(stdout); 163827088Sminshall } 163927088Sminshall 164027088Sminshall /*VARARGS*/ 164127088Sminshall suspend() 164227088Sminshall { 164327110Sminshall setcommandmode(); 164427088Sminshall kill(0, SIGTSTP); 164527088Sminshall /* reget parameters in case they were changed */ 164627088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 164727088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 164827088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 164927088Sminshall } 165027088Sminshall 165127088Sminshall /*VARARGS*/ 165227088Sminshall bye() 165327088Sminshall { 165427088Sminshall register char *op; 165527088Sminshall 165627088Sminshall if (connected) { 165727088Sminshall shutdown(net, 2); 165827088Sminshall printf("Connection closed.\n"); 165927088Sminshall close(net); 166027088Sminshall connected = 0; 166127088Sminshall /* reset his options */ 166227088Sminshall for (op = hisopts; op < &hisopts[256]; op++) 166327088Sminshall *op = 0; 166427088Sminshall } 166527088Sminshall } 166627088Sminshall 166727088Sminshall /*VARARGS*/ 166827088Sminshall quit() 166927088Sminshall { 167027088Sminshall call(bye, "bye", 0); 167127088Sminshall exit(0); 167227088Sminshall } 167327088Sminshall 167427088Sminshall /* 167527088Sminshall * Print status about the connection. 167627088Sminshall */ 1677*27186Sminshall /*ARGSUSED*/ 167827178Sminshall status(argc, argv) 167927178Sminshall int argc; 168027178Sminshall char *argv[]; 168127088Sminshall { 168227178Sminshall if (connected) { 168327178Sminshall printf("Connected to %s.\n", hostname); 168427178Sminshall if (argc < 2) { 168527178Sminshall printf("Operating in %s.\n", modedescriptions[getconnmode()]); 168627178Sminshall if (localsigs || ((!donelclsigs) && (getconnmode() >= 3))) { 168727178Sminshall printf("Catching signals locally.\n"); 168827178Sminshall } 168927110Sminshall } 169027178Sminshall } else { 169127178Sminshall printf("No connection.\n"); 169227178Sminshall } 169327178Sminshall printf("Escape character is '%s'.\n", control(escape)); 169427178Sminshall fflush(stdout); 169527088Sminshall } 169627088Sminshall 169727088Sminshall tn(argc, argv) 169827088Sminshall int argc; 169927088Sminshall char *argv[]; 170027088Sminshall { 170127088Sminshall register struct hostent *host = 0; 170227088Sminshall 170327088Sminshall if (connected) { 170427088Sminshall printf("?Already connected to %s\n", hostname); 170527088Sminshall return; 170627088Sminshall } 170727088Sminshall if (argc < 2) { 1708*27186Sminshall (void) strcpy(line, "Connect "); 170927088Sminshall printf("(to) "); 171027088Sminshall gets(&line[strlen(line)]); 171127088Sminshall makeargv(); 171227088Sminshall argc = margc; 171327088Sminshall argv = margv; 171427088Sminshall } 171527088Sminshall if (argc > 3) { 171627088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 171727088Sminshall return; 171827088Sminshall } 171927088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 172027088Sminshall if (sin.sin_addr.s_addr != -1) { 172127088Sminshall sin.sin_family = AF_INET; 1722*27186Sminshall (void) strcpy(hnamebuf, argv[1]); 172327088Sminshall hostname = hnamebuf; 172427088Sminshall } else { 172527088Sminshall host = gethostbyname(argv[1]); 172627088Sminshall if (host) { 172727088Sminshall sin.sin_family = host->h_addrtype; 172827088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 172927088Sminshall host->h_length); 173027088Sminshall hostname = host->h_name; 173127088Sminshall } else { 173227088Sminshall printf("%s: unknown host\n", argv[1]); 173327088Sminshall return; 173427088Sminshall } 173527088Sminshall } 173627088Sminshall sin.sin_port = sp->s_port; 173727088Sminshall if (argc == 3) { 173827088Sminshall sin.sin_port = atoi(argv[2]); 1739*27186Sminshall if (sin.sin_port == 0) { 174027088Sminshall sp = getservbyname(argv[2], "tcp"); 174127088Sminshall if (sp) 174227088Sminshall sin.sin_port = sp->s_port; 174327088Sminshall else { 174427088Sminshall printf("%s: bad port number\n", argv[2]); 174527088Sminshall return; 174627088Sminshall } 174727088Sminshall } else { 174827088Sminshall sin.sin_port = atoi(argv[2]); 174927088Sminshall sin.sin_port = htons(sin.sin_port); 175027088Sminshall } 175127088Sminshall telnetport = 0; 175227110Sminshall } else { 175327110Sminshall telnetport = 1; 175427088Sminshall } 175527088Sminshall signal(SIGINT, intr); 175627110Sminshall signal(SIGQUIT, intr2); 175727088Sminshall signal(SIGPIPE, deadpeer); 175827088Sminshall printf("Trying...\n"); 175927088Sminshall do { 176027088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 176127088Sminshall if (net < 0) { 176227088Sminshall perror("telnet: socket"); 176327088Sminshall return; 176427088Sminshall } 1765*27186Sminshall if (debug && 1766*27186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, 1767*27186Sminshall (char *)&debug, sizeof(debug)) < 0) { 176827088Sminshall perror("setsockopt (SO_DEBUG)"); 1769*27186Sminshall } 1770*27186Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 177127088Sminshall if (host && host->h_addr_list[1]) { 177227088Sminshall int oerrno = errno; 177327088Sminshall 177427088Sminshall fprintf(stderr, 177527088Sminshall "telnet: connect to address %s: ", 177627088Sminshall inet_ntoa(sin.sin_addr)); 177727088Sminshall errno = oerrno; 1778*27186Sminshall perror((char *)0); 177927088Sminshall host->h_addr_list++; 178027088Sminshall bcopy(host->h_addr_list[0], 178127088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 178227088Sminshall fprintf(stderr, "Trying %s...\n", 178327088Sminshall inet_ntoa(sin.sin_addr)); 178427088Sminshall (void) close(net); 178527088Sminshall continue; 178627088Sminshall } 178727088Sminshall perror("telnet: connect"); 178827088Sminshall signal(SIGINT, SIG_DFL); 178927088Sminshall return; 179027088Sminshall } 179127088Sminshall connected++; 179227088Sminshall } while (connected == 0); 179327178Sminshall call(status, "status", "notmuch", 0); 179427088Sminshall if (setjmp(peerdied) == 0) 179527088Sminshall telnet(); 179627088Sminshall fprintf(stderr, "Connection closed by foreign host.\n"); 179727088Sminshall exit(1); 179827088Sminshall } 179927088Sminshall 180027088Sminshall 180127088Sminshall #define HELPINDENT (sizeof ("connect")) 180227088Sminshall 180327088Sminshall char openhelp[] = "connect to a site"; 180427088Sminshall char closehelp[] = "close current connection"; 180527088Sminshall char quithelp[] = "exit telnet"; 180627088Sminshall char zhelp[] = "suspend telnet"; 180727088Sminshall char escapehelp[] = "set escape character"; 180827088Sminshall char statushelp[] = "print status information"; 180927088Sminshall char helphelp[] = "print help information"; 181027110Sminshall char sendhelp[] = "transmit special characters ('send ?' for more)"; 181127178Sminshall char sethelp[] = "set operating parameters ('set ?' for more)"; 181227178Sminshall char togglestring[] ="toggle operating parameters ('toggle ?' for more)"; 181327178Sminshall char displayhelp[] = "display operating parameters"; 181427178Sminshall char modehelp[] = 181527178Sminshall "try to enter line-by-line or character-at-a-time mode"; 181627088Sminshall 181727088Sminshall int help(); 181827088Sminshall 181927088Sminshall struct cmd cmdtab[] = { 182027110Sminshall { "open", openhelp, tn, 1, 0 }, 182127110Sminshall { "close", closehelp, bye, 1, 1 }, 182227110Sminshall { "quit", quithelp, quit, 1, 0 }, 182327110Sminshall { "z", zhelp, suspend, 1, 0 }, 182427110Sminshall { "escape", escapehelp, setescape, 1, 0 }, 182527110Sminshall { "status", statushelp, status, 1, 0 }, 182627178Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 182727110Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 182827110Sminshall { "transmit", sendhelp, sendcmd, 0, 1 }, 182927110Sminshall { "xmit", sendhelp, sendcmd, 0, 1 }, 183027178Sminshall { "set", sethelp, setcmd, 1, 0 }, 183127110Sminshall { "toggle", togglestring, toggle, 1, 0 }, 183227178Sminshall { "display", displayhelp, display, 1, 0 }, 183327178Sminshall { "mode", modehelp, modecmd, 1, 1 }, 183427110Sminshall { "?", helphelp, help, 1, 0 }, 183527110Sminshall { "help", helphelp, help, 0, 0 }, 183627088Sminshall 0 183727088Sminshall }; 183827088Sminshall 183927088Sminshall 184027088Sminshall /* 184127088Sminshall * Help command. 184227088Sminshall */ 184327088Sminshall help(argc, argv) 184427088Sminshall int argc; 184527088Sminshall char *argv[]; 184627088Sminshall { 184727088Sminshall register struct cmd *c; 184827088Sminshall 184927088Sminshall if (argc == 1) { 185027088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 185127088Sminshall for (c = cmdtab; c->name; c++) 185227088Sminshall if (c->dohelp) { 185327088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 185427088Sminshall c->help); 185527088Sminshall } 185627088Sminshall return; 185727088Sminshall } 185827088Sminshall while (--argc > 0) { 185927088Sminshall register char *arg; 186027088Sminshall arg = *++argv; 186127088Sminshall c = getcmd(arg); 1862*27186Sminshall if (c == Ambiguous(struct cmd *)) 186327088Sminshall printf("?Ambiguous help command %s\n", arg); 186427088Sminshall else if (c == (struct cmd *)0) 186527088Sminshall printf("?Invalid help command %s\n", arg); 186627088Sminshall else 186727088Sminshall printf("%s\n", c->help); 186827088Sminshall } 186927088Sminshall } 187027088Sminshall /* 187127088Sminshall * Call routine with argc, argv set from args (terminated by 0). 187227088Sminshall * VARARGS2 187327088Sminshall */ 187427088Sminshall call(routine, args) 187527088Sminshall int (*routine)(); 1876*27186Sminshall char *args; 187727088Sminshall { 1878*27186Sminshall register char **argp; 187927088Sminshall register int argc; 188027088Sminshall 188127088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 188227088Sminshall ; 188327088Sminshall (*routine)(argc, &args); 188427088Sminshall } 188527088Sminshall 188627088Sminshall makeargv() 188727088Sminshall { 188827088Sminshall register char *cp; 188927088Sminshall register char **argp = margv; 189027088Sminshall 189127088Sminshall margc = 0; 189227088Sminshall for (cp = line; *cp;) { 189327088Sminshall while (isspace(*cp)) 189427088Sminshall cp++; 189527088Sminshall if (*cp == '\0') 189627088Sminshall break; 189727088Sminshall *argp++ = cp; 189827088Sminshall margc += 1; 189927088Sminshall while (*cp != '\0' && !isspace(*cp)) 190027088Sminshall cp++; 190127088Sminshall if (*cp == '\0') 190227088Sminshall break; 190327088Sminshall *cp++ = '\0'; 190427088Sminshall } 190527088Sminshall *argp++ = 0; 190627088Sminshall } 190727088Sminshall 190827088Sminshall char ** 190927088Sminshall getnextcmd(name) 191027088Sminshall char *name; 191127088Sminshall { 191227088Sminshall struct cmd *c = (struct cmd *) name; 191327088Sminshall 191427088Sminshall return (char **) (c+1); 191527088Sminshall } 191627088Sminshall 191727088Sminshall struct cmd * 191827088Sminshall getcmd(name) 191927088Sminshall char *name; 192027088Sminshall { 192127088Sminshall return (struct cmd *) genget(name, (char **) cmdtab, getnextcmd); 192227088Sminshall } 192327088Sminshall 192427088Sminshall command(top) 192527088Sminshall int top; 192627088Sminshall { 192727088Sminshall register struct cmd *c; 192827088Sminshall 192927110Sminshall setcommandmode(); 193027088Sminshall if (!top) 193127088Sminshall putchar('\n'); 193227088Sminshall else 193327088Sminshall signal(SIGINT, SIG_DFL); 193427088Sminshall for (;;) { 193527088Sminshall printf("%s> ", prompt); 193627088Sminshall if (gets(line) == 0) { 193727088Sminshall if (feof(stdin)) 193827088Sminshall quit(); 193927088Sminshall break; 194027088Sminshall } 194127088Sminshall if (line[0] == 0) 194227088Sminshall break; 194327088Sminshall makeargv(); 194427088Sminshall c = getcmd(margv[0]); 1945*27186Sminshall if (c == Ambiguous(struct cmd *)) { 194627088Sminshall printf("?Ambiguous command\n"); 194727088Sminshall continue; 194827088Sminshall } 194927088Sminshall if (c == 0) { 195027088Sminshall printf("?Invalid command\n"); 195127088Sminshall continue; 195227088Sminshall } 195327088Sminshall if (c->needconnect && !connected) { 195427088Sminshall printf("?Need to be connected first.\n"); 195527088Sminshall continue; 195627088Sminshall } 195727088Sminshall (*c->handler)(margc, margv); 195827088Sminshall if (c->handler != help) 195927088Sminshall break; 196027088Sminshall } 196127088Sminshall if (!top) { 196227110Sminshall if (!connected) { 196327088Sminshall longjmp(toplevel, 1); 196427110Sminshall /*NOTREACHED*/ 196527110Sminshall } 196627110Sminshall setconnmode(); 196727088Sminshall } 196827088Sminshall } 1969*27186Sminshall 1970*27186Sminshall /* 1971*27186Sminshall * main. Parse arguments, invoke the protocol or command parser. 1972*27186Sminshall */ 1973*27186Sminshall 1974*27186Sminshall 1975*27186Sminshall main(argc, argv) 1976*27186Sminshall int argc; 1977*27186Sminshall char *argv[]; 1978*27186Sminshall { 1979*27186Sminshall sp = getservbyname("telnet", "tcp"); 1980*27186Sminshall if (sp == 0) { 1981*27186Sminshall fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1982*27186Sminshall exit(1); 1983*27186Sminshall } 1984*27186Sminshall NetTrace = stdout; 1985*27186Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 1986*27186Sminshall ioctl(0, TIOCGETC, (char *)&otc); 1987*27186Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 1988*27186Sminshall ntc = otc; 1989*27186Sminshall ntc.t_eofc = -1; /* we don't want to use EOF */ 1990*27186Sminshall nttyb = ottyb; 1991*27186Sminshall setbuf(stdin, (char *)0); 1992*27186Sminshall setbuf(stdout, (char *)0); 1993*27186Sminshall prompt = argv[0]; 1994*27186Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 1995*27186Sminshall debug = 1; 1996*27186Sminshall argv++; 1997*27186Sminshall argc--; 1998*27186Sminshall } 1999*27186Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 2000*27186Sminshall argv++; 2001*27186Sminshall argc--; 2002*27186Sminshall if (argc > 1) { /* get file name */ 2003*27186Sminshall NetTrace = fopen(argv[1], "w"); 2004*27186Sminshall argv++; 2005*27186Sminshall argc--; 2006*27186Sminshall if (NetTrace == NULL) { 2007*27186Sminshall NetTrace = stdout; 2008*27186Sminshall } 2009*27186Sminshall } 2010*27186Sminshall } 2011*27186Sminshall if (argc != 1) { 2012*27186Sminshall if (setjmp(toplevel) != 0) 2013*27186Sminshall exit(0); 2014*27186Sminshall tn(argc, argv); 2015*27186Sminshall } 2016*27186Sminshall setjmp(toplevel); 2017*27186Sminshall for (;;) 2018*27186Sminshall command(1); 2019*27186Sminshall } 2020