Newer
Older
/***************************************************************************
Daniel Stenberg
committed
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
Daniel Stenberg
committed
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
***************************************************************************/
#ifndef CURL_DISABLE_TELNET
/* -- WIN32 approved -- */
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef HAVE_SYS_TYPES_H
#endif
#ifdef HAVE_SYS_STAT_H
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <time.h>
#include <io.h>
#else
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <netinet/in.h>
#include <sys/time.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <netdb.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
#include <sys/ioctl.h>
#include <signal.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#endif
#include "urldata.h"
#include <curl/curl.h>
Daniel Stenberg
committed
#include "transfer.h"
#include "telnet.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
#define TELOPTS
#define TELCMDS
#include "arpa_telnet.h"
#include "memory.h"
/* The last #include file should be: */
#include "memdebug.h"
Daniel Stenberg
committed
#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer;
#define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
#define CURL_SB_ACCUM(x,c) \
if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
*x->subpointer++ = (c); \
}
Daniel Stenberg
committed
#define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
#define CURL_SB_EOF(x) (x->subpointer >= x->subend)
#define CURL_SB_LEN(x) (x->subend - x->subpointer)
#ifdef WIN32
typedef FARPROC WSOCK2_FUNC;
static CURLcode check_wsock2 ( struct SessionHandle *data );
#endif
static
void telrcv(struct connectdata *,
unsigned char *inbuf, /* Data received from socket */
ssize_t count); /* Number of bytes received */
Daniel Stenberg
committed
static void printoption(struct SessionHandle *data,
const char *direction,
int cmd, int option);
static void negotiate(struct connectdata *);
static void send_negotiation(struct connectdata *, int cmd, int option);
static void set_local_option(struct connectdata *, int cmd, int option);
static void set_remote_option(struct connectdata *, int cmd, int option);
Daniel Stenberg
committed
static void printsub(struct SessionHandle *data,
int direction, unsigned char *pointer,
size_t length);
static void suboption(struct connectdata *);
/* For negotiation compliant to RFC 1143 */
#define CURL_NO 0
#define CURL_YES 1
#define CURL_WANTYES 2
#define CURL_WANTNO 3
Daniel Stenberg
committed
#define CURL_OPPOSITE 1
Daniel Stenberg
committed
CURL_TS_DATA = 0,
CURL_TS_IAC,
CURL_TS_WILL,
CURL_TS_WONT,
CURL_TS_DO,
CURL_TS_DONT,
CURL_TS_CR,
CURL_TS_SB, /* sub-option collection */
CURL_TS_SE /* looking for sub-option end */
} TelnetReceive;
struct TELNET {
int please_negotiate;
int already_negotiated;
Daniel Stenberg
committed
int us[256];
int usq[256];
int us_preferred[256];
int him[256];
int himq[256];
int him_preferred[256];
char subopt_ttype[32]; /* Set with suboption TTYPE */
char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
struct curl_slist *telnet_vars; /* Environment variables */
/* suboptions */
char subbuffer[SUBBUFSIZE];
char *subpointer, *subend; /* buffer for sub-options */
Daniel Stenberg
committed
TelnetReceive telrcv_state;
};
#ifdef WIN32
static CURLcode
check_wsock2 ( struct SessionHandle *data )
{
Daniel Stenberg
committed
int err;
WORD wVersionRequested;
WSADATA wsaData;
curlassert(data);
/* telnet requires at least WinSock 2.0 so ask for it. */
wVersionRequested = MAKEWORD(2, 0);
Daniel Stenberg
committed
err = WSAStartup(wVersionRequested, &wsaData);
/* We must've called this once already, so this call */
/* should always succeed. But, just in case... */
if (err != 0) {
failf(data,"WSAStartup failed (%d)",err);
Daniel Stenberg
committed
return CURLE_FAILED_INIT;
}
/* We have to have a WSACleanup call for every successful */
/* WSAStartup call. */
WSACleanup();
/* Check that our version is supported */
if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
/* Our version isn't supported */
failf(data,"insufficient winsock version to support "
return CURLE_FAILED_INIT;
}
/* Our version is supported */
return CURLE_OK;
}
#endif
static
CURLcode init_telnet(struct connectdata *conn)
{
struct TELNET *tn;
Daniel Stenberg
committed
tn = (struct TELNET *)calloc(1, sizeof(struct TELNET));
if(!tn)
return CURLE_OUT_OF_MEMORY;
Daniel Stenberg
committed
conn->proto.telnet = (void *)tn; /* make us known */
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
Daniel Stenberg
committed
CURL_SB_CLEAR(tn);
/* Set the options we want by default */
Daniel Stenberg
committed
tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
static void negotiate(struct connectdata *conn)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
Daniel Stenberg
committed
Daniel Stenberg
committed
for(i = 0;i < CURL_NTELOPTS;i++)
Daniel Stenberg
committed
if(tn->us_preferred[i] == CURL_YES)
set_local_option(conn, i, CURL_YES);
Daniel Stenberg
committed
Daniel Stenberg
committed
if(tn->him_preferred[i] == CURL_YES)
set_remote_option(conn, i, CURL_YES);
Daniel Stenberg
committed
static void printoption(struct SessionHandle *data,
const char *direction, int cmd, int option)
Daniel Stenberg
committed
Daniel Stenberg
committed
if (data->set.verbose)
Daniel Stenberg
committed
if (cmd == CURL_IAC)
Daniel Stenberg
committed
if (CURL_TELCMD_OK(option))
Curl_infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
Curl_infof(data, "%s IAC %d\n", direction, option);
Daniel Stenberg
committed
fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
(cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
Daniel Stenberg
committed
if (CURL_TELOPT_OK(option))
opt = CURL_TELOPT(option);
else if (option == CURL_TELOPT_EXOPL)
opt = "EXOPL";
else
opt = NULL;
if(opt)
Curl_infof(data, "%s %s %s\n", direction, fmt, opt);
Curl_infof(data, "%s %s %d\n", direction, fmt, option);
Curl_infof(data, "%s %d %d\n", direction, cmd, option);
static void send_negotiation(struct connectdata *conn, int cmd, int option)
Daniel Stenberg
committed
buf[0] = CURL_IAC;
Daniel Stenberg
committed
Daniel Stenberg
committed
(void)swrite(conn->sock[FIRSTSOCKET], buf, 3);
Daniel Stenberg
committed
printoption(conn->data, "SENT", cmd, option);
static
void set_remote_option(struct connectdata *conn, int option, int newstate)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
Daniel Stenberg
committed
if(newstate == CURL_YES)
Daniel Stenberg
committed
case CURL_NO:
tn->him[option] = CURL_WANTYES;
send_negotiation(conn, CURL_DO, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_YES:
/* Already enabled */
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTNO:
Daniel Stenberg
committed
case CURL_EMPTY:
/* Already negotiating for CURL_YES, queue the request */
tn->himq[option] = CURL_OPPOSITE;
Daniel Stenberg
committed
case CURL_OPPOSITE:
/* Error: already queued an enable request */
break;
}
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTYES:
Daniel Stenberg
committed
case CURL_EMPTY:
/* Error: already negotiating for enable */
break;
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->himq[option] = CURL_EMPTY;
break;
}
break;
}
}
else /* NO */
{
Daniel Stenberg
committed
case CURL_NO:
/* Already disabled */
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_YES:
tn->him[option] = CURL_WANTNO;
send_negotiation(conn, CURL_DONT, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTNO:
Daniel Stenberg
committed
case CURL_EMPTY:
/* Already negotiating for NO */
break;
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->himq[option] = CURL_EMPTY;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTYES:
Daniel Stenberg
committed
case CURL_EMPTY:
tn->himq[option] = CURL_OPPOSITE;
Daniel Stenberg
committed
case CURL_OPPOSITE:
break;
}
break;
}
}
static
void rec_will(struct connectdata *conn, int option)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->him[option])
Daniel Stenberg
committed
case CURL_NO:
if(tn->him_preferred[option] == CURL_YES)
Daniel Stenberg
committed
tn->him[option] = CURL_YES;
send_negotiation(conn, CURL_DO, option);
Daniel Stenberg
committed
send_negotiation(conn, CURL_DONT, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_YES:
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTNO:
Daniel Stenberg
committed
case CURL_EMPTY:
/* Error: DONT answered by WILL */
Daniel Stenberg
committed
tn->him[option] = CURL_NO;
Daniel Stenberg
committed
case CURL_OPPOSITE:
/* Error: DONT answered by WILL */
Daniel Stenberg
committed
tn->him[option] = CURL_YES;
tn->himq[option] = CURL_EMPTY;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTYES:
Daniel Stenberg
committed
case CURL_EMPTY:
tn->him[option] = CURL_YES;
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->him[option] = CURL_WANTNO;
tn->himq[option] = CURL_EMPTY;
send_negotiation(conn, CURL_DONT, option);
Daniel Stenberg
committed
static
void rec_wont(struct connectdata *conn, int option)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->him[option])
Daniel Stenberg
committed
case CURL_NO:
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_YES:
tn->him[option] = CURL_NO;
send_negotiation(conn, CURL_DONT, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTNO:
Daniel Stenberg
committed
case CURL_EMPTY:
tn->him[option] = CURL_NO;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->him[option] = CURL_WANTYES;
tn->himq[option] = CURL_EMPTY;
send_negotiation(conn, CURL_DO, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTYES:
Daniel Stenberg
committed
case CURL_EMPTY:
tn->him[option] = CURL_NO;
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->him[option] = CURL_NO;
tn->himq[option] = CURL_EMPTY;
Daniel Stenberg
committed
static void
set_local_option(struct connectdata *conn, int option, int newstate)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
Daniel Stenberg
committed
if(newstate == CURL_YES)
Daniel Stenberg
committed
case CURL_NO:
tn->us[option] = CURL_WANTYES;
send_negotiation(conn, CURL_WILL, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_YES:
/* Already enabled */
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTNO:
Daniel Stenberg
committed
case CURL_EMPTY:
/* Already negotiating for CURL_YES, queue the request */
tn->usq[option] = CURL_OPPOSITE;
Daniel Stenberg
committed
case CURL_OPPOSITE:
/* Error: already queued an enable request */
break;
}
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTYES:
Daniel Stenberg
committed
case CURL_EMPTY:
/* Error: already negotiating for enable */
break;
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->usq[option] = CURL_EMPTY;
break;
}
break;
}
}
else /* NO */
{
Daniel Stenberg
committed
case CURL_NO:
/* Already disabled */
break;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_YES:
tn->us[option] = CURL_WANTNO;
send_negotiation(conn, CURL_WONT, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTNO:
Daniel Stenberg
committed
case CURL_EMPTY:
/* Already negotiating for NO */
break;
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->usq[option] = CURL_EMPTY;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTYES:
Daniel Stenberg
committed
case CURL_EMPTY:
tn->usq[option] = CURL_OPPOSITE;
Daniel Stenberg
committed
case CURL_OPPOSITE:
break;
}
break;
}
}
static
void rec_do(struct connectdata *conn, int option)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->us[option])
Daniel Stenberg
committed
case CURL_NO:
if(tn->us_preferred[option] == CURL_YES)
Daniel Stenberg
committed
tn->us[option] = CURL_YES;
send_negotiation(conn, CURL_WILL, option);
Daniel Stenberg
committed
send_negotiation(conn, CURL_WONT, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_YES:
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTNO:
Daniel Stenberg
committed
case CURL_EMPTY:
/* Error: DONT answered by WILL */
Daniel Stenberg
committed
tn->us[option] = CURL_NO;
Daniel Stenberg
committed
case CURL_OPPOSITE:
/* Error: DONT answered by WILL */
Daniel Stenberg
committed
tn->us[option] = CURL_YES;
tn->usq[option] = CURL_EMPTY;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTYES:
Daniel Stenberg
committed
case CURL_EMPTY:
tn->us[option] = CURL_YES;
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->us[option] = CURL_WANTNO;
tn->himq[option] = CURL_EMPTY;
send_negotiation(conn, CURL_WONT, option);
Daniel Stenberg
committed
static
void rec_dont(struct connectdata *conn, int option)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->us[option])
Daniel Stenberg
committed
case CURL_NO:
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_YES:
tn->us[option] = CURL_NO;
send_negotiation(conn, CURL_WONT, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTNO:
Daniel Stenberg
committed
case CURL_EMPTY:
tn->us[option] = CURL_NO;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->us[option] = CURL_WANTYES;
tn->usq[option] = CURL_EMPTY;
send_negotiation(conn, CURL_WILL, option);
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_WANTYES:
Daniel Stenberg
committed
case CURL_EMPTY:
tn->us[option] = CURL_NO;
Daniel Stenberg
committed
case CURL_OPPOSITE:
tn->us[option] = CURL_NO;
tn->usq[option] = CURL_EMPTY;
Daniel Stenberg
committed
static void printsub(struct SessionHandle *data,
int direction, /* '<' or '>' */
unsigned char *pointer, /* where suboption data is */
size_t length) /* length of suboption data */
unsigned int i = 0;
Daniel Stenberg
committed
if (data->set.verbose)
Curl_infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
int j;
i = pointer[length-2];
j = pointer[length-1];
Daniel Stenberg
committed
if (i != CURL_IAC || j != CURL_SE)
Curl_infof(data, "(terminated by ");
Daniel Stenberg
committed
if (CURL_TELOPT_OK(i))
Curl_infof(data, "%s ", CURL_TELOPT(i));
else if (CURL_TELCMD_OK(i))
Curl_infof(data, "%s ", CURL_TELCMD(i));
Daniel Stenberg
committed
if (CURL_TELOPT_OK(j))
Curl_infof(data, "%s", CURL_TELOPT(j));
else if (CURL_TELCMD_OK(j))
Curl_infof(data, "%s", CURL_TELCMD(j));
Curl_infof(data, "%d", j);
Curl_infof(data, ", not IAC SE!) ");
}
}
length -= 2;
}
if (length < 1)
{
Curl_infof(data, "(Empty suboption?)");
Daniel Stenberg
committed
if (CURL_TELOPT_OK(pointer[0])) {
Daniel Stenberg
committed
case CURL_TELOPT_TTYPE:
case CURL_TELOPT_XDISPLOC:
case CURL_TELOPT_NEW_ENVIRON:
Curl_infof(data, "%s", CURL_TELOPT(pointer[0]));
Daniel Stenberg
committed
Curl_infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
break;
}
}
else
Curl_infof(data, "%d (unknown)", pointer[i]);
Daniel Stenberg
committed
case CURL_TELQUAL_IS:
Daniel Stenberg
committed
case CURL_TELQUAL_SEND:
Daniel Stenberg
committed
case CURL_TELQUAL_INFO:
Daniel Stenberg
committed
case CURL_TELQUAL_NAME:
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_TELOPT_TTYPE:
case CURL_TELOPT_XDISPLOC:
Curl_infof(data, " \"%s\"", &pointer[2]);
Daniel Stenberg
committed
case CURL_TELOPT_NEW_ENVIRON:
if(pointer[1] == CURL_TELQUAL_IS) {
for(i = 3;i < length;i++) {
switch(pointer[i]) {
Daniel Stenberg
committed
case CURL_NEW_ENV_VAR:
Daniel Stenberg
committed
case CURL_NEW_ENV_VALUE:
}
}
break;
default:
for (i = 2; i < length; i++)
Curl_infof(data, " %.2x", pointer[i]);
Daniel Stenberg
committed
static CURLcode check_telnet_options(struct connectdata *conn)
{
struct curl_slist *head;
char option_keyword[128];
char option_arg[256];
char *buf;
Daniel Stenberg
committed
struct SessionHandle *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
/* Add the user name as an environment variable if it
was given on the command line */
Daniel Stenberg
committed
if(conn->bits.user_passwd)
snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg);
Daniel Stenberg
committed
tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
Daniel Stenberg
committed
for(head = data->set.telnet_options; head; head=head->next) {
if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
option_keyword, option_arg) == 2) {
/* Terminal type */
Daniel Stenberg
committed
if(curl_strequal(option_keyword, "TTYPE")) {
strncpy(tn->subopt_ttype, option_arg, 31);
tn->subopt_ttype[31] = 0; /* String termination */
Daniel Stenberg
committed
tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
Daniel Stenberg
committed
if(curl_strequal(option_keyword, "XDISPLOC")) {
strncpy(tn->subopt_xdisploc, option_arg, 127);
tn->subopt_xdisploc[127] = 0; /* String termination */
Daniel Stenberg
committed
tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
Daniel Stenberg
committed
if(curl_strequal(option_keyword, "NEW_ENV")) {
buf = strdup(option_arg);
if(!buf)
return CURLE_OUT_OF_MEMORY;
tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
Daniel Stenberg
committed
tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
failf(data, "Unknown telnet option %s", head->data);
return CURLE_UNKNOWN_TELNET_OPTION;
} else {
failf(data, "Syntax error in telnet option: %s", head->data);
return CURLE_TELNET_OPTION_SYNTAX;
}
}
return CURLE_OK;
}
/*
* suboption()
*
* Look at the sub-option buffer, and try to be helpful to the other
* side.
*/
static void suboption(struct connectdata *conn)
struct curl_slist *v;
unsigned char temp[2048];
size_t len;
size_t tmplen;
char varname[128];
char varval[128];
Daniel Stenberg
committed
struct SessionHandle *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
Daniel Stenberg
committed
printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
switch (CURL_SB_GET(tn)) {
Daniel Stenberg
committed
case CURL_TELOPT_TTYPE:
len = strlen(tn->subopt_ttype) + 4 + 2;
snprintf((char *)temp, sizeof(temp),
Daniel Stenberg
committed
"%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
Daniel Stenberg
committed
(void)swrite(conn->sock[FIRSTSOCKET], temp, len);
printsub(data, '>', &temp[2], len-2);
break;
Daniel Stenberg
committed
case CURL_TELOPT_XDISPLOC:
len = strlen(tn->subopt_xdisploc) + 4 + 2;
snprintf((char *)temp, sizeof(temp),
Daniel Stenberg
committed
"%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
Daniel Stenberg
committed
(void)swrite(conn->sock[FIRSTSOCKET], temp, len);
printsub(data, '>', &temp[2], len-2);
break;
Daniel Stenberg
committed
case CURL_TELOPT_NEW_ENVIRON:
snprintf((char *)temp, sizeof(temp),
Daniel Stenberg
committed
"%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
CURL_TELQUAL_IS);
for(v = tn->telnet_vars;v;v = v->next) {
tmplen = (strlen(v->data) + 1);
/* Add the variable only if it fits */
if(len + tmplen < (int)sizeof(temp)-6) {
sscanf(v->data, "%127[^,],%127s", varname, varval);
snprintf((char *)&temp[len], sizeof(temp) - len,
Daniel Stenberg
committed
"%c%s%c%s", CURL_NEW_ENV_VAR, varname,
CURL_NEW_ENV_VALUE, varval);
len += tmplen;
}
}
snprintf((char *)&temp[len], sizeof(temp) - len,
Daniel Stenberg
committed
"%c%c", CURL_IAC, CURL_SE);
Daniel Stenberg
committed
(void)swrite(conn->sock[FIRSTSOCKET], temp, len);
printsub(data, '>', &temp[2], len-2);
break;
}
return;
static
void telrcv(struct connectdata *conn,
unsigned char *inbuf, /* Data received from socket */
ssize_t count) /* Number of bytes received */
Daniel Stenberg
committed
struct SessionHandle *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
Daniel Stenberg
committed
case CURL_TS_CR:
tn->telrcv_state = CURL_TS_DATA;
if (c == '\0')
{
break; /* Ignore \0 after CR */
}
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
continue;
Daniel Stenberg
committed
case CURL_TS_DATA:
if (c == CURL_IAC)
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_IAC;
break;
}
else if(c == '\r')
{
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_CR;
}
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
continue;
Daniel Stenberg
committed
case CURL_TS_IAC:
process_iac:
switch (c)
{
Daniel Stenberg
committed
case CURL_WILL:
tn->telrcv_state = CURL_TS_WILL;
Daniel Stenberg
committed
case CURL_WONT:
tn->telrcv_state = CURL_TS_WONT;
Daniel Stenberg
committed
case CURL_DO:
tn->telrcv_state = CURL_TS_DO;
Daniel Stenberg
committed
case CURL_DONT:
tn->telrcv_state = CURL_TS_DONT;
Daniel Stenberg
committed
case CURL_SB:
CURL_SB_CLEAR(tn);
tn->telrcv_state = CURL_TS_SB;
Daniel Stenberg
committed
case CURL_IAC:
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
Daniel Stenberg
committed
case CURL_DM:
case CURL_NOP:
case CURL_GA:
Daniel Stenberg
committed
printoption(data, "RCVD", CURL_IAC, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
Daniel Stenberg
committed
case CURL_TS_WILL:
printoption(data, "RCVD", CURL_WILL, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_TS_WONT:
printoption(data, "RCVD", CURL_WONT, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_TS_DO:
printoption(data, "RCVD", CURL_DO, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;
Daniel Stenberg
committed
Daniel Stenberg
committed
case CURL_TS_DONT:
printoption(data, "RCVD", CURL_DONT, c);
Daniel Stenberg
committed
tn->telrcv_state = CURL_TS_DATA;