SCCS-vsn: usr.bin/telnet/telnet.c 5.11
#endif not lint
#ifndef lint
#endif not lint
#ifndef lint
-static char sccsid[] = "@(#)telnet.c 5.10 (Berkeley) %G%";
+static char sccsid[] = "@(#)telnet.c 5.11 (Berkeley) %G%";
-#define strip(x) ((x)&0x3f)
+#define strip(x) ((x)&0x7f)
-char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
-#define TTYADD(c) { if (!SYNCHing) { *tfrontp++ = c; } }
+char ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
+#define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
+#define TTYLOC() (tfrontp)
+#define TTYMAX() (ttyobuf+sizeof ttyobuf-1)
+#define TTYMIN() (netobuf)
+#define TTYBYTES() (tfrontp-tbackp)
+#define TTYROOM() (TTYMAX()-TTYLOC()+1)
-char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
+char netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
#define NETADD(c) { *nfrontp++ = c; }
#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); }
#define NETLOC() (nfrontp)
#define NETADD(c) { *nfrontp++ = c; }
#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); }
#define NETLOC() (nfrontp)
+#define NETMAX() (netobuf+sizeof netobuf-1)
+#define NETBYTES() (nfrontp-nbackp)
+#define NETROOM() (NETMAX()-NETLOC()+1)
char *neturg = 0; /* one past last byte of urgent data */
char hisopts[256];
char *neturg = 0; /* one past last byte of urgent data */
char hisopts[256];
int SYNCHing = 0; /* we are in TELNET SYNCH mode */
int flushout = 0; /* flush output */
int SYNCHing = 0; /* we are in TELNET SYNCH mode */
int flushout = 0; /* flush output */
+int autoflush = 0; /* flush output when interrupting? */
int autosynch = 0; /* send interrupt characters with SYNCH? */
int localsigs = 0; /* we recognize interrupt/quit */
int donelclsigs = 0; /* the user has set "localsigs" */
int autosynch = 0; /* send interrupt characters with SYNCH? */
int localsigs = 0; /* we recognize interrupt/quit */
int donelclsigs = 0; /* the user has set "localsigs" */
struct servent *sp;
struct tchars otc, ntc;
struct servent *sp;
struct tchars otc, ntc;
+struct ltchars oltc, nltc;
struct sgttyb ottyb, nttyb;
int globalmode = 0;
int flushline = 1;
struct sgttyb ottyb, nttyb;
int globalmode = 0;
int flushline = 1;
case '^':
b = *++s;
if (b == '?') {
case '^':
b = *++s;
if (b == '?') {
- c = b | 0x80; /* DEL */
+ c = b | 0x40; /* DEL */
return ("^?");
if (c == '\377') {
return "off";
return ("^?");
if (c == '\377') {
return "off";
int n;
if ((n = tfrontp - tbackp) > 0) {
int n;
if ((n = tfrontp - tbackp) > 0) {
+ if (!(SYNCHing||flushout)) {
n = write(tout, tbackp, n);
} else {
ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
n = write(tout, tbackp, n);
} else {
ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
+ /* we leave 'n' alone! */
{
if (localsigs) {
intp();
{
if (localsigs) {
intp();
- if (autosynch) {
- dosynch();
- }
return;
}
setcommandmode();
return;
}
setcommandmode();
{
if (localsigs) {
sendbrk();
{
if (localsigs) {
sendbrk();
- if (autosynch) {
- dosynch();
- }
* Mode - set up terminal to a specific mode.
*/
* Mode - set up terminal to a specific mode.
*/
-struct tchars notc = { -1, -1, -1, -1, -1, -1 };
-struct tchars notc2;
-struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
-struct ltchars noltc2;
struct ltchars *ltc;
struct sgttyb sb;
int onoff, old;
struct ltchars *ltc;
struct sgttyb sb;
int onoff, old;
+ struct tchars notc2;
+ struct ltchars noltc2;
+ static struct tchars notc = { -1, -1, -1, -1, -1, -1 };
+ static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
globalmode = f;
if (prevmode == f)
globalmode = f;
if (prevmode == f)
* If user hasn't specified one way or the other,
* then default to not trapping signals.
*/
* If user hasn't specified one way or the other,
* then default to not trapping signals.
*/
if (localsigs) {
notc2 = notc;
notc2.t_intrc = ntc.t_intrc;
notc2.t_quitc = ntc.t_quitc;
if (localsigs) {
notc2 = notc;
notc2.t_intrc = ntc.t_intrc;
notc2.t_quitc = ntc.t_quitc;
- notc2.t_eofc = ntc.t_eofc;
tc = ¬c2;
} else
tc = ¬c;
tc = ¬c2;
} else
tc = ¬c;
sb.sg_flags |= ECHO;
else
sb.sg_flags &= ~ECHO;
sb.sg_flags |= ECHO;
else
sb.sg_flags &= ~ECHO;
+ notc2 = ntc;
+ tc = ¬c2;
+ noltc2 = oltc;
+ ltc = &noltc2;
/*
* If user hasn't specified one way or the other,
* then default to trapping signals.
*/
/*
* If user hasn't specified one way or the other,
* then default to trapping signals.
*/
- if (localsigs)
- tc = &ntc;
- else {
- notc2 = ntc;
+ }
+ if (localsigs) {
+ notc2.t_brkc = nltc.t_flushc;
+ noltc2.t_flushc = -1;
+ } else {
notc2.t_intrc = notc2.t_quitc = -1;
notc2.t_intrc = notc2.t_quitc = -1;
noltc2.t_suspc = escape;
noltc2.t_dsuspc = -1;
noltc2.t_suspc = escape;
noltc2.t_dsuspc = -1;
char tibuf[BUFSIZ], *tbp;
int scc, tcc;
char tibuf[BUFSIZ], *tbp;
int scc, tcc;
/*
* Select from tty and network...
*/
/*
* Select from tty and network...
*/
tout = fileno(stdout);
setconnmode();
tout = fileno(stdout);
setconnmode();
ioctl(net, FIONBIO, (char *)&on);
ioctl(net, FIONBIO, (char *)&on);
-#if defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY)
- ioctl(net, asdf, asdf); /* handle urgent data in band */
-#endif /* defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */
+#if defined(xxxSO_OOBINLINE)
+ setsockopt(net, SOL_SOCKET, SO_OOBINLINE, on, sizeof on);
+#endif /* defined(xxxSO_OOBINLINE) */
if (telnetport && !hisopts[TELOPT_SGA]) {
willoption(TELOPT_SGA);
}
if (telnetport && !hisopts[TELOPT_SGA]) {
willoption(TELOPT_SGA);
}
FD_ZERO(&obits);
FD_ZERO(&xbits);
FD_ZERO(&obits);
FD_ZERO(&xbits);
- if (((globalmode < 4) || flushline) && (nfrontp - nbackp)) {
+ if (((globalmode < 4) || flushline) && NETBYTES()) {
FD_SET(net, &obits);
} else {
FD_SET(tin, &ibits);
}
FD_SET(net, &obits);
} else {
FD_SET(tin, &ibits);
}
- if (tfrontp - tbackp) {
FD_SET(tout, &obits);
} else {
FD_SET(net, &ibits);
FD_SET(tout, &obits);
} else {
FD_SET(net, &ibits);
* Something to read from the network...
*/
if (FD_ISSET(net, &ibits)) {
* Something to read from the network...
*/
if (FD_ISSET(net, &ibits)) {
-#if !defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY)
+ int canread;
+
+ if (scc == 0) {
+ sbp = sibuf;
+ }
+ canread = sibuf + sizeof sibuf - sbp;
+#if !defined(xxxSO_OOBINLINE)
/*
* In 4.2 (and some early 4.3) systems, the
* OOB indication and data handling in the kernel
/*
* In 4.2 (and some early 4.3) systems, the
* OOB indication and data handling in the kernel
ioctl(net, SIOCATMARK, (char *)&atmark);
if (atmark) {
ioctl(net, SIOCATMARK, (char *)&atmark);
if (atmark) {
- scc = recv(net, sibuf, sizeof (sibuf), MSG_OOB);
- if ((scc == -1) && (errno == EINVAL)) {
- scc = read(net, sibuf, sizeof (sibuf));
+ c = recv(net, sibuf, canread, MSG_OOB);
+ if ((c == -1) && (errno == EINVAL)) {
+ c = read(net, sibuf, canread);
if (clocks.didnetreceive < clocks.gotDM) {
SYNCHing = stilloob(net);
}
}
} else {
if (clocks.didnetreceive < clocks.gotDM) {
SYNCHing = stilloob(net);
}
}
} else {
- scc = read(net, sibuf, sizeof (sibuf));
+ c = read(net, sibuf, canread);
- scc = read(net, sibuf, sizeof (sibuf));
+ c = read(net, sibuf, canread);
}
settimer(didnetreceive);
}
settimer(didnetreceive);
-#else /* !defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */
- scc = read(net, sibuf, sizeof (sibuf));
-#endif /* !defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */
- if (scc < 0 && errno == EWOULDBLOCK)
- scc = 0;
- else {
- if (scc <= 0) {
- break;
- }
- sbp = sibuf;
- if (netdata) {
- Dump('<', sbp, scc);
- }
+#else /* !defined(xxxSO_OOBINLINE) */
+ c = read(net, sbp, canread);
+#endif /* !defined(xxxSO_OOBINLINE) */
+ if (c < 0 && errno == EWOULDBLOCK) {
+ c = 0;
+ } else if (c <= 0) {
+ break;
+ if (netdata) {
+ Dump('<', sbp, c);
+ }
+ scc += c;
}
/*
* Something to read from the tty...
*/
if (FD_ISSET(tin, &ibits)) {
}
/*
* Something to read from the tty...
*/
if (FD_ISSET(tin, &ibits)) {
- tcc = read(tin, tibuf, sizeof (tibuf));
- if (tcc < 0 && errno == EWOULDBLOCK)
- tcc = 0;
- else {
- if (tcc <= 0)
- break;
- tbp = tibuf;
+ if (tcc == 0) {
+ tbp = tibuf; /* nothing left, reset */
+ }
+ c = read(tin, tbp, tibuf+sizeof tibuf - tbp);
+ if (c < 0 && errno == EWOULDBLOCK) {
+ c = 0;
+ } else if (c <= 0) {
+ tcc = c;
+ break;
}
while (tcc > 0) {
register int sc;
}
while (tcc > 0) {
register int sc;
- if ((&netobuf[BUFSIZ] - nfrontp) < 2) {
} else if (sc == ntc.t_quitc) {
sendbrk();
break;
} else if (sc == ntc.t_quitc) {
sendbrk();
break;
+ } else if (sc == nltc.t_flushc) {
+ NET2ADD(IAC, AO);
+ if (autoflush) {
+ doflush();
+ }
+ break;
} else if (globalmode > 2) {
;
} else if (sc == nttyb.sg_kill) {
} else if (globalmode > 2) {
;
} else if (sc == nttyb.sg_kill) {
}
}
if (((globalmode < 4) || flushline) &&
}
}
if (((globalmode < 4) || flushline) &&
- (FD_ISSET(net, &obits) && (nfrontp - nbackp) > 0)) {
+ FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
netflush(net);
}
if (scc > 0)
telrcv();
netflush(net);
}
if (scc > 0)
telrcv();
- if (FD_ISSET(tout, &obits) && (tfrontp - tbackp) > 0)
+ if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0))
ttyflush();
}
setcommandmode();
ttyflush();
}
setcommandmode();
register int c;
static int state = TS_DATA;
register int c;
static int state = TS_DATA;
+ while ((scc > 0) && (TTYROOM() > 2)) {
c = *sbp++ & 0xff, scc--;
switch (state) {
case TS_CR:
state = TS_DATA;
c = *sbp++ & 0xff, scc--;
switch (state) {
case TS_CR:
state = TS_DATA;
- if ((c == '\0') || (c == '\n')) {
- break; /* by now, we ignore \n */
+ if (c == '\0') {
+ break; /* Ignore \0 after CR */
+ } else if (c == '\n') {
+ if (hisopts[TELOPT_ECHO] && !crmod) {
+ TTYADD(c);
+ }
+ break;
+ /* Else, fall through */
case TS_DATA:
if (c == IAC) {
state = TS_IAC;
continue;
}
case TS_DATA:
if (c == IAC) {
state = TS_IAC;
continue;
}
+ /*
+ * The 'crmod' hack (see following) is needed
+ * since we can't * set CRMOD on output only.
+ * Machines like MULTICS like to send \r without
+ * \n; since we must turn off CRMOD to get proper
+ * input, the mapping is done here (sigh).
+ */
if (c == '\r') {
if (scc > 0) {
c = *sbp&0xff;
if (c == 0) {
sbp++, scc--;
if (c == '\r') {
if (scc > 0) {
c = *sbp&0xff;
if (c == 0) {
sbp++, scc--;
- /*
- * The following hack is needed since we can't
- * set CRMOD on output only. Machines like
- * MULTICS like to send \r without \n; since
- * we must turn off CRMOD to get proper input,
- * the mapping is done here (sigh).
- */
- if (crmod) {
- TTYADD('\n');
- }
} else if (!hisopts[TELOPT_ECHO] &&
(c == '\n')) {
sbp++, scc--;
TTYADD('\n');
} else {
TTYADD('\r');
} else if (!hisopts[TELOPT_ECHO] &&
(c == '\n')) {
sbp++, scc--;
TTYADD('\n');
} else {
TTYADD('\r');
+ if (crmod) {
+ TTYADD('\n');
+ }
}
} else {
state = TS_CR;
TTYADD('\r');
}
} else {
state = TS_CR;
TTYADD('\r');
+ if (crmod) {
+ TTYADD('\n');
+ }
neturg = NETLOC()-1; /* Some systems are off by one XXX */
}
neturg = NETLOC()-1; /* Some systems are off by one XXX */
}
+doflush()
+{
+ /* This shouldn't really be here... */
+ NET2ADD(IAC, DO);
+ NETADD(TELOPT_TM);
+ printoption("SENT", doopt, TELOPT_TM);
+ flushline = 1;
+ flushout = 1;
+ ttyflush();
+}
+
intp()
{
NET2ADD(IAC, IP);
intp()
{
NET2ADD(IAC, IP);
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch();
+ }
-#if 0
- /*
- * There is a question here. Should we send a TM to flush the stream?
- * Should we also send a TELNET SYNCH also?
- */
- *nfrontp++ = IAC;
- *nfrontp++ = DO;
- *nfrontp++ = TELOPT_TM;
- flushout = 1;
- printoption("SENT", doopt, TELOPT_TM);
-#endif /* 0 */
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch();
+ }
}
}
/* Now, do we have enough room? */
}
}
/* Now, do we have enough room? */
- if (netobuf+sizeof netobuf-nfrontp-1 < count) {
+ if (NETROOM() < count) {
printf("There is not enough room in the buffer TO the network\n");
printf("to process your request. Nothing will be done.\n");
printf("('send synch' will throw away most data in the network\n");
printf("There is not enough room in the buffer TO the network\n");
printf("to process your request. Nothing will be done.\n");
printf("('send synch' will throw away most data in the network\n");
1,
&autosynch,
"send interrupt characters in urgent mode" },
1,
&autosynch,
"send interrupt characters in urgent mode" },
+ { "autoflush",
+ "toggle automatic flushing of output when sending interrupt characters",
+ 0,
+ 1,
+ &autoflush,
+ "flush output when sending interrupt characters" },
struct setlist Setlist[] = {
{ "echo", "character to toggle local echoing on/off", &echoc },
{ "escape", "character to escape back to telnet command mode", &escape },
struct setlist Setlist[] = {
{ "echo", "character to toggle local echoing on/off", &echoc },
{ "escape", "character to escape back to telnet command mode", &escape },
+ { "\200", "" },
+ { "\200", "The following need 'localsigs' to be toggled true", 0 },
{ "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
{ "quit", "character to cause a Break", &ntc.t_quitc },
{ "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
{ "quit", "character to cause a Break", &ntc.t_quitc },
+ { "flush output", "character to cause an Abort Oubput", &nltc.t_flushc },
{ "erase", "character to cause an Erase Character", &nttyb.sg_erase },
{ "kill", "character to cause an Erase Line", &nttyb.sg_kill },
{ 0 }
{ "erase", "character to cause an Erase Character", &nttyb.sg_erase },
{ "kill", "character to cause an Erase Line", &nttyb.sg_kill },
{ 0 }
printf("Connected to %s.\n", hostname);
if (argc < 2) {
printf("Operating in %s.\n", modedescriptions[getconnmode()]);
printf("Connected to %s.\n", hostname);
if (argc < 2) {
printf("Operating in %s.\n", modedescriptions[getconnmode()]);
- if (localsigs || ((!donelclsigs) && (getconnmode() >= 3))) {
printf("Catching signals locally.\n");
}
}
printf("Catching signals locally.\n");
}
}
ioctl(0, TIOCGETP, (char *)&ottyb);
ioctl(0, TIOCGETC, (char *)&otc);
ioctl(0, TIOCGLTC, (char *)&oltc);
ioctl(0, TIOCGETP, (char *)&ottyb);
ioctl(0, TIOCGETC, (char *)&otc);
ioctl(0, TIOCGLTC, (char *)&oltc);
+#if defined(LNOFLSH)
+ ioctl(0, TIOCLGET, (char *)&autoflush);
+ autoflush &= LNOFLSH;
+#endif /* LNOFLSH */
ntc = otc;
ntc.t_eofc = -1; /* we don't want to use EOF */
ntc = otc;
ntc.t_eofc = -1; /* we don't want to use EOF */
nttyb = ottyb;
setbuf(stdin, (char *)0);
setbuf(stdout, (char *)0);
nttyb = ottyb;
setbuf(stdin, (char *)0);
setbuf(stdout, (char *)0);