diff options
Diffstat (limited to 'lib/telnet.c')
-rw-r--r-- | lib/telnet.c | 1137 |
1 files changed, 658 insertions, 479 deletions
diff --git a/lib/telnet.c b/lib/telnet.c index cda76d446..23a55b62f 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -96,7 +96,7 @@ #define SB_LEN() (subend - subpointer) static -void telrcv(struct UrlData *data, +void telrcv(struct connectdata *, unsigned char *inbuf, /* Data received from socket */ int count); /* Number of bytes received */ @@ -104,14 +104,14 @@ static void printoption(struct UrlData *data, const char *direction, int cmd, int option); -static void negotiate(struct UrlData *data); -static void send_negotiation(struct UrlData *data, int cmd, int option); -static void set_local_option(struct UrlData *data, int cmd, int option); -static void set_remote_option(struct UrlData *data, 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); static void printsub(struct UrlData *data, int direction, unsigned char *pointer, int length); -static void suboption(struct UrlData *data); +static void suboption(struct connectdata *); /* suboptions */ static char subbuffer[SUBBUFSIZE]; @@ -142,6 +142,8 @@ static enum #define EMPTY 0 #define OPPOSITE 1 +static int please_negotiate = 0; +static int already_negotiated = 0; static int us[256]; static int usq[256]; static int us_preferred[256]; @@ -149,86 +151,87 @@ static int him[256]; static int himq[256]; static int him_preferred[256]; +static char *subopt_ttype = NULL; /* Set with suboption TTYPE */ +static char *subopt_xdisploc = NULL; /* Set with suboption XDISPLOC */ +static struct curl_slist *telnet_vars = NULL; /* Environment variables */ + static -void init_telnet(struct UrlData *data) +void init_telnet(struct connectdata *conn) { - telrcv_state = TS_DATA; - - /* Init suboptions */ - SB_CLEAR(); - - /* Set all options to NO */ - memset(us, NO, 256); - memset(usq, NO, 256); - memset(us_preferred, NO, 256); - memset(him, NO, 256); - memset(himq, NO, 256); - memset(him_preferred, NO, 256); - - /* Set the options we want */ - us_preferred[TELOPT_BINARY] = YES; - us_preferred[TELOPT_SGA] = YES; - him_preferred[TELOPT_BINARY] = YES; - him_preferred[TELOPT_SGA] = YES; - - /* Start negotiating */ - negotiate(data); + telrcv_state = TS_DATA; + + /* Init suboptions */ + SB_CLEAR(); + + /* Set all options to NO */ + memset(us, NO, 256); + memset(usq, NO, 256); + memset(us_preferred, NO, 256); + memset(him, NO, 256); + memset(himq, NO, 256); + memset(him_preferred, NO, 256); + + /* Set the options we want by default */ + us_preferred[TELOPT_BINARY] = YES; + us_preferred[TELOPT_SGA] = YES; + him_preferred[TELOPT_BINARY] = YES; + him_preferred[TELOPT_SGA] = YES; } -static void negotiate(struct UrlData *data) +static void negotiate(struct connectdata *conn) { - int i; + int i; - for(i = 0;i < NTELOPTS;i++) - { - if(us_preferred[i] == YES) - set_local_option(data, i, YES); + for(i = 0;i < NTELOPTS;i++) + { + if(us_preferred[i] == YES) + set_local_option(conn, i, YES); - if(him_preferred[i] == YES) - set_remote_option(data, i, YES); - } + if(him_preferred[i] == YES) + set_remote_option(conn, i, YES); + } } static void printoption(struct UrlData *data, const char *direction, int cmd, int option) { - char *fmt; - char *opt; + char *fmt; + char *opt; - if (data->bits.verbose) - { - if (cmd == IAC) - { - if (TELCMD_OK(option)) - printf("%s IAC %s\n", direction, TELCMD(option)); - else - printf("%s IAC %d\n", direction, option); - } + if (data->bits.verbose) + { + if (cmd == IAC) + { + if (TELCMD_OK(option)) + printf("%s IAC %s\n", direction, TELCMD(option)); else + printf("%s IAC %d\n", direction, option); + } + else + { + fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : + (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; + if (fmt) { - fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : - (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; - if (fmt) - { - if (TELOPT_OK(option)) - opt = TELOPT(option); - else if (option == TELOPT_EXOPL) - opt = "EXOPL"; - else - opt = NULL; - - if(opt) - printf("%s %s %s\n", direction, fmt, opt); - else - printf("%s %s %d\n", direction, fmt, option); - } - else - printf("%s %d %d\n", direction, cmd, option); + if (TELOPT_OK(option)) + opt = TELOPT(option); + else if (option == TELOPT_EXOPL) + opt = "EXOPL"; + else + opt = NULL; + + if(opt) + printf("%s %s %s\n", direction, fmt, opt); + else + printf("%s %s %d\n", direction, fmt, option); } - } + else + printf("%s %d %d\n", direction, cmd, option); + } + } } -static void send_negotiation(struct UrlData *data, int cmd, int option) +static void send_negotiation(struct connectdata *conn, int cmd, int option) { unsigned char buf[3]; @@ -236,362 +239,362 @@ static void send_negotiation(struct UrlData *data, int cmd, int option) buf[1] = cmd; buf[2] = option; - swrite(data->firstsocket, buf, 3); + swrite(conn->firstsocket, buf, 3); - printoption(data, "SENT", cmd, option); + printoption(conn->data, "SENT", cmd, option); } static -void set_remote_option(struct UrlData *data, int option, int newstate) +void set_remote_option(struct connectdata *conn, int option, int newstate) { - if(newstate == YES) - { - switch(him[option]) - { + if(newstate == YES) + { + switch(him[option]) + { case NO: - him[option] = WANTYES; - send_negotiation(data, DO, option); - break; + him[option] = WANTYES; + send_negotiation(conn, DO, option); + break; case YES: - /* Already enabled */ - break; + /* Already enabled */ + break; case WANTNO: - switch(himq[option]) - { - case EMPTY: - /* Already negotiating for YES, queue the request */ - himq[option] = OPPOSITE; - break; - case OPPOSITE: - /* Error: already queued an enable request */ - break; - } - break; + switch(himq[option]) + { + case EMPTY: + /* Already negotiating for YES, queue the request */ + himq[option] = OPPOSITE; + break; + case OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; case WANTYES: - switch(himq[option]) - { - case EMPTY: - /* Error: already negotiating for enable */ - break; - case OPPOSITE: - himq[option] = EMPTY; - break; - } - break; - } - } - else /* NO */ - { - switch(him[option]) - { + switch(himq[option]) + { + case EMPTY: + /* Error: already negotiating for enable */ + break; + case OPPOSITE: + himq[option] = EMPTY; + break; + } + break; + } + } + else /* NO */ + { + switch(him[option]) + { case NO: - /* Already disabled */ - break; + /* Already disabled */ + break; case YES: - him[option] = WANTNO; - send_negotiation(data, DONT, option); - break; + him[option] = WANTNO; + send_negotiation(conn, DONT, option); + break; case WANTNO: - switch(himq[option]) - { - case EMPTY: - /* Already negotiating for NO */ - break; - case OPPOSITE: - himq[option] = EMPTY; - break; - } - break; + switch(himq[option]) + { + case EMPTY: + /* Already negotiating for NO */ + break; + case OPPOSITE: + himq[option] = EMPTY; + break; + } + break; case WANTYES: - switch(himq[option]) - { - case EMPTY: - himq[option] = OPPOSITE; - break; - case OPPOSITE: - break; - } - break; - } - } + switch(himq[option]) + { + case EMPTY: + himq[option] = OPPOSITE; + break; + case OPPOSITE: + break; + } + break; + } + } } static -void rec_will(struct UrlData *data, int option) +void rec_will(struct connectdata *conn, int option) { - switch(him[option]) - { - case NO: + switch(him[option]) + { + case NO: if(him_preferred[option] == YES) { - him[option] = YES; - send_negotiation(data, DO, option); + him[option] = YES; + send_negotiation(conn, DO, option); } else { - send_negotiation(data, DONT, option); + send_negotiation(conn, DONT, option); } break; - case YES: + case YES: /* Already enabled */ break; - case WANTNO: + case WANTNO: switch(himq[option]) { - case EMPTY: - /* Error: DONT answered by WILL */ - him[option] = NO; - break; - case OPPOSITE: - /* Error: DONT answered by WILL */ - him[option] = YES; - himq[option] = EMPTY; - break; + case EMPTY: + /* Error: DONT answered by WILL */ + him[option] = NO; + break; + case OPPOSITE: + /* Error: DONT answered by WILL */ + him[option] = YES; + himq[option] = EMPTY; + break; } break; - case WANTYES: + case WANTYES: switch(himq[option]) { - case EMPTY: - him[option] = YES; - break; - case OPPOSITE: - him[option] = WANTNO; - himq[option] = EMPTY; - send_negotiation(data, DONT, option); - break; + case EMPTY: + him[option] = YES; + break; + case OPPOSITE: + him[option] = WANTNO; + himq[option] = EMPTY; + send_negotiation(conn, DONT, option); + break; } break; - } + } } static -void rec_wont(struct UrlData *data, int option) +void rec_wont(struct connectdata *conn, int option) { - switch(him[option]) - { - case NO: + switch(him[option]) + { + case NO: /* Already disabled */ break; - case YES: + case YES: him[option] = NO; - send_negotiation(data, DONT, option); + send_negotiation(conn, DONT, option); break; - case WANTNO: + case WANTNO: switch(himq[option]) { - case EMPTY: - him[option] = NO; - break; + case EMPTY: + him[option] = NO; + break; - case OPPOSITE: - him[option] = WANTYES; - himq[option] = EMPTY; - send_negotiation(data, DO, option); - break; + case OPPOSITE: + him[option] = WANTYES; + himq[option] = EMPTY; + send_negotiation(conn, DO, option); + break; } break; - case WANTYES: + case WANTYES: switch(himq[option]) { - case EMPTY: - him[option] = NO; - break; - case OPPOSITE: - him[option] = NO; - himq[option] = EMPTY; - break; + case EMPTY: + him[option] = NO; + break; + case OPPOSITE: + him[option] = NO; + himq[option] = EMPTY; + break; } break; - } + } } -void set_local_option(struct UrlData *data, int option, int newstate) +void set_local_option(struct connectdata *conn, int option, int newstate) { - if(newstate == YES) - { - switch(us[option]) - { + if(newstate == YES) + { + switch(us[option]) + { case NO: - us[option] = WANTYES; - send_negotiation(data, WILL, option); - break; + us[option] = WANTYES; + send_negotiation(conn, WILL, option); + break; case YES: - /* Already enabled */ - break; + /* Already enabled */ + break; case WANTNO: - switch(usq[option]) - { - case EMPTY: - /* Already negotiating for YES, queue the request */ - usq[option] = OPPOSITE; - break; - case OPPOSITE: - /* Error: already queued an enable request */ - break; - } - break; + switch(usq[option]) + { + case EMPTY: + /* Already negotiating for YES, queue the request */ + usq[option] = OPPOSITE; + break; + case OPPOSITE: + /* Error: already queued an enable request */ + break; + } + break; case WANTYES: - switch(usq[option]) - { - case EMPTY: - /* Error: already negotiating for enable */ - break; - case OPPOSITE: - usq[option] = EMPTY; - break; - } - break; - } - } - else /* NO */ - { - switch(us[option]) - { + switch(usq[option]) + { + case EMPTY: + /* Error: already negotiating for enable */ + break; + case OPPOSITE: + usq[option] = EMPTY; + break; + } + break; + } + } + else /* NO */ + { + switch(us[option]) + { case NO: - /* Already disabled */ - break; + /* Already disabled */ + break; case YES: - us[option] = WANTNO; - send_negotiation(data, WONT, option); - break; + us[option] = WANTNO; + send_negotiation(conn, WONT, option); + break; case WANTNO: - switch(usq[option]) - { - case EMPTY: - /* Already negotiating for NO */ - break; - case OPPOSITE: - usq[option] = EMPTY; - break; - } - break; + switch(usq[option]) + { + case EMPTY: + /* Already negotiating for NO */ + break; + case OPPOSITE: + usq[option] = EMPTY; + break; + } + break; case WANTYES: - switch(usq[option]) - { - case EMPTY: - usq[option] = OPPOSITE; - break; - case OPPOSITE: - break; - } - break; - } - } + switch(usq[option]) + { + case EMPTY: + usq[option] = OPPOSITE; + break; + case OPPOSITE: + break; + } + break; + } + } } static -void rec_do(struct UrlData *data, int option) +void rec_do(struct connectdata *conn, int option) { - switch(us[option]) - { - case NO: + switch(us[option]) + { + case NO: if(us_preferred[option] == YES) { - us[option] = YES; - send_negotiation(data, WILL, option); + us[option] = YES; + send_negotiation(conn, WILL, option); } else { - send_negotiation(data, WONT, option); + send_negotiation(conn, WONT, option); } break; - case YES: + case YES: /* Already enabled */ break; - case WANTNO: + case WANTNO: switch(usq[option]) { - case EMPTY: - /* Error: DONT answered by WILL */ - us[option] = NO; - break; - case OPPOSITE: - /* Error: DONT answered by WILL */ - us[option] = YES; - usq[option] = EMPTY; - break; + case EMPTY: + /* Error: DONT answered by WILL */ + us[option] = NO; + break; + case OPPOSITE: + /* Error: DONT answered by WILL */ + us[option] = YES; + usq[option] = EMPTY; + break; } break; - case WANTYES: + case WANTYES: switch(usq[option]) { - case EMPTY: - us[option] = YES; - break; - case OPPOSITE: - us[option] = WANTNO; - himq[option] = EMPTY; - send_negotiation(data, WONT, option); - break; + case EMPTY: + us[option] = YES; + break; + case OPPOSITE: + us[option] = WANTNO; + himq[option] = EMPTY; + send_negotiation(conn, WONT, option); + break; } break; - } + } } static -void rec_dont(struct UrlData *data, int option) +void rec_dont(struct connectdata *conn, int option) { - switch(us[option]) - { - case NO: + switch(us[option]) + { + case NO: /* Already disabled */ break; - case YES: + case YES: us[option] = NO; - send_negotiation(data, WONT, option); + send_negotiation(conn, WONT, option); break; - case WANTNO: + case WANTNO: switch(usq[option]) { - case EMPTY: - us[option] = NO; - break; + case EMPTY: + us[option] = NO; + break; - case OPPOSITE: - us[option] = WANTYES; - usq[option] = EMPTY; - send_negotiation(data, WILL, option); - break; + case OPPOSITE: + us[option] = WANTYES; + usq[option] = EMPTY; + send_negotiation(conn, WILL, option); + break; } break; - case WANTYES: + case WANTYES: switch(usq[option]) { - case EMPTY: - us[option] = NO; - break; - case OPPOSITE: - us[option] = NO; - usq[option] = EMPTY; - break; + case EMPTY: + us[option] = NO; + break; + case OPPOSITE: + us[option] = NO; + usq[option] = EMPTY; + break; } break; - } + } } @@ -599,60 +602,170 @@ static void printsub(struct UrlData *data, int direction, /* '<' or '>' */ unsigned char *pointer, /* where suboption data is */ int length) /* length of suboption data */ - { - int i = 0; - - if (data->bits.verbose) - { - if (direction) + int i = 0; + + if (data->bits.verbose) + { + if (direction) + { + printf("%s IAC SB ", (direction == '<')? "RCVD":"SENT"); + if (length >= 3) { - printf("%s IAC SB ", (direction == '<')? "RCVD":"SENT"); - if (length >= 3) - { - int j; - - i = pointer[length-2]; - j = pointer[length-1]; - - if (i != IAC || j != SE) - { - printf("(terminated by "); - if (TELOPT_OK(i)) - printf("%s ", TELOPT(i)); - else if (TELCMD_OK(i)) - printf("%s ", TELCMD(i)); - else - printf("%d ", i); - if (TELOPT_OK(j)) - printf("%s", TELOPT(j)); - else if (TELCMD_OK(j)) - printf("%s", TELCMD(j)); - else - printf("%d", j); - printf(", not IAC SE!) "); + int j; + + i = pointer[length-2]; + j = pointer[length-1]; + + if (i != IAC || j != SE) + { + printf("(terminated by "); + if (TELOPT_OK(i)) + printf("%s ", TELOPT(i)); + else if (TELCMD_OK(i)) + printf("%s ", TELCMD(i)); + else + printf("%d ", i); + if (TELOPT_OK(j)) + printf("%s", TELOPT(j)); + else if (TELCMD_OK(j)) + printf("%s", TELCMD(j)); + else + printf("%d", j); + printf(", not IAC SE!) "); + } + } + length -= 2; + } + if (length < 1) + { + printf("(Empty suboption?)"); + return; + } + + if (TELOPT_OK(pointer[0])) { + switch(pointer[0]) { + case TELOPT_TTYPE: + case TELOPT_XDISPLOC: + case TELOPT_NEW_ENVIRON: + printf("%s", TELOPT(pointer[0])); + break; + default: + printf("%s (unsupported)", TELOPT(pointer[0])); + break; + } + } + else + printf("%d (unknown)", pointer[i]); + + switch(pointer[1]) { + case TELQUAL_IS: + printf(" IS"); + break; + case TELQUAL_SEND: + printf(" SEND"); + break; + case TELQUAL_INFO: + printf(" INFO/REPLY"); + break; + case TELQUAL_NAME: + printf(" NAME"); + break; + } + + switch(pointer[0]) { + case TELOPT_TTYPE: + case TELOPT_XDISPLOC: + pointer[length] = 0; + printf(" \"%s\"", &pointer[2]); + break; + case TELOPT_NEW_ENVIRON: + if(pointer[1] == TELQUAL_IS) { + printf(" "); + for(i = 3;i < length;i++) { + switch(pointer[i]) { + case NEW_ENV_VAR: + printf(", "); + break; + case NEW_ENV_VALUE: + printf(" = "); + break; + default: + printf("%c", pointer[i]); + break; } - } - length -= 2; + } + } + break; + default: + for (i = 2; i < length; i++) + printf(" %.2x", pointer[i]); + break; + } + + if (direction) + { + printf("\n"); + } + } +} + +static int check_telnet_options(struct connectdata *conn) +{ + struct curl_slist *head; + char option_keyword[128]; + char option_arg[256]; + char *buf; + struct UrlData *data = conn->data; + + /* Add the user name as an environment variable if it + was given on the command line */ + if(data->bits.user_passwd) + { + char *buf = malloc(256); + sprintf(buf, "USER,%s", data->user); + telnet_vars = curl_slist_append(telnet_vars, buf); + + us_preferred[TELOPT_NEW_ENVIRON] = YES; + } + + for(head = data->telnet_options; head; head=head->next) { + if(sscanf(head->data, "%127[^= ]%*[ =]%255s", + option_keyword, option_arg) == 2) { + + /* Terminal type */ + if(strequal(option_keyword, "TTYPE")) { + subopt_ttype = option_arg; + us_preferred[TELOPT_TTYPE] = YES; + continue; } - if (length < 1) - { - printf("(Empty suboption?)"); - return; + + /* Display variable */ + if(strequal(option_keyword, "XDISPLOC")) { + subopt_xdisploc = option_arg; + us_preferred[TELOPT_XDISPLOC] = YES; + continue; } - if (TELOPT_OK(pointer[0])) - printf("%s (unknown)", TELOPT(pointer[0])); - else - printf("%d (unknown)", pointer[i]); - for (i = 1; i < length; i++) - printf(" %d", pointer[i]); - - if (direction) - { - printf("\n"); + /* Environment variable */ + if(strequal(option_keyword, "NEW_ENV")) { + buf = strdup(option_arg); + if(!buf) + return CURLE_OUT_OF_MEMORY; + telnet_vars = curl_slist_append(telnet_vars, buf); + us_preferred[TELOPT_NEW_ENVIRON] = YES; + continue; } - } + + 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; } /* @@ -663,171 +776,227 @@ static void printsub(struct UrlData *data, * No suboptions are supported yet. */ -static void suboption(struct UrlData *data) +static void suboption(struct connectdata *conn) { - printsub(data, '<', (unsigned char *)subbuffer, SB_LEN()+2); - return; + struct curl_slist *v; + unsigned char subchar; + unsigned char temp[2048]; + int len; + int tmplen; + char varname[128]; + char varval[128]; + struct UrlData *data = conn->data; + + printsub(data, '<', (unsigned char *)subbuffer, SB_LEN()+2); + switch (subchar = SB_GET()) { + case TELOPT_TTYPE: + len = strlen(subopt_ttype) + 4 + 2; + snprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, + TELQUAL_IS, subopt_ttype, IAC, SE); + swrite(conn->firstsocket, temp, len); + printsub(data, '>', &temp[2], len-2); + break; + case TELOPT_XDISPLOC: + len = strlen(subopt_xdisploc) + 4 + 2; + snprintf((char *)temp, sizeof(temp), + "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, + TELQUAL_IS, subopt_xdisploc, IAC, SE); + swrite(conn->firstsocket, temp, len); + printsub(data, '>', &temp[2], len-2); + break; + case TELOPT_NEW_ENVIRON: + snprintf((char *)temp, sizeof(temp), + "%c%c%c%c", IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_IS); + len = 4; + + for(v = telnet_vars;v;v = v->next) { + tmplen = (strlen(v->data) + 1); + /* Add the variable only if it fits */ + if(len + tmplen < sizeof(temp)-6) { + sscanf(v->data, "%127[^,],%s", varname, varval); + snprintf((char *)&temp[len], sizeof(temp) - len, + "%c%s%c%s", NEW_ENV_VAR, varname, + NEW_ENV_VALUE, varval); + len += tmplen; + } + } + snprintf((char *)&temp[len], sizeof(temp) - len, + "%c%c", IAC, SE); + len += 2; + swrite(conn->firstsocket, temp, len); + printsub(data, '>', &temp[2], len-2); + break; + } + return; } static -void telrcv(struct UrlData *data, - unsigned char *inbuf, /* Data received from socket */ - int count) /* Number of bytes received */ +void telrcv(struct connectdata *conn, + unsigned char *inbuf, /* Data received from socket */ + int count) /* Number of bytes received */ { - unsigned char c; - int index = 0; + unsigned char c; + int index = 0; + struct UrlData *data = conn->data; - while(count--) - { - c = inbuf[index++]; + while(count--) + { + c = inbuf[index++]; - switch (telrcv_state) - { + switch (telrcv_state) + { case TS_CR: - telrcv_state = TS_DATA; - if (c == '\0') - { - break; /* Ignore \0 after CR */ - } + telrcv_state = TS_DATA; + if (c == '\0') + { + break; /* Ignore \0 after CR */ + } - Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1); - continue; + Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1); + continue; case TS_DATA: - if (c == IAC) - { - telrcv_state = TS_IAC; - break; - } - else if(c == '\r') - { - telrcv_state = TS_CR; - } - - Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1); - continue; + if (c == IAC) + { + telrcv_state = TS_IAC; + break; + } + else if(c == '\r') + { + telrcv_state = TS_CR; + } + + Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1); + continue; case TS_IAC: - process_iac: - switch (c) - { - case WILL: - telrcv_state = TS_WILL; - continue; - case WONT: - telrcv_state = TS_WONT; - continue; - case DO: - telrcv_state = TS_DO; - continue; - case DONT: - telrcv_state = TS_DONT; - continue; - case SB: - SB_CLEAR(); - telrcv_state = TS_SB; - continue; - case IAC: + process_iac: + switch (c) + { + case WILL: + telrcv_state = TS_WILL; + continue; + case WONT: + telrcv_state = TS_WONT; + continue; + case DO: + telrcv_state = TS_DO; + continue; + case DONT: + telrcv_state = TS_DONT; + continue; + case SB: + SB_CLEAR(); + telrcv_state = TS_SB; + continue; + case IAC: Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1); break; - case DM: - case NOP: - case GA: - default: - printoption(data, "RCVD", IAC, c); - break; - } - telrcv_state = TS_DATA; - continue; + case DM: + case NOP: + case GA: + default: + printoption(data, "RCVD", IAC, c); + break; + } + telrcv_state = TS_DATA; + continue; case TS_WILL: - printoption(data, "RCVD", WILL, c); - rec_will(data, c); - telrcv_state = TS_DATA; - continue; + printoption(data, "RCVD", WILL, c); + please_negotiate = 1; + rec_will(conn, c); + telrcv_state = TS_DATA; + continue; case TS_WONT: - printoption(data, "RCVD", WONT, c); - rec_wont(data, c); - telrcv_state = TS_DATA; - continue; + printoption(data, "RCVD", WONT, c); + please_negotiate = 1; + rec_wont(conn, c); + telrcv_state = TS_DATA; + continue; case TS_DO: - printoption(data, "RCVD", DO, c); - rec_do(data, c); - telrcv_state = TS_DATA; - continue; + printoption(data, "RCVD", DO, c); + please_negotiate = 1; + rec_do(conn, c); + telrcv_state = TS_DATA; + continue; case TS_DONT: - printoption(data, "RCVD", DONT, c); - rec_dont(data, c); - telrcv_state = TS_DATA; - continue; + printoption(data, "RCVD", DONT, c); + please_negotiate = 1; + rec_dont(conn, c); + telrcv_state = TS_DATA; + continue; case TS_SB: - if (c == IAC) - { - telrcv_state = TS_SE; - } - else - { - SB_ACCUM(c); - } - continue; + if (c == IAC) + { + telrcv_state = TS_SE; + } + else + { + SB_ACCUM(c); + } + continue; case TS_SE: - if (c != SE) - { - if (c != IAC) - { - /* - * This is an error. We only expect to get - * "IAC IAC" or "IAC SE". Several things may - * have happend. An IAC was not doubled, the - * IAC SE was left off, or another option got - * inserted into the suboption are all possibilities. - * If we assume that the IAC was not doubled, - * and really the IAC SE was left off, we could - * get into an infinate loop here. So, instead, - * we terminate the suboption, and process the - * partial suboption if we can. - */ - SB_ACCUM((unsigned char)IAC); - SB_ACCUM(c); - subpointer -= 2; - SB_TERM(); + if (c != SE) + { + if (c != IAC) + { + /* + * This is an error. We only expect to get + * "IAC IAC" or "IAC SE". Several things may + * have happend. An IAC was not doubled, the + * IAC SE was left off, or another option got + * inserted into the suboption are all possibilities. + * If we assume that the IAC was not doubled, + * and really the IAC SE was left off, we could + * get into an infinate loop here. So, instead, + * we terminate the suboption, and process the + * partial suboption if we can. + */ + SB_ACCUM((unsigned char)IAC); + SB_ACCUM(c); + subpointer -= 2; + SB_TERM(); - printoption(data, "In SUBOPTION processing, RCVD", IAC, c); - suboption(data); /* handle sub-option */ - telrcv_state = TS_IAC; - goto process_iac; - } - SB_ACCUM(c); - telrcv_state = TS_SB; - } - else - { - SB_ACCUM((unsigned char)IAC); - SB_ACCUM((unsigned char)SE); - subpointer -= 2; - SB_TERM(); - suboption(data); /* handle sub-option */ - telrcv_state = TS_DATA; - } - break; - } - } + printoption(data, "In SUBOPTION processing, RCVD", IAC, c); + suboption(conn); /* handle sub-option */ + telrcv_state = TS_IAC; + goto process_iac; + } + SB_ACCUM(c); + telrcv_state = TS_SB; + } + else + { + SB_ACCUM((unsigned char)IAC); + SB_ACCUM((unsigned char)SE); + subpointer -= 2; + SB_TERM(); + suboption(conn); /* handle sub-option */ + telrcv_state = TS_DATA; + } + break; + } + } } CURLcode Curl_telnet_done(struct connectdata *conn) { + curl_slist_free_all(telnet_vars); return CURLE_OK; } CURLcode Curl_telnet(struct connectdata *conn) { + CURLcode code; struct UrlData *data = conn->data; - int sockfd = data->firstsocket; + int sockfd = conn->firstsocket; fd_set readfd; fd_set keepfd; @@ -835,8 +1004,12 @@ CURLcode Curl_telnet(struct connectdata *conn) char *buf = data->buffer; ssize_t nread; - init_telnet(data); + init_telnet(conn); + code = check_telnet_options(conn); + if(code) + return code; + FD_ZERO (&readfd); /* clear it */ FD_SET (sockfd, &readfd); FD_SET (1, &readfd); @@ -867,7 +1040,7 @@ CURLcode Curl_telnet(struct connectdata *conn) if(outbuf[0] == IAC) outbuf[out_count++] = IAC; - Curl_write(conn, data->firstsocket, outbuf, + Curl_write(conn, conn->firstsocket, outbuf, out_count, &bytes_written); } } @@ -882,12 +1055,18 @@ CURLcode Curl_telnet(struct connectdata *conn) break; } - telrcv(data, (unsigned char *)buf, nread); + telrcv(conn, (unsigned char *)buf, nread); + + /* Negotiate if the peer has started negotiating, + otherwise don't. We don't want to speak telnet with + non-telnet servers, like POP or SMTP. */ + if(please_negotiate && !already_negotiated) { + negotiate(conn); + already_negotiated = 1; + } } } } /* mark this as "no further transfer wanted" */ return Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL); } - - |