113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#ifndef CURL_DISABLE_TELNET 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3013498266Sopenharmony_ci#include <netinet/in.h> 3113498266Sopenharmony_ci#endif 3213498266Sopenharmony_ci#ifdef HAVE_NETDB_H 3313498266Sopenharmony_ci#include <netdb.h> 3413498266Sopenharmony_ci#endif 3513498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 3613498266Sopenharmony_ci#include <arpa/inet.h> 3713498266Sopenharmony_ci#endif 3813498266Sopenharmony_ci#ifdef HAVE_NET_IF_H 3913498266Sopenharmony_ci#include <net/if.h> 4013498266Sopenharmony_ci#endif 4113498266Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 4213498266Sopenharmony_ci#include <sys/ioctl.h> 4313498266Sopenharmony_ci#endif 4413498266Sopenharmony_ci 4513498266Sopenharmony_ci#ifdef HAVE_SYS_PARAM_H 4613498266Sopenharmony_ci#include <sys/param.h> 4713498266Sopenharmony_ci#endif 4813498266Sopenharmony_ci 4913498266Sopenharmony_ci#include "urldata.h" 5013498266Sopenharmony_ci#include <curl/curl.h> 5113498266Sopenharmony_ci#include "transfer.h" 5213498266Sopenharmony_ci#include "sendf.h" 5313498266Sopenharmony_ci#include "telnet.h" 5413498266Sopenharmony_ci#include "connect.h" 5513498266Sopenharmony_ci#include "progress.h" 5613498266Sopenharmony_ci#include "system_win32.h" 5713498266Sopenharmony_ci#include "arpa_telnet.h" 5813498266Sopenharmony_ci#include "select.h" 5913498266Sopenharmony_ci#include "strcase.h" 6013498266Sopenharmony_ci#include "warnless.h" 6113498266Sopenharmony_ci 6213498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 6313498266Sopenharmony_ci#include "curl_printf.h" 6413498266Sopenharmony_ci#include "curl_memory.h" 6513498266Sopenharmony_ci#include "memdebug.h" 6613498266Sopenharmony_ci 6713498266Sopenharmony_ci#define SUBBUFSIZE 512 6813498266Sopenharmony_ci 6913498266Sopenharmony_ci#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer 7013498266Sopenharmony_ci#define CURL_SB_TERM(x) \ 7113498266Sopenharmony_ci do { \ 7213498266Sopenharmony_ci x->subend = x->subpointer; \ 7313498266Sopenharmony_ci CURL_SB_CLEAR(x); \ 7413498266Sopenharmony_ci } while(0) 7513498266Sopenharmony_ci#define CURL_SB_ACCUM(x,c) \ 7613498266Sopenharmony_ci do { \ 7713498266Sopenharmony_ci if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer))) \ 7813498266Sopenharmony_ci *x->subpointer++ = (c); \ 7913498266Sopenharmony_ci } while(0) 8013498266Sopenharmony_ci 8113498266Sopenharmony_ci#define CURL_SB_GET(x) ((*x->subpointer++)&0xff) 8213498266Sopenharmony_ci#define CURL_SB_LEN(x) (x->subend - x->subpointer) 8313498266Sopenharmony_ci 8413498266Sopenharmony_ci/* For posterity: 8513498266Sopenharmony_ci#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff) 8613498266Sopenharmony_ci#define CURL_SB_EOF(x) (x->subpointer >= x->subend) */ 8713498266Sopenharmony_ci 8813498266Sopenharmony_ci#ifdef CURL_DISABLE_VERBOSE_STRINGS 8913498266Sopenharmony_ci#define printoption(a,b,c,d) Curl_nop_stmt 9013498266Sopenharmony_ci#endif 9113498266Sopenharmony_ci 9213498266Sopenharmony_cistatic 9313498266Sopenharmony_ciCURLcode telrcv(struct Curl_easy *data, 9413498266Sopenharmony_ci const unsigned char *inbuf, /* Data received from socket */ 9513498266Sopenharmony_ci ssize_t count); /* Number of bytes received */ 9613498266Sopenharmony_ci 9713498266Sopenharmony_ci#ifndef CURL_DISABLE_VERBOSE_STRINGS 9813498266Sopenharmony_cistatic void printoption(struct Curl_easy *data, 9913498266Sopenharmony_ci const char *direction, 10013498266Sopenharmony_ci int cmd, int option); 10113498266Sopenharmony_ci#endif 10213498266Sopenharmony_ci 10313498266Sopenharmony_cistatic void negotiate(struct Curl_easy *data); 10413498266Sopenharmony_cistatic void send_negotiation(struct Curl_easy *data, int cmd, int option); 10513498266Sopenharmony_cistatic void set_local_option(struct Curl_easy *data, 10613498266Sopenharmony_ci int option, int newstate); 10713498266Sopenharmony_cistatic void set_remote_option(struct Curl_easy *data, 10813498266Sopenharmony_ci int option, int newstate); 10913498266Sopenharmony_ci 11013498266Sopenharmony_cistatic void printsub(struct Curl_easy *data, 11113498266Sopenharmony_ci int direction, unsigned char *pointer, 11213498266Sopenharmony_ci size_t length); 11313498266Sopenharmony_cistatic void suboption(struct Curl_easy *data); 11413498266Sopenharmony_cistatic void sendsuboption(struct Curl_easy *data, int option); 11513498266Sopenharmony_ci 11613498266Sopenharmony_cistatic CURLcode telnet_do(struct Curl_easy *data, bool *done); 11713498266Sopenharmony_cistatic CURLcode telnet_done(struct Curl_easy *data, 11813498266Sopenharmony_ci CURLcode, bool premature); 11913498266Sopenharmony_cistatic CURLcode send_telnet_data(struct Curl_easy *data, 12013498266Sopenharmony_ci char *buffer, ssize_t nread); 12113498266Sopenharmony_ci 12213498266Sopenharmony_ci/* For negotiation compliant to RFC 1143 */ 12313498266Sopenharmony_ci#define CURL_NO 0 12413498266Sopenharmony_ci#define CURL_YES 1 12513498266Sopenharmony_ci#define CURL_WANTYES 2 12613498266Sopenharmony_ci#define CURL_WANTNO 3 12713498266Sopenharmony_ci 12813498266Sopenharmony_ci#define CURL_EMPTY 0 12913498266Sopenharmony_ci#define CURL_OPPOSITE 1 13013498266Sopenharmony_ci 13113498266Sopenharmony_ci/* 13213498266Sopenharmony_ci * Telnet receiver states for fsm 13313498266Sopenharmony_ci */ 13413498266Sopenharmony_citypedef enum 13513498266Sopenharmony_ci{ 13613498266Sopenharmony_ci CURL_TS_DATA = 0, 13713498266Sopenharmony_ci CURL_TS_IAC, 13813498266Sopenharmony_ci CURL_TS_WILL, 13913498266Sopenharmony_ci CURL_TS_WONT, 14013498266Sopenharmony_ci CURL_TS_DO, 14113498266Sopenharmony_ci CURL_TS_DONT, 14213498266Sopenharmony_ci CURL_TS_CR, 14313498266Sopenharmony_ci CURL_TS_SB, /* sub-option collection */ 14413498266Sopenharmony_ci CURL_TS_SE /* looking for sub-option end */ 14513498266Sopenharmony_ci} TelnetReceive; 14613498266Sopenharmony_ci 14713498266Sopenharmony_cistruct TELNET { 14813498266Sopenharmony_ci int please_negotiate; 14913498266Sopenharmony_ci int already_negotiated; 15013498266Sopenharmony_ci int us[256]; 15113498266Sopenharmony_ci int usq[256]; 15213498266Sopenharmony_ci int us_preferred[256]; 15313498266Sopenharmony_ci int him[256]; 15413498266Sopenharmony_ci int himq[256]; 15513498266Sopenharmony_ci int him_preferred[256]; 15613498266Sopenharmony_ci int subnegotiation[256]; 15713498266Sopenharmony_ci char subopt_ttype[32]; /* Set with suboption TTYPE */ 15813498266Sopenharmony_ci char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */ 15913498266Sopenharmony_ci unsigned short subopt_wsx; /* Set with suboption NAWS */ 16013498266Sopenharmony_ci unsigned short subopt_wsy; /* Set with suboption NAWS */ 16113498266Sopenharmony_ci TelnetReceive telrcv_state; 16213498266Sopenharmony_ci struct curl_slist *telnet_vars; /* Environment variables */ 16313498266Sopenharmony_ci struct dynbuf out; /* output buffer */ 16413498266Sopenharmony_ci 16513498266Sopenharmony_ci /* suboptions */ 16613498266Sopenharmony_ci unsigned char subbuffer[SUBBUFSIZE]; 16713498266Sopenharmony_ci unsigned char *subpointer, *subend; /* buffer for sub-options */ 16813498266Sopenharmony_ci}; 16913498266Sopenharmony_ci 17013498266Sopenharmony_ci 17113498266Sopenharmony_ci/* 17213498266Sopenharmony_ci * TELNET protocol handler. 17313498266Sopenharmony_ci */ 17413498266Sopenharmony_ci 17513498266Sopenharmony_ciconst struct Curl_handler Curl_handler_telnet = { 17613498266Sopenharmony_ci "TELNET", /* scheme */ 17713498266Sopenharmony_ci ZERO_NULL, /* setup_connection */ 17813498266Sopenharmony_ci telnet_do, /* do_it */ 17913498266Sopenharmony_ci telnet_done, /* done */ 18013498266Sopenharmony_ci ZERO_NULL, /* do_more */ 18113498266Sopenharmony_ci ZERO_NULL, /* connect_it */ 18213498266Sopenharmony_ci ZERO_NULL, /* connecting */ 18313498266Sopenharmony_ci ZERO_NULL, /* doing */ 18413498266Sopenharmony_ci ZERO_NULL, /* proto_getsock */ 18513498266Sopenharmony_ci ZERO_NULL, /* doing_getsock */ 18613498266Sopenharmony_ci ZERO_NULL, /* domore_getsock */ 18713498266Sopenharmony_ci ZERO_NULL, /* perform_getsock */ 18813498266Sopenharmony_ci ZERO_NULL, /* disconnect */ 18913498266Sopenharmony_ci ZERO_NULL, /* write_resp */ 19013498266Sopenharmony_ci ZERO_NULL, /* connection_check */ 19113498266Sopenharmony_ci ZERO_NULL, /* attach connection */ 19213498266Sopenharmony_ci PORT_TELNET, /* defport */ 19313498266Sopenharmony_ci CURLPROTO_TELNET, /* protocol */ 19413498266Sopenharmony_ci CURLPROTO_TELNET, /* family */ 19513498266Sopenharmony_ci PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ 19613498266Sopenharmony_ci}; 19713498266Sopenharmony_ci 19813498266Sopenharmony_ci 19913498266Sopenharmony_cistatic 20013498266Sopenharmony_ciCURLcode init_telnet(struct Curl_easy *data) 20113498266Sopenharmony_ci{ 20213498266Sopenharmony_ci struct TELNET *tn; 20313498266Sopenharmony_ci 20413498266Sopenharmony_ci tn = calloc(1, sizeof(struct TELNET)); 20513498266Sopenharmony_ci if(!tn) 20613498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 20713498266Sopenharmony_ci 20813498266Sopenharmony_ci Curl_dyn_init(&tn->out, 0xffff); 20913498266Sopenharmony_ci data->req.p.telnet = tn; /* make us known */ 21013498266Sopenharmony_ci 21113498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 21213498266Sopenharmony_ci 21313498266Sopenharmony_ci /* Init suboptions */ 21413498266Sopenharmony_ci CURL_SB_CLEAR(tn); 21513498266Sopenharmony_ci 21613498266Sopenharmony_ci /* Set the options we want by default */ 21713498266Sopenharmony_ci tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES; 21813498266Sopenharmony_ci tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES; 21913498266Sopenharmony_ci 22013498266Sopenharmony_ci /* To be compliant with previous releases of libcurl 22113498266Sopenharmony_ci we enable this option by default. This behavior 22213498266Sopenharmony_ci can be changed thanks to the "BINARY" option in 22313498266Sopenharmony_ci CURLOPT_TELNETOPTIONS 22413498266Sopenharmony_ci */ 22513498266Sopenharmony_ci tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES; 22613498266Sopenharmony_ci tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES; 22713498266Sopenharmony_ci 22813498266Sopenharmony_ci /* We must allow the server to echo what we sent 22913498266Sopenharmony_ci but it is not necessary to request the server 23013498266Sopenharmony_ci to do so (it might forces the server to close 23113498266Sopenharmony_ci the connection). Hence, we ignore ECHO in the 23213498266Sopenharmony_ci negotiate function 23313498266Sopenharmony_ci */ 23413498266Sopenharmony_ci tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES; 23513498266Sopenharmony_ci 23613498266Sopenharmony_ci /* Set the subnegotiation fields to send information 23713498266Sopenharmony_ci just after negotiation passed (do/will) 23813498266Sopenharmony_ci 23913498266Sopenharmony_ci Default values are (0,0) initialized by calloc. 24013498266Sopenharmony_ci According to the RFC1013 it is valid: 24113498266Sopenharmony_ci A value equal to zero is acceptable for the width (or height), 24213498266Sopenharmony_ci and means that no character width (or height) is being sent. 24313498266Sopenharmony_ci In this case, the width (or height) that will be assumed by the 24413498266Sopenharmony_ci Telnet server is operating system specific (it will probably be 24513498266Sopenharmony_ci based upon the terminal type information that may have been sent 24613498266Sopenharmony_ci using the TERMINAL TYPE Telnet option). */ 24713498266Sopenharmony_ci tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES; 24813498266Sopenharmony_ci return CURLE_OK; 24913498266Sopenharmony_ci} 25013498266Sopenharmony_ci 25113498266Sopenharmony_cistatic void negotiate(struct Curl_easy *data) 25213498266Sopenharmony_ci{ 25313498266Sopenharmony_ci int i; 25413498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 25513498266Sopenharmony_ci 25613498266Sopenharmony_ci for(i = 0; i < CURL_NTELOPTS; i++) { 25713498266Sopenharmony_ci if(i == CURL_TELOPT_ECHO) 25813498266Sopenharmony_ci continue; 25913498266Sopenharmony_ci 26013498266Sopenharmony_ci if(tn->us_preferred[i] == CURL_YES) 26113498266Sopenharmony_ci set_local_option(data, i, CURL_YES); 26213498266Sopenharmony_ci 26313498266Sopenharmony_ci if(tn->him_preferred[i] == CURL_YES) 26413498266Sopenharmony_ci set_remote_option(data, i, CURL_YES); 26513498266Sopenharmony_ci } 26613498266Sopenharmony_ci} 26713498266Sopenharmony_ci 26813498266Sopenharmony_ci#ifndef CURL_DISABLE_VERBOSE_STRINGS 26913498266Sopenharmony_cistatic void printoption(struct Curl_easy *data, 27013498266Sopenharmony_ci const char *direction, int cmd, int option) 27113498266Sopenharmony_ci{ 27213498266Sopenharmony_ci if(data->set.verbose) { 27313498266Sopenharmony_ci if(cmd == CURL_IAC) { 27413498266Sopenharmony_ci if(CURL_TELCMD_OK(option)) 27513498266Sopenharmony_ci infof(data, "%s IAC %s", direction, CURL_TELCMD(option)); 27613498266Sopenharmony_ci else 27713498266Sopenharmony_ci infof(data, "%s IAC %d", direction, option); 27813498266Sopenharmony_ci } 27913498266Sopenharmony_ci else { 28013498266Sopenharmony_ci const char *fmt = (cmd == CURL_WILL) ? "WILL" : 28113498266Sopenharmony_ci (cmd == CURL_WONT) ? "WONT" : 28213498266Sopenharmony_ci (cmd == CURL_DO) ? "DO" : 28313498266Sopenharmony_ci (cmd == CURL_DONT) ? "DONT" : 0; 28413498266Sopenharmony_ci if(fmt) { 28513498266Sopenharmony_ci const char *opt; 28613498266Sopenharmony_ci if(CURL_TELOPT_OK(option)) 28713498266Sopenharmony_ci opt = CURL_TELOPT(option); 28813498266Sopenharmony_ci else if(option == CURL_TELOPT_EXOPL) 28913498266Sopenharmony_ci opt = "EXOPL"; 29013498266Sopenharmony_ci else 29113498266Sopenharmony_ci opt = NULL; 29213498266Sopenharmony_ci 29313498266Sopenharmony_ci if(opt) 29413498266Sopenharmony_ci infof(data, "%s %s %s", direction, fmt, opt); 29513498266Sopenharmony_ci else 29613498266Sopenharmony_ci infof(data, "%s %s %d", direction, fmt, option); 29713498266Sopenharmony_ci } 29813498266Sopenharmony_ci else 29913498266Sopenharmony_ci infof(data, "%s %d %d", direction, cmd, option); 30013498266Sopenharmony_ci } 30113498266Sopenharmony_ci } 30213498266Sopenharmony_ci} 30313498266Sopenharmony_ci#endif 30413498266Sopenharmony_ci 30513498266Sopenharmony_cistatic void send_negotiation(struct Curl_easy *data, int cmd, int option) 30613498266Sopenharmony_ci{ 30713498266Sopenharmony_ci unsigned char buf[3]; 30813498266Sopenharmony_ci ssize_t bytes_written; 30913498266Sopenharmony_ci struct connectdata *conn = data->conn; 31013498266Sopenharmony_ci 31113498266Sopenharmony_ci buf[0] = CURL_IAC; 31213498266Sopenharmony_ci buf[1] = (unsigned char)cmd; 31313498266Sopenharmony_ci buf[2] = (unsigned char)option; 31413498266Sopenharmony_ci 31513498266Sopenharmony_ci bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3); 31613498266Sopenharmony_ci if(bytes_written < 0) { 31713498266Sopenharmony_ci int err = SOCKERRNO; 31813498266Sopenharmony_ci failf(data,"Sending data failed (%d)",err); 31913498266Sopenharmony_ci } 32013498266Sopenharmony_ci 32113498266Sopenharmony_ci printoption(data, "SENT", cmd, option); 32213498266Sopenharmony_ci} 32313498266Sopenharmony_ci 32413498266Sopenharmony_cistatic 32513498266Sopenharmony_civoid set_remote_option(struct Curl_easy *data, int option, int newstate) 32613498266Sopenharmony_ci{ 32713498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 32813498266Sopenharmony_ci if(newstate == CURL_YES) { 32913498266Sopenharmony_ci switch(tn->him[option]) { 33013498266Sopenharmony_ci case CURL_NO: 33113498266Sopenharmony_ci tn->him[option] = CURL_WANTYES; 33213498266Sopenharmony_ci send_negotiation(data, CURL_DO, option); 33313498266Sopenharmony_ci break; 33413498266Sopenharmony_ci 33513498266Sopenharmony_ci case CURL_YES: 33613498266Sopenharmony_ci /* Already enabled */ 33713498266Sopenharmony_ci break; 33813498266Sopenharmony_ci 33913498266Sopenharmony_ci case CURL_WANTNO: 34013498266Sopenharmony_ci switch(tn->himq[option]) { 34113498266Sopenharmony_ci case CURL_EMPTY: 34213498266Sopenharmony_ci /* Already negotiating for CURL_YES, queue the request */ 34313498266Sopenharmony_ci tn->himq[option] = CURL_OPPOSITE; 34413498266Sopenharmony_ci break; 34513498266Sopenharmony_ci case CURL_OPPOSITE: 34613498266Sopenharmony_ci /* Error: already queued an enable request */ 34713498266Sopenharmony_ci break; 34813498266Sopenharmony_ci } 34913498266Sopenharmony_ci break; 35013498266Sopenharmony_ci 35113498266Sopenharmony_ci case CURL_WANTYES: 35213498266Sopenharmony_ci switch(tn->himq[option]) { 35313498266Sopenharmony_ci case CURL_EMPTY: 35413498266Sopenharmony_ci /* Error: already negotiating for enable */ 35513498266Sopenharmony_ci break; 35613498266Sopenharmony_ci case CURL_OPPOSITE: 35713498266Sopenharmony_ci tn->himq[option] = CURL_EMPTY; 35813498266Sopenharmony_ci break; 35913498266Sopenharmony_ci } 36013498266Sopenharmony_ci break; 36113498266Sopenharmony_ci } 36213498266Sopenharmony_ci } 36313498266Sopenharmony_ci else { /* NO */ 36413498266Sopenharmony_ci switch(tn->him[option]) { 36513498266Sopenharmony_ci case CURL_NO: 36613498266Sopenharmony_ci /* Already disabled */ 36713498266Sopenharmony_ci break; 36813498266Sopenharmony_ci 36913498266Sopenharmony_ci case CURL_YES: 37013498266Sopenharmony_ci tn->him[option] = CURL_WANTNO; 37113498266Sopenharmony_ci send_negotiation(data, CURL_DONT, option); 37213498266Sopenharmony_ci break; 37313498266Sopenharmony_ci 37413498266Sopenharmony_ci case CURL_WANTNO: 37513498266Sopenharmony_ci switch(tn->himq[option]) { 37613498266Sopenharmony_ci case CURL_EMPTY: 37713498266Sopenharmony_ci /* Already negotiating for NO */ 37813498266Sopenharmony_ci break; 37913498266Sopenharmony_ci case CURL_OPPOSITE: 38013498266Sopenharmony_ci tn->himq[option] = CURL_EMPTY; 38113498266Sopenharmony_ci break; 38213498266Sopenharmony_ci } 38313498266Sopenharmony_ci break; 38413498266Sopenharmony_ci 38513498266Sopenharmony_ci case CURL_WANTYES: 38613498266Sopenharmony_ci switch(tn->himq[option]) { 38713498266Sopenharmony_ci case CURL_EMPTY: 38813498266Sopenharmony_ci tn->himq[option] = CURL_OPPOSITE; 38913498266Sopenharmony_ci break; 39013498266Sopenharmony_ci case CURL_OPPOSITE: 39113498266Sopenharmony_ci break; 39213498266Sopenharmony_ci } 39313498266Sopenharmony_ci break; 39413498266Sopenharmony_ci } 39513498266Sopenharmony_ci } 39613498266Sopenharmony_ci} 39713498266Sopenharmony_ci 39813498266Sopenharmony_cistatic 39913498266Sopenharmony_civoid rec_will(struct Curl_easy *data, int option) 40013498266Sopenharmony_ci{ 40113498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 40213498266Sopenharmony_ci switch(tn->him[option]) { 40313498266Sopenharmony_ci case CURL_NO: 40413498266Sopenharmony_ci if(tn->him_preferred[option] == CURL_YES) { 40513498266Sopenharmony_ci tn->him[option] = CURL_YES; 40613498266Sopenharmony_ci send_negotiation(data, CURL_DO, option); 40713498266Sopenharmony_ci } 40813498266Sopenharmony_ci else 40913498266Sopenharmony_ci send_negotiation(data, CURL_DONT, option); 41013498266Sopenharmony_ci 41113498266Sopenharmony_ci break; 41213498266Sopenharmony_ci 41313498266Sopenharmony_ci case CURL_YES: 41413498266Sopenharmony_ci /* Already enabled */ 41513498266Sopenharmony_ci break; 41613498266Sopenharmony_ci 41713498266Sopenharmony_ci case CURL_WANTNO: 41813498266Sopenharmony_ci switch(tn->himq[option]) { 41913498266Sopenharmony_ci case CURL_EMPTY: 42013498266Sopenharmony_ci /* Error: DONT answered by WILL */ 42113498266Sopenharmony_ci tn->him[option] = CURL_NO; 42213498266Sopenharmony_ci break; 42313498266Sopenharmony_ci case CURL_OPPOSITE: 42413498266Sopenharmony_ci /* Error: DONT answered by WILL */ 42513498266Sopenharmony_ci tn->him[option] = CURL_YES; 42613498266Sopenharmony_ci tn->himq[option] = CURL_EMPTY; 42713498266Sopenharmony_ci break; 42813498266Sopenharmony_ci } 42913498266Sopenharmony_ci break; 43013498266Sopenharmony_ci 43113498266Sopenharmony_ci case CURL_WANTYES: 43213498266Sopenharmony_ci switch(tn->himq[option]) { 43313498266Sopenharmony_ci case CURL_EMPTY: 43413498266Sopenharmony_ci tn->him[option] = CURL_YES; 43513498266Sopenharmony_ci break; 43613498266Sopenharmony_ci case CURL_OPPOSITE: 43713498266Sopenharmony_ci tn->him[option] = CURL_WANTNO; 43813498266Sopenharmony_ci tn->himq[option] = CURL_EMPTY; 43913498266Sopenharmony_ci send_negotiation(data, CURL_DONT, option); 44013498266Sopenharmony_ci break; 44113498266Sopenharmony_ci } 44213498266Sopenharmony_ci break; 44313498266Sopenharmony_ci } 44413498266Sopenharmony_ci} 44513498266Sopenharmony_ci 44613498266Sopenharmony_cistatic 44713498266Sopenharmony_civoid rec_wont(struct Curl_easy *data, int option) 44813498266Sopenharmony_ci{ 44913498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 45013498266Sopenharmony_ci switch(tn->him[option]) { 45113498266Sopenharmony_ci case CURL_NO: 45213498266Sopenharmony_ci /* Already disabled */ 45313498266Sopenharmony_ci break; 45413498266Sopenharmony_ci 45513498266Sopenharmony_ci case CURL_YES: 45613498266Sopenharmony_ci tn->him[option] = CURL_NO; 45713498266Sopenharmony_ci send_negotiation(data, CURL_DONT, option); 45813498266Sopenharmony_ci break; 45913498266Sopenharmony_ci 46013498266Sopenharmony_ci case CURL_WANTNO: 46113498266Sopenharmony_ci switch(tn->himq[option]) { 46213498266Sopenharmony_ci case CURL_EMPTY: 46313498266Sopenharmony_ci tn->him[option] = CURL_NO; 46413498266Sopenharmony_ci break; 46513498266Sopenharmony_ci 46613498266Sopenharmony_ci case CURL_OPPOSITE: 46713498266Sopenharmony_ci tn->him[option] = CURL_WANTYES; 46813498266Sopenharmony_ci tn->himq[option] = CURL_EMPTY; 46913498266Sopenharmony_ci send_negotiation(data, CURL_DO, option); 47013498266Sopenharmony_ci break; 47113498266Sopenharmony_ci } 47213498266Sopenharmony_ci break; 47313498266Sopenharmony_ci 47413498266Sopenharmony_ci case CURL_WANTYES: 47513498266Sopenharmony_ci switch(tn->himq[option]) { 47613498266Sopenharmony_ci case CURL_EMPTY: 47713498266Sopenharmony_ci tn->him[option] = CURL_NO; 47813498266Sopenharmony_ci break; 47913498266Sopenharmony_ci case CURL_OPPOSITE: 48013498266Sopenharmony_ci tn->him[option] = CURL_NO; 48113498266Sopenharmony_ci tn->himq[option] = CURL_EMPTY; 48213498266Sopenharmony_ci break; 48313498266Sopenharmony_ci } 48413498266Sopenharmony_ci break; 48513498266Sopenharmony_ci } 48613498266Sopenharmony_ci} 48713498266Sopenharmony_ci 48813498266Sopenharmony_cistatic void 48913498266Sopenharmony_ciset_local_option(struct Curl_easy *data, int option, int newstate) 49013498266Sopenharmony_ci{ 49113498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 49213498266Sopenharmony_ci if(newstate == CURL_YES) { 49313498266Sopenharmony_ci switch(tn->us[option]) { 49413498266Sopenharmony_ci case CURL_NO: 49513498266Sopenharmony_ci tn->us[option] = CURL_WANTYES; 49613498266Sopenharmony_ci send_negotiation(data, CURL_WILL, option); 49713498266Sopenharmony_ci break; 49813498266Sopenharmony_ci 49913498266Sopenharmony_ci case CURL_YES: 50013498266Sopenharmony_ci /* Already enabled */ 50113498266Sopenharmony_ci break; 50213498266Sopenharmony_ci 50313498266Sopenharmony_ci case CURL_WANTNO: 50413498266Sopenharmony_ci switch(tn->usq[option]) { 50513498266Sopenharmony_ci case CURL_EMPTY: 50613498266Sopenharmony_ci /* Already negotiating for CURL_YES, queue the request */ 50713498266Sopenharmony_ci tn->usq[option] = CURL_OPPOSITE; 50813498266Sopenharmony_ci break; 50913498266Sopenharmony_ci case CURL_OPPOSITE: 51013498266Sopenharmony_ci /* Error: already queued an enable request */ 51113498266Sopenharmony_ci break; 51213498266Sopenharmony_ci } 51313498266Sopenharmony_ci break; 51413498266Sopenharmony_ci 51513498266Sopenharmony_ci case CURL_WANTYES: 51613498266Sopenharmony_ci switch(tn->usq[option]) { 51713498266Sopenharmony_ci case CURL_EMPTY: 51813498266Sopenharmony_ci /* Error: already negotiating for enable */ 51913498266Sopenharmony_ci break; 52013498266Sopenharmony_ci case CURL_OPPOSITE: 52113498266Sopenharmony_ci tn->usq[option] = CURL_EMPTY; 52213498266Sopenharmony_ci break; 52313498266Sopenharmony_ci } 52413498266Sopenharmony_ci break; 52513498266Sopenharmony_ci } 52613498266Sopenharmony_ci } 52713498266Sopenharmony_ci else { /* NO */ 52813498266Sopenharmony_ci switch(tn->us[option]) { 52913498266Sopenharmony_ci case CURL_NO: 53013498266Sopenharmony_ci /* Already disabled */ 53113498266Sopenharmony_ci break; 53213498266Sopenharmony_ci 53313498266Sopenharmony_ci case CURL_YES: 53413498266Sopenharmony_ci tn->us[option] = CURL_WANTNO; 53513498266Sopenharmony_ci send_negotiation(data, CURL_WONT, option); 53613498266Sopenharmony_ci break; 53713498266Sopenharmony_ci 53813498266Sopenharmony_ci case CURL_WANTNO: 53913498266Sopenharmony_ci switch(tn->usq[option]) { 54013498266Sopenharmony_ci case CURL_EMPTY: 54113498266Sopenharmony_ci /* Already negotiating for NO */ 54213498266Sopenharmony_ci break; 54313498266Sopenharmony_ci case CURL_OPPOSITE: 54413498266Sopenharmony_ci tn->usq[option] = CURL_EMPTY; 54513498266Sopenharmony_ci break; 54613498266Sopenharmony_ci } 54713498266Sopenharmony_ci break; 54813498266Sopenharmony_ci 54913498266Sopenharmony_ci case CURL_WANTYES: 55013498266Sopenharmony_ci switch(tn->usq[option]) { 55113498266Sopenharmony_ci case CURL_EMPTY: 55213498266Sopenharmony_ci tn->usq[option] = CURL_OPPOSITE; 55313498266Sopenharmony_ci break; 55413498266Sopenharmony_ci case CURL_OPPOSITE: 55513498266Sopenharmony_ci break; 55613498266Sopenharmony_ci } 55713498266Sopenharmony_ci break; 55813498266Sopenharmony_ci } 55913498266Sopenharmony_ci } 56013498266Sopenharmony_ci} 56113498266Sopenharmony_ci 56213498266Sopenharmony_cistatic 56313498266Sopenharmony_civoid rec_do(struct Curl_easy *data, int option) 56413498266Sopenharmony_ci{ 56513498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 56613498266Sopenharmony_ci switch(tn->us[option]) { 56713498266Sopenharmony_ci case CURL_NO: 56813498266Sopenharmony_ci if(tn->us_preferred[option] == CURL_YES) { 56913498266Sopenharmony_ci tn->us[option] = CURL_YES; 57013498266Sopenharmony_ci send_negotiation(data, CURL_WILL, option); 57113498266Sopenharmony_ci if(tn->subnegotiation[option] == CURL_YES) 57213498266Sopenharmony_ci /* transmission of data option */ 57313498266Sopenharmony_ci sendsuboption(data, option); 57413498266Sopenharmony_ci } 57513498266Sopenharmony_ci else if(tn->subnegotiation[option] == CURL_YES) { 57613498266Sopenharmony_ci /* send information to achieve this option */ 57713498266Sopenharmony_ci tn->us[option] = CURL_YES; 57813498266Sopenharmony_ci send_negotiation(data, CURL_WILL, option); 57913498266Sopenharmony_ci sendsuboption(data, option); 58013498266Sopenharmony_ci } 58113498266Sopenharmony_ci else 58213498266Sopenharmony_ci send_negotiation(data, CURL_WONT, option); 58313498266Sopenharmony_ci break; 58413498266Sopenharmony_ci 58513498266Sopenharmony_ci case CURL_YES: 58613498266Sopenharmony_ci /* Already enabled */ 58713498266Sopenharmony_ci break; 58813498266Sopenharmony_ci 58913498266Sopenharmony_ci case CURL_WANTNO: 59013498266Sopenharmony_ci switch(tn->usq[option]) { 59113498266Sopenharmony_ci case CURL_EMPTY: 59213498266Sopenharmony_ci /* Error: DONT answered by WILL */ 59313498266Sopenharmony_ci tn->us[option] = CURL_NO; 59413498266Sopenharmony_ci break; 59513498266Sopenharmony_ci case CURL_OPPOSITE: 59613498266Sopenharmony_ci /* Error: DONT answered by WILL */ 59713498266Sopenharmony_ci tn->us[option] = CURL_YES; 59813498266Sopenharmony_ci tn->usq[option] = CURL_EMPTY; 59913498266Sopenharmony_ci break; 60013498266Sopenharmony_ci } 60113498266Sopenharmony_ci break; 60213498266Sopenharmony_ci 60313498266Sopenharmony_ci case CURL_WANTYES: 60413498266Sopenharmony_ci switch(tn->usq[option]) { 60513498266Sopenharmony_ci case CURL_EMPTY: 60613498266Sopenharmony_ci tn->us[option] = CURL_YES; 60713498266Sopenharmony_ci if(tn->subnegotiation[option] == CURL_YES) { 60813498266Sopenharmony_ci /* transmission of data option */ 60913498266Sopenharmony_ci sendsuboption(data, option); 61013498266Sopenharmony_ci } 61113498266Sopenharmony_ci break; 61213498266Sopenharmony_ci case CURL_OPPOSITE: 61313498266Sopenharmony_ci tn->us[option] = CURL_WANTNO; 61413498266Sopenharmony_ci tn->himq[option] = CURL_EMPTY; 61513498266Sopenharmony_ci send_negotiation(data, CURL_WONT, option); 61613498266Sopenharmony_ci break; 61713498266Sopenharmony_ci } 61813498266Sopenharmony_ci break; 61913498266Sopenharmony_ci } 62013498266Sopenharmony_ci} 62113498266Sopenharmony_ci 62213498266Sopenharmony_cistatic 62313498266Sopenharmony_civoid rec_dont(struct Curl_easy *data, int option) 62413498266Sopenharmony_ci{ 62513498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 62613498266Sopenharmony_ci switch(tn->us[option]) { 62713498266Sopenharmony_ci case CURL_NO: 62813498266Sopenharmony_ci /* Already disabled */ 62913498266Sopenharmony_ci break; 63013498266Sopenharmony_ci 63113498266Sopenharmony_ci case CURL_YES: 63213498266Sopenharmony_ci tn->us[option] = CURL_NO; 63313498266Sopenharmony_ci send_negotiation(data, CURL_WONT, option); 63413498266Sopenharmony_ci break; 63513498266Sopenharmony_ci 63613498266Sopenharmony_ci case CURL_WANTNO: 63713498266Sopenharmony_ci switch(tn->usq[option]) { 63813498266Sopenharmony_ci case CURL_EMPTY: 63913498266Sopenharmony_ci tn->us[option] = CURL_NO; 64013498266Sopenharmony_ci break; 64113498266Sopenharmony_ci 64213498266Sopenharmony_ci case CURL_OPPOSITE: 64313498266Sopenharmony_ci tn->us[option] = CURL_WANTYES; 64413498266Sopenharmony_ci tn->usq[option] = CURL_EMPTY; 64513498266Sopenharmony_ci send_negotiation(data, CURL_WILL, option); 64613498266Sopenharmony_ci break; 64713498266Sopenharmony_ci } 64813498266Sopenharmony_ci break; 64913498266Sopenharmony_ci 65013498266Sopenharmony_ci case CURL_WANTYES: 65113498266Sopenharmony_ci switch(tn->usq[option]) { 65213498266Sopenharmony_ci case CURL_EMPTY: 65313498266Sopenharmony_ci tn->us[option] = CURL_NO; 65413498266Sopenharmony_ci break; 65513498266Sopenharmony_ci case CURL_OPPOSITE: 65613498266Sopenharmony_ci tn->us[option] = CURL_NO; 65713498266Sopenharmony_ci tn->usq[option] = CURL_EMPTY; 65813498266Sopenharmony_ci break; 65913498266Sopenharmony_ci } 66013498266Sopenharmony_ci break; 66113498266Sopenharmony_ci } 66213498266Sopenharmony_ci} 66313498266Sopenharmony_ci 66413498266Sopenharmony_ci 66513498266Sopenharmony_cistatic void printsub(struct Curl_easy *data, 66613498266Sopenharmony_ci int direction, /* '<' or '>' */ 66713498266Sopenharmony_ci unsigned char *pointer, /* where suboption data is */ 66813498266Sopenharmony_ci size_t length) /* length of suboption data */ 66913498266Sopenharmony_ci{ 67013498266Sopenharmony_ci if(data->set.verbose) { 67113498266Sopenharmony_ci unsigned int i = 0; 67213498266Sopenharmony_ci if(direction) { 67313498266Sopenharmony_ci infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); 67413498266Sopenharmony_ci if(length >= 3) { 67513498266Sopenharmony_ci int j; 67613498266Sopenharmony_ci 67713498266Sopenharmony_ci i = pointer[length-2]; 67813498266Sopenharmony_ci j = pointer[length-1]; 67913498266Sopenharmony_ci 68013498266Sopenharmony_ci if(i != CURL_IAC || j != CURL_SE) { 68113498266Sopenharmony_ci infof(data, "(terminated by "); 68213498266Sopenharmony_ci if(CURL_TELOPT_OK(i)) 68313498266Sopenharmony_ci infof(data, "%s ", CURL_TELOPT(i)); 68413498266Sopenharmony_ci else if(CURL_TELCMD_OK(i)) 68513498266Sopenharmony_ci infof(data, "%s ", CURL_TELCMD(i)); 68613498266Sopenharmony_ci else 68713498266Sopenharmony_ci infof(data, "%u ", i); 68813498266Sopenharmony_ci if(CURL_TELOPT_OK(j)) 68913498266Sopenharmony_ci infof(data, "%s", CURL_TELOPT(j)); 69013498266Sopenharmony_ci else if(CURL_TELCMD_OK(j)) 69113498266Sopenharmony_ci infof(data, "%s", CURL_TELCMD(j)); 69213498266Sopenharmony_ci else 69313498266Sopenharmony_ci infof(data, "%d", j); 69413498266Sopenharmony_ci infof(data, ", not IAC SE) "); 69513498266Sopenharmony_ci } 69613498266Sopenharmony_ci } 69713498266Sopenharmony_ci length -= 2; 69813498266Sopenharmony_ci } 69913498266Sopenharmony_ci if(length < 1) { 70013498266Sopenharmony_ci infof(data, "(Empty suboption?)"); 70113498266Sopenharmony_ci return; 70213498266Sopenharmony_ci } 70313498266Sopenharmony_ci 70413498266Sopenharmony_ci if(CURL_TELOPT_OK(pointer[0])) { 70513498266Sopenharmony_ci switch(pointer[0]) { 70613498266Sopenharmony_ci case CURL_TELOPT_TTYPE: 70713498266Sopenharmony_ci case CURL_TELOPT_XDISPLOC: 70813498266Sopenharmony_ci case CURL_TELOPT_NEW_ENVIRON: 70913498266Sopenharmony_ci case CURL_TELOPT_NAWS: 71013498266Sopenharmony_ci infof(data, "%s", CURL_TELOPT(pointer[0])); 71113498266Sopenharmony_ci break; 71213498266Sopenharmony_ci default: 71313498266Sopenharmony_ci infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0])); 71413498266Sopenharmony_ci break; 71513498266Sopenharmony_ci } 71613498266Sopenharmony_ci } 71713498266Sopenharmony_ci else 71813498266Sopenharmony_ci infof(data, "%d (unknown)", pointer[i]); 71913498266Sopenharmony_ci 72013498266Sopenharmony_ci switch(pointer[0]) { 72113498266Sopenharmony_ci case CURL_TELOPT_NAWS: 72213498266Sopenharmony_ci if(length > 4) 72313498266Sopenharmony_ci infof(data, "Width: %d ; Height: %d", (pointer[1]<<8) | pointer[2], 72413498266Sopenharmony_ci (pointer[3]<<8) | pointer[4]); 72513498266Sopenharmony_ci break; 72613498266Sopenharmony_ci default: 72713498266Sopenharmony_ci switch(pointer[1]) { 72813498266Sopenharmony_ci case CURL_TELQUAL_IS: 72913498266Sopenharmony_ci infof(data, " IS"); 73013498266Sopenharmony_ci break; 73113498266Sopenharmony_ci case CURL_TELQUAL_SEND: 73213498266Sopenharmony_ci infof(data, " SEND"); 73313498266Sopenharmony_ci break; 73413498266Sopenharmony_ci case CURL_TELQUAL_INFO: 73513498266Sopenharmony_ci infof(data, " INFO/REPLY"); 73613498266Sopenharmony_ci break; 73713498266Sopenharmony_ci case CURL_TELQUAL_NAME: 73813498266Sopenharmony_ci infof(data, " NAME"); 73913498266Sopenharmony_ci break; 74013498266Sopenharmony_ci } 74113498266Sopenharmony_ci 74213498266Sopenharmony_ci switch(pointer[0]) { 74313498266Sopenharmony_ci case CURL_TELOPT_TTYPE: 74413498266Sopenharmony_ci case CURL_TELOPT_XDISPLOC: 74513498266Sopenharmony_ci pointer[length] = 0; 74613498266Sopenharmony_ci infof(data, " \"%s\"", &pointer[2]); 74713498266Sopenharmony_ci break; 74813498266Sopenharmony_ci case CURL_TELOPT_NEW_ENVIRON: 74913498266Sopenharmony_ci if(pointer[1] == CURL_TELQUAL_IS) { 75013498266Sopenharmony_ci infof(data, " "); 75113498266Sopenharmony_ci for(i = 3; i < length; i++) { 75213498266Sopenharmony_ci switch(pointer[i]) { 75313498266Sopenharmony_ci case CURL_NEW_ENV_VAR: 75413498266Sopenharmony_ci infof(data, ", "); 75513498266Sopenharmony_ci break; 75613498266Sopenharmony_ci case CURL_NEW_ENV_VALUE: 75713498266Sopenharmony_ci infof(data, " = "); 75813498266Sopenharmony_ci break; 75913498266Sopenharmony_ci default: 76013498266Sopenharmony_ci infof(data, "%c", pointer[i]); 76113498266Sopenharmony_ci break; 76213498266Sopenharmony_ci } 76313498266Sopenharmony_ci } 76413498266Sopenharmony_ci } 76513498266Sopenharmony_ci break; 76613498266Sopenharmony_ci default: 76713498266Sopenharmony_ci for(i = 2; i < length; i++) 76813498266Sopenharmony_ci infof(data, " %.2x", pointer[i]); 76913498266Sopenharmony_ci break; 77013498266Sopenharmony_ci } 77113498266Sopenharmony_ci } 77213498266Sopenharmony_ci } 77313498266Sopenharmony_ci} 77413498266Sopenharmony_ci 77513498266Sopenharmony_ci#ifdef _MSC_VER 77613498266Sopenharmony_ci#pragma warning(push) 77713498266Sopenharmony_ci/* warning C4706: assignment within conditional expression */ 77813498266Sopenharmony_ci#pragma warning(disable:4706) 77913498266Sopenharmony_ci#endif 78013498266Sopenharmony_cistatic bool str_is_nonascii(const char *str) 78113498266Sopenharmony_ci{ 78213498266Sopenharmony_ci char c; 78313498266Sopenharmony_ci while((c = *str++)) 78413498266Sopenharmony_ci if(c & 0x80) 78513498266Sopenharmony_ci return TRUE; 78613498266Sopenharmony_ci 78713498266Sopenharmony_ci return FALSE; 78813498266Sopenharmony_ci} 78913498266Sopenharmony_ci#ifdef _MSC_VER 79013498266Sopenharmony_ci#pragma warning(pop) 79113498266Sopenharmony_ci#endif 79213498266Sopenharmony_ci 79313498266Sopenharmony_cistatic CURLcode check_telnet_options(struct Curl_easy *data) 79413498266Sopenharmony_ci{ 79513498266Sopenharmony_ci struct curl_slist *head; 79613498266Sopenharmony_ci struct curl_slist *beg; 79713498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 79813498266Sopenharmony_ci CURLcode result = CURLE_OK; 79913498266Sopenharmony_ci 80013498266Sopenharmony_ci /* Add the user name as an environment variable if it 80113498266Sopenharmony_ci was given on the command line */ 80213498266Sopenharmony_ci if(data->state.aptr.user) { 80313498266Sopenharmony_ci char buffer[256]; 80413498266Sopenharmony_ci if(str_is_nonascii(data->conn->user)) { 80513498266Sopenharmony_ci DEBUGF(infof(data, "set a non ASCII user name in telnet")); 80613498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 80713498266Sopenharmony_ci } 80813498266Sopenharmony_ci msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); 80913498266Sopenharmony_ci beg = curl_slist_append(tn->telnet_vars, buffer); 81013498266Sopenharmony_ci if(!beg) { 81113498266Sopenharmony_ci curl_slist_free_all(tn->telnet_vars); 81213498266Sopenharmony_ci tn->telnet_vars = NULL; 81313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 81413498266Sopenharmony_ci } 81513498266Sopenharmony_ci tn->telnet_vars = beg; 81613498266Sopenharmony_ci tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; 81713498266Sopenharmony_ci } 81813498266Sopenharmony_ci 81913498266Sopenharmony_ci for(head = data->set.telnet_options; head && !result; head = head->next) { 82013498266Sopenharmony_ci size_t olen; 82113498266Sopenharmony_ci char *option = head->data; 82213498266Sopenharmony_ci char *arg; 82313498266Sopenharmony_ci char *sep = strchr(option, '='); 82413498266Sopenharmony_ci if(sep) { 82513498266Sopenharmony_ci olen = sep - option; 82613498266Sopenharmony_ci arg = ++sep; 82713498266Sopenharmony_ci if(str_is_nonascii(arg)) 82813498266Sopenharmony_ci continue; 82913498266Sopenharmony_ci switch(olen) { 83013498266Sopenharmony_ci case 5: 83113498266Sopenharmony_ci /* Terminal type */ 83213498266Sopenharmony_ci if(strncasecompare(option, "TTYPE", 5)) { 83313498266Sopenharmony_ci size_t l = strlen(arg); 83413498266Sopenharmony_ci if(l < sizeof(tn->subopt_ttype)) { 83513498266Sopenharmony_ci strcpy(tn->subopt_ttype, arg); 83613498266Sopenharmony_ci tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; 83713498266Sopenharmony_ci break; 83813498266Sopenharmony_ci } 83913498266Sopenharmony_ci } 84013498266Sopenharmony_ci result = CURLE_UNKNOWN_OPTION; 84113498266Sopenharmony_ci break; 84213498266Sopenharmony_ci 84313498266Sopenharmony_ci case 8: 84413498266Sopenharmony_ci /* Display variable */ 84513498266Sopenharmony_ci if(strncasecompare(option, "XDISPLOC", 8)) { 84613498266Sopenharmony_ci size_t l = strlen(arg); 84713498266Sopenharmony_ci if(l < sizeof(tn->subopt_xdisploc)) { 84813498266Sopenharmony_ci strcpy(tn->subopt_xdisploc, arg); 84913498266Sopenharmony_ci tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; 85013498266Sopenharmony_ci break; 85113498266Sopenharmony_ci } 85213498266Sopenharmony_ci } 85313498266Sopenharmony_ci result = CURLE_UNKNOWN_OPTION; 85413498266Sopenharmony_ci break; 85513498266Sopenharmony_ci 85613498266Sopenharmony_ci case 7: 85713498266Sopenharmony_ci /* Environment variable */ 85813498266Sopenharmony_ci if(strncasecompare(option, "NEW_ENV", 7)) { 85913498266Sopenharmony_ci beg = curl_slist_append(tn->telnet_vars, arg); 86013498266Sopenharmony_ci if(!beg) { 86113498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 86213498266Sopenharmony_ci break; 86313498266Sopenharmony_ci } 86413498266Sopenharmony_ci tn->telnet_vars = beg; 86513498266Sopenharmony_ci tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; 86613498266Sopenharmony_ci } 86713498266Sopenharmony_ci else 86813498266Sopenharmony_ci result = CURLE_UNKNOWN_OPTION; 86913498266Sopenharmony_ci break; 87013498266Sopenharmony_ci 87113498266Sopenharmony_ci case 2: 87213498266Sopenharmony_ci /* Window Size */ 87313498266Sopenharmony_ci if(strncasecompare(option, "WS", 2)) { 87413498266Sopenharmony_ci char *p; 87513498266Sopenharmony_ci unsigned long x = strtoul(arg, &p, 10); 87613498266Sopenharmony_ci unsigned long y = 0; 87713498266Sopenharmony_ci if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') { 87813498266Sopenharmony_ci p++; 87913498266Sopenharmony_ci y = strtoul(p, NULL, 10); 88013498266Sopenharmony_ci if(y && (y <= 0xffff)) { 88113498266Sopenharmony_ci tn->subopt_wsx = (unsigned short)x; 88213498266Sopenharmony_ci tn->subopt_wsy = (unsigned short)y; 88313498266Sopenharmony_ci tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; 88413498266Sopenharmony_ci } 88513498266Sopenharmony_ci } 88613498266Sopenharmony_ci if(!y) { 88713498266Sopenharmony_ci failf(data, "Syntax error in telnet option: %s", head->data); 88813498266Sopenharmony_ci result = CURLE_SETOPT_OPTION_SYNTAX; 88913498266Sopenharmony_ci } 89013498266Sopenharmony_ci } 89113498266Sopenharmony_ci else 89213498266Sopenharmony_ci result = CURLE_UNKNOWN_OPTION; 89313498266Sopenharmony_ci break; 89413498266Sopenharmony_ci 89513498266Sopenharmony_ci case 6: 89613498266Sopenharmony_ci /* To take care or not of the 8th bit in data exchange */ 89713498266Sopenharmony_ci if(strncasecompare(option, "BINARY", 6)) { 89813498266Sopenharmony_ci int binary_option = atoi(arg); 89913498266Sopenharmony_ci if(binary_option != 1) { 90013498266Sopenharmony_ci tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; 90113498266Sopenharmony_ci tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; 90213498266Sopenharmony_ci } 90313498266Sopenharmony_ci } 90413498266Sopenharmony_ci else 90513498266Sopenharmony_ci result = CURLE_UNKNOWN_OPTION; 90613498266Sopenharmony_ci break; 90713498266Sopenharmony_ci default: 90813498266Sopenharmony_ci failf(data, "Unknown telnet option %s", head->data); 90913498266Sopenharmony_ci result = CURLE_UNKNOWN_OPTION; 91013498266Sopenharmony_ci break; 91113498266Sopenharmony_ci } 91213498266Sopenharmony_ci } 91313498266Sopenharmony_ci else { 91413498266Sopenharmony_ci failf(data, "Syntax error in telnet option: %s", head->data); 91513498266Sopenharmony_ci result = CURLE_SETOPT_OPTION_SYNTAX; 91613498266Sopenharmony_ci } 91713498266Sopenharmony_ci } 91813498266Sopenharmony_ci 91913498266Sopenharmony_ci if(result) { 92013498266Sopenharmony_ci curl_slist_free_all(tn->telnet_vars); 92113498266Sopenharmony_ci tn->telnet_vars = NULL; 92213498266Sopenharmony_ci } 92313498266Sopenharmony_ci 92413498266Sopenharmony_ci return result; 92513498266Sopenharmony_ci} 92613498266Sopenharmony_ci 92713498266Sopenharmony_ci/* 92813498266Sopenharmony_ci * suboption() 92913498266Sopenharmony_ci * 93013498266Sopenharmony_ci * Look at the sub-option buffer, and try to be helpful to the other 93113498266Sopenharmony_ci * side. 93213498266Sopenharmony_ci */ 93313498266Sopenharmony_ci 93413498266Sopenharmony_cistatic void suboption(struct Curl_easy *data) 93513498266Sopenharmony_ci{ 93613498266Sopenharmony_ci struct curl_slist *v; 93713498266Sopenharmony_ci unsigned char temp[2048]; 93813498266Sopenharmony_ci ssize_t bytes_written; 93913498266Sopenharmony_ci size_t len; 94013498266Sopenharmony_ci int err; 94113498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 94213498266Sopenharmony_ci struct connectdata *conn = data->conn; 94313498266Sopenharmony_ci 94413498266Sopenharmony_ci printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2); 94513498266Sopenharmony_ci switch(CURL_SB_GET(tn)) { 94613498266Sopenharmony_ci case CURL_TELOPT_TTYPE: 94713498266Sopenharmony_ci len = strlen(tn->subopt_ttype) + 4 + 2; 94813498266Sopenharmony_ci msnprintf((char *)temp, sizeof(temp), 94913498266Sopenharmony_ci "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, 95013498266Sopenharmony_ci CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); 95113498266Sopenharmony_ci bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); 95213498266Sopenharmony_ci if(bytes_written < 0) { 95313498266Sopenharmony_ci err = SOCKERRNO; 95413498266Sopenharmony_ci failf(data,"Sending data failed (%d)",err); 95513498266Sopenharmony_ci } 95613498266Sopenharmony_ci printsub(data, '>', &temp[2], len-2); 95713498266Sopenharmony_ci break; 95813498266Sopenharmony_ci case CURL_TELOPT_XDISPLOC: 95913498266Sopenharmony_ci len = strlen(tn->subopt_xdisploc) + 4 + 2; 96013498266Sopenharmony_ci msnprintf((char *)temp, sizeof(temp), 96113498266Sopenharmony_ci "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, 96213498266Sopenharmony_ci CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); 96313498266Sopenharmony_ci bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); 96413498266Sopenharmony_ci if(bytes_written < 0) { 96513498266Sopenharmony_ci err = SOCKERRNO; 96613498266Sopenharmony_ci failf(data,"Sending data failed (%d)",err); 96713498266Sopenharmony_ci } 96813498266Sopenharmony_ci printsub(data, '>', &temp[2], len-2); 96913498266Sopenharmony_ci break; 97013498266Sopenharmony_ci case CURL_TELOPT_NEW_ENVIRON: 97113498266Sopenharmony_ci msnprintf((char *)temp, sizeof(temp), 97213498266Sopenharmony_ci "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON, 97313498266Sopenharmony_ci CURL_TELQUAL_IS); 97413498266Sopenharmony_ci len = 4; 97513498266Sopenharmony_ci 97613498266Sopenharmony_ci for(v = tn->telnet_vars; v; v = v->next) { 97713498266Sopenharmony_ci size_t tmplen = (strlen(v->data) + 1); 97813498266Sopenharmony_ci /* Add the variable if it fits */ 97913498266Sopenharmony_ci if(len + tmplen < (int)sizeof(temp)-6) { 98013498266Sopenharmony_ci char *s = strchr(v->data, ','); 98113498266Sopenharmony_ci if(!s) 98213498266Sopenharmony_ci len += msnprintf((char *)&temp[len], sizeof(temp) - len, 98313498266Sopenharmony_ci "%c%s", CURL_NEW_ENV_VAR, v->data); 98413498266Sopenharmony_ci else { 98513498266Sopenharmony_ci size_t vlen = s - v->data; 98613498266Sopenharmony_ci len += msnprintf((char *)&temp[len], sizeof(temp) - len, 98713498266Sopenharmony_ci "%c%.*s%c%s", CURL_NEW_ENV_VAR, 98813498266Sopenharmony_ci (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s); 98913498266Sopenharmony_ci } 99013498266Sopenharmony_ci } 99113498266Sopenharmony_ci } 99213498266Sopenharmony_ci msnprintf((char *)&temp[len], sizeof(temp) - len, 99313498266Sopenharmony_ci "%c%c", CURL_IAC, CURL_SE); 99413498266Sopenharmony_ci len += 2; 99513498266Sopenharmony_ci bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len); 99613498266Sopenharmony_ci if(bytes_written < 0) { 99713498266Sopenharmony_ci err = SOCKERRNO; 99813498266Sopenharmony_ci failf(data,"Sending data failed (%d)",err); 99913498266Sopenharmony_ci } 100013498266Sopenharmony_ci printsub(data, '>', &temp[2], len-2); 100113498266Sopenharmony_ci break; 100213498266Sopenharmony_ci } 100313498266Sopenharmony_ci return; 100413498266Sopenharmony_ci} 100513498266Sopenharmony_ci 100613498266Sopenharmony_ci 100713498266Sopenharmony_ci/* 100813498266Sopenharmony_ci * sendsuboption() 100913498266Sopenharmony_ci * 101013498266Sopenharmony_ci * Send suboption information to the server side. 101113498266Sopenharmony_ci */ 101213498266Sopenharmony_ci 101313498266Sopenharmony_cistatic void sendsuboption(struct Curl_easy *data, int option) 101413498266Sopenharmony_ci{ 101513498266Sopenharmony_ci ssize_t bytes_written; 101613498266Sopenharmony_ci int err; 101713498266Sopenharmony_ci unsigned short x, y; 101813498266Sopenharmony_ci unsigned char *uc1, *uc2; 101913498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 102013498266Sopenharmony_ci struct connectdata *conn = data->conn; 102113498266Sopenharmony_ci 102213498266Sopenharmony_ci switch(option) { 102313498266Sopenharmony_ci case CURL_TELOPT_NAWS: 102413498266Sopenharmony_ci /* We prepare data to be sent */ 102513498266Sopenharmony_ci CURL_SB_CLEAR(tn); 102613498266Sopenharmony_ci CURL_SB_ACCUM(tn, CURL_IAC); 102713498266Sopenharmony_ci CURL_SB_ACCUM(tn, CURL_SB); 102813498266Sopenharmony_ci CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS); 102913498266Sopenharmony_ci /* We must deal either with little or big endian processors */ 103013498266Sopenharmony_ci /* Window size must be sent according to the 'network order' */ 103113498266Sopenharmony_ci x = htons(tn->subopt_wsx); 103213498266Sopenharmony_ci y = htons(tn->subopt_wsy); 103313498266Sopenharmony_ci uc1 = (unsigned char *)&x; 103413498266Sopenharmony_ci uc2 = (unsigned char *)&y; 103513498266Sopenharmony_ci CURL_SB_ACCUM(tn, uc1[0]); 103613498266Sopenharmony_ci CURL_SB_ACCUM(tn, uc1[1]); 103713498266Sopenharmony_ci CURL_SB_ACCUM(tn, uc2[0]); 103813498266Sopenharmony_ci CURL_SB_ACCUM(tn, uc2[1]); 103913498266Sopenharmony_ci 104013498266Sopenharmony_ci CURL_SB_ACCUM(tn, CURL_IAC); 104113498266Sopenharmony_ci CURL_SB_ACCUM(tn, CURL_SE); 104213498266Sopenharmony_ci CURL_SB_TERM(tn); 104313498266Sopenharmony_ci /* data suboption is now ready */ 104413498266Sopenharmony_ci 104513498266Sopenharmony_ci printsub(data, '>', (unsigned char *)tn->subbuffer + 2, 104613498266Sopenharmony_ci CURL_SB_LEN(tn)-2); 104713498266Sopenharmony_ci 104813498266Sopenharmony_ci /* we send the header of the suboption... */ 104913498266Sopenharmony_ci bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3); 105013498266Sopenharmony_ci if(bytes_written < 0) { 105113498266Sopenharmony_ci err = SOCKERRNO; 105213498266Sopenharmony_ci failf(data, "Sending data failed (%d)", err); 105313498266Sopenharmony_ci } 105413498266Sopenharmony_ci /* ... then the window size with the send_telnet_data() function 105513498266Sopenharmony_ci to deal with 0xFF cases ... */ 105613498266Sopenharmony_ci send_telnet_data(data, (char *)tn->subbuffer + 3, 4); 105713498266Sopenharmony_ci /* ... and the footer */ 105813498266Sopenharmony_ci bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2); 105913498266Sopenharmony_ci if(bytes_written < 0) { 106013498266Sopenharmony_ci err = SOCKERRNO; 106113498266Sopenharmony_ci failf(data, "Sending data failed (%d)", err); 106213498266Sopenharmony_ci } 106313498266Sopenharmony_ci break; 106413498266Sopenharmony_ci } 106513498266Sopenharmony_ci} 106613498266Sopenharmony_ci 106713498266Sopenharmony_ci 106813498266Sopenharmony_cistatic 106913498266Sopenharmony_ciCURLcode telrcv(struct Curl_easy *data, 107013498266Sopenharmony_ci const unsigned char *inbuf, /* Data received from socket */ 107113498266Sopenharmony_ci ssize_t count) /* Number of bytes received */ 107213498266Sopenharmony_ci{ 107313498266Sopenharmony_ci unsigned char c; 107413498266Sopenharmony_ci CURLcode result; 107513498266Sopenharmony_ci int in = 0; 107613498266Sopenharmony_ci int startwrite = -1; 107713498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 107813498266Sopenharmony_ci 107913498266Sopenharmony_ci#define startskipping() \ 108013498266Sopenharmony_ci if(startwrite >= 0) { \ 108113498266Sopenharmony_ci result = Curl_client_write(data, \ 108213498266Sopenharmony_ci CLIENTWRITE_BODY, \ 108313498266Sopenharmony_ci (char *)&inbuf[startwrite], \ 108413498266Sopenharmony_ci in-startwrite); \ 108513498266Sopenharmony_ci if(result) \ 108613498266Sopenharmony_ci return result; \ 108713498266Sopenharmony_ci } \ 108813498266Sopenharmony_ci startwrite = -1 108913498266Sopenharmony_ci 109013498266Sopenharmony_ci#define writebyte() \ 109113498266Sopenharmony_ci if(startwrite < 0) \ 109213498266Sopenharmony_ci startwrite = in 109313498266Sopenharmony_ci 109413498266Sopenharmony_ci#define bufferflush() startskipping() 109513498266Sopenharmony_ci 109613498266Sopenharmony_ci while(count--) { 109713498266Sopenharmony_ci c = inbuf[in]; 109813498266Sopenharmony_ci 109913498266Sopenharmony_ci switch(tn->telrcv_state) { 110013498266Sopenharmony_ci case CURL_TS_CR: 110113498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 110213498266Sopenharmony_ci if(c == '\0') { 110313498266Sopenharmony_ci startskipping(); 110413498266Sopenharmony_ci break; /* Ignore \0 after CR */ 110513498266Sopenharmony_ci } 110613498266Sopenharmony_ci writebyte(); 110713498266Sopenharmony_ci break; 110813498266Sopenharmony_ci 110913498266Sopenharmony_ci case CURL_TS_DATA: 111013498266Sopenharmony_ci if(c == CURL_IAC) { 111113498266Sopenharmony_ci tn->telrcv_state = CURL_TS_IAC; 111213498266Sopenharmony_ci startskipping(); 111313498266Sopenharmony_ci break; 111413498266Sopenharmony_ci } 111513498266Sopenharmony_ci else if(c == '\r') 111613498266Sopenharmony_ci tn->telrcv_state = CURL_TS_CR; 111713498266Sopenharmony_ci writebyte(); 111813498266Sopenharmony_ci break; 111913498266Sopenharmony_ci 112013498266Sopenharmony_ci case CURL_TS_IAC: 112113498266Sopenharmony_ciprocess_iac: 112213498266Sopenharmony_ci DEBUGASSERT(startwrite < 0); 112313498266Sopenharmony_ci switch(c) { 112413498266Sopenharmony_ci case CURL_WILL: 112513498266Sopenharmony_ci tn->telrcv_state = CURL_TS_WILL; 112613498266Sopenharmony_ci break; 112713498266Sopenharmony_ci case CURL_WONT: 112813498266Sopenharmony_ci tn->telrcv_state = CURL_TS_WONT; 112913498266Sopenharmony_ci break; 113013498266Sopenharmony_ci case CURL_DO: 113113498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DO; 113213498266Sopenharmony_ci break; 113313498266Sopenharmony_ci case CURL_DONT: 113413498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DONT; 113513498266Sopenharmony_ci break; 113613498266Sopenharmony_ci case CURL_SB: 113713498266Sopenharmony_ci CURL_SB_CLEAR(tn); 113813498266Sopenharmony_ci tn->telrcv_state = CURL_TS_SB; 113913498266Sopenharmony_ci break; 114013498266Sopenharmony_ci case CURL_IAC: 114113498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 114213498266Sopenharmony_ci writebyte(); 114313498266Sopenharmony_ci break; 114413498266Sopenharmony_ci case CURL_DM: 114513498266Sopenharmony_ci case CURL_NOP: 114613498266Sopenharmony_ci case CURL_GA: 114713498266Sopenharmony_ci default: 114813498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 114913498266Sopenharmony_ci printoption(data, "RCVD", CURL_IAC, c); 115013498266Sopenharmony_ci break; 115113498266Sopenharmony_ci } 115213498266Sopenharmony_ci break; 115313498266Sopenharmony_ci 115413498266Sopenharmony_ci case CURL_TS_WILL: 115513498266Sopenharmony_ci printoption(data, "RCVD", CURL_WILL, c); 115613498266Sopenharmony_ci tn->please_negotiate = 1; 115713498266Sopenharmony_ci rec_will(data, c); 115813498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 115913498266Sopenharmony_ci break; 116013498266Sopenharmony_ci 116113498266Sopenharmony_ci case CURL_TS_WONT: 116213498266Sopenharmony_ci printoption(data, "RCVD", CURL_WONT, c); 116313498266Sopenharmony_ci tn->please_negotiate = 1; 116413498266Sopenharmony_ci rec_wont(data, c); 116513498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 116613498266Sopenharmony_ci break; 116713498266Sopenharmony_ci 116813498266Sopenharmony_ci case CURL_TS_DO: 116913498266Sopenharmony_ci printoption(data, "RCVD", CURL_DO, c); 117013498266Sopenharmony_ci tn->please_negotiate = 1; 117113498266Sopenharmony_ci rec_do(data, c); 117213498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 117313498266Sopenharmony_ci break; 117413498266Sopenharmony_ci 117513498266Sopenharmony_ci case CURL_TS_DONT: 117613498266Sopenharmony_ci printoption(data, "RCVD", CURL_DONT, c); 117713498266Sopenharmony_ci tn->please_negotiate = 1; 117813498266Sopenharmony_ci rec_dont(data, c); 117913498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 118013498266Sopenharmony_ci break; 118113498266Sopenharmony_ci 118213498266Sopenharmony_ci case CURL_TS_SB: 118313498266Sopenharmony_ci if(c == CURL_IAC) 118413498266Sopenharmony_ci tn->telrcv_state = CURL_TS_SE; 118513498266Sopenharmony_ci else 118613498266Sopenharmony_ci CURL_SB_ACCUM(tn, c); 118713498266Sopenharmony_ci break; 118813498266Sopenharmony_ci 118913498266Sopenharmony_ci case CURL_TS_SE: 119013498266Sopenharmony_ci if(c != CURL_SE) { 119113498266Sopenharmony_ci if(c != CURL_IAC) { 119213498266Sopenharmony_ci /* 119313498266Sopenharmony_ci * This is an error. We only expect to get "IAC IAC" or "IAC SE". 119413498266Sopenharmony_ci * Several things may have happened. An IAC was not doubled, the 119513498266Sopenharmony_ci * IAC SE was left off, or another option got inserted into the 119613498266Sopenharmony_ci * suboption are all possibilities. If we assume that the IAC was 119713498266Sopenharmony_ci * not doubled, and really the IAC SE was left off, we could get 119813498266Sopenharmony_ci * into an infinite loop here. So, instead, we terminate the 119913498266Sopenharmony_ci * suboption, and process the partial suboption if we can. 120013498266Sopenharmony_ci */ 120113498266Sopenharmony_ci CURL_SB_ACCUM(tn, CURL_IAC); 120213498266Sopenharmony_ci CURL_SB_ACCUM(tn, c); 120313498266Sopenharmony_ci tn->subpointer -= 2; 120413498266Sopenharmony_ci CURL_SB_TERM(tn); 120513498266Sopenharmony_ci 120613498266Sopenharmony_ci printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); 120713498266Sopenharmony_ci suboption(data); /* handle sub-option */ 120813498266Sopenharmony_ci tn->telrcv_state = CURL_TS_IAC; 120913498266Sopenharmony_ci goto process_iac; 121013498266Sopenharmony_ci } 121113498266Sopenharmony_ci CURL_SB_ACCUM(tn, c); 121213498266Sopenharmony_ci tn->telrcv_state = CURL_TS_SB; 121313498266Sopenharmony_ci } 121413498266Sopenharmony_ci else { 121513498266Sopenharmony_ci CURL_SB_ACCUM(tn, CURL_IAC); 121613498266Sopenharmony_ci CURL_SB_ACCUM(tn, CURL_SE); 121713498266Sopenharmony_ci tn->subpointer -= 2; 121813498266Sopenharmony_ci CURL_SB_TERM(tn); 121913498266Sopenharmony_ci suboption(data); /* handle sub-option */ 122013498266Sopenharmony_ci tn->telrcv_state = CURL_TS_DATA; 122113498266Sopenharmony_ci } 122213498266Sopenharmony_ci break; 122313498266Sopenharmony_ci } 122413498266Sopenharmony_ci ++in; 122513498266Sopenharmony_ci } 122613498266Sopenharmony_ci bufferflush(); 122713498266Sopenharmony_ci return CURLE_OK; 122813498266Sopenharmony_ci} 122913498266Sopenharmony_ci 123013498266Sopenharmony_ci/* Escape and send a telnet data block */ 123113498266Sopenharmony_cistatic CURLcode send_telnet_data(struct Curl_easy *data, 123213498266Sopenharmony_ci char *buffer, ssize_t nread) 123313498266Sopenharmony_ci{ 123413498266Sopenharmony_ci ssize_t i, outlen; 123513498266Sopenharmony_ci unsigned char *outbuf; 123613498266Sopenharmony_ci CURLcode result = CURLE_OK; 123713498266Sopenharmony_ci ssize_t bytes_written, total_written = 0; 123813498266Sopenharmony_ci struct connectdata *conn = data->conn; 123913498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 124013498266Sopenharmony_ci 124113498266Sopenharmony_ci DEBUGASSERT(tn); 124213498266Sopenharmony_ci 124313498266Sopenharmony_ci if(memchr(buffer, CURL_IAC, nread)) { 124413498266Sopenharmony_ci /* only use the escape buffer when necessary */ 124513498266Sopenharmony_ci Curl_dyn_reset(&tn->out); 124613498266Sopenharmony_ci 124713498266Sopenharmony_ci for(i = 0; i < nread && !result; i++) { 124813498266Sopenharmony_ci result = Curl_dyn_addn(&tn->out, &buffer[i], 1); 124913498266Sopenharmony_ci if(!result && ((unsigned char)buffer[i] == CURL_IAC)) 125013498266Sopenharmony_ci /* IAC is FF in hex */ 125113498266Sopenharmony_ci result = Curl_dyn_addn(&tn->out, "\xff", 1); 125213498266Sopenharmony_ci } 125313498266Sopenharmony_ci 125413498266Sopenharmony_ci outlen = Curl_dyn_len(&tn->out); 125513498266Sopenharmony_ci outbuf = Curl_dyn_uptr(&tn->out); 125613498266Sopenharmony_ci } 125713498266Sopenharmony_ci else { 125813498266Sopenharmony_ci outlen = nread; 125913498266Sopenharmony_ci outbuf = (unsigned char *)buffer; 126013498266Sopenharmony_ci } 126113498266Sopenharmony_ci while(!result && total_written < outlen) { 126213498266Sopenharmony_ci /* Make sure socket is writable to avoid EWOULDBLOCK condition */ 126313498266Sopenharmony_ci struct pollfd pfd[1]; 126413498266Sopenharmony_ci pfd[0].fd = conn->sock[FIRSTSOCKET]; 126513498266Sopenharmony_ci pfd[0].events = POLLOUT; 126613498266Sopenharmony_ci switch(Curl_poll(pfd, 1, -1)) { 126713498266Sopenharmony_ci case -1: /* error, abort writing */ 126813498266Sopenharmony_ci case 0: /* timeout (will never happen) */ 126913498266Sopenharmony_ci result = CURLE_SEND_ERROR; 127013498266Sopenharmony_ci break; 127113498266Sopenharmony_ci default: /* write! */ 127213498266Sopenharmony_ci bytes_written = 0; 127313498266Sopenharmony_ci result = Curl_nwrite(data, FIRSTSOCKET, outbuf + total_written, 127413498266Sopenharmony_ci outlen - total_written, &bytes_written); 127513498266Sopenharmony_ci total_written += bytes_written; 127613498266Sopenharmony_ci break; 127713498266Sopenharmony_ci } 127813498266Sopenharmony_ci } 127913498266Sopenharmony_ci 128013498266Sopenharmony_ci return result; 128113498266Sopenharmony_ci} 128213498266Sopenharmony_ci 128313498266Sopenharmony_cistatic CURLcode telnet_done(struct Curl_easy *data, 128413498266Sopenharmony_ci CURLcode status, bool premature) 128513498266Sopenharmony_ci{ 128613498266Sopenharmony_ci struct TELNET *tn = data->req.p.telnet; 128713498266Sopenharmony_ci (void)status; /* unused */ 128813498266Sopenharmony_ci (void)premature; /* not used */ 128913498266Sopenharmony_ci 129013498266Sopenharmony_ci if(!tn) 129113498266Sopenharmony_ci return CURLE_OK; 129213498266Sopenharmony_ci 129313498266Sopenharmony_ci curl_slist_free_all(tn->telnet_vars); 129413498266Sopenharmony_ci tn->telnet_vars = NULL; 129513498266Sopenharmony_ci Curl_dyn_free(&tn->out); 129613498266Sopenharmony_ci return CURLE_OK; 129713498266Sopenharmony_ci} 129813498266Sopenharmony_ci 129913498266Sopenharmony_cistatic CURLcode telnet_do(struct Curl_easy *data, bool *done) 130013498266Sopenharmony_ci{ 130113498266Sopenharmony_ci CURLcode result; 130213498266Sopenharmony_ci struct connectdata *conn = data->conn; 130313498266Sopenharmony_ci curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; 130413498266Sopenharmony_ci#ifdef USE_WINSOCK 130513498266Sopenharmony_ci WSAEVENT event_handle; 130613498266Sopenharmony_ci WSANETWORKEVENTS events; 130713498266Sopenharmony_ci HANDLE stdin_handle; 130813498266Sopenharmony_ci HANDLE objs[2]; 130913498266Sopenharmony_ci DWORD obj_count; 131013498266Sopenharmony_ci DWORD wait_timeout; 131113498266Sopenharmony_ci DWORD readfile_read; 131213498266Sopenharmony_ci int err; 131313498266Sopenharmony_ci#else 131413498266Sopenharmony_ci timediff_t interval_ms; 131513498266Sopenharmony_ci struct pollfd pfd[2]; 131613498266Sopenharmony_ci int poll_cnt; 131713498266Sopenharmony_ci curl_off_t total_dl = 0; 131813498266Sopenharmony_ci curl_off_t total_ul = 0; 131913498266Sopenharmony_ci#endif 132013498266Sopenharmony_ci ssize_t nread; 132113498266Sopenharmony_ci struct curltime now; 132213498266Sopenharmony_ci bool keepon = TRUE; 132313498266Sopenharmony_ci char buffer[4*1024]; 132413498266Sopenharmony_ci struct TELNET *tn; 132513498266Sopenharmony_ci 132613498266Sopenharmony_ci *done = TRUE; /* unconditionally */ 132713498266Sopenharmony_ci 132813498266Sopenharmony_ci result = init_telnet(data); 132913498266Sopenharmony_ci if(result) 133013498266Sopenharmony_ci return result; 133113498266Sopenharmony_ci 133213498266Sopenharmony_ci tn = data->req.p.telnet; 133313498266Sopenharmony_ci 133413498266Sopenharmony_ci result = check_telnet_options(data); 133513498266Sopenharmony_ci if(result) 133613498266Sopenharmony_ci return result; 133713498266Sopenharmony_ci 133813498266Sopenharmony_ci#ifdef USE_WINSOCK 133913498266Sopenharmony_ci /* We want to wait for both stdin and the socket. Since 134013498266Sopenharmony_ci ** the select() function in winsock only works on sockets 134113498266Sopenharmony_ci ** we have to use the WaitForMultipleObjects() call. 134213498266Sopenharmony_ci */ 134313498266Sopenharmony_ci 134413498266Sopenharmony_ci /* First, create a sockets event object */ 134513498266Sopenharmony_ci event_handle = WSACreateEvent(); 134613498266Sopenharmony_ci if(event_handle == WSA_INVALID_EVENT) { 134713498266Sopenharmony_ci failf(data, "WSACreateEvent failed (%d)", SOCKERRNO); 134813498266Sopenharmony_ci return CURLE_FAILED_INIT; 134913498266Sopenharmony_ci } 135013498266Sopenharmony_ci 135113498266Sopenharmony_ci /* Tell winsock what events we want to listen to */ 135213498266Sopenharmony_ci if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { 135313498266Sopenharmony_ci WSACloseEvent(event_handle); 135413498266Sopenharmony_ci return CURLE_OK; 135513498266Sopenharmony_ci } 135613498266Sopenharmony_ci 135713498266Sopenharmony_ci /* The get the Windows file handle for stdin */ 135813498266Sopenharmony_ci stdin_handle = GetStdHandle(STD_INPUT_HANDLE); 135913498266Sopenharmony_ci 136013498266Sopenharmony_ci /* Create the list of objects to wait for */ 136113498266Sopenharmony_ci objs[0] = event_handle; 136213498266Sopenharmony_ci objs[1] = stdin_handle; 136313498266Sopenharmony_ci 136413498266Sopenharmony_ci /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, 136513498266Sopenharmony_ci else use the old WaitForMultipleObjects() way */ 136613498266Sopenharmony_ci if(GetFileType(stdin_handle) == FILE_TYPE_PIPE || 136713498266Sopenharmony_ci data->set.is_fread_set) { 136813498266Sopenharmony_ci /* Don't wait for stdin_handle, just wait for event_handle */ 136913498266Sopenharmony_ci obj_count = 1; 137013498266Sopenharmony_ci /* Check stdin_handle per 100 milliseconds */ 137113498266Sopenharmony_ci wait_timeout = 100; 137213498266Sopenharmony_ci } 137313498266Sopenharmony_ci else { 137413498266Sopenharmony_ci obj_count = 2; 137513498266Sopenharmony_ci wait_timeout = 1000; 137613498266Sopenharmony_ci } 137713498266Sopenharmony_ci 137813498266Sopenharmony_ci /* Keep on listening and act on events */ 137913498266Sopenharmony_ci while(keepon) { 138013498266Sopenharmony_ci const DWORD buf_size = (DWORD)sizeof(buffer); 138113498266Sopenharmony_ci DWORD waitret = WaitForMultipleObjects(obj_count, objs, 138213498266Sopenharmony_ci FALSE, wait_timeout); 138313498266Sopenharmony_ci switch(waitret) { 138413498266Sopenharmony_ci 138513498266Sopenharmony_ci case WAIT_TIMEOUT: 138613498266Sopenharmony_ci { 138713498266Sopenharmony_ci for(;;) { 138813498266Sopenharmony_ci if(data->set.is_fread_set) { 138913498266Sopenharmony_ci size_t n; 139013498266Sopenharmony_ci /* read from user-supplied method */ 139113498266Sopenharmony_ci n = data->state.fread_func(buffer, 1, buf_size, data->state.in); 139213498266Sopenharmony_ci if(n == CURL_READFUNC_ABORT) { 139313498266Sopenharmony_ci keepon = FALSE; 139413498266Sopenharmony_ci result = CURLE_READ_ERROR; 139513498266Sopenharmony_ci break; 139613498266Sopenharmony_ci } 139713498266Sopenharmony_ci 139813498266Sopenharmony_ci if(n == CURL_READFUNC_PAUSE) 139913498266Sopenharmony_ci break; 140013498266Sopenharmony_ci 140113498266Sopenharmony_ci if(n == 0) /* no bytes */ 140213498266Sopenharmony_ci break; 140313498266Sopenharmony_ci 140413498266Sopenharmony_ci /* fall through with number of bytes read */ 140513498266Sopenharmony_ci readfile_read = (DWORD)n; 140613498266Sopenharmony_ci } 140713498266Sopenharmony_ci else { 140813498266Sopenharmony_ci /* read from stdin */ 140913498266Sopenharmony_ci if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, 141013498266Sopenharmony_ci &readfile_read, NULL)) { 141113498266Sopenharmony_ci keepon = FALSE; 141213498266Sopenharmony_ci result = CURLE_READ_ERROR; 141313498266Sopenharmony_ci break; 141413498266Sopenharmony_ci } 141513498266Sopenharmony_ci 141613498266Sopenharmony_ci if(!readfile_read) 141713498266Sopenharmony_ci break; 141813498266Sopenharmony_ci 141913498266Sopenharmony_ci if(!ReadFile(stdin_handle, buffer, buf_size, 142013498266Sopenharmony_ci &readfile_read, NULL)) { 142113498266Sopenharmony_ci keepon = FALSE; 142213498266Sopenharmony_ci result = CURLE_READ_ERROR; 142313498266Sopenharmony_ci break; 142413498266Sopenharmony_ci } 142513498266Sopenharmony_ci } 142613498266Sopenharmony_ci 142713498266Sopenharmony_ci result = send_telnet_data(data, buffer, readfile_read); 142813498266Sopenharmony_ci if(result) { 142913498266Sopenharmony_ci keepon = FALSE; 143013498266Sopenharmony_ci break; 143113498266Sopenharmony_ci } 143213498266Sopenharmony_ci } 143313498266Sopenharmony_ci } 143413498266Sopenharmony_ci break; 143513498266Sopenharmony_ci 143613498266Sopenharmony_ci case WAIT_OBJECT_0 + 1: 143713498266Sopenharmony_ci { 143813498266Sopenharmony_ci if(!ReadFile(stdin_handle, buffer, buf_size, 143913498266Sopenharmony_ci &readfile_read, NULL)) { 144013498266Sopenharmony_ci keepon = FALSE; 144113498266Sopenharmony_ci result = CURLE_READ_ERROR; 144213498266Sopenharmony_ci break; 144313498266Sopenharmony_ci } 144413498266Sopenharmony_ci 144513498266Sopenharmony_ci result = send_telnet_data(data, buffer, readfile_read); 144613498266Sopenharmony_ci if(result) { 144713498266Sopenharmony_ci keepon = FALSE; 144813498266Sopenharmony_ci break; 144913498266Sopenharmony_ci } 145013498266Sopenharmony_ci } 145113498266Sopenharmony_ci break; 145213498266Sopenharmony_ci 145313498266Sopenharmony_ci case WAIT_OBJECT_0: 145413498266Sopenharmony_ci { 145513498266Sopenharmony_ci events.lNetworkEvents = 0; 145613498266Sopenharmony_ci if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) { 145713498266Sopenharmony_ci err = SOCKERRNO; 145813498266Sopenharmony_ci if(err != EINPROGRESS) { 145913498266Sopenharmony_ci infof(data, "WSAEnumNetworkEvents failed (%d)", err); 146013498266Sopenharmony_ci keepon = FALSE; 146113498266Sopenharmony_ci result = CURLE_READ_ERROR; 146213498266Sopenharmony_ci } 146313498266Sopenharmony_ci break; 146413498266Sopenharmony_ci } 146513498266Sopenharmony_ci if(events.lNetworkEvents & FD_READ) { 146613498266Sopenharmony_ci /* read data from network */ 146713498266Sopenharmony_ci result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread); 146813498266Sopenharmony_ci /* read would've blocked. Loop again */ 146913498266Sopenharmony_ci if(result == CURLE_AGAIN) 147013498266Sopenharmony_ci break; 147113498266Sopenharmony_ci /* returned not-zero, this an error */ 147213498266Sopenharmony_ci else if(result) { 147313498266Sopenharmony_ci keepon = FALSE; 147413498266Sopenharmony_ci break; 147513498266Sopenharmony_ci } 147613498266Sopenharmony_ci /* returned zero but actually received 0 or less here, 147713498266Sopenharmony_ci the server closed the connection and we bail out */ 147813498266Sopenharmony_ci else if(nread <= 0) { 147913498266Sopenharmony_ci keepon = FALSE; 148013498266Sopenharmony_ci break; 148113498266Sopenharmony_ci } 148213498266Sopenharmony_ci 148313498266Sopenharmony_ci result = telrcv(data, (unsigned char *) buffer, nread); 148413498266Sopenharmony_ci if(result) { 148513498266Sopenharmony_ci keepon = FALSE; 148613498266Sopenharmony_ci break; 148713498266Sopenharmony_ci } 148813498266Sopenharmony_ci 148913498266Sopenharmony_ci /* Negotiate if the peer has started negotiating, 149013498266Sopenharmony_ci otherwise don't. We don't want to speak telnet with 149113498266Sopenharmony_ci non-telnet servers, like POP or SMTP. */ 149213498266Sopenharmony_ci if(tn->please_negotiate && !tn->already_negotiated) { 149313498266Sopenharmony_ci negotiate(data); 149413498266Sopenharmony_ci tn->already_negotiated = 1; 149513498266Sopenharmony_ci } 149613498266Sopenharmony_ci } 149713498266Sopenharmony_ci if(events.lNetworkEvents & FD_CLOSE) { 149813498266Sopenharmony_ci keepon = FALSE; 149913498266Sopenharmony_ci } 150013498266Sopenharmony_ci } 150113498266Sopenharmony_ci break; 150213498266Sopenharmony_ci 150313498266Sopenharmony_ci } 150413498266Sopenharmony_ci 150513498266Sopenharmony_ci if(data->set.timeout) { 150613498266Sopenharmony_ci now = Curl_now(); 150713498266Sopenharmony_ci if(Curl_timediff(now, conn->created) >= data->set.timeout) { 150813498266Sopenharmony_ci failf(data, "Time-out"); 150913498266Sopenharmony_ci result = CURLE_OPERATION_TIMEDOUT; 151013498266Sopenharmony_ci keepon = FALSE; 151113498266Sopenharmony_ci } 151213498266Sopenharmony_ci } 151313498266Sopenharmony_ci } 151413498266Sopenharmony_ci 151513498266Sopenharmony_ci /* We called WSACreateEvent, so call WSACloseEvent */ 151613498266Sopenharmony_ci if(!WSACloseEvent(event_handle)) { 151713498266Sopenharmony_ci infof(data, "WSACloseEvent failed (%d)", SOCKERRNO); 151813498266Sopenharmony_ci } 151913498266Sopenharmony_ci#else 152013498266Sopenharmony_ci pfd[0].fd = sockfd; 152113498266Sopenharmony_ci pfd[0].events = POLLIN; 152213498266Sopenharmony_ci 152313498266Sopenharmony_ci if(data->set.is_fread_set) { 152413498266Sopenharmony_ci poll_cnt = 1; 152513498266Sopenharmony_ci interval_ms = 100; /* poll user-supplied read function */ 152613498266Sopenharmony_ci } 152713498266Sopenharmony_ci else { 152813498266Sopenharmony_ci /* really using fread, so infile is a FILE* */ 152913498266Sopenharmony_ci pfd[1].fd = fileno((FILE *)data->state.in); 153013498266Sopenharmony_ci pfd[1].events = POLLIN; 153113498266Sopenharmony_ci poll_cnt = 2; 153213498266Sopenharmony_ci interval_ms = 1 * 1000; 153313498266Sopenharmony_ci } 153413498266Sopenharmony_ci 153513498266Sopenharmony_ci while(keepon) { 153613498266Sopenharmony_ci DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt)); 153713498266Sopenharmony_ci switch(Curl_poll(pfd, poll_cnt, interval_ms)) { 153813498266Sopenharmony_ci case -1: /* error, stop reading */ 153913498266Sopenharmony_ci keepon = FALSE; 154013498266Sopenharmony_ci continue; 154113498266Sopenharmony_ci case 0: /* timeout */ 154213498266Sopenharmony_ci pfd[0].revents = 0; 154313498266Sopenharmony_ci pfd[1].revents = 0; 154413498266Sopenharmony_ci FALLTHROUGH(); 154513498266Sopenharmony_ci default: /* read! */ 154613498266Sopenharmony_ci if(pfd[0].revents & POLLIN) { 154713498266Sopenharmony_ci /* read data from network */ 154813498266Sopenharmony_ci result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread); 154913498266Sopenharmony_ci /* read would've blocked. Loop again */ 155013498266Sopenharmony_ci if(result == CURLE_AGAIN) 155113498266Sopenharmony_ci break; 155213498266Sopenharmony_ci /* returned not-zero, this an error */ 155313498266Sopenharmony_ci if(result) { 155413498266Sopenharmony_ci keepon = FALSE; 155513498266Sopenharmony_ci /* TODO: in test 1452, macOS sees a ECONNRESET sometimes? 155613498266Sopenharmony_ci * Is this the telnet test server not shutting down the socket 155713498266Sopenharmony_ci * in a clean way? Seems to be timing related, happens more 155813498266Sopenharmony_ci * on slow debug build */ 155913498266Sopenharmony_ci if(data->state.os_errno == ECONNRESET) { 156013498266Sopenharmony_ci DEBUGF(infof(data, "telnet_do, unexpected ECONNRESET on recv")); 156113498266Sopenharmony_ci } 156213498266Sopenharmony_ci break; 156313498266Sopenharmony_ci } 156413498266Sopenharmony_ci /* returned zero but actually received 0 or less here, 156513498266Sopenharmony_ci the server closed the connection and we bail out */ 156613498266Sopenharmony_ci else if(nread <= 0) { 156713498266Sopenharmony_ci keepon = FALSE; 156813498266Sopenharmony_ci break; 156913498266Sopenharmony_ci } 157013498266Sopenharmony_ci 157113498266Sopenharmony_ci total_dl += nread; 157213498266Sopenharmony_ci result = Curl_pgrsSetDownloadCounter(data, total_dl); 157313498266Sopenharmony_ci if(!result) 157413498266Sopenharmony_ci result = telrcv(data, (unsigned char *)buffer, nread); 157513498266Sopenharmony_ci if(result) { 157613498266Sopenharmony_ci keepon = FALSE; 157713498266Sopenharmony_ci break; 157813498266Sopenharmony_ci } 157913498266Sopenharmony_ci 158013498266Sopenharmony_ci /* Negotiate if the peer has started negotiating, 158113498266Sopenharmony_ci otherwise don't. We don't want to speak telnet with 158213498266Sopenharmony_ci non-telnet servers, like POP or SMTP. */ 158313498266Sopenharmony_ci if(tn->please_negotiate && !tn->already_negotiated) { 158413498266Sopenharmony_ci negotiate(data); 158513498266Sopenharmony_ci tn->already_negotiated = 1; 158613498266Sopenharmony_ci } 158713498266Sopenharmony_ci } 158813498266Sopenharmony_ci 158913498266Sopenharmony_ci nread = 0; 159013498266Sopenharmony_ci if(poll_cnt == 2) { 159113498266Sopenharmony_ci if(pfd[1].revents & POLLIN) { /* read from in file */ 159213498266Sopenharmony_ci nread = read(pfd[1].fd, buffer, sizeof(buffer)); 159313498266Sopenharmony_ci } 159413498266Sopenharmony_ci } 159513498266Sopenharmony_ci else { 159613498266Sopenharmony_ci /* read from user-supplied method */ 159713498266Sopenharmony_ci nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer), 159813498266Sopenharmony_ci data->state.in); 159913498266Sopenharmony_ci if(nread == CURL_READFUNC_ABORT) { 160013498266Sopenharmony_ci keepon = FALSE; 160113498266Sopenharmony_ci break; 160213498266Sopenharmony_ci } 160313498266Sopenharmony_ci if(nread == CURL_READFUNC_PAUSE) 160413498266Sopenharmony_ci break; 160513498266Sopenharmony_ci } 160613498266Sopenharmony_ci 160713498266Sopenharmony_ci if(nread > 0) { 160813498266Sopenharmony_ci result = send_telnet_data(data, buffer, nread); 160913498266Sopenharmony_ci if(result) { 161013498266Sopenharmony_ci keepon = FALSE; 161113498266Sopenharmony_ci break; 161213498266Sopenharmony_ci } 161313498266Sopenharmony_ci total_ul += nread; 161413498266Sopenharmony_ci Curl_pgrsSetUploadCounter(data, total_ul); 161513498266Sopenharmony_ci } 161613498266Sopenharmony_ci else if(nread < 0) 161713498266Sopenharmony_ci keepon = FALSE; 161813498266Sopenharmony_ci 161913498266Sopenharmony_ci break; 162013498266Sopenharmony_ci } /* poll switch statement */ 162113498266Sopenharmony_ci 162213498266Sopenharmony_ci if(data->set.timeout) { 162313498266Sopenharmony_ci now = Curl_now(); 162413498266Sopenharmony_ci if(Curl_timediff(now, conn->created) >= data->set.timeout) { 162513498266Sopenharmony_ci failf(data, "Time-out"); 162613498266Sopenharmony_ci result = CURLE_OPERATION_TIMEDOUT; 162713498266Sopenharmony_ci keepon = FALSE; 162813498266Sopenharmony_ci } 162913498266Sopenharmony_ci } 163013498266Sopenharmony_ci 163113498266Sopenharmony_ci if(Curl_pgrsUpdate(data)) { 163213498266Sopenharmony_ci result = CURLE_ABORTED_BY_CALLBACK; 163313498266Sopenharmony_ci break; 163413498266Sopenharmony_ci } 163513498266Sopenharmony_ci } 163613498266Sopenharmony_ci#endif 163713498266Sopenharmony_ci /* mark this as "no further transfer wanted" */ 163813498266Sopenharmony_ci Curl_setup_transfer(data, -1, -1, FALSE, -1); 163913498266Sopenharmony_ci 164013498266Sopenharmony_ci return result; 164113498266Sopenharmony_ci} 164213498266Sopenharmony_ci#endif 1643