/*
- * Copyright (c) 1988 Regents of the University of California.
+ * Copyright (c) 1988, 1990 Regents of the University of California.
* All rights reserved.
*
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
#ifndef lint
-static char sccsid[] = "@(#)telnet.c 5.44 (Berkeley) %G%";
+static char sccsid[] = "@(#)telnet.c 5.53 (Berkeley) 3/22/91";
#endif /* not lint */
#include <sys/types.h>
#include <arpa/telnet.h>
-#if defined(unix)
-#include <strings.h>
-#else /* defined(unix) */
-#include <string.h>
-#endif /* defined(unix) */
-
#include <ctype.h>
#include "ring.h"
\f
#define strip(x) ((x)&0x7f)
-
-static char subbuffer[SUBBUFSIZE],
- *subpointer, *subend; /* buffer for sub-options */
+static unsigned char subbuffer[SUBBUFSIZE],
+ *subpointer, *subend; /* buffer for sub-options */
#define SB_CLEAR() subpointer = subbuffer;
-#define SB_TERM() subend = subpointer;
+#define SB_TERM() { subend = subpointer; SB_CLEAR(); }
#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
*subpointer++ = (c); \
}
+#define SB_GET() ((*subpointer++)&0xff)
+#define SB_PEEK() ((*subpointer)&0xff)
+#define SB_EOF() (subpointer >= subend)
+#define SB_LEN() (subend - subpointer)
+
char options[256]; /* The combined options */
char do_dont_resp[256];
char will_wont_resp[256];
int
+ eight = 0,
+ autologin = 0, /* Autologin anyone? */
+ skiprc = 0,
connected,
showoptions,
In3270, /* Are we in 3270 mode? */
dontlecho, /* do we suppress local echoing right now? */
globalmode;
-#define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */
+char *prompt = 0;
-unsigned char
- *prompt = 0,
- escape,
- echoc;
+cc_t escape;
+cc_t rlogin;
+#ifdef KLUDGELINEMODE
+cc_t echoc;
+#endif
/*
* Telnet receiver states for fsm
* Initialize telnet environment.
*/
+ void
init_telnet()
{
+ env_init();
+
SB_CLEAR();
ClearArray(options);
connected = In3270 = ISend = localflow = donebinarytoggle = 0;
+#if defined(ENCRYPT) || defined(AUTHENTICATE)
+ auth_encrypt_connect(connected);
+#endif
SYNCHing = 0;
/* Don't change NetTrace */
escape = CONTROL(']');
+ rlogin = _POSIX_VDISABLE;
+#ifdef KLUDGELINEMODE
echoc = CONTROL('E');
+#endif
flushline = 1;
telrcv_state = TS_DATA;
}
\f
+#ifdef notdef
#include <varargs.h>
-/*VARARGS*/
-static void
+ /*VARARGS*/
+ static void
printring(va_alist)
-va_dcl
+ va_dcl
{
va_list ap;
char buffer[100]; /* where things go */
}
ring_supply_data(ring, buffer, ptr-buffer);
}
+#endif
/*
* These routines are in charge of sending option negotiations
* is in disagreement as to what the current state should be.
*/
+ void
send_do(c, init)
-register int c, init;
+ register int c, init;
{
if (init) {
if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
}
NET2ADD(IAC, DO);
NETADD(c);
- printoption("SENT", "do", c);
+ printoption("SENT", DO, c);
}
-void
+ void
send_dont(c, init)
-register int c, init;
+ register int c, init;
{
if (init) {
if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
}
NET2ADD(IAC, DONT);
NETADD(c);
- printoption("SENT", "dont", c);
+ printoption("SENT", DONT, c);
}
-void
+ void
send_will(c, init)
-register int c, init;
+ register int c, init;
{
if (init) {
if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
}
NET2ADD(IAC, WILL);
NETADD(c);
- printoption("SENT", "will", c);
+ printoption("SENT", WILL, c);
}
-void
+ void
send_wont(c, init)
-register int c, init;
+ register int c, init;
{
if (init) {
if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
}
NET2ADD(IAC, WONT);
NETADD(c);
- printoption("SENT", "wont", c);
+ printoption("SENT", WONT, c);
}
-void
+ void
willoption(option)
int option;
{
- char *fmt;
int new_state_ok = 0;
if (do_dont_resp[option]) {
settimer(modenegotiated);
/* FALL THROUGH */
case TELOPT_STATUS:
+#if defined(AUTHENTICATE)
+ case TELOPT_AUTHENTICATION:
+#endif
+#if defined(ENCRYPT)
+ case TELOPT_ENCRYPT:
+#endif
new_state_ok = 1;
break;
}
}
set_my_state_do(option);
+#if defined(ENCRYPT)
+ if (option == TELOPT_ENCRYPT)
+ encrypt_send_support();
+#endif
}
-void
+ void
wontoption(option)
int option;
{
- char *fmt;
-
if (do_dont_resp[option]) {
--do_dont_resp[option];
if (do_dont_resp[option] && my_state_is_dont(option))
break;
}
set_my_want_state_dont(option);
- send_dont(option, 0);
+ if (my_state_is_do(option))
+ send_dont(option, 0);
setconnmode(0); /* Set new tty mode */
} else if (option == TELOPT_TM) {
/*
set_my_state_dont(option);
}
-static void
+ static void
dooption(option)
int option;
{
- char *fmt;
int new_state_ok = 0;
if (will_wont_resp[option]) {
case TELOPT_LFLOW: /* local flow control */
case TELOPT_TTYPE: /* terminal type option */
case TELOPT_SGA: /* no big deal */
+ case TELOPT_ENVIRON: /* environment variable option */
+#if defined(ENCRYPT)
+ case TELOPT_ENCRYPT: /* encryption variable option */
+#endif
new_state_ok = 1;
break;
+#if defined(AUTHENTICATE)
+ case TELOPT_AUTHENTICATION:
+ if (autologin)
+ new_state_ok = 1;
+ break;
+#endif
+
+ case TELOPT_XDISPLOC: /* X Display location */
+ if (env_getvalue((unsigned char *)"DISPLAY"))
+ new_state_ok = 1;
+ break;
case TELOPT_LINEMODE:
#ifdef KLUDGELINEMODE
kludgelinemode = 0;
+ send_do(TELOPT_SGA, 1);
#endif
set_my_want_state_will(TELOPT_LINEMODE);
send_will(option, 0);
if (new_state_ok) {
set_my_want_state_will(option);
send_will(option, 0);
+ setconnmode(0); /* Set new tty mode */
} else {
will_wont_resp[option]++;
send_wont(option, 0);
case TELOPT_LINEMODE:
#ifdef KLUDGELINEMODE
kludgelinemode = 0;
+ send_do(TELOPT_SGA, 1);
#endif
set_my_state_will(option);
slc_init();
+ send_do(TELOPT_SGA, 0);
return;
}
}
set_my_state_will(option);
}
-static void
+ static void
dontoption(option)
int option;
{
}
/* we always accept a DONT */
set_my_want_state_wont(option);
- send_wont(option, 0);
+ if (my_state_is_will(option))
+ send_wont(option, 0);
setconnmode(0); /* Set new tty mode */
}
set_my_state_wont(option);
* duplicate, or verbose names (names with spaces).
*/
-static char *unknown[] = { "UNKNOWN", 0 };
+static char *name_unknown = "UNKNOWN";
+static char *unknown[] = { 0, 0 };
-char **
+ char **
mklist(buf, name)
-char *buf, *name;
+ char *buf, *name;
{
register int n;
- register char c, *cp, **argvp, *cp2, **argv;
- char *malloc();
+ register char c, *cp, **argvp, *cp2, **argv, **avt;
if (name) {
- if (strlen(name) > 40)
+ if (strlen(name) > 40) {
name = 0;
- else {
+ unknown[0] = name_unknown;
+ } else {
unknown[0] = name;
upcase(name);
}
- }
+ } else
+ unknown[0] = name_unknown;
/*
* Count up the number of names.
*/
* only 2 characters long, move it to the end of the array.
*/
if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
+ --argvp;
+ for (avt = &argv[1]; avt < argvp; avt++)
+ *avt = *(avt+1);
*argvp++ = buf;
- cp = *argv++;
- *argv = cp;
}
/*
if (*argv == 0) {
if (name)
*argv = name;
- else
- argv++;
+ else {
+ --argvp;
+ for (avt = argv; avt < argvp; avt++)
+ *avt = *(avt+1);
+ }
}
if (*argv)
return(argv);
return(unknown);
}
+ int
is_unique(name, as, ae)
-register char *name, **as, **ae;
+ register char *name, **as, **ae;
{
register char **ap;
register int n;
#ifdef TERMCAP
char termbuf[1024];
+
+ /*ARGSUSED*/
+ int
setupterm(tname, fd, errp)
-char *tname;
-int fd, *errp;
+ char *tname;
+ int fd, *errp;
{
if (tgetent(termbuf, tname) == 1) {
termbuf[1023] = '\0';
extern char ttytype[];
#endif
-char *
+int resettermname = 1;
+
+ char *
gettermname()
{
char *tname;
- static int first = 1;
- static char **tnamep;
+ static char **tnamep = 0;
static char **next;
- char *getenv();
int err;
- if (first) {
- first = 0;
- if ((tname = getenv("TERM")) &&
+ if (resettermname) {
+ resettermname = 0;
+ if (tnamep && tnamep != unknown)
+ free(tnamep);
+ if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
(setupterm(tname, 1, &err) == 0)) {
tnamep = mklist(termbuf, tname);
} else {
if (tname && (strlen(tname) <= 40)) {
unknown[0] = tname;
upcase(tname);
- }
+ } else
+ unknown[0] = name_unknown;
tnamep = unknown;
}
next = tnamep;
* Linemode
*/
-static void
+ static void
suboption()
{
- printsub('<', subbuffer, subend-subbuffer+2);
- switch (subbuffer[0]&0xff) {
+ printsub('<', subbuffer, SB_LEN()+2);
+ switch (SB_GET()) {
case TELOPT_TTYPE:
if (my_want_state_is_wont(TELOPT_TTYPE))
return;
- if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
- ;
+ if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
+ return;
} else {
char *name;
- extern char *getenv();
- char temp[50];
+ unsigned char temp[50];
int len;
#if defined(TN3270)
name = gettermname();
len = strlen(name) + 4 + 2;
if (len < NETROOM()) {
- sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+ sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
TELQUAL_IS, name, IAC, SE);
ring_supply_data(&netoring, temp, len);
printsub('>', &temp[2], len-2);
case TELOPT_TSPEED:
if (my_want_state_is_wont(TELOPT_TSPEED))
return;
- if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
- long ospeed,ispeed;
- char temp[50];
+ if (SB_EOF())
+ return;
+ if (SB_GET() == TELQUAL_SEND) {
+ long ospeed, ispeed;
+ unsigned char temp[50];
int len;
TerminalSpeeds(&ispeed, &ospeed);
- sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
+ sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
TELQUAL_IS, ospeed, ispeed, IAC, SE);
- len = strlen(temp+4) + 4; /* temp[3] is 0 ... */
+ len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
if (len < NETROOM()) {
ring_supply_data(&netoring, temp, len);
printsub('>', temp+2, len - 2);
}
+/*@*/ else printf("lm_will: not enough room in buffer\n");
}
break;
case TELOPT_LFLOW:
if (my_want_state_is_wont(TELOPT_LFLOW))
return;
- if ((subbuffer[1]&0xff) == 1) {
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case 1:
localflow = 1;
- } else if ((subbuffer[1]&0xff) == 0) {
+ break;
+ case 0:
localflow = 0;
+ break;
+ default:
+ return;
}
setcommandmode();
setconnmode(0);
case TELOPT_LINEMODE:
if (my_want_state_is_wont(TELOPT_LINEMODE))
return;
- switch (subbuffer[1]&0xff) {
+ if (SB_EOF())
+ return;
+ switch (SB_GET()) {
case WILL:
- lm_will(&subbuffer[2], subend - &subbuffer[2]);
+ lm_will(subpointer, SB_LEN());
break;
case WONT:
- lm_wont(&subbuffer[2], subend - &subbuffer[2]);
+ lm_wont(subpointer, SB_LEN());
break;
case DO:
- lm_do(&subbuffer[2], subend - &subbuffer[2]);
+ lm_do(subpointer, SB_LEN());
break;
case DONT:
- lm_dont(&subbuffer[2], subend - &subbuffer[2]);
+ lm_dont(subpointer, SB_LEN());
break;
case LM_SLC:
- slc(&subbuffer[2], subend - &subbuffer[2]);
+ slc(subpointer, SB_LEN());
break;
case LM_MODE:
- lm_mode(&subbuffer[2], subend - &subbuffer[2], 0);
+ lm_mode(subpointer, SB_LEN(), 0);
break;
default:
+ break;
+ }
+ break;
+
+ case TELOPT_ENVIRON:
+ if (SB_EOF())
+ return;
+ switch(SB_PEEK()) {
+ case TELQUAL_IS:
+ case TELQUAL_INFO:
+ if (my_want_state_is_dont(TELOPT_ENVIRON))
+ return;
+ break;
+ case TELQUAL_SEND:
+ if (my_want_state_is_wont(TELOPT_ENVIRON)) {
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ env_opt(subpointer, SB_LEN());
+ break;
+
+ case TELOPT_XDISPLOC:
+ if (my_want_state_is_wont(TELOPT_XDISPLOC))
+ return;
+ if (SB_EOF())
+ return;
+ if (SB_GET() == TELQUAL_SEND) {
+ unsigned char temp[50], *dp;
+ int len;
+
+ if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
+ /*
+ * Something happened, we no longer have a DISPLAY
+ * variable. So, turn off the option.
+ */
+ send_wont(TELOPT_XDISPLOC, 1);
break;
+ }
+ sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
+ TELQUAL_IS, dp, IAC, SE);
+ len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
+
+ if (len < NETROOM()) {
+ ring_supply_data(&netoring, temp, len);
+ printsub('>', temp+2, len - 2);
+ }
+/*@*/ else printf("lm_will: not enough room in buffer\n");
+ }
+ break;
+
+#if defined(AUTHENTICATE)
+ case TELOPT_AUTHENTICATION: {
+ if (!autologin)
+ break;
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case TELQUAL_IS:
+ if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
+ return;
+ auth_is(subpointer, SB_LEN());
+ break;
+ case TELQUAL_SEND:
+ if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+ return;
+ auth_send(subpointer, SB_LEN());
+ break;
+ case TELQUAL_REPLY:
+ if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+ return;
+ auth_reply(subpointer, SB_LEN());
+ break;
+ case TELQUAL_NAME:
+ if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
+ return;
+ auth_name(subpointer, SB_LEN());
+ break;
+ }
}
break;
+#endif
+#if defined(ENCRYPT)
+ case TELOPT_ENCRYPT:
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case ENCRYPT_START:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_END:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_end();
+ break;
+ case ENCRYPT_SUPPORT:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_support(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REQSTART:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_request_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REQEND:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ /*
+ * We can always send an REQEND so that we cannot
+ * get stuck encrypting. We should only get this
+ * if we have been able to get in the correct mode
+ * anyhow.
+ */
+ encrypt_request_end();
+ break;
+ case ENCRYPT_IS:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_is(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REPLY:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_reply(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_ENC_KEYID:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_enc_keyid(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_DEC_KEYID:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_dec_keyid(subpointer, SB_LEN());
+ break;
+ default:
+ break;
+ }
+ break;
+#endif
default:
break;
}
}
-static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
+static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
+ void
lm_will(cmd, len)
-char *cmd;
+ unsigned char *cmd;
+ int len;
{
+ if (len < 1) {
+/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
+ return;
+ }
switch(cmd[0]) {
case LM_FORWARDMASK: /* We shouldn't ever get this... */
default:
}
}
+ void
lm_wont(cmd, len)
-char *cmd;
+ unsigned char *cmd;
+ int len;
{
+ if (len < 1) {
+/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
+ return;
+ }
switch(cmd[0]) {
case LM_FORWARDMASK: /* We shouldn't ever get this... */
default:
}
}
+ void
lm_do(cmd, len)
-char *cmd;
+ unsigned char *cmd;
+ int len;
{
+ if (len < 1) {
+/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
+ return;
+ }
switch(cmd[0]) {
case LM_FORWARDMASK:
default:
}
}
+ void
lm_dont(cmd, len)
-char *cmd;
+ unsigned char *cmd;
+ int len;
{
+ if (len < 1) {
+/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
+ return;
+ }
switch(cmd[0]) {
case LM_FORWARDMASK:
default:
}
}
-static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE };
+static unsigned char str_lm_mode[] = {
+ IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
+};
+ void
lm_mode(cmd, len, init)
-char *cmd;
-int len, init;
+ unsigned char *cmd;
+ int len, init;
{
if (len != 1)
return;
- if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd)
+ if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
return;
if (*cmd&MODE_ACK)
return;
- linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG));
+ linemode = *cmd&(MODE_MASK&~MODE_ACK);
str_lm_mode[4] = linemode;
if (!init)
str_lm_mode[4] |= MODE_ACK;
*/
struct spc {
- char val;
- char *valp;
+ cc_t val;
+ cc_t *valp;
char flags; /* Current flags & level */
char mylevel; /* Maximum level & flags */
} spc_data[NSLC+1];
#define SLC_RVALUE 2
static int slc_mode = SLC_EXPORT;
+ void
slc_init()
{
register struct spc *spcp;
- extern char *tcval();
localchars = 1;
for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
#endif
- /* No FORW1 */
+ initfunc(SLC_FORW1, 0);
+#ifdef USE_TERMIO
+ initfunc(SLC_FORW2, 0);
/* No FORW2 */
+#endif
initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
#undef initfunc
}
+ void
slcstate()
{
printf("Special characters are %s values\n",
"remote");
}
+ void
slc_mode_export()
{
slc_mode = SLC_EXPORT;
slc_export();
}
+ void
slc_mode_import(def)
+ int def;
{
slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
if (my_state_is_will(TELOPT_LINEMODE))
slc_import(def);
}
-char slc_import_val[] = {
+unsigned char slc_import_val[] = {
IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
};
-char slc_import_def[] = {
+unsigned char slc_import_def[] = {
IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
};
+ void
slc_import(def)
-int def;
+ int def;
{
if (NETROOM() > sizeof(slc_import_val)) {
if (def) {
/*@*/ else printf("slc_import: not enough room\n");
}
+ void
slc_export()
{
register struct spc *spcp;
slc_start_reply();
for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
if (spcp->mylevel != SLC_NOSUPPORT) {
- spcp->flags = spcp->mylevel;
+ if (spcp->val == (cc_t)(_POSIX_VDISABLE))
+ spcp->flags = SLC_NOSUPPORT;
+ else
+ spcp->flags = spcp->mylevel;
if (spcp->valp)
spcp->val = *spcp->valp;
- slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val);
+ slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
}
}
slc_end_reply();
- if (slc_update())
- setconnmode(1); /* set the new character values */
+ (void)slc_update();
+ setconnmode(1); /* Make sure the character values are set */
}
+ void
slc(cp, len)
-register char *cp;
-int len;
+ register unsigned char *cp;
+ int len;
{
register struct spc *spcp;
register int func,level;
continue;
}
if (func > NSLC) {
- if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT)
+ if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
slc_add_reply(func, SLC_NOSUPPORT, 0);
continue;
}
level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
- if ((cp[SLC_VALUE] == spcp->val) &&
+ if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
continue;
}
}
if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
- spcp->val = cp[SLC_VALUE];
+ spcp->val = (cc_t)cp[SLC_VALUE];
spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
continue;
}
if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
- spcp->val = cp[SLC_VALUE];
+ spcp->val = (cc_t)cp[SLC_VALUE];
}
if (level == SLC_DEFAULT) {
if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
setconnmode(1); /* set the new character values */
}
+ void
slc_check()
{
register struct spc *spcp;
for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
if (spcp->valp && spcp->val != *spcp->valp) {
spcp->val = *spcp->valp;
- slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val);
+ if (spcp->val == (cc_t)(_POSIX_VDISABLE))
+ spcp->flags = SLC_NOSUPPORT;
+ else
+ spcp->flags = spcp->mylevel;
+ slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
}
}
slc_end_reply();
unsigned char slc_reply[128];
unsigned char *slc_replyp;
+
+ void
slc_start_reply()
{
slc_replyp = slc_reply;
*slc_replyp++ = LM_SLC;
}
+ void
slc_add_reply(func, flags, value)
-char func;
-char flags;
-char value;
+ unsigned char func;
+ unsigned char flags;
+ cc_t value;
{
if ((*slc_replyp++ = func) == IAC)
*slc_replyp++ = IAC;
if ((*slc_replyp++ = flags) == IAC)
*slc_replyp++ = IAC;
- if ((*slc_replyp++ = value) == IAC)
+ if ((*slc_replyp++ = (unsigned char)value) == IAC)
*slc_replyp++ = IAC;
}
+ void
slc_end_reply()
{
- register char *cp;
register int len;
*slc_replyp++ = IAC;
/*@*/else printf("slc_end_reply: not enough room\n");
}
+ int
slc_update()
{
register struct spc *spcp;
return(need_update);
}
+ void
+env_opt(buf, len)
+ register unsigned char *buf;
+ register int len;
+{
+ register unsigned char *ep = 0, *epc = 0;
+ register int i;
+
+ switch(buf[0]&0xff) {
+ case TELQUAL_SEND:
+ env_opt_start();
+ if (len == 1) {
+ env_opt_add(NULL);
+ } else for (i = 1; i < len; i++) {
+ switch (buf[i]&0xff) {
+ case ENV_VALUE:
+ if (ep) {
+ *epc = 0;
+ env_opt_add(ep);
+ }
+ ep = epc = &buf[i+1];
+ break;
+ case ENV_ESC:
+ i++;
+ /*FALL THROUGH*/
+ default:
+ if (epc)
+ *epc++ = buf[i];
+ break;
+ }
+ if (ep) {
+ *epc = 0;
+ env_opt_add(ep);
+ }
+ }
+ env_opt_end(1);
+ break;
+
+ case TELQUAL_IS:
+ case TELQUAL_INFO:
+ /* Ignore for now. We shouldn't get it anyway. */
+ break;
+
+ default:
+ break;
+ }
+}
+
+#define OPT_REPLY_SIZE 256
+unsigned char *opt_reply;
+unsigned char *opt_replyp;
+unsigned char *opt_replyend;
+
+ void
+env_opt_start()
+{
+ if (opt_reply)
+ opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
+ else
+ opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
+ if (opt_reply == NULL) {
+/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ return;
+ }
+ opt_replyp = opt_reply;
+ opt_replyend = opt_reply + OPT_REPLY_SIZE;
+ *opt_replyp++ = IAC;
+ *opt_replyp++ = SB;
+ *opt_replyp++ = TELOPT_ENVIRON;
+ *opt_replyp++ = TELQUAL_IS;
+}
+
+ void
+env_opt_start_info()
+{
+ env_opt_start();
+ if (opt_replyp)
+ opt_replyp[-1] = TELQUAL_INFO;
+}
+
+ void
+env_opt_add(ep)
+ register unsigned char *ep;
+{
+ register unsigned char *vp, c;
+
+ if (opt_reply == NULL) /*XXX*/
+ return; /*XXX*/
+
+ if (ep == NULL || *ep == '\0') {
+ env_default(1);
+ while (ep = env_default(0))
+ env_opt_add(ep);
+ return;
+ }
+ vp = env_getvalue(ep);
+ if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
+ strlen((char *)ep) + 6 > opt_replyend)
+ {
+ register int len;
+ opt_replyend += OPT_REPLY_SIZE;
+ len = opt_replyend - opt_reply;
+ opt_reply = (unsigned char *)realloc(opt_reply, len);
+ if (opt_reply == NULL) {
+/*@*/ printf("env_opt_add: realloc() failed!!!\n");
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ return;
+ }
+ opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
+ opt_replyend = opt_reply + len;
+ }
+ *opt_replyp++ = ENV_VAR;
+ for (;;) {
+ while (c = *ep++) {
+ switch(c&0xff) {
+ case IAC:
+ *opt_replyp++ = IAC;
+ break;
+ case ENV_VALUE:
+ case ENV_VAR:
+ case ENV_ESC:
+ *opt_replyp++ = ENV_ESC;
+ break;
+ }
+ *opt_replyp++ = c;
+ }
+ if (ep = vp) {
+ *opt_replyp++ = ENV_VALUE;
+ vp = NULL;
+ } else
+ break;
+ }
+}
+
+ void
+env_opt_end(emptyok)
+ register int emptyok;
+{
+ register int len;
+
+ len = opt_replyp - opt_reply + 2;
+ if (emptyok || len > 6) {
+ *opt_replyp++ = IAC;
+ *opt_replyp++ = SE;
+ if (NETROOM() > len) {
+ ring_supply_data(&netoring, opt_reply, len);
+ printsub('>', &opt_reply[2], len - 2);
+ }
+/*@*/ else printf("slc_end_reply: not enough room\n");
+ }
+ if (opt_reply) {
+ free(opt_reply);
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ }
+}
+
\f
-int
+ int
telrcv()
{
register int c;
register int scc;
- register char *sbp;
+ register unsigned char *sbp;
int count;
int returnValue = 0;
}
c = *sbp++ & 0xff, scc--; count++;
+#if defined(ENCRYPT)
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif
switch (telrcv_state) {
*Ifrontp++ = c;
while (scc > 0) {
c = *sbp++ & 0377, scc--; count++;
+#if defined(ENCRYPT)
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif
if (c == IAC) {
telrcv_state = TS_IAC;
break;
if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
if (scc > 0) {
c = *sbp&0xff;
+#if defined(ENCRYPT)
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif
if (c == 0) {
sbp++, scc--; count++;
/* a "true" CR */
sbp++, scc--; count++;
TTYADD('\n');
} else {
+#if defined(ENCRYPT)
+ if (decrypt_input)
+ (*decrypt_input)(-1);
+#endif
+
TTYADD('\r');
if (crmod) {
TTYADD('\n');
* so make sure we flush whatever is in the
* buffer currently.
*/
+ printoption("RCVD", IAC, DM);
SYNCHing = 1;
- ttyflush(1);
+ (void) ttyflush(1);
SYNCHing = stilloob();
settimer(gotDM);
break;
- case NOP:
- case GA:
- break;
-
case SB:
SB_CLEAR();
telrcv_state = TS_SB;
- printoption("RCVD", "IAC", SB);
continue;
# if defined(TN3270)
case EOR:
if (In3270) {
- Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
if (Ibackp == Ifrontp) {
Ibackp = Ifrontp = Ibuf;
ISend = 0; /* should have been! */
} else {
+ Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
ISend = 1;
}
}
+ printoption("RCVD", IAC, EOR);
break;
# endif /* defined(TN3270) */
# endif /* !defined(TN3270) */
break;
+ case NOP:
+ case GA:
default:
+ printoption("RCVD", IAC, c);
break;
}
telrcv_state = TS_DATA;
continue;
case TS_WILL:
- printoption("RCVD", "will", c);
+ printoption("RCVD", WILL, c);
willoption(c);
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_WONT:
- printoption("RCVD", "wont", c);
+ printoption("RCVD", WONT, c);
wontoption(c);
SetIn3270();
telrcv_state = TS_DATA;
continue;
case TS_DO:
- printoption("RCVD", "do", c);
+ printoption("RCVD", DO, c);
dooption(c);
SetIn3270();
if (c == TELOPT_NAWS) {
continue;
case TS_DONT:
- printoption("RCVD", "dont", c);
+ printoption("RCVD", DONT, c);
dontoption(c);
flushline = 1;
setconnmode(0); /* set new tty mode (maybe) */
* we terminate the suboption, and process the
* partial suboption if we can.
*/
- SB_TERM();
SB_ACCUM(IAC);
SB_ACCUM(c);
- printoption("In SUBOPTION processing, RCVD", "IAC", c);
+ subpointer -= 2;
+ SB_TERM();
+
+ printoption("In SUBOPTION processing, RCVD", IAC, c);
suboption(); /* handle sub-option */
SetIn3270();
telrcv_state = TS_IAC;
SB_ACCUM(c);
telrcv_state = TS_SB;
} else {
- SB_TERM();
SB_ACCUM(IAC);
SB_ACCUM(SE);
+ subpointer -= 2;
+ SB_TERM();
suboption(); /* handle sub-option */
SetIn3270();
telrcv_state = TS_DATA;
return returnValue||count;
}
-static int
+static int bol = 1, local = 0;
+
+ int
+rlogin_susp()
+{
+ if (local) {
+ local = 0;
+ bol = 1;
+ command(0, "z\n", 2);
+ return(1);
+ }
+ return(0);
+}
+
+ static int
telsnd()
{
int tcc;
int count;
int returnValue = 0;
- char *tbp;
+ unsigned char *tbp;
tcc = 0;
count = 0;
}
}
c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
- if (sc == escape) {
+ if (rlogin != _POSIX_VDISABLE) {
+ if (bol) {
+ bol = 0;
+ if (sc == rlogin) {
+ local = 1;
+ continue;
+ }
+ } else if (local) {
+ local = 0;
+ if (sc == '.' || c == termEofChar) {
+ bol = 1;
+ command(0, "close\n", 6);
+ continue;
+ }
+ if (sc == termSuspChar) {
+ bol = 1;
+ command(0, "z\n", 2);
+ continue;
+ }
+ if (sc == escape) {
+ command(0, (char *)tbp, tcc);
+ bol = 1;
+ count += tcc;
+ tcc = 0;
+ flushline = 1;
+ break;
+ }
+ if (sc != rlogin) {
+ ++tcc;
+ --tbp;
+ --count;
+ c = sc = rlogin;
+ }
+ }
+ if ((sc == '\n') || (sc == '\r'))
+ bol = 1;
+ } else if (sc == escape) {
/*
* Double escape is a pass through of a single escape character.
*/
tbp++;
tcc--;
count++;
+ bol = 0;
} else {
- command(0, tbp, tcc);
+ command(0, (char *)tbp, tcc);
+ bol = 1;
count += tcc;
tcc = 0;
flushline = 1;
break;
}
- }
+ } else
+ bol = 0;
#ifdef KLUDGELINEMODE
if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
if (tcc > 0 && strip(*tbp) == echoc) {
#endif
if (MODE_LOCAL_CHARS(globalmode)) {
if (TerminalSpecialChars(sc) == 0) {
+ bol = 1;
break;
}
}
NETADD('\r');
}
NETADD('\n');
- flushline = 1;
+ bol = flushline = 1;
break;
case '\r':
if (!crlf) {
} else {
NET2ADD('\r', '\n');
}
- flushline = 1;
+ bol = flushline = 1;
break;
case IAC:
NET2ADD(IAC, IAC);
*/
-int
+ int
Scheduler(block)
-int block; /* should we block in the select ? */
+ int block; /* should we block in the select ? */
{
/* One wants to be a bit careful about setting returnValue
* to one, since a one implies we did some useful work,
# if defined(TN3270) && defined(unix)
if (HaveInput) {
HaveInput = 0;
- signal(SIGIO, inputAvailable);
+ (void) signal(SIGIO, inputAvailable);
}
#endif /* defined(TN3270) && defined(unix) */
/*
* Select from tty and network...
*/
-void
-telnet()
+ void
+telnet(user)
+ char *user;
{
sys_telnet_init();
+#if defined(ENCRYPT) || defined(AUTHENTICATE)
+ {
+ static char local_host[256] = { 0 };
+ int len = sizeof(local_host);
+
+ if (!local_host[0]) {
+ gethostname(local_host, &len);
+ local_host[sizeof(local_host)-1] = 0;
+ }
+ auth_encrypt_init(local_host, hostname, "TELNET", 0);
+ auth_encrypt_user(user);
+ }
+#endif
# if !defined(TN3270)
if (telnetport) {
+#if defined(AUTHENTICATE)
+ if (autologin)
+ send_will(TELOPT_AUTHENTICATION, 1);
+#endif
+#if defined(ENCRYPT)
+ send_do(TELOPT_ENCRYPT, 1);
+ send_will(TELOPT_ENCRYPT, 1);
+#endif
send_do(TELOPT_SGA, 1);
send_will(TELOPT_TTYPE, 1);
send_will(TELOPT_NAWS, 1);
send_will(TELOPT_TSPEED, 1);
send_will(TELOPT_LFLOW, 1);
send_will(TELOPT_LINEMODE, 1);
+ send_will(TELOPT_ENVIRON, 1);
send_do(TELOPT_STATUS, 1);
+ if (env_getvalue((unsigned char *)"DISPLAY"))
+ send_will(TELOPT_XDISPLOC, 1);
+ if (eight)
+ tel_enter_binary(eight);
}
# endif /* !defined(TN3270) */
* character.
*/
-static char *
+ static char *
nextitem(current)
-char *current;
+ char *current;
{
if ((*current&0xff) != IAC) {
return current+1;
* us in any case.
*/
-static void
+ static void
netclear()
{
#if 0 /* XXX */
* These routines add various telnet commands to the data stream.
*/
-static void
+ static void
doflush()
{
NET2ADD(IAC, DO);
NETADD(TELOPT_TM);
flushline = 1;
flushout = 1;
- ttyflush(1); /* Flush/drop output */
+ (void) ttyflush(1); /* Flush/drop output */
/* do printoption AFTER flush, otherwise the output gets tossed... */
- printoption("SENT", "do", TELOPT_TM);
+ printoption("SENT", DO, TELOPT_TM);
}
-void
+ void
xmitAO()
{
NET2ADD(IAC, AO);
- printoption("SENT", "IAC", AO);
+ printoption("SENT", IAC, AO);
if (autoflush) {
doflush();
}
}
-void
+ void
xmitEL()
{
NET2ADD(IAC, EL);
- printoption("SENT", "IAC", EL);
+ printoption("SENT", IAC, EL);
}
-void
+ void
xmitEC()
{
NET2ADD(IAC, EC);
- printoption("SENT", "IAC", EC);
+ printoption("SENT", IAC, EC);
}
-#if defined(NOT43)
-int
-#else /* defined(NOT43) */
-void
-#endif /* defined(NOT43) */
+ int
dosynch()
{
netclear(); /* clear the path to the network */
NETADD(IAC);
setneturg();
NETADD(DM);
- printoption("SENT", "IAC", DM);
-
-#if defined(NOT43)
- return 0;
-#endif /* defined(NOT43) */
+ printoption("SENT", IAC, DM);
+ return 1;
}
-void
+int want_status_response = 0;
+
+ int
get_status()
{
- char tmp[16];
- register char *cp;
+ unsigned char tmp[16];
+ register unsigned char *cp;
if (my_want_state_is_dont(TELOPT_STATUS)) {
printf("Remote side does not support STATUS option\n");
- return;
+ return 0;
}
- if (!showoptions)
- printf("You will not see the response unless you set \"options\"\n");
-
cp = tmp;
*cp++ = IAC;
ring_supply_data(&netoring, tmp, cp-tmp);
printsub('>', tmp+2, cp - tmp - 2);
}
+ ++want_status_response;
+ return 1;
}
-void
+ void
intp()
{
NET2ADD(IAC, IP);
- printoption("SENT", "IAC", IP);
+ printoption("SENT", IAC, IP);
flushline = 1;
if (autoflush) {
doflush();
}
}
-void
+ void
sendbrk()
{
NET2ADD(IAC, BREAK);
- printoption("SENT", "IAC", BREAK);
+ printoption("SENT", IAC, BREAK);
flushline = 1;
if (autoflush) {
doflush();
}
}
-void
+ void
sendabort()
{
NET2ADD(IAC, ABORT);
- printoption("SENT", "IAC", ABORT);
+ printoption("SENT", IAC, ABORT);
flushline = 1;
if (autoflush) {
doflush();
}
}
-void
+ void
sendsusp()
{
NET2ADD(IAC, SUSP);
- printoption("SENT", "IAC", SUSP);
+ printoption("SENT", IAC, SUSP);
flushline = 1;
if (autoflush) {
doflush();
}
}
-void
+ void
sendeof()
{
NET2ADD(IAC, xEOF);
- printoption("SENT", "IAC", xEOF);
+ printoption("SENT", IAC, xEOF);
+}
+
+ void
+sendayt()
+{
+ NET2ADD(IAC, AYT);
+ printoption("SENT", IAC, AYT);
}
/*
* Send a window size update to the remote system.
*/
-void
+ void
sendnaws()
{
long rows, cols;
}
}
+ void
tel_enter_binary(rw)
-int rw;
+ int rw;
{
if (rw&1)
send_do(TELOPT_BINARY, 1);
send_will(TELOPT_BINARY, 1);
}
+ void
tel_leave_binary(rw)
-int rw;
+ int rw;
{
if (rw&1)
send_dont(TELOPT_BINARY, 1);