xref: /aosp_15_r20/external/curl/lib/telnet.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_TELNET
28*6236dae4SAndroid Build Coastguard Worker 
29*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN_H
30*6236dae4SAndroid Build Coastguard Worker #include <netinet/in.h>
31*6236dae4SAndroid Build Coastguard Worker #endif
32*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
33*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
34*6236dae4SAndroid Build Coastguard Worker #endif
35*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
36*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
37*6236dae4SAndroid Build Coastguard Worker #endif
38*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NET_IF_H
39*6236dae4SAndroid Build Coastguard Worker #include <net/if.h>
40*6236dae4SAndroid Build Coastguard Worker #endif
41*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SYS_IOCTL_H
42*6236dae4SAndroid Build Coastguard Worker #include <sys/ioctl.h>
43*6236dae4SAndroid Build Coastguard Worker #endif
44*6236dae4SAndroid Build Coastguard Worker 
45*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SYS_PARAM_H
46*6236dae4SAndroid Build Coastguard Worker #include <sys/param.h>
47*6236dae4SAndroid Build Coastguard Worker #endif
48*6236dae4SAndroid Build Coastguard Worker 
49*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
50*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
51*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
52*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
53*6236dae4SAndroid Build Coastguard Worker #include "telnet.h"
54*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
55*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
56*6236dae4SAndroid Build Coastguard Worker #include "system_win32.h"
57*6236dae4SAndroid Build Coastguard Worker #include "arpa_telnet.h"
58*6236dae4SAndroid Build Coastguard Worker #include "select.h"
59*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
60*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
61*6236dae4SAndroid Build Coastguard Worker 
62*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
63*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
64*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
65*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
66*6236dae4SAndroid Build Coastguard Worker 
67*6236dae4SAndroid Build Coastguard Worker #define SUBBUFSIZE 512
68*6236dae4SAndroid Build Coastguard Worker 
69*6236dae4SAndroid Build Coastguard Worker #define CURL_SB_CLEAR(x)  x->subpointer = x->subbuffer
70*6236dae4SAndroid Build Coastguard Worker #define CURL_SB_TERM(x)                                 \
71*6236dae4SAndroid Build Coastguard Worker   do {                                                  \
72*6236dae4SAndroid Build Coastguard Worker     x->subend = x->subpointer;                          \
73*6236dae4SAndroid Build Coastguard Worker     CURL_SB_CLEAR(x);                                   \
74*6236dae4SAndroid Build Coastguard Worker   } while(0)
75*6236dae4SAndroid Build Coastguard Worker #define CURL_SB_ACCUM(x,c)                                      \
76*6236dae4SAndroid Build Coastguard Worker   do {                                                          \
77*6236dae4SAndroid Build Coastguard Worker     if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer)))   \
78*6236dae4SAndroid Build Coastguard Worker       *x->subpointer++ = (c);                                   \
79*6236dae4SAndroid Build Coastguard Worker   } while(0)
80*6236dae4SAndroid Build Coastguard Worker 
81*6236dae4SAndroid Build Coastguard Worker #define  CURL_SB_GET(x) ((*x->subpointer++)&0xff)
82*6236dae4SAndroid Build Coastguard Worker #define  CURL_SB_LEN(x) (x->subend - x->subpointer)
83*6236dae4SAndroid Build Coastguard Worker 
84*6236dae4SAndroid Build Coastguard Worker /* For posterity:
85*6236dae4SAndroid Build Coastguard Worker #define  CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
86*6236dae4SAndroid Build Coastguard Worker #define  CURL_SB_EOF(x) (x->subpointer >= x->subend) */
87*6236dae4SAndroid Build Coastguard Worker 
88*6236dae4SAndroid Build Coastguard Worker #ifdef CURL_DISABLE_VERBOSE_STRINGS
89*6236dae4SAndroid Build Coastguard Worker #define printoption(a,b,c,d)  Curl_nop_stmt
90*6236dae4SAndroid Build Coastguard Worker #endif
91*6236dae4SAndroid Build Coastguard Worker 
92*6236dae4SAndroid Build Coastguard Worker static
93*6236dae4SAndroid Build Coastguard Worker CURLcode telrcv(struct Curl_easy *data,
94*6236dae4SAndroid Build Coastguard Worker                 const unsigned char *inbuf, /* Data received from socket */
95*6236dae4SAndroid Build Coastguard Worker                 ssize_t count);             /* Number of bytes received */
96*6236dae4SAndroid Build Coastguard Worker 
97*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
98*6236dae4SAndroid Build Coastguard Worker static void printoption(struct Curl_easy *data,
99*6236dae4SAndroid Build Coastguard Worker                         const char *direction,
100*6236dae4SAndroid Build Coastguard Worker                         int cmd, int option);
101*6236dae4SAndroid Build Coastguard Worker #endif
102*6236dae4SAndroid Build Coastguard Worker 
103*6236dae4SAndroid Build Coastguard Worker static void negotiate(struct Curl_easy *data);
104*6236dae4SAndroid Build Coastguard Worker static void send_negotiation(struct Curl_easy *data, int cmd, int option);
105*6236dae4SAndroid Build Coastguard Worker static void set_local_option(struct Curl_easy *data,
106*6236dae4SAndroid Build Coastguard Worker                              int option, int newstate);
107*6236dae4SAndroid Build Coastguard Worker static void set_remote_option(struct Curl_easy *data,
108*6236dae4SAndroid Build Coastguard Worker                               int option, int newstate);
109*6236dae4SAndroid Build Coastguard Worker 
110*6236dae4SAndroid Build Coastguard Worker static void printsub(struct Curl_easy *data,
111*6236dae4SAndroid Build Coastguard Worker                      int direction, unsigned char *pointer,
112*6236dae4SAndroid Build Coastguard Worker                      size_t length);
113*6236dae4SAndroid Build Coastguard Worker static void suboption(struct Curl_easy *data);
114*6236dae4SAndroid Build Coastguard Worker static void sendsuboption(struct Curl_easy *data, int option);
115*6236dae4SAndroid Build Coastguard Worker 
116*6236dae4SAndroid Build Coastguard Worker static CURLcode telnet_do(struct Curl_easy *data, bool *done);
117*6236dae4SAndroid Build Coastguard Worker static CURLcode telnet_done(struct Curl_easy *data,
118*6236dae4SAndroid Build Coastguard Worker                                  CURLcode, bool premature);
119*6236dae4SAndroid Build Coastguard Worker static CURLcode send_telnet_data(struct Curl_easy *data,
120*6236dae4SAndroid Build Coastguard Worker                                  char *buffer, ssize_t nread);
121*6236dae4SAndroid Build Coastguard Worker 
122*6236dae4SAndroid Build Coastguard Worker /* For negotiation compliant to RFC 1143 */
123*6236dae4SAndroid Build Coastguard Worker #define CURL_NO          0
124*6236dae4SAndroid Build Coastguard Worker #define CURL_YES         1
125*6236dae4SAndroid Build Coastguard Worker #define CURL_WANTYES     2
126*6236dae4SAndroid Build Coastguard Worker #define CURL_WANTNO      3
127*6236dae4SAndroid Build Coastguard Worker 
128*6236dae4SAndroid Build Coastguard Worker #define CURL_EMPTY       0
129*6236dae4SAndroid Build Coastguard Worker #define CURL_OPPOSITE    1
130*6236dae4SAndroid Build Coastguard Worker 
131*6236dae4SAndroid Build Coastguard Worker /*
132*6236dae4SAndroid Build Coastguard Worker  * Telnet receiver states for fsm
133*6236dae4SAndroid Build Coastguard Worker  */
134*6236dae4SAndroid Build Coastguard Worker typedef enum
135*6236dae4SAndroid Build Coastguard Worker {
136*6236dae4SAndroid Build Coastguard Worker    CURL_TS_DATA = 0,
137*6236dae4SAndroid Build Coastguard Worker    CURL_TS_IAC,
138*6236dae4SAndroid Build Coastguard Worker    CURL_TS_WILL,
139*6236dae4SAndroid Build Coastguard Worker    CURL_TS_WONT,
140*6236dae4SAndroid Build Coastguard Worker    CURL_TS_DO,
141*6236dae4SAndroid Build Coastguard Worker    CURL_TS_DONT,
142*6236dae4SAndroid Build Coastguard Worker    CURL_TS_CR,
143*6236dae4SAndroid Build Coastguard Worker    CURL_TS_SB,   /* sub-option collection */
144*6236dae4SAndroid Build Coastguard Worker    CURL_TS_SE   /* looking for sub-option end */
145*6236dae4SAndroid Build Coastguard Worker } TelnetReceive;
146*6236dae4SAndroid Build Coastguard Worker 
147*6236dae4SAndroid Build Coastguard Worker struct TELNET {
148*6236dae4SAndroid Build Coastguard Worker   int please_negotiate;
149*6236dae4SAndroid Build Coastguard Worker   int already_negotiated;
150*6236dae4SAndroid Build Coastguard Worker   int us[256];
151*6236dae4SAndroid Build Coastguard Worker   int usq[256];
152*6236dae4SAndroid Build Coastguard Worker   int us_preferred[256];
153*6236dae4SAndroid Build Coastguard Worker   int him[256];
154*6236dae4SAndroid Build Coastguard Worker   int himq[256];
155*6236dae4SAndroid Build Coastguard Worker   int him_preferred[256];
156*6236dae4SAndroid Build Coastguard Worker   int subnegotiation[256];
157*6236dae4SAndroid Build Coastguard Worker   char *subopt_ttype;                /* Set with suboption TTYPE */
158*6236dae4SAndroid Build Coastguard Worker   char *subopt_xdisploc;             /* Set with suboption XDISPLOC */
159*6236dae4SAndroid Build Coastguard Worker   unsigned short subopt_wsx;         /* Set with suboption NAWS */
160*6236dae4SAndroid Build Coastguard Worker   unsigned short subopt_wsy;         /* Set with suboption NAWS */
161*6236dae4SAndroid Build Coastguard Worker   TelnetReceive telrcv_state;
162*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *telnet_vars;    /* Environment variables */
163*6236dae4SAndroid Build Coastguard Worker   struct dynbuf out;                 /* output buffer */
164*6236dae4SAndroid Build Coastguard Worker 
165*6236dae4SAndroid Build Coastguard Worker   /* suboptions */
166*6236dae4SAndroid Build Coastguard Worker   unsigned char subbuffer[SUBBUFSIZE];
167*6236dae4SAndroid Build Coastguard Worker   unsigned char *subpointer, *subend;      /* buffer for sub-options */
168*6236dae4SAndroid Build Coastguard Worker };
169*6236dae4SAndroid Build Coastguard Worker 
170*6236dae4SAndroid Build Coastguard Worker 
171*6236dae4SAndroid Build Coastguard Worker /*
172*6236dae4SAndroid Build Coastguard Worker  * TELNET protocol handler.
173*6236dae4SAndroid Build Coastguard Worker  */
174*6236dae4SAndroid Build Coastguard Worker 
175*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_telnet = {
176*6236dae4SAndroid Build Coastguard Worker   "telnet",                             /* scheme */
177*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* setup_connection */
178*6236dae4SAndroid Build Coastguard Worker   telnet_do,                            /* do_it */
179*6236dae4SAndroid Build Coastguard Worker   telnet_done,                          /* done */
180*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* do_more */
181*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* connect_it */
182*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* connecting */
183*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* doing */
184*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* proto_getsock */
185*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* doing_getsock */
186*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* domore_getsock */
187*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* perform_getsock */
188*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* disconnect */
189*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* write_resp */
190*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* write_resp_hd */
191*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* connection_check */
192*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                            /* attach connection */
193*6236dae4SAndroid Build Coastguard Worker   PORT_TELNET,                          /* defport */
194*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_TELNET,                     /* protocol */
195*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_TELNET,                     /* family */
196*6236dae4SAndroid Build Coastguard Worker   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
197*6236dae4SAndroid Build Coastguard Worker };
198*6236dae4SAndroid Build Coastguard Worker 
199*6236dae4SAndroid Build Coastguard Worker 
200*6236dae4SAndroid Build Coastguard Worker static
init_telnet(struct Curl_easy * data)201*6236dae4SAndroid Build Coastguard Worker CURLcode init_telnet(struct Curl_easy *data)
202*6236dae4SAndroid Build Coastguard Worker {
203*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn;
204*6236dae4SAndroid Build Coastguard Worker 
205*6236dae4SAndroid Build Coastguard Worker   tn = calloc(1, sizeof(struct TELNET));
206*6236dae4SAndroid Build Coastguard Worker   if(!tn)
207*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
208*6236dae4SAndroid Build Coastguard Worker 
209*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&tn->out, 0xffff);
210*6236dae4SAndroid Build Coastguard Worker   data->req.p.telnet = tn; /* make us known */
211*6236dae4SAndroid Build Coastguard Worker 
212*6236dae4SAndroid Build Coastguard Worker   tn->telrcv_state = CURL_TS_DATA;
213*6236dae4SAndroid Build Coastguard Worker 
214*6236dae4SAndroid Build Coastguard Worker   /* Init suboptions */
215*6236dae4SAndroid Build Coastguard Worker   CURL_SB_CLEAR(tn);
216*6236dae4SAndroid Build Coastguard Worker 
217*6236dae4SAndroid Build Coastguard Worker   /* Set the options we want by default */
218*6236dae4SAndroid Build Coastguard Worker   tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
219*6236dae4SAndroid Build Coastguard Worker   tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
220*6236dae4SAndroid Build Coastguard Worker 
221*6236dae4SAndroid Build Coastguard Worker   /* To be compliant with previous releases of libcurl
222*6236dae4SAndroid Build Coastguard Worker      we enable this option by default. This behavior
223*6236dae4SAndroid Build Coastguard Worker          can be changed thanks to the "BINARY" option in
224*6236dae4SAndroid Build Coastguard Worker          CURLOPT_TELNETOPTIONS
225*6236dae4SAndroid Build Coastguard Worker   */
226*6236dae4SAndroid Build Coastguard Worker   tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
227*6236dae4SAndroid Build Coastguard Worker   tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
228*6236dae4SAndroid Build Coastguard Worker 
229*6236dae4SAndroid Build Coastguard Worker   /* We must allow the server to echo what we sent
230*6236dae4SAndroid Build Coastguard Worker          but it is not necessary to request the server
231*6236dae4SAndroid Build Coastguard Worker          to do so (it might forces the server to close
232*6236dae4SAndroid Build Coastguard Worker          the connection). Hence, we ignore ECHO in the
233*6236dae4SAndroid Build Coastguard Worker          negotiate function
234*6236dae4SAndroid Build Coastguard Worker   */
235*6236dae4SAndroid Build Coastguard Worker   tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
236*6236dae4SAndroid Build Coastguard Worker 
237*6236dae4SAndroid Build Coastguard Worker   /* Set the subnegotiation fields to send information
238*6236dae4SAndroid Build Coastguard Worker     just after negotiation passed (do/will)
239*6236dae4SAndroid Build Coastguard Worker 
240*6236dae4SAndroid Build Coastguard Worker      Default values are (0,0) initialized by calloc.
241*6236dae4SAndroid Build Coastguard Worker      According to the RFC1013 it is valid:
242*6236dae4SAndroid Build Coastguard Worker      A value equal to zero is acceptable for the width (or height),
243*6236dae4SAndroid Build Coastguard Worker          and means that no character width (or height) is being sent.
244*6236dae4SAndroid Build Coastguard Worker          In this case, the width (or height) that will be assumed by the
245*6236dae4SAndroid Build Coastguard Worker          Telnet server is operating system specific (it will probably be
246*6236dae4SAndroid Build Coastguard Worker          based upon the terminal type information that may have been sent
247*6236dae4SAndroid Build Coastguard Worker          using the TERMINAL TYPE Telnet option). */
248*6236dae4SAndroid Build Coastguard Worker   tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
249*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
250*6236dae4SAndroid Build Coastguard Worker }
251*6236dae4SAndroid Build Coastguard Worker 
negotiate(struct Curl_easy * data)252*6236dae4SAndroid Build Coastguard Worker static void negotiate(struct Curl_easy *data)
253*6236dae4SAndroid Build Coastguard Worker {
254*6236dae4SAndroid Build Coastguard Worker   int i;
255*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
256*6236dae4SAndroid Build Coastguard Worker 
257*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < CURL_NTELOPTS; i++) {
258*6236dae4SAndroid Build Coastguard Worker     if(i == CURL_TELOPT_ECHO)
259*6236dae4SAndroid Build Coastguard Worker       continue;
260*6236dae4SAndroid Build Coastguard Worker 
261*6236dae4SAndroid Build Coastguard Worker     if(tn->us_preferred[i] == CURL_YES)
262*6236dae4SAndroid Build Coastguard Worker       set_local_option(data, i, CURL_YES);
263*6236dae4SAndroid Build Coastguard Worker 
264*6236dae4SAndroid Build Coastguard Worker     if(tn->him_preferred[i] == CURL_YES)
265*6236dae4SAndroid Build Coastguard Worker       set_remote_option(data, i, CURL_YES);
266*6236dae4SAndroid Build Coastguard Worker   }
267*6236dae4SAndroid Build Coastguard Worker }
268*6236dae4SAndroid Build Coastguard Worker 
269*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
printoption(struct Curl_easy * data,const char * direction,int cmd,int option)270*6236dae4SAndroid Build Coastguard Worker static void printoption(struct Curl_easy *data,
271*6236dae4SAndroid Build Coastguard Worker                         const char *direction, int cmd, int option)
272*6236dae4SAndroid Build Coastguard Worker {
273*6236dae4SAndroid Build Coastguard Worker   if(data->set.verbose) {
274*6236dae4SAndroid Build Coastguard Worker     if(cmd == CURL_IAC) {
275*6236dae4SAndroid Build Coastguard Worker       if(CURL_TELCMD_OK(option))
276*6236dae4SAndroid Build Coastguard Worker         infof(data, "%s IAC %s", direction, CURL_TELCMD(option));
277*6236dae4SAndroid Build Coastguard Worker       else
278*6236dae4SAndroid Build Coastguard Worker         infof(data, "%s IAC %d", direction, option);
279*6236dae4SAndroid Build Coastguard Worker     }
280*6236dae4SAndroid Build Coastguard Worker     else {
281*6236dae4SAndroid Build Coastguard Worker       const char *fmt = (cmd == CURL_WILL) ? "WILL" :
282*6236dae4SAndroid Build Coastguard Worker                         (cmd == CURL_WONT) ? "WONT" :
283*6236dae4SAndroid Build Coastguard Worker                         (cmd == CURL_DO) ? "DO" :
284*6236dae4SAndroid Build Coastguard Worker                         (cmd == CURL_DONT) ? "DONT" : 0;
285*6236dae4SAndroid Build Coastguard Worker       if(fmt) {
286*6236dae4SAndroid Build Coastguard Worker         const char *opt;
287*6236dae4SAndroid Build Coastguard Worker         if(CURL_TELOPT_OK(option))
288*6236dae4SAndroid Build Coastguard Worker           opt = CURL_TELOPT(option);
289*6236dae4SAndroid Build Coastguard Worker         else if(option == CURL_TELOPT_EXOPL)
290*6236dae4SAndroid Build Coastguard Worker           opt = "EXOPL";
291*6236dae4SAndroid Build Coastguard Worker         else
292*6236dae4SAndroid Build Coastguard Worker           opt = NULL;
293*6236dae4SAndroid Build Coastguard Worker 
294*6236dae4SAndroid Build Coastguard Worker         if(opt)
295*6236dae4SAndroid Build Coastguard Worker           infof(data, "%s %s %s", direction, fmt, opt);
296*6236dae4SAndroid Build Coastguard Worker         else
297*6236dae4SAndroid Build Coastguard Worker           infof(data, "%s %s %d", direction, fmt, option);
298*6236dae4SAndroid Build Coastguard Worker       }
299*6236dae4SAndroid Build Coastguard Worker       else
300*6236dae4SAndroid Build Coastguard Worker         infof(data, "%s %d %d", direction, cmd, option);
301*6236dae4SAndroid Build Coastguard Worker     }
302*6236dae4SAndroid Build Coastguard Worker   }
303*6236dae4SAndroid Build Coastguard Worker }
304*6236dae4SAndroid Build Coastguard Worker #endif
305*6236dae4SAndroid Build Coastguard Worker 
send_negotiation(struct Curl_easy * data,int cmd,int option)306*6236dae4SAndroid Build Coastguard Worker static void send_negotiation(struct Curl_easy *data, int cmd, int option)
307*6236dae4SAndroid Build Coastguard Worker {
308*6236dae4SAndroid Build Coastguard Worker   unsigned char buf[3];
309*6236dae4SAndroid Build Coastguard Worker   ssize_t bytes_written;
310*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
311*6236dae4SAndroid Build Coastguard Worker 
312*6236dae4SAndroid Build Coastguard Worker   buf[0] = CURL_IAC;
313*6236dae4SAndroid Build Coastguard Worker   buf[1] = (unsigned char)cmd;
314*6236dae4SAndroid Build Coastguard Worker   buf[2] = (unsigned char)option;
315*6236dae4SAndroid Build Coastguard Worker 
316*6236dae4SAndroid Build Coastguard Worker   bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
317*6236dae4SAndroid Build Coastguard Worker   if(bytes_written < 0) {
318*6236dae4SAndroid Build Coastguard Worker     int err = SOCKERRNO;
319*6236dae4SAndroid Build Coastguard Worker     failf(data,"Sending data failed (%d)",err);
320*6236dae4SAndroid Build Coastguard Worker   }
321*6236dae4SAndroid Build Coastguard Worker 
322*6236dae4SAndroid Build Coastguard Worker   printoption(data, "SENT", cmd, option);
323*6236dae4SAndroid Build Coastguard Worker }
324*6236dae4SAndroid Build Coastguard Worker 
325*6236dae4SAndroid Build Coastguard Worker static
set_remote_option(struct Curl_easy * data,int option,int newstate)326*6236dae4SAndroid Build Coastguard Worker void set_remote_option(struct Curl_easy *data, int option, int newstate)
327*6236dae4SAndroid Build Coastguard Worker {
328*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
329*6236dae4SAndroid Build Coastguard Worker   if(newstate == CURL_YES) {
330*6236dae4SAndroid Build Coastguard Worker     switch(tn->him[option]) {
331*6236dae4SAndroid Build Coastguard Worker     case CURL_NO:
332*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_WANTYES;
333*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_DO, option);
334*6236dae4SAndroid Build Coastguard Worker       break;
335*6236dae4SAndroid Build Coastguard Worker 
336*6236dae4SAndroid Build Coastguard Worker     case CURL_YES:
337*6236dae4SAndroid Build Coastguard Worker       /* Already enabled */
338*6236dae4SAndroid Build Coastguard Worker       break;
339*6236dae4SAndroid Build Coastguard Worker 
340*6236dae4SAndroid Build Coastguard Worker     case CURL_WANTNO:
341*6236dae4SAndroid Build Coastguard Worker       switch(tn->himq[option]) {
342*6236dae4SAndroid Build Coastguard Worker       case CURL_EMPTY:
343*6236dae4SAndroid Build Coastguard Worker         /* Already negotiating for CURL_YES, queue the request */
344*6236dae4SAndroid Build Coastguard Worker         tn->himq[option] = CURL_OPPOSITE;
345*6236dae4SAndroid Build Coastguard Worker         break;
346*6236dae4SAndroid Build Coastguard Worker       case CURL_OPPOSITE:
347*6236dae4SAndroid Build Coastguard Worker         /* Error: already queued an enable request */
348*6236dae4SAndroid Build Coastguard Worker         break;
349*6236dae4SAndroid Build Coastguard Worker       }
350*6236dae4SAndroid Build Coastguard Worker       break;
351*6236dae4SAndroid Build Coastguard Worker 
352*6236dae4SAndroid Build Coastguard Worker     case CURL_WANTYES:
353*6236dae4SAndroid Build Coastguard Worker       switch(tn->himq[option]) {
354*6236dae4SAndroid Build Coastguard Worker       case CURL_EMPTY:
355*6236dae4SAndroid Build Coastguard Worker         /* Error: already negotiating for enable */
356*6236dae4SAndroid Build Coastguard Worker         break;
357*6236dae4SAndroid Build Coastguard Worker       case CURL_OPPOSITE:
358*6236dae4SAndroid Build Coastguard Worker         tn->himq[option] = CURL_EMPTY;
359*6236dae4SAndroid Build Coastguard Worker         break;
360*6236dae4SAndroid Build Coastguard Worker       }
361*6236dae4SAndroid Build Coastguard Worker       break;
362*6236dae4SAndroid Build Coastguard Worker     }
363*6236dae4SAndroid Build Coastguard Worker   }
364*6236dae4SAndroid Build Coastguard Worker   else { /* NO */
365*6236dae4SAndroid Build Coastguard Worker     switch(tn->him[option]) {
366*6236dae4SAndroid Build Coastguard Worker     case CURL_NO:
367*6236dae4SAndroid Build Coastguard Worker       /* Already disabled */
368*6236dae4SAndroid Build Coastguard Worker       break;
369*6236dae4SAndroid Build Coastguard Worker 
370*6236dae4SAndroid Build Coastguard Worker     case CURL_YES:
371*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_WANTNO;
372*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_DONT, option);
373*6236dae4SAndroid Build Coastguard Worker       break;
374*6236dae4SAndroid Build Coastguard Worker 
375*6236dae4SAndroid Build Coastguard Worker     case CURL_WANTNO:
376*6236dae4SAndroid Build Coastguard Worker       switch(tn->himq[option]) {
377*6236dae4SAndroid Build Coastguard Worker       case CURL_EMPTY:
378*6236dae4SAndroid Build Coastguard Worker         /* Already negotiating for NO */
379*6236dae4SAndroid Build Coastguard Worker         break;
380*6236dae4SAndroid Build Coastguard Worker       case CURL_OPPOSITE:
381*6236dae4SAndroid Build Coastguard Worker         tn->himq[option] = CURL_EMPTY;
382*6236dae4SAndroid Build Coastguard Worker         break;
383*6236dae4SAndroid Build Coastguard Worker       }
384*6236dae4SAndroid Build Coastguard Worker       break;
385*6236dae4SAndroid Build Coastguard Worker 
386*6236dae4SAndroid Build Coastguard Worker     case CURL_WANTYES:
387*6236dae4SAndroid Build Coastguard Worker       switch(tn->himq[option]) {
388*6236dae4SAndroid Build Coastguard Worker       case CURL_EMPTY:
389*6236dae4SAndroid Build Coastguard Worker         tn->himq[option] = CURL_OPPOSITE;
390*6236dae4SAndroid Build Coastguard Worker         break;
391*6236dae4SAndroid Build Coastguard Worker       case CURL_OPPOSITE:
392*6236dae4SAndroid Build Coastguard Worker         break;
393*6236dae4SAndroid Build Coastguard Worker       }
394*6236dae4SAndroid Build Coastguard Worker       break;
395*6236dae4SAndroid Build Coastguard Worker     }
396*6236dae4SAndroid Build Coastguard Worker   }
397*6236dae4SAndroid Build Coastguard Worker }
398*6236dae4SAndroid Build Coastguard Worker 
399*6236dae4SAndroid Build Coastguard Worker static
rec_will(struct Curl_easy * data,int option)400*6236dae4SAndroid Build Coastguard Worker void rec_will(struct Curl_easy *data, int option)
401*6236dae4SAndroid Build Coastguard Worker {
402*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
403*6236dae4SAndroid Build Coastguard Worker   switch(tn->him[option]) {
404*6236dae4SAndroid Build Coastguard Worker   case CURL_NO:
405*6236dae4SAndroid Build Coastguard Worker     if(tn->him_preferred[option] == CURL_YES) {
406*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_YES;
407*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_DO, option);
408*6236dae4SAndroid Build Coastguard Worker     }
409*6236dae4SAndroid Build Coastguard Worker     else
410*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_DONT, option);
411*6236dae4SAndroid Build Coastguard Worker 
412*6236dae4SAndroid Build Coastguard Worker     break;
413*6236dae4SAndroid Build Coastguard Worker 
414*6236dae4SAndroid Build Coastguard Worker   case CURL_YES:
415*6236dae4SAndroid Build Coastguard Worker     /* Already enabled */
416*6236dae4SAndroid Build Coastguard Worker     break;
417*6236dae4SAndroid Build Coastguard Worker 
418*6236dae4SAndroid Build Coastguard Worker   case CURL_WANTNO:
419*6236dae4SAndroid Build Coastguard Worker     switch(tn->himq[option]) {
420*6236dae4SAndroid Build Coastguard Worker     case CURL_EMPTY:
421*6236dae4SAndroid Build Coastguard Worker       /* Error: DONT answered by WILL */
422*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_NO;
423*6236dae4SAndroid Build Coastguard Worker       break;
424*6236dae4SAndroid Build Coastguard Worker     case CURL_OPPOSITE:
425*6236dae4SAndroid Build Coastguard Worker       /* Error: DONT answered by WILL */
426*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_YES;
427*6236dae4SAndroid Build Coastguard Worker       tn->himq[option] = CURL_EMPTY;
428*6236dae4SAndroid Build Coastguard Worker       break;
429*6236dae4SAndroid Build Coastguard Worker     }
430*6236dae4SAndroid Build Coastguard Worker     break;
431*6236dae4SAndroid Build Coastguard Worker 
432*6236dae4SAndroid Build Coastguard Worker   case CURL_WANTYES:
433*6236dae4SAndroid Build Coastguard Worker     switch(tn->himq[option]) {
434*6236dae4SAndroid Build Coastguard Worker     case CURL_EMPTY:
435*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_YES;
436*6236dae4SAndroid Build Coastguard Worker       break;
437*6236dae4SAndroid Build Coastguard Worker     case CURL_OPPOSITE:
438*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_WANTNO;
439*6236dae4SAndroid Build Coastguard Worker       tn->himq[option] = CURL_EMPTY;
440*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_DONT, option);
441*6236dae4SAndroid Build Coastguard Worker       break;
442*6236dae4SAndroid Build Coastguard Worker     }
443*6236dae4SAndroid Build Coastguard Worker     break;
444*6236dae4SAndroid Build Coastguard Worker   }
445*6236dae4SAndroid Build Coastguard Worker }
446*6236dae4SAndroid Build Coastguard Worker 
447*6236dae4SAndroid Build Coastguard Worker static
rec_wont(struct Curl_easy * data,int option)448*6236dae4SAndroid Build Coastguard Worker void rec_wont(struct Curl_easy *data, int option)
449*6236dae4SAndroid Build Coastguard Worker {
450*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
451*6236dae4SAndroid Build Coastguard Worker   switch(tn->him[option]) {
452*6236dae4SAndroid Build Coastguard Worker   case CURL_NO:
453*6236dae4SAndroid Build Coastguard Worker     /* Already disabled */
454*6236dae4SAndroid Build Coastguard Worker     break;
455*6236dae4SAndroid Build Coastguard Worker 
456*6236dae4SAndroid Build Coastguard Worker   case CURL_YES:
457*6236dae4SAndroid Build Coastguard Worker     tn->him[option] = CURL_NO;
458*6236dae4SAndroid Build Coastguard Worker     send_negotiation(data, CURL_DONT, option);
459*6236dae4SAndroid Build Coastguard Worker     break;
460*6236dae4SAndroid Build Coastguard Worker 
461*6236dae4SAndroid Build Coastguard Worker   case CURL_WANTNO:
462*6236dae4SAndroid Build Coastguard Worker     switch(tn->himq[option]) {
463*6236dae4SAndroid Build Coastguard Worker     case CURL_EMPTY:
464*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_NO;
465*6236dae4SAndroid Build Coastguard Worker       break;
466*6236dae4SAndroid Build Coastguard Worker 
467*6236dae4SAndroid Build Coastguard Worker     case CURL_OPPOSITE:
468*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_WANTYES;
469*6236dae4SAndroid Build Coastguard Worker       tn->himq[option] = CURL_EMPTY;
470*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_DO, option);
471*6236dae4SAndroid Build Coastguard Worker       break;
472*6236dae4SAndroid Build Coastguard Worker     }
473*6236dae4SAndroid Build Coastguard Worker     break;
474*6236dae4SAndroid Build Coastguard Worker 
475*6236dae4SAndroid Build Coastguard Worker   case CURL_WANTYES:
476*6236dae4SAndroid Build Coastguard Worker     switch(tn->himq[option]) {
477*6236dae4SAndroid Build Coastguard Worker     case CURL_EMPTY:
478*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_NO;
479*6236dae4SAndroid Build Coastguard Worker       break;
480*6236dae4SAndroid Build Coastguard Worker     case CURL_OPPOSITE:
481*6236dae4SAndroid Build Coastguard Worker       tn->him[option] = CURL_NO;
482*6236dae4SAndroid Build Coastguard Worker       tn->himq[option] = CURL_EMPTY;
483*6236dae4SAndroid Build Coastguard Worker       break;
484*6236dae4SAndroid Build Coastguard Worker     }
485*6236dae4SAndroid Build Coastguard Worker     break;
486*6236dae4SAndroid Build Coastguard Worker   }
487*6236dae4SAndroid Build Coastguard Worker }
488*6236dae4SAndroid Build Coastguard Worker 
489*6236dae4SAndroid Build Coastguard Worker static void
set_local_option(struct Curl_easy * data,int option,int newstate)490*6236dae4SAndroid Build Coastguard Worker set_local_option(struct Curl_easy *data, int option, int newstate)
491*6236dae4SAndroid Build Coastguard Worker {
492*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
493*6236dae4SAndroid Build Coastguard Worker   if(newstate == CURL_YES) {
494*6236dae4SAndroid Build Coastguard Worker     switch(tn->us[option]) {
495*6236dae4SAndroid Build Coastguard Worker     case CURL_NO:
496*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_WANTYES;
497*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_WILL, option);
498*6236dae4SAndroid Build Coastguard Worker       break;
499*6236dae4SAndroid Build Coastguard Worker 
500*6236dae4SAndroid Build Coastguard Worker     case CURL_YES:
501*6236dae4SAndroid Build Coastguard Worker       /* Already enabled */
502*6236dae4SAndroid Build Coastguard Worker       break;
503*6236dae4SAndroid Build Coastguard Worker 
504*6236dae4SAndroid Build Coastguard Worker     case CURL_WANTNO:
505*6236dae4SAndroid Build Coastguard Worker       switch(tn->usq[option]) {
506*6236dae4SAndroid Build Coastguard Worker       case CURL_EMPTY:
507*6236dae4SAndroid Build Coastguard Worker         /* Already negotiating for CURL_YES, queue the request */
508*6236dae4SAndroid Build Coastguard Worker         tn->usq[option] = CURL_OPPOSITE;
509*6236dae4SAndroid Build Coastguard Worker         break;
510*6236dae4SAndroid Build Coastguard Worker       case CURL_OPPOSITE:
511*6236dae4SAndroid Build Coastguard Worker         /* Error: already queued an enable request */
512*6236dae4SAndroid Build Coastguard Worker         break;
513*6236dae4SAndroid Build Coastguard Worker       }
514*6236dae4SAndroid Build Coastguard Worker       break;
515*6236dae4SAndroid Build Coastguard Worker 
516*6236dae4SAndroid Build Coastguard Worker     case CURL_WANTYES:
517*6236dae4SAndroid Build Coastguard Worker       switch(tn->usq[option]) {
518*6236dae4SAndroid Build Coastguard Worker       case CURL_EMPTY:
519*6236dae4SAndroid Build Coastguard Worker         /* Error: already negotiating for enable */
520*6236dae4SAndroid Build Coastguard Worker         break;
521*6236dae4SAndroid Build Coastguard Worker       case CURL_OPPOSITE:
522*6236dae4SAndroid Build Coastguard Worker         tn->usq[option] = CURL_EMPTY;
523*6236dae4SAndroid Build Coastguard Worker         break;
524*6236dae4SAndroid Build Coastguard Worker       }
525*6236dae4SAndroid Build Coastguard Worker       break;
526*6236dae4SAndroid Build Coastguard Worker     }
527*6236dae4SAndroid Build Coastguard Worker   }
528*6236dae4SAndroid Build Coastguard Worker   else { /* NO */
529*6236dae4SAndroid Build Coastguard Worker     switch(tn->us[option]) {
530*6236dae4SAndroid Build Coastguard Worker     case CURL_NO:
531*6236dae4SAndroid Build Coastguard Worker       /* Already disabled */
532*6236dae4SAndroid Build Coastguard Worker       break;
533*6236dae4SAndroid Build Coastguard Worker 
534*6236dae4SAndroid Build Coastguard Worker     case CURL_YES:
535*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_WANTNO;
536*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_WONT, option);
537*6236dae4SAndroid Build Coastguard Worker       break;
538*6236dae4SAndroid Build Coastguard Worker 
539*6236dae4SAndroid Build Coastguard Worker     case CURL_WANTNO:
540*6236dae4SAndroid Build Coastguard Worker       switch(tn->usq[option]) {
541*6236dae4SAndroid Build Coastguard Worker       case CURL_EMPTY:
542*6236dae4SAndroid Build Coastguard Worker         /* Already negotiating for NO */
543*6236dae4SAndroid Build Coastguard Worker         break;
544*6236dae4SAndroid Build Coastguard Worker       case CURL_OPPOSITE:
545*6236dae4SAndroid Build Coastguard Worker         tn->usq[option] = CURL_EMPTY;
546*6236dae4SAndroid Build Coastguard Worker         break;
547*6236dae4SAndroid Build Coastguard Worker       }
548*6236dae4SAndroid Build Coastguard Worker       break;
549*6236dae4SAndroid Build Coastguard Worker 
550*6236dae4SAndroid Build Coastguard Worker     case CURL_WANTYES:
551*6236dae4SAndroid Build Coastguard Worker       switch(tn->usq[option]) {
552*6236dae4SAndroid Build Coastguard Worker       case CURL_EMPTY:
553*6236dae4SAndroid Build Coastguard Worker         tn->usq[option] = CURL_OPPOSITE;
554*6236dae4SAndroid Build Coastguard Worker         break;
555*6236dae4SAndroid Build Coastguard Worker       case CURL_OPPOSITE:
556*6236dae4SAndroid Build Coastguard Worker         break;
557*6236dae4SAndroid Build Coastguard Worker       }
558*6236dae4SAndroid Build Coastguard Worker       break;
559*6236dae4SAndroid Build Coastguard Worker     }
560*6236dae4SAndroid Build Coastguard Worker   }
561*6236dae4SAndroid Build Coastguard Worker }
562*6236dae4SAndroid Build Coastguard Worker 
563*6236dae4SAndroid Build Coastguard Worker static
rec_do(struct Curl_easy * data,int option)564*6236dae4SAndroid Build Coastguard Worker void rec_do(struct Curl_easy *data, int option)
565*6236dae4SAndroid Build Coastguard Worker {
566*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
567*6236dae4SAndroid Build Coastguard Worker   switch(tn->us[option]) {
568*6236dae4SAndroid Build Coastguard Worker   case CURL_NO:
569*6236dae4SAndroid Build Coastguard Worker     if(tn->us_preferred[option] == CURL_YES) {
570*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_YES;
571*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_WILL, option);
572*6236dae4SAndroid Build Coastguard Worker       if(tn->subnegotiation[option] == CURL_YES)
573*6236dae4SAndroid Build Coastguard Worker         /* transmission of data option */
574*6236dae4SAndroid Build Coastguard Worker         sendsuboption(data, option);
575*6236dae4SAndroid Build Coastguard Worker     }
576*6236dae4SAndroid Build Coastguard Worker     else if(tn->subnegotiation[option] == CURL_YES) {
577*6236dae4SAndroid Build Coastguard Worker       /* send information to achieve this option */
578*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_YES;
579*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_WILL, option);
580*6236dae4SAndroid Build Coastguard Worker       sendsuboption(data, option);
581*6236dae4SAndroid Build Coastguard Worker     }
582*6236dae4SAndroid Build Coastguard Worker     else
583*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_WONT, option);
584*6236dae4SAndroid Build Coastguard Worker     break;
585*6236dae4SAndroid Build Coastguard Worker 
586*6236dae4SAndroid Build Coastguard Worker   case CURL_YES:
587*6236dae4SAndroid Build Coastguard Worker     /* Already enabled */
588*6236dae4SAndroid Build Coastguard Worker     break;
589*6236dae4SAndroid Build Coastguard Worker 
590*6236dae4SAndroid Build Coastguard Worker   case CURL_WANTNO:
591*6236dae4SAndroid Build Coastguard Worker     switch(tn->usq[option]) {
592*6236dae4SAndroid Build Coastguard Worker     case CURL_EMPTY:
593*6236dae4SAndroid Build Coastguard Worker       /* Error: DONT answered by WILL */
594*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_NO;
595*6236dae4SAndroid Build Coastguard Worker       break;
596*6236dae4SAndroid Build Coastguard Worker     case CURL_OPPOSITE:
597*6236dae4SAndroid Build Coastguard Worker       /* Error: DONT answered by WILL */
598*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_YES;
599*6236dae4SAndroid Build Coastguard Worker       tn->usq[option] = CURL_EMPTY;
600*6236dae4SAndroid Build Coastguard Worker       break;
601*6236dae4SAndroid Build Coastguard Worker     }
602*6236dae4SAndroid Build Coastguard Worker     break;
603*6236dae4SAndroid Build Coastguard Worker 
604*6236dae4SAndroid Build Coastguard Worker   case CURL_WANTYES:
605*6236dae4SAndroid Build Coastguard Worker     switch(tn->usq[option]) {
606*6236dae4SAndroid Build Coastguard Worker     case CURL_EMPTY:
607*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_YES;
608*6236dae4SAndroid Build Coastguard Worker       if(tn->subnegotiation[option] == CURL_YES) {
609*6236dae4SAndroid Build Coastguard Worker         /* transmission of data option */
610*6236dae4SAndroid Build Coastguard Worker         sendsuboption(data, option);
611*6236dae4SAndroid Build Coastguard Worker       }
612*6236dae4SAndroid Build Coastguard Worker       break;
613*6236dae4SAndroid Build Coastguard Worker     case CURL_OPPOSITE:
614*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_WANTNO;
615*6236dae4SAndroid Build Coastguard Worker       tn->himq[option] = CURL_EMPTY;
616*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_WONT, option);
617*6236dae4SAndroid Build Coastguard Worker       break;
618*6236dae4SAndroid Build Coastguard Worker     }
619*6236dae4SAndroid Build Coastguard Worker     break;
620*6236dae4SAndroid Build Coastguard Worker   }
621*6236dae4SAndroid Build Coastguard Worker }
622*6236dae4SAndroid Build Coastguard Worker 
623*6236dae4SAndroid Build Coastguard Worker static
rec_dont(struct Curl_easy * data,int option)624*6236dae4SAndroid Build Coastguard Worker void rec_dont(struct Curl_easy *data, int option)
625*6236dae4SAndroid Build Coastguard Worker {
626*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
627*6236dae4SAndroid Build Coastguard Worker   switch(tn->us[option]) {
628*6236dae4SAndroid Build Coastguard Worker   case CURL_NO:
629*6236dae4SAndroid Build Coastguard Worker     /* Already disabled */
630*6236dae4SAndroid Build Coastguard Worker     break;
631*6236dae4SAndroid Build Coastguard Worker 
632*6236dae4SAndroid Build Coastguard Worker   case CURL_YES:
633*6236dae4SAndroid Build Coastguard Worker     tn->us[option] = CURL_NO;
634*6236dae4SAndroid Build Coastguard Worker     send_negotiation(data, CURL_WONT, option);
635*6236dae4SAndroid Build Coastguard Worker     break;
636*6236dae4SAndroid Build Coastguard Worker 
637*6236dae4SAndroid Build Coastguard Worker   case CURL_WANTNO:
638*6236dae4SAndroid Build Coastguard Worker     switch(tn->usq[option]) {
639*6236dae4SAndroid Build Coastguard Worker     case CURL_EMPTY:
640*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_NO;
641*6236dae4SAndroid Build Coastguard Worker       break;
642*6236dae4SAndroid Build Coastguard Worker 
643*6236dae4SAndroid Build Coastguard Worker     case CURL_OPPOSITE:
644*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_WANTYES;
645*6236dae4SAndroid Build Coastguard Worker       tn->usq[option] = CURL_EMPTY;
646*6236dae4SAndroid Build Coastguard Worker       send_negotiation(data, CURL_WILL, option);
647*6236dae4SAndroid Build Coastguard Worker       break;
648*6236dae4SAndroid Build Coastguard Worker     }
649*6236dae4SAndroid Build Coastguard Worker     break;
650*6236dae4SAndroid Build Coastguard Worker 
651*6236dae4SAndroid Build Coastguard Worker   case CURL_WANTYES:
652*6236dae4SAndroid Build Coastguard Worker     switch(tn->usq[option]) {
653*6236dae4SAndroid Build Coastguard Worker     case CURL_EMPTY:
654*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_NO;
655*6236dae4SAndroid Build Coastguard Worker       break;
656*6236dae4SAndroid Build Coastguard Worker     case CURL_OPPOSITE:
657*6236dae4SAndroid Build Coastguard Worker       tn->us[option] = CURL_NO;
658*6236dae4SAndroid Build Coastguard Worker       tn->usq[option] = CURL_EMPTY;
659*6236dae4SAndroid Build Coastguard Worker       break;
660*6236dae4SAndroid Build Coastguard Worker     }
661*6236dae4SAndroid Build Coastguard Worker     break;
662*6236dae4SAndroid Build Coastguard Worker   }
663*6236dae4SAndroid Build Coastguard Worker }
664*6236dae4SAndroid Build Coastguard Worker 
665*6236dae4SAndroid Build Coastguard Worker 
printsub(struct Curl_easy * data,int direction,unsigned char * pointer,size_t length)666*6236dae4SAndroid Build Coastguard Worker static void printsub(struct Curl_easy *data,
667*6236dae4SAndroid Build Coastguard Worker                      int direction,             /* '<' or '>' */
668*6236dae4SAndroid Build Coastguard Worker                      unsigned char *pointer,    /* where suboption data is */
669*6236dae4SAndroid Build Coastguard Worker                      size_t length)             /* length of suboption data */
670*6236dae4SAndroid Build Coastguard Worker {
671*6236dae4SAndroid Build Coastguard Worker   if(data->set.verbose) {
672*6236dae4SAndroid Build Coastguard Worker     unsigned int i = 0;
673*6236dae4SAndroid Build Coastguard Worker     if(direction) {
674*6236dae4SAndroid Build Coastguard Worker       infof(data, "%s IAC SB ", (direction == '<') ? "RCVD" : "SENT");
675*6236dae4SAndroid Build Coastguard Worker       if(length >= 3) {
676*6236dae4SAndroid Build Coastguard Worker         int j;
677*6236dae4SAndroid Build Coastguard Worker 
678*6236dae4SAndroid Build Coastguard Worker         i = pointer[length-2];
679*6236dae4SAndroid Build Coastguard Worker         j = pointer[length-1];
680*6236dae4SAndroid Build Coastguard Worker 
681*6236dae4SAndroid Build Coastguard Worker         if(i != CURL_IAC || j != CURL_SE) {
682*6236dae4SAndroid Build Coastguard Worker           infof(data, "(terminated by ");
683*6236dae4SAndroid Build Coastguard Worker           if(CURL_TELOPT_OK(i))
684*6236dae4SAndroid Build Coastguard Worker             infof(data, "%s ", CURL_TELOPT(i));
685*6236dae4SAndroid Build Coastguard Worker           else if(CURL_TELCMD_OK(i))
686*6236dae4SAndroid Build Coastguard Worker             infof(data, "%s ", CURL_TELCMD(i));
687*6236dae4SAndroid Build Coastguard Worker           else
688*6236dae4SAndroid Build Coastguard Worker             infof(data, "%u ", i);
689*6236dae4SAndroid Build Coastguard Worker           if(CURL_TELOPT_OK(j))
690*6236dae4SAndroid Build Coastguard Worker             infof(data, "%s", CURL_TELOPT(j));
691*6236dae4SAndroid Build Coastguard Worker           else if(CURL_TELCMD_OK(j))
692*6236dae4SAndroid Build Coastguard Worker             infof(data, "%s", CURL_TELCMD(j));
693*6236dae4SAndroid Build Coastguard Worker           else
694*6236dae4SAndroid Build Coastguard Worker             infof(data, "%d", j);
695*6236dae4SAndroid Build Coastguard Worker           infof(data, ", not IAC SE) ");
696*6236dae4SAndroid Build Coastguard Worker         }
697*6236dae4SAndroid Build Coastguard Worker       }
698*6236dae4SAndroid Build Coastguard Worker       length -= 2;
699*6236dae4SAndroid Build Coastguard Worker     }
700*6236dae4SAndroid Build Coastguard Worker     if(length < 1) {
701*6236dae4SAndroid Build Coastguard Worker       infof(data, "(Empty suboption?)");
702*6236dae4SAndroid Build Coastguard Worker       return;
703*6236dae4SAndroid Build Coastguard Worker     }
704*6236dae4SAndroid Build Coastguard Worker 
705*6236dae4SAndroid Build Coastguard Worker     if(CURL_TELOPT_OK(pointer[0])) {
706*6236dae4SAndroid Build Coastguard Worker       switch(pointer[0]) {
707*6236dae4SAndroid Build Coastguard Worker       case CURL_TELOPT_TTYPE:
708*6236dae4SAndroid Build Coastguard Worker       case CURL_TELOPT_XDISPLOC:
709*6236dae4SAndroid Build Coastguard Worker       case CURL_TELOPT_NEW_ENVIRON:
710*6236dae4SAndroid Build Coastguard Worker       case CURL_TELOPT_NAWS:
711*6236dae4SAndroid Build Coastguard Worker         infof(data, "%s", CURL_TELOPT(pointer[0]));
712*6236dae4SAndroid Build Coastguard Worker         break;
713*6236dae4SAndroid Build Coastguard Worker       default:
714*6236dae4SAndroid Build Coastguard Worker         infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
715*6236dae4SAndroid Build Coastguard Worker         break;
716*6236dae4SAndroid Build Coastguard Worker       }
717*6236dae4SAndroid Build Coastguard Worker     }
718*6236dae4SAndroid Build Coastguard Worker     else
719*6236dae4SAndroid Build Coastguard Worker       infof(data, "%d (unknown)", pointer[i]);
720*6236dae4SAndroid Build Coastguard Worker 
721*6236dae4SAndroid Build Coastguard Worker     switch(pointer[0]) {
722*6236dae4SAndroid Build Coastguard Worker     case CURL_TELOPT_NAWS:
723*6236dae4SAndroid Build Coastguard Worker       if(length > 4)
724*6236dae4SAndroid Build Coastguard Worker         infof(data, "Width: %d ; Height: %d", (pointer[1] << 8) | pointer[2],
725*6236dae4SAndroid Build Coastguard Worker               (pointer[3] << 8) | pointer[4]);
726*6236dae4SAndroid Build Coastguard Worker       break;
727*6236dae4SAndroid Build Coastguard Worker     default:
728*6236dae4SAndroid Build Coastguard Worker       switch(pointer[1]) {
729*6236dae4SAndroid Build Coastguard Worker       case CURL_TELQUAL_IS:
730*6236dae4SAndroid Build Coastguard Worker         infof(data, " IS");
731*6236dae4SAndroid Build Coastguard Worker         break;
732*6236dae4SAndroid Build Coastguard Worker       case CURL_TELQUAL_SEND:
733*6236dae4SAndroid Build Coastguard Worker         infof(data, " SEND");
734*6236dae4SAndroid Build Coastguard Worker         break;
735*6236dae4SAndroid Build Coastguard Worker       case CURL_TELQUAL_INFO:
736*6236dae4SAndroid Build Coastguard Worker         infof(data, " INFO/REPLY");
737*6236dae4SAndroid Build Coastguard Worker         break;
738*6236dae4SAndroid Build Coastguard Worker       case CURL_TELQUAL_NAME:
739*6236dae4SAndroid Build Coastguard Worker         infof(data, " NAME");
740*6236dae4SAndroid Build Coastguard Worker         break;
741*6236dae4SAndroid Build Coastguard Worker       }
742*6236dae4SAndroid Build Coastguard Worker 
743*6236dae4SAndroid Build Coastguard Worker       switch(pointer[0]) {
744*6236dae4SAndroid Build Coastguard Worker       case CURL_TELOPT_TTYPE:
745*6236dae4SAndroid Build Coastguard Worker       case CURL_TELOPT_XDISPLOC:
746*6236dae4SAndroid Build Coastguard Worker         pointer[length] = 0;
747*6236dae4SAndroid Build Coastguard Worker         infof(data, " \"%s\"", &pointer[2]);
748*6236dae4SAndroid Build Coastguard Worker         break;
749*6236dae4SAndroid Build Coastguard Worker       case CURL_TELOPT_NEW_ENVIRON:
750*6236dae4SAndroid Build Coastguard Worker         if(pointer[1] == CURL_TELQUAL_IS) {
751*6236dae4SAndroid Build Coastguard Worker           infof(data, " ");
752*6236dae4SAndroid Build Coastguard Worker           for(i = 3; i < length; i++) {
753*6236dae4SAndroid Build Coastguard Worker             switch(pointer[i]) {
754*6236dae4SAndroid Build Coastguard Worker             case CURL_NEW_ENV_VAR:
755*6236dae4SAndroid Build Coastguard Worker               infof(data, ", ");
756*6236dae4SAndroid Build Coastguard Worker               break;
757*6236dae4SAndroid Build Coastguard Worker             case CURL_NEW_ENV_VALUE:
758*6236dae4SAndroid Build Coastguard Worker               infof(data, " = ");
759*6236dae4SAndroid Build Coastguard Worker               break;
760*6236dae4SAndroid Build Coastguard Worker             default:
761*6236dae4SAndroid Build Coastguard Worker               infof(data, "%c", pointer[i]);
762*6236dae4SAndroid Build Coastguard Worker               break;
763*6236dae4SAndroid Build Coastguard Worker             }
764*6236dae4SAndroid Build Coastguard Worker           }
765*6236dae4SAndroid Build Coastguard Worker         }
766*6236dae4SAndroid Build Coastguard Worker         break;
767*6236dae4SAndroid Build Coastguard Worker       default:
768*6236dae4SAndroid Build Coastguard Worker         for(i = 2; i < length; i++)
769*6236dae4SAndroid Build Coastguard Worker           infof(data, " %.2x", pointer[i]);
770*6236dae4SAndroid Build Coastguard Worker         break;
771*6236dae4SAndroid Build Coastguard Worker       }
772*6236dae4SAndroid Build Coastguard Worker     }
773*6236dae4SAndroid Build Coastguard Worker   }
774*6236dae4SAndroid Build Coastguard Worker }
775*6236dae4SAndroid Build Coastguard Worker 
776*6236dae4SAndroid Build Coastguard Worker #ifdef _MSC_VER
777*6236dae4SAndroid Build Coastguard Worker #pragma warning(push)
778*6236dae4SAndroid Build Coastguard Worker /* warning C4706: assignment within conditional expression */
779*6236dae4SAndroid Build Coastguard Worker #pragma warning(disable:4706)
780*6236dae4SAndroid Build Coastguard Worker #endif
str_is_nonascii(const char * str)781*6236dae4SAndroid Build Coastguard Worker static bool str_is_nonascii(const char *str)
782*6236dae4SAndroid Build Coastguard Worker {
783*6236dae4SAndroid Build Coastguard Worker   char c;
784*6236dae4SAndroid Build Coastguard Worker   while((c = *str++))
785*6236dae4SAndroid Build Coastguard Worker     if(c & 0x80)
786*6236dae4SAndroid Build Coastguard Worker       return TRUE;
787*6236dae4SAndroid Build Coastguard Worker 
788*6236dae4SAndroid Build Coastguard Worker   return FALSE;
789*6236dae4SAndroid Build Coastguard Worker }
790*6236dae4SAndroid Build Coastguard Worker #ifdef _MSC_VER
791*6236dae4SAndroid Build Coastguard Worker #pragma warning(pop)
792*6236dae4SAndroid Build Coastguard Worker #endif
793*6236dae4SAndroid Build Coastguard Worker 
check_telnet_options(struct Curl_easy * data)794*6236dae4SAndroid Build Coastguard Worker static CURLcode check_telnet_options(struct Curl_easy *data)
795*6236dae4SAndroid Build Coastguard Worker {
796*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *head;
797*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *beg;
798*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
799*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
800*6236dae4SAndroid Build Coastguard Worker 
801*6236dae4SAndroid Build Coastguard Worker   /* Add the username as an environment variable if it
802*6236dae4SAndroid Build Coastguard Worker      was given on the command line */
803*6236dae4SAndroid Build Coastguard Worker   if(data->state.aptr.user) {
804*6236dae4SAndroid Build Coastguard Worker     char buffer[256];
805*6236dae4SAndroid Build Coastguard Worker     if(str_is_nonascii(data->conn->user)) {
806*6236dae4SAndroid Build Coastguard Worker       DEBUGF(infof(data, "set a non ASCII username in telnet"));
807*6236dae4SAndroid Build Coastguard Worker       return CURLE_BAD_FUNCTION_ARGUMENT;
808*6236dae4SAndroid Build Coastguard Worker     }
809*6236dae4SAndroid Build Coastguard Worker     msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user);
810*6236dae4SAndroid Build Coastguard Worker     beg = curl_slist_append(tn->telnet_vars, buffer);
811*6236dae4SAndroid Build Coastguard Worker     if(!beg) {
812*6236dae4SAndroid Build Coastguard Worker       curl_slist_free_all(tn->telnet_vars);
813*6236dae4SAndroid Build Coastguard Worker       tn->telnet_vars = NULL;
814*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
815*6236dae4SAndroid Build Coastguard Worker     }
816*6236dae4SAndroid Build Coastguard Worker     tn->telnet_vars = beg;
817*6236dae4SAndroid Build Coastguard Worker     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
818*6236dae4SAndroid Build Coastguard Worker   }
819*6236dae4SAndroid Build Coastguard Worker 
820*6236dae4SAndroid Build Coastguard Worker   for(head = data->set.telnet_options; head && !result; head = head->next) {
821*6236dae4SAndroid Build Coastguard Worker     size_t olen;
822*6236dae4SAndroid Build Coastguard Worker     char *option = head->data;
823*6236dae4SAndroid Build Coastguard Worker     char *arg;
824*6236dae4SAndroid Build Coastguard Worker     char *sep = strchr(option, '=');
825*6236dae4SAndroid Build Coastguard Worker     if(sep) {
826*6236dae4SAndroid Build Coastguard Worker       olen = sep - option;
827*6236dae4SAndroid Build Coastguard Worker       arg = ++sep;
828*6236dae4SAndroid Build Coastguard Worker       if(str_is_nonascii(arg))
829*6236dae4SAndroid Build Coastguard Worker         continue;
830*6236dae4SAndroid Build Coastguard Worker       switch(olen) {
831*6236dae4SAndroid Build Coastguard Worker       case 5:
832*6236dae4SAndroid Build Coastguard Worker         /* Terminal type */
833*6236dae4SAndroid Build Coastguard Worker         if(strncasecompare(option, "TTYPE", 5)) {
834*6236dae4SAndroid Build Coastguard Worker           tn->subopt_ttype = arg;
835*6236dae4SAndroid Build Coastguard Worker           tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
836*6236dae4SAndroid Build Coastguard Worker           break;
837*6236dae4SAndroid Build Coastguard Worker         }
838*6236dae4SAndroid Build Coastguard Worker         result = CURLE_UNKNOWN_OPTION;
839*6236dae4SAndroid Build Coastguard Worker         break;
840*6236dae4SAndroid Build Coastguard Worker 
841*6236dae4SAndroid Build Coastguard Worker       case 8:
842*6236dae4SAndroid Build Coastguard Worker         /* Display variable */
843*6236dae4SAndroid Build Coastguard Worker         if(strncasecompare(option, "XDISPLOC", 8)) {
844*6236dae4SAndroid Build Coastguard Worker           tn->subopt_xdisploc = arg;
845*6236dae4SAndroid Build Coastguard Worker           tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
846*6236dae4SAndroid Build Coastguard Worker           break;
847*6236dae4SAndroid Build Coastguard Worker         }
848*6236dae4SAndroid Build Coastguard Worker         result = CURLE_UNKNOWN_OPTION;
849*6236dae4SAndroid Build Coastguard Worker         break;
850*6236dae4SAndroid Build Coastguard Worker 
851*6236dae4SAndroid Build Coastguard Worker       case 7:
852*6236dae4SAndroid Build Coastguard Worker         /* Environment variable */
853*6236dae4SAndroid Build Coastguard Worker         if(strncasecompare(option, "NEW_ENV", 7)) {
854*6236dae4SAndroid Build Coastguard Worker           beg = curl_slist_append(tn->telnet_vars, arg);
855*6236dae4SAndroid Build Coastguard Worker           if(!beg) {
856*6236dae4SAndroid Build Coastguard Worker             result = CURLE_OUT_OF_MEMORY;
857*6236dae4SAndroid Build Coastguard Worker             break;
858*6236dae4SAndroid Build Coastguard Worker           }
859*6236dae4SAndroid Build Coastguard Worker           tn->telnet_vars = beg;
860*6236dae4SAndroid Build Coastguard Worker           tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
861*6236dae4SAndroid Build Coastguard Worker         }
862*6236dae4SAndroid Build Coastguard Worker         else
863*6236dae4SAndroid Build Coastguard Worker           result = CURLE_UNKNOWN_OPTION;
864*6236dae4SAndroid Build Coastguard Worker         break;
865*6236dae4SAndroid Build Coastguard Worker 
866*6236dae4SAndroid Build Coastguard Worker       case 2:
867*6236dae4SAndroid Build Coastguard Worker         /* Window Size */
868*6236dae4SAndroid Build Coastguard Worker         if(strncasecompare(option, "WS", 2)) {
869*6236dae4SAndroid Build Coastguard Worker           char *p;
870*6236dae4SAndroid Build Coastguard Worker           unsigned long x = strtoul(arg, &p, 10);
871*6236dae4SAndroid Build Coastguard Worker           unsigned long y = 0;
872*6236dae4SAndroid Build Coastguard Worker           if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') {
873*6236dae4SAndroid Build Coastguard Worker             p++;
874*6236dae4SAndroid Build Coastguard Worker             y = strtoul(p, NULL, 10);
875*6236dae4SAndroid Build Coastguard Worker             if(y && (y <= 0xffff)) {
876*6236dae4SAndroid Build Coastguard Worker               tn->subopt_wsx = (unsigned short)x;
877*6236dae4SAndroid Build Coastguard Worker               tn->subopt_wsy = (unsigned short)y;
878*6236dae4SAndroid Build Coastguard Worker               tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
879*6236dae4SAndroid Build Coastguard Worker             }
880*6236dae4SAndroid Build Coastguard Worker           }
881*6236dae4SAndroid Build Coastguard Worker           if(!y) {
882*6236dae4SAndroid Build Coastguard Worker             failf(data, "Syntax error in telnet option: %s", head->data);
883*6236dae4SAndroid Build Coastguard Worker             result = CURLE_SETOPT_OPTION_SYNTAX;
884*6236dae4SAndroid Build Coastguard Worker           }
885*6236dae4SAndroid Build Coastguard Worker         }
886*6236dae4SAndroid Build Coastguard Worker         else
887*6236dae4SAndroid Build Coastguard Worker           result = CURLE_UNKNOWN_OPTION;
888*6236dae4SAndroid Build Coastguard Worker         break;
889*6236dae4SAndroid Build Coastguard Worker 
890*6236dae4SAndroid Build Coastguard Worker       case 6:
891*6236dae4SAndroid Build Coastguard Worker         /* To take care or not of the 8th bit in data exchange */
892*6236dae4SAndroid Build Coastguard Worker         if(strncasecompare(option, "BINARY", 6)) {
893*6236dae4SAndroid Build Coastguard Worker           int binary_option = atoi(arg);
894*6236dae4SAndroid Build Coastguard Worker           if(binary_option != 1) {
895*6236dae4SAndroid Build Coastguard Worker             tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
896*6236dae4SAndroid Build Coastguard Worker             tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
897*6236dae4SAndroid Build Coastguard Worker           }
898*6236dae4SAndroid Build Coastguard Worker         }
899*6236dae4SAndroid Build Coastguard Worker         else
900*6236dae4SAndroid Build Coastguard Worker           result = CURLE_UNKNOWN_OPTION;
901*6236dae4SAndroid Build Coastguard Worker         break;
902*6236dae4SAndroid Build Coastguard Worker       default:
903*6236dae4SAndroid Build Coastguard Worker         failf(data, "Unknown telnet option %s", head->data);
904*6236dae4SAndroid Build Coastguard Worker         result = CURLE_UNKNOWN_OPTION;
905*6236dae4SAndroid Build Coastguard Worker         break;
906*6236dae4SAndroid Build Coastguard Worker       }
907*6236dae4SAndroid Build Coastguard Worker     }
908*6236dae4SAndroid Build Coastguard Worker     else {
909*6236dae4SAndroid Build Coastguard Worker       failf(data, "Syntax error in telnet option: %s", head->data);
910*6236dae4SAndroid Build Coastguard Worker       result = CURLE_SETOPT_OPTION_SYNTAX;
911*6236dae4SAndroid Build Coastguard Worker     }
912*6236dae4SAndroid Build Coastguard Worker   }
913*6236dae4SAndroid Build Coastguard Worker 
914*6236dae4SAndroid Build Coastguard Worker   if(result) {
915*6236dae4SAndroid Build Coastguard Worker     curl_slist_free_all(tn->telnet_vars);
916*6236dae4SAndroid Build Coastguard Worker     tn->telnet_vars = NULL;
917*6236dae4SAndroid Build Coastguard Worker   }
918*6236dae4SAndroid Build Coastguard Worker 
919*6236dae4SAndroid Build Coastguard Worker   return result;
920*6236dae4SAndroid Build Coastguard Worker }
921*6236dae4SAndroid Build Coastguard Worker 
922*6236dae4SAndroid Build Coastguard Worker /*
923*6236dae4SAndroid Build Coastguard Worker  * suboption()
924*6236dae4SAndroid Build Coastguard Worker  *
925*6236dae4SAndroid Build Coastguard Worker  * Look at the sub-option buffer, and try to be helpful to the other
926*6236dae4SAndroid Build Coastguard Worker  * side.
927*6236dae4SAndroid Build Coastguard Worker  */
928*6236dae4SAndroid Build Coastguard Worker 
suboption(struct Curl_easy * data)929*6236dae4SAndroid Build Coastguard Worker static void suboption(struct Curl_easy *data)
930*6236dae4SAndroid Build Coastguard Worker {
931*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *v;
932*6236dae4SAndroid Build Coastguard Worker   unsigned char temp[2048];
933*6236dae4SAndroid Build Coastguard Worker   ssize_t bytes_written;
934*6236dae4SAndroid Build Coastguard Worker   size_t len;
935*6236dae4SAndroid Build Coastguard Worker   int err;
936*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
937*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
938*6236dae4SAndroid Build Coastguard Worker 
939*6236dae4SAndroid Build Coastguard Worker   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
940*6236dae4SAndroid Build Coastguard Worker   switch(CURL_SB_GET(tn)) {
941*6236dae4SAndroid Build Coastguard Worker     case CURL_TELOPT_TTYPE:
942*6236dae4SAndroid Build Coastguard Worker       len = strlen(tn->subopt_ttype) + 4 + 2;
943*6236dae4SAndroid Build Coastguard Worker       msnprintf((char *)temp, sizeof(temp),
944*6236dae4SAndroid Build Coastguard Worker                 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
945*6236dae4SAndroid Build Coastguard Worker                 CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
946*6236dae4SAndroid Build Coastguard Worker       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
947*6236dae4SAndroid Build Coastguard Worker       if(bytes_written < 0) {
948*6236dae4SAndroid Build Coastguard Worker         err = SOCKERRNO;
949*6236dae4SAndroid Build Coastguard Worker         failf(data,"Sending data failed (%d)",err);
950*6236dae4SAndroid Build Coastguard Worker       }
951*6236dae4SAndroid Build Coastguard Worker       printsub(data, '>', &temp[2], len-2);
952*6236dae4SAndroid Build Coastguard Worker       break;
953*6236dae4SAndroid Build Coastguard Worker     case CURL_TELOPT_XDISPLOC:
954*6236dae4SAndroid Build Coastguard Worker       len = strlen(tn->subopt_xdisploc) + 4 + 2;
955*6236dae4SAndroid Build Coastguard Worker       msnprintf((char *)temp, sizeof(temp),
956*6236dae4SAndroid Build Coastguard Worker                 "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
957*6236dae4SAndroid Build Coastguard Worker                 CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
958*6236dae4SAndroid Build Coastguard Worker       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
959*6236dae4SAndroid Build Coastguard Worker       if(bytes_written < 0) {
960*6236dae4SAndroid Build Coastguard Worker         err = SOCKERRNO;
961*6236dae4SAndroid Build Coastguard Worker         failf(data,"Sending data failed (%d)",err);
962*6236dae4SAndroid Build Coastguard Worker       }
963*6236dae4SAndroid Build Coastguard Worker       printsub(data, '>', &temp[2], len-2);
964*6236dae4SAndroid Build Coastguard Worker       break;
965*6236dae4SAndroid Build Coastguard Worker     case CURL_TELOPT_NEW_ENVIRON:
966*6236dae4SAndroid Build Coastguard Worker       msnprintf((char *)temp, sizeof(temp),
967*6236dae4SAndroid Build Coastguard Worker                 "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
968*6236dae4SAndroid Build Coastguard Worker                 CURL_TELQUAL_IS);
969*6236dae4SAndroid Build Coastguard Worker       len = 4;
970*6236dae4SAndroid Build Coastguard Worker 
971*6236dae4SAndroid Build Coastguard Worker       for(v = tn->telnet_vars; v; v = v->next) {
972*6236dae4SAndroid Build Coastguard Worker         size_t tmplen = (strlen(v->data) + 1);
973*6236dae4SAndroid Build Coastguard Worker         /* Add the variable if it fits */
974*6236dae4SAndroid Build Coastguard Worker         if(len + tmplen < (int)sizeof(temp)-6) {
975*6236dae4SAndroid Build Coastguard Worker           char *s = strchr(v->data, ',');
976*6236dae4SAndroid Build Coastguard Worker           if(!s)
977*6236dae4SAndroid Build Coastguard Worker             len += msnprintf((char *)&temp[len], sizeof(temp) - len,
978*6236dae4SAndroid Build Coastguard Worker                              "%c%s", CURL_NEW_ENV_VAR, v->data);
979*6236dae4SAndroid Build Coastguard Worker           else {
980*6236dae4SAndroid Build Coastguard Worker             size_t vlen = s - v->data;
981*6236dae4SAndroid Build Coastguard Worker             len += msnprintf((char *)&temp[len], sizeof(temp) - len,
982*6236dae4SAndroid Build Coastguard Worker                              "%c%.*s%c%s", CURL_NEW_ENV_VAR,
983*6236dae4SAndroid Build Coastguard Worker                              (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s);
984*6236dae4SAndroid Build Coastguard Worker           }
985*6236dae4SAndroid Build Coastguard Worker         }
986*6236dae4SAndroid Build Coastguard Worker       }
987*6236dae4SAndroid Build Coastguard Worker       msnprintf((char *)&temp[len], sizeof(temp) - len,
988*6236dae4SAndroid Build Coastguard Worker                 "%c%c", CURL_IAC, CURL_SE);
989*6236dae4SAndroid Build Coastguard Worker       len += 2;
990*6236dae4SAndroid Build Coastguard Worker       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
991*6236dae4SAndroid Build Coastguard Worker       if(bytes_written < 0) {
992*6236dae4SAndroid Build Coastguard Worker         err = SOCKERRNO;
993*6236dae4SAndroid Build Coastguard Worker         failf(data,"Sending data failed (%d)",err);
994*6236dae4SAndroid Build Coastguard Worker       }
995*6236dae4SAndroid Build Coastguard Worker       printsub(data, '>', &temp[2], len-2);
996*6236dae4SAndroid Build Coastguard Worker       break;
997*6236dae4SAndroid Build Coastguard Worker   }
998*6236dae4SAndroid Build Coastguard Worker   return;
999*6236dae4SAndroid Build Coastguard Worker }
1000*6236dae4SAndroid Build Coastguard Worker 
1001*6236dae4SAndroid Build Coastguard Worker 
1002*6236dae4SAndroid Build Coastguard Worker /*
1003*6236dae4SAndroid Build Coastguard Worker  * sendsuboption()
1004*6236dae4SAndroid Build Coastguard Worker  *
1005*6236dae4SAndroid Build Coastguard Worker  * Send suboption information to the server side.
1006*6236dae4SAndroid Build Coastguard Worker  */
1007*6236dae4SAndroid Build Coastguard Worker 
sendsuboption(struct Curl_easy * data,int option)1008*6236dae4SAndroid Build Coastguard Worker static void sendsuboption(struct Curl_easy *data, int option)
1009*6236dae4SAndroid Build Coastguard Worker {
1010*6236dae4SAndroid Build Coastguard Worker   ssize_t bytes_written;
1011*6236dae4SAndroid Build Coastguard Worker   int err;
1012*6236dae4SAndroid Build Coastguard Worker   unsigned short x, y;
1013*6236dae4SAndroid Build Coastguard Worker   unsigned char *uc1, *uc2;
1014*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
1015*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1016*6236dae4SAndroid Build Coastguard Worker 
1017*6236dae4SAndroid Build Coastguard Worker   switch(option) {
1018*6236dae4SAndroid Build Coastguard Worker   case CURL_TELOPT_NAWS:
1019*6236dae4SAndroid Build Coastguard Worker     /* We prepare data to be sent */
1020*6236dae4SAndroid Build Coastguard Worker     CURL_SB_CLEAR(tn);
1021*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, CURL_IAC);
1022*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, CURL_SB);
1023*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1024*6236dae4SAndroid Build Coastguard Worker     /* We must deal either with little or big endian processors */
1025*6236dae4SAndroid Build Coastguard Worker     /* Window size must be sent according to the 'network order' */
1026*6236dae4SAndroid Build Coastguard Worker     x = htons(tn->subopt_wsx);
1027*6236dae4SAndroid Build Coastguard Worker     y = htons(tn->subopt_wsy);
1028*6236dae4SAndroid Build Coastguard Worker     uc1 = (unsigned char *)&x;
1029*6236dae4SAndroid Build Coastguard Worker     uc2 = (unsigned char *)&y;
1030*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, uc1[0]);
1031*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, uc1[1]);
1032*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, uc2[0]);
1033*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, uc2[1]);
1034*6236dae4SAndroid Build Coastguard Worker 
1035*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, CURL_IAC);
1036*6236dae4SAndroid Build Coastguard Worker     CURL_SB_ACCUM(tn, CURL_SE);
1037*6236dae4SAndroid Build Coastguard Worker     CURL_SB_TERM(tn);
1038*6236dae4SAndroid Build Coastguard Worker     /* data suboption is now ready */
1039*6236dae4SAndroid Build Coastguard Worker 
1040*6236dae4SAndroid Build Coastguard Worker     printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
1041*6236dae4SAndroid Build Coastguard Worker              CURL_SB_LEN(tn)-2);
1042*6236dae4SAndroid Build Coastguard Worker 
1043*6236dae4SAndroid Build Coastguard Worker     /* we send the header of the suboption... */
1044*6236dae4SAndroid Build Coastguard Worker     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1045*6236dae4SAndroid Build Coastguard Worker     if(bytes_written < 0) {
1046*6236dae4SAndroid Build Coastguard Worker       err = SOCKERRNO;
1047*6236dae4SAndroid Build Coastguard Worker       failf(data, "Sending data failed (%d)", err);
1048*6236dae4SAndroid Build Coastguard Worker     }
1049*6236dae4SAndroid Build Coastguard Worker     /* ... then the window size with the send_telnet_data() function
1050*6236dae4SAndroid Build Coastguard Worker        to deal with 0xFF cases ... */
1051*6236dae4SAndroid Build Coastguard Worker     send_telnet_data(data, (char *)tn->subbuffer + 3, 4);
1052*6236dae4SAndroid Build Coastguard Worker     /* ... and the footer */
1053*6236dae4SAndroid Build Coastguard Worker     bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
1054*6236dae4SAndroid Build Coastguard Worker     if(bytes_written < 0) {
1055*6236dae4SAndroid Build Coastguard Worker       err = SOCKERRNO;
1056*6236dae4SAndroid Build Coastguard Worker       failf(data, "Sending data failed (%d)", err);
1057*6236dae4SAndroid Build Coastguard Worker     }
1058*6236dae4SAndroid Build Coastguard Worker     break;
1059*6236dae4SAndroid Build Coastguard Worker   }
1060*6236dae4SAndroid Build Coastguard Worker }
1061*6236dae4SAndroid Build Coastguard Worker 
1062*6236dae4SAndroid Build Coastguard Worker 
1063*6236dae4SAndroid Build Coastguard Worker static
telrcv(struct Curl_easy * data,const unsigned char * inbuf,ssize_t count)1064*6236dae4SAndroid Build Coastguard Worker CURLcode telrcv(struct Curl_easy *data,
1065*6236dae4SAndroid Build Coastguard Worker                 const unsigned char *inbuf, /* Data received from socket */
1066*6236dae4SAndroid Build Coastguard Worker                 ssize_t count)              /* Number of bytes received */
1067*6236dae4SAndroid Build Coastguard Worker {
1068*6236dae4SAndroid Build Coastguard Worker   unsigned char c;
1069*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
1070*6236dae4SAndroid Build Coastguard Worker   int in = 0;
1071*6236dae4SAndroid Build Coastguard Worker   int startwrite = -1;
1072*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
1073*6236dae4SAndroid Build Coastguard Worker 
1074*6236dae4SAndroid Build Coastguard Worker #define startskipping()                                       \
1075*6236dae4SAndroid Build Coastguard Worker   if(startwrite >= 0) {                                       \
1076*6236dae4SAndroid Build Coastguard Worker     result = Curl_client_write(data,                          \
1077*6236dae4SAndroid Build Coastguard Worker                                CLIENTWRITE_BODY,              \
1078*6236dae4SAndroid Build Coastguard Worker                                (char *)&inbuf[startwrite],    \
1079*6236dae4SAndroid Build Coastguard Worker                                in-startwrite);                \
1080*6236dae4SAndroid Build Coastguard Worker     if(result)                                                \
1081*6236dae4SAndroid Build Coastguard Worker       return result;                                          \
1082*6236dae4SAndroid Build Coastguard Worker   }                                                           \
1083*6236dae4SAndroid Build Coastguard Worker   startwrite = -1
1084*6236dae4SAndroid Build Coastguard Worker 
1085*6236dae4SAndroid Build Coastguard Worker #define writebyte() \
1086*6236dae4SAndroid Build Coastguard Worker     if(startwrite < 0) \
1087*6236dae4SAndroid Build Coastguard Worker       startwrite = in
1088*6236dae4SAndroid Build Coastguard Worker 
1089*6236dae4SAndroid Build Coastguard Worker #define bufferflush() startskipping()
1090*6236dae4SAndroid Build Coastguard Worker 
1091*6236dae4SAndroid Build Coastguard Worker   while(count--) {
1092*6236dae4SAndroid Build Coastguard Worker     c = inbuf[in];
1093*6236dae4SAndroid Build Coastguard Worker 
1094*6236dae4SAndroid Build Coastguard Worker     switch(tn->telrcv_state) {
1095*6236dae4SAndroid Build Coastguard Worker     case CURL_TS_CR:
1096*6236dae4SAndroid Build Coastguard Worker       tn->telrcv_state = CURL_TS_DATA;
1097*6236dae4SAndroid Build Coastguard Worker       if(c == '\0') {
1098*6236dae4SAndroid Build Coastguard Worker         startskipping();
1099*6236dae4SAndroid Build Coastguard Worker         break;   /* Ignore \0 after CR */
1100*6236dae4SAndroid Build Coastguard Worker       }
1101*6236dae4SAndroid Build Coastguard Worker       writebyte();
1102*6236dae4SAndroid Build Coastguard Worker       break;
1103*6236dae4SAndroid Build Coastguard Worker 
1104*6236dae4SAndroid Build Coastguard Worker     case CURL_TS_DATA:
1105*6236dae4SAndroid Build Coastguard Worker       if(c == CURL_IAC) {
1106*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_IAC;
1107*6236dae4SAndroid Build Coastguard Worker         startskipping();
1108*6236dae4SAndroid Build Coastguard Worker         break;
1109*6236dae4SAndroid Build Coastguard Worker       }
1110*6236dae4SAndroid Build Coastguard Worker       else if(c == '\r')
1111*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_CR;
1112*6236dae4SAndroid Build Coastguard Worker       writebyte();
1113*6236dae4SAndroid Build Coastguard Worker       break;
1114*6236dae4SAndroid Build Coastguard Worker 
1115*6236dae4SAndroid Build Coastguard Worker     case CURL_TS_IAC:
1116*6236dae4SAndroid Build Coastguard Worker process_iac:
1117*6236dae4SAndroid Build Coastguard Worker       DEBUGASSERT(startwrite < 0);
1118*6236dae4SAndroid Build Coastguard Worker       switch(c) {
1119*6236dae4SAndroid Build Coastguard Worker       case CURL_WILL:
1120*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_WILL;
1121*6236dae4SAndroid Build Coastguard Worker         break;
1122*6236dae4SAndroid Build Coastguard Worker       case CURL_WONT:
1123*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_WONT;
1124*6236dae4SAndroid Build Coastguard Worker         break;
1125*6236dae4SAndroid Build Coastguard Worker       case CURL_DO:
1126*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_DO;
1127*6236dae4SAndroid Build Coastguard Worker         break;
1128*6236dae4SAndroid Build Coastguard Worker       case CURL_DONT:
1129*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_DONT;
1130*6236dae4SAndroid Build Coastguard Worker         break;
1131*6236dae4SAndroid Build Coastguard Worker       case CURL_SB:
1132*6236dae4SAndroid Build Coastguard Worker         CURL_SB_CLEAR(tn);
1133*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_SB;
1134*6236dae4SAndroid Build Coastguard Worker         break;
1135*6236dae4SAndroid Build Coastguard Worker       case CURL_IAC:
1136*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_DATA;
1137*6236dae4SAndroid Build Coastguard Worker         writebyte();
1138*6236dae4SAndroid Build Coastguard Worker         break;
1139*6236dae4SAndroid Build Coastguard Worker       case CURL_DM:
1140*6236dae4SAndroid Build Coastguard Worker       case CURL_NOP:
1141*6236dae4SAndroid Build Coastguard Worker       case CURL_GA:
1142*6236dae4SAndroid Build Coastguard Worker       default:
1143*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_DATA;
1144*6236dae4SAndroid Build Coastguard Worker         printoption(data, "RCVD", CURL_IAC, c);
1145*6236dae4SAndroid Build Coastguard Worker         break;
1146*6236dae4SAndroid Build Coastguard Worker       }
1147*6236dae4SAndroid Build Coastguard Worker       break;
1148*6236dae4SAndroid Build Coastguard Worker 
1149*6236dae4SAndroid Build Coastguard Worker       case CURL_TS_WILL:
1150*6236dae4SAndroid Build Coastguard Worker         printoption(data, "RCVD", CURL_WILL, c);
1151*6236dae4SAndroid Build Coastguard Worker         tn->please_negotiate = 1;
1152*6236dae4SAndroid Build Coastguard Worker         rec_will(data, c);
1153*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_DATA;
1154*6236dae4SAndroid Build Coastguard Worker         break;
1155*6236dae4SAndroid Build Coastguard Worker 
1156*6236dae4SAndroid Build Coastguard Worker       case CURL_TS_WONT:
1157*6236dae4SAndroid Build Coastguard Worker         printoption(data, "RCVD", CURL_WONT, c);
1158*6236dae4SAndroid Build Coastguard Worker         tn->please_negotiate = 1;
1159*6236dae4SAndroid Build Coastguard Worker         rec_wont(data, c);
1160*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_DATA;
1161*6236dae4SAndroid Build Coastguard Worker         break;
1162*6236dae4SAndroid Build Coastguard Worker 
1163*6236dae4SAndroid Build Coastguard Worker       case CURL_TS_DO:
1164*6236dae4SAndroid Build Coastguard Worker         printoption(data, "RCVD", CURL_DO, c);
1165*6236dae4SAndroid Build Coastguard Worker         tn->please_negotiate = 1;
1166*6236dae4SAndroid Build Coastguard Worker         rec_do(data, c);
1167*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_DATA;
1168*6236dae4SAndroid Build Coastguard Worker         break;
1169*6236dae4SAndroid Build Coastguard Worker 
1170*6236dae4SAndroid Build Coastguard Worker       case CURL_TS_DONT:
1171*6236dae4SAndroid Build Coastguard Worker         printoption(data, "RCVD", CURL_DONT, c);
1172*6236dae4SAndroid Build Coastguard Worker         tn->please_negotiate = 1;
1173*6236dae4SAndroid Build Coastguard Worker         rec_dont(data, c);
1174*6236dae4SAndroid Build Coastguard Worker         tn->telrcv_state = CURL_TS_DATA;
1175*6236dae4SAndroid Build Coastguard Worker         break;
1176*6236dae4SAndroid Build Coastguard Worker 
1177*6236dae4SAndroid Build Coastguard Worker       case CURL_TS_SB:
1178*6236dae4SAndroid Build Coastguard Worker         if(c == CURL_IAC)
1179*6236dae4SAndroid Build Coastguard Worker           tn->telrcv_state = CURL_TS_SE;
1180*6236dae4SAndroid Build Coastguard Worker         else
1181*6236dae4SAndroid Build Coastguard Worker           CURL_SB_ACCUM(tn, c);
1182*6236dae4SAndroid Build Coastguard Worker         break;
1183*6236dae4SAndroid Build Coastguard Worker 
1184*6236dae4SAndroid Build Coastguard Worker       case CURL_TS_SE:
1185*6236dae4SAndroid Build Coastguard Worker         if(c != CURL_SE) {
1186*6236dae4SAndroid Build Coastguard Worker           if(c != CURL_IAC) {
1187*6236dae4SAndroid Build Coastguard Worker             /*
1188*6236dae4SAndroid Build Coastguard Worker              * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1189*6236dae4SAndroid Build Coastguard Worker              * Several things may have happened. An IAC was not doubled, the
1190*6236dae4SAndroid Build Coastguard Worker              * IAC SE was left off, or another option got inserted into the
1191*6236dae4SAndroid Build Coastguard Worker              * suboption are all possibilities. If we assume that the IAC was
1192*6236dae4SAndroid Build Coastguard Worker              * not doubled, and really the IAC SE was left off, we could get
1193*6236dae4SAndroid Build Coastguard Worker              * into an infinite loop here. So, instead, we terminate the
1194*6236dae4SAndroid Build Coastguard Worker              * suboption, and process the partial suboption if we can.
1195*6236dae4SAndroid Build Coastguard Worker              */
1196*6236dae4SAndroid Build Coastguard Worker             CURL_SB_ACCUM(tn, CURL_IAC);
1197*6236dae4SAndroid Build Coastguard Worker             CURL_SB_ACCUM(tn, c);
1198*6236dae4SAndroid Build Coastguard Worker             tn->subpointer -= 2;
1199*6236dae4SAndroid Build Coastguard Worker             CURL_SB_TERM(tn);
1200*6236dae4SAndroid Build Coastguard Worker 
1201*6236dae4SAndroid Build Coastguard Worker             printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1202*6236dae4SAndroid Build Coastguard Worker             suboption(data);   /* handle sub-option */
1203*6236dae4SAndroid Build Coastguard Worker             tn->telrcv_state = CURL_TS_IAC;
1204*6236dae4SAndroid Build Coastguard Worker             goto process_iac;
1205*6236dae4SAndroid Build Coastguard Worker           }
1206*6236dae4SAndroid Build Coastguard Worker           CURL_SB_ACCUM(tn, c);
1207*6236dae4SAndroid Build Coastguard Worker           tn->telrcv_state = CURL_TS_SB;
1208*6236dae4SAndroid Build Coastguard Worker         }
1209*6236dae4SAndroid Build Coastguard Worker         else {
1210*6236dae4SAndroid Build Coastguard Worker           CURL_SB_ACCUM(tn, CURL_IAC);
1211*6236dae4SAndroid Build Coastguard Worker           CURL_SB_ACCUM(tn, CURL_SE);
1212*6236dae4SAndroid Build Coastguard Worker           tn->subpointer -= 2;
1213*6236dae4SAndroid Build Coastguard Worker           CURL_SB_TERM(tn);
1214*6236dae4SAndroid Build Coastguard Worker           suboption(data);   /* handle sub-option */
1215*6236dae4SAndroid Build Coastguard Worker           tn->telrcv_state = CURL_TS_DATA;
1216*6236dae4SAndroid Build Coastguard Worker         }
1217*6236dae4SAndroid Build Coastguard Worker         break;
1218*6236dae4SAndroid Build Coastguard Worker     }
1219*6236dae4SAndroid Build Coastguard Worker     ++in;
1220*6236dae4SAndroid Build Coastguard Worker   }
1221*6236dae4SAndroid Build Coastguard Worker   bufferflush();
1222*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1223*6236dae4SAndroid Build Coastguard Worker }
1224*6236dae4SAndroid Build Coastguard Worker 
1225*6236dae4SAndroid Build Coastguard Worker /* Escape and send a telnet data block */
send_telnet_data(struct Curl_easy * data,char * buffer,ssize_t nread)1226*6236dae4SAndroid Build Coastguard Worker static CURLcode send_telnet_data(struct Curl_easy *data,
1227*6236dae4SAndroid Build Coastguard Worker                                  char *buffer, ssize_t nread)
1228*6236dae4SAndroid Build Coastguard Worker {
1229*6236dae4SAndroid Build Coastguard Worker   size_t i, outlen;
1230*6236dae4SAndroid Build Coastguard Worker   unsigned char *outbuf;
1231*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1232*6236dae4SAndroid Build Coastguard Worker   size_t bytes_written;
1233*6236dae4SAndroid Build Coastguard Worker   size_t total_written = 0;
1234*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1235*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
1236*6236dae4SAndroid Build Coastguard Worker 
1237*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(tn);
1238*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(nread > 0);
1239*6236dae4SAndroid Build Coastguard Worker   if(nread < 0)
1240*6236dae4SAndroid Build Coastguard Worker     return CURLE_TOO_LARGE;
1241*6236dae4SAndroid Build Coastguard Worker 
1242*6236dae4SAndroid Build Coastguard Worker   if(memchr(buffer, CURL_IAC, nread)) {
1243*6236dae4SAndroid Build Coastguard Worker     /* only use the escape buffer when necessary */
1244*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_reset(&tn->out);
1245*6236dae4SAndroid Build Coastguard Worker 
1246*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i < (size_t)nread && !result; i++) {
1247*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_addn(&tn->out, &buffer[i], 1);
1248*6236dae4SAndroid Build Coastguard Worker       if(!result && ((unsigned char)buffer[i] == CURL_IAC))
1249*6236dae4SAndroid Build Coastguard Worker         /* IAC is FF in hex */
1250*6236dae4SAndroid Build Coastguard Worker         result = Curl_dyn_addn(&tn->out, "\xff", 1);
1251*6236dae4SAndroid Build Coastguard Worker     }
1252*6236dae4SAndroid Build Coastguard Worker 
1253*6236dae4SAndroid Build Coastguard Worker     outlen = Curl_dyn_len(&tn->out);
1254*6236dae4SAndroid Build Coastguard Worker     outbuf = Curl_dyn_uptr(&tn->out);
1255*6236dae4SAndroid Build Coastguard Worker   }
1256*6236dae4SAndroid Build Coastguard Worker   else {
1257*6236dae4SAndroid Build Coastguard Worker     outlen = (size_t)nread;
1258*6236dae4SAndroid Build Coastguard Worker     outbuf = (unsigned char *)buffer;
1259*6236dae4SAndroid Build Coastguard Worker   }
1260*6236dae4SAndroid Build Coastguard Worker   while(!result && total_written < outlen) {
1261*6236dae4SAndroid Build Coastguard Worker     /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1262*6236dae4SAndroid Build Coastguard Worker     struct pollfd pfd[1];
1263*6236dae4SAndroid Build Coastguard Worker     pfd[0].fd = conn->sock[FIRSTSOCKET];
1264*6236dae4SAndroid Build Coastguard Worker     pfd[0].events = POLLOUT;
1265*6236dae4SAndroid Build Coastguard Worker     switch(Curl_poll(pfd, 1, -1)) {
1266*6236dae4SAndroid Build Coastguard Worker       case -1:                    /* error, abort writing */
1267*6236dae4SAndroid Build Coastguard Worker       case 0:                     /* timeout (will never happen) */
1268*6236dae4SAndroid Build Coastguard Worker         result = CURLE_SEND_ERROR;
1269*6236dae4SAndroid Build Coastguard Worker         break;
1270*6236dae4SAndroid Build Coastguard Worker       default:                    /* write! */
1271*6236dae4SAndroid Build Coastguard Worker         bytes_written = 0;
1272*6236dae4SAndroid Build Coastguard Worker         result = Curl_xfer_send(data, outbuf + total_written,
1273*6236dae4SAndroid Build Coastguard Worker                                 outlen - total_written, FALSE, &bytes_written);
1274*6236dae4SAndroid Build Coastguard Worker         total_written += bytes_written;
1275*6236dae4SAndroid Build Coastguard Worker         break;
1276*6236dae4SAndroid Build Coastguard Worker     }
1277*6236dae4SAndroid Build Coastguard Worker   }
1278*6236dae4SAndroid Build Coastguard Worker 
1279*6236dae4SAndroid Build Coastguard Worker   return result;
1280*6236dae4SAndroid Build Coastguard Worker }
1281*6236dae4SAndroid Build Coastguard Worker 
telnet_done(struct Curl_easy * data,CURLcode status,bool premature)1282*6236dae4SAndroid Build Coastguard Worker static CURLcode telnet_done(struct Curl_easy *data,
1283*6236dae4SAndroid Build Coastguard Worker                             CURLcode status, bool premature)
1284*6236dae4SAndroid Build Coastguard Worker {
1285*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn = data->req.p.telnet;
1286*6236dae4SAndroid Build Coastguard Worker   (void)status; /* unused */
1287*6236dae4SAndroid Build Coastguard Worker   (void)premature; /* not used */
1288*6236dae4SAndroid Build Coastguard Worker 
1289*6236dae4SAndroid Build Coastguard Worker   if(!tn)
1290*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
1291*6236dae4SAndroid Build Coastguard Worker 
1292*6236dae4SAndroid Build Coastguard Worker   curl_slist_free_all(tn->telnet_vars);
1293*6236dae4SAndroid Build Coastguard Worker   tn->telnet_vars = NULL;
1294*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&tn->out);
1295*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1296*6236dae4SAndroid Build Coastguard Worker }
1297*6236dae4SAndroid Build Coastguard Worker 
telnet_do(struct Curl_easy * data,bool * done)1298*6236dae4SAndroid Build Coastguard Worker static CURLcode telnet_do(struct Curl_easy *data, bool *done)
1299*6236dae4SAndroid Build Coastguard Worker {
1300*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
1301*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1302*6236dae4SAndroid Build Coastguard Worker   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1303*6236dae4SAndroid Build Coastguard Worker #ifdef USE_WINSOCK
1304*6236dae4SAndroid Build Coastguard Worker   WSAEVENT event_handle;
1305*6236dae4SAndroid Build Coastguard Worker   WSANETWORKEVENTS events;
1306*6236dae4SAndroid Build Coastguard Worker   HANDLE stdin_handle;
1307*6236dae4SAndroid Build Coastguard Worker   HANDLE objs[2];
1308*6236dae4SAndroid Build Coastguard Worker   DWORD  obj_count;
1309*6236dae4SAndroid Build Coastguard Worker   DWORD  wait_timeout;
1310*6236dae4SAndroid Build Coastguard Worker   DWORD readfile_read;
1311*6236dae4SAndroid Build Coastguard Worker   int err;
1312*6236dae4SAndroid Build Coastguard Worker #else
1313*6236dae4SAndroid Build Coastguard Worker   timediff_t interval_ms;
1314*6236dae4SAndroid Build Coastguard Worker   struct pollfd pfd[2];
1315*6236dae4SAndroid Build Coastguard Worker   int poll_cnt;
1316*6236dae4SAndroid Build Coastguard Worker   curl_off_t total_dl = 0;
1317*6236dae4SAndroid Build Coastguard Worker   curl_off_t total_ul = 0;
1318*6236dae4SAndroid Build Coastguard Worker #endif
1319*6236dae4SAndroid Build Coastguard Worker   ssize_t nread;
1320*6236dae4SAndroid Build Coastguard Worker   struct curltime now;
1321*6236dae4SAndroid Build Coastguard Worker   bool keepon = TRUE;
1322*6236dae4SAndroid Build Coastguard Worker   char buffer[4*1024];
1323*6236dae4SAndroid Build Coastguard Worker   struct TELNET *tn;
1324*6236dae4SAndroid Build Coastguard Worker 
1325*6236dae4SAndroid Build Coastguard Worker   *done = TRUE; /* unconditionally */
1326*6236dae4SAndroid Build Coastguard Worker 
1327*6236dae4SAndroid Build Coastguard Worker   result = init_telnet(data);
1328*6236dae4SAndroid Build Coastguard Worker   if(result)
1329*6236dae4SAndroid Build Coastguard Worker     return result;
1330*6236dae4SAndroid Build Coastguard Worker 
1331*6236dae4SAndroid Build Coastguard Worker   tn = data->req.p.telnet;
1332*6236dae4SAndroid Build Coastguard Worker 
1333*6236dae4SAndroid Build Coastguard Worker   result = check_telnet_options(data);
1334*6236dae4SAndroid Build Coastguard Worker   if(result)
1335*6236dae4SAndroid Build Coastguard Worker     return result;
1336*6236dae4SAndroid Build Coastguard Worker 
1337*6236dae4SAndroid Build Coastguard Worker #ifdef USE_WINSOCK
1338*6236dae4SAndroid Build Coastguard Worker   /* We want to wait for both stdin and the socket. Since
1339*6236dae4SAndroid Build Coastguard Worker   ** the select() function in Winsock only works on sockets
1340*6236dae4SAndroid Build Coastguard Worker   ** we have to use the WaitForMultipleObjects() call.
1341*6236dae4SAndroid Build Coastguard Worker   */
1342*6236dae4SAndroid Build Coastguard Worker 
1343*6236dae4SAndroid Build Coastguard Worker   /* First, create a sockets event object */
1344*6236dae4SAndroid Build Coastguard Worker   event_handle = WSACreateEvent();
1345*6236dae4SAndroid Build Coastguard Worker   if(event_handle == WSA_INVALID_EVENT) {
1346*6236dae4SAndroid Build Coastguard Worker     failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1347*6236dae4SAndroid Build Coastguard Worker     return CURLE_FAILED_INIT;
1348*6236dae4SAndroid Build Coastguard Worker   }
1349*6236dae4SAndroid Build Coastguard Worker 
1350*6236dae4SAndroid Build Coastguard Worker   /* Tell Winsock what events we want to listen to */
1351*6236dae4SAndroid Build Coastguard Worker   if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
1352*6236dae4SAndroid Build Coastguard Worker     WSACloseEvent(event_handle);
1353*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
1354*6236dae4SAndroid Build Coastguard Worker   }
1355*6236dae4SAndroid Build Coastguard Worker 
1356*6236dae4SAndroid Build Coastguard Worker   /* The get the Windows file handle for stdin */
1357*6236dae4SAndroid Build Coastguard Worker   stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1358*6236dae4SAndroid Build Coastguard Worker 
1359*6236dae4SAndroid Build Coastguard Worker   /* Create the list of objects to wait for */
1360*6236dae4SAndroid Build Coastguard Worker   objs[0] = event_handle;
1361*6236dae4SAndroid Build Coastguard Worker   objs[1] = stdin_handle;
1362*6236dae4SAndroid Build Coastguard Worker 
1363*6236dae4SAndroid Build Coastguard Worker   /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1364*6236dae4SAndroid Build Coastguard Worker      else use the old WaitForMultipleObjects() way */
1365*6236dae4SAndroid Build Coastguard Worker   if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1366*6236dae4SAndroid Build Coastguard Worker      data->set.is_fread_set) {
1367*6236dae4SAndroid Build Coastguard Worker     /* Do not wait for stdin_handle, just wait for event_handle */
1368*6236dae4SAndroid Build Coastguard Worker     obj_count = 1;
1369*6236dae4SAndroid Build Coastguard Worker     /* Check stdin_handle per 100 milliseconds */
1370*6236dae4SAndroid Build Coastguard Worker     wait_timeout = 100;
1371*6236dae4SAndroid Build Coastguard Worker   }
1372*6236dae4SAndroid Build Coastguard Worker   else {
1373*6236dae4SAndroid Build Coastguard Worker     obj_count = 2;
1374*6236dae4SAndroid Build Coastguard Worker     wait_timeout = 1000;
1375*6236dae4SAndroid Build Coastguard Worker   }
1376*6236dae4SAndroid Build Coastguard Worker 
1377*6236dae4SAndroid Build Coastguard Worker   /* Keep on listening and act on events */
1378*6236dae4SAndroid Build Coastguard Worker   while(keepon) {
1379*6236dae4SAndroid Build Coastguard Worker     const DWORD buf_size = (DWORD)sizeof(buffer);
1380*6236dae4SAndroid Build Coastguard Worker     DWORD waitret = WaitForMultipleObjects(obj_count, objs,
1381*6236dae4SAndroid Build Coastguard Worker                                            FALSE, wait_timeout);
1382*6236dae4SAndroid Build Coastguard Worker     switch(waitret) {
1383*6236dae4SAndroid Build Coastguard Worker 
1384*6236dae4SAndroid Build Coastguard Worker     case WAIT_TIMEOUT:
1385*6236dae4SAndroid Build Coastguard Worker     {
1386*6236dae4SAndroid Build Coastguard Worker       for(;;) {
1387*6236dae4SAndroid Build Coastguard Worker         if(data->set.is_fread_set) {
1388*6236dae4SAndroid Build Coastguard Worker           size_t n;
1389*6236dae4SAndroid Build Coastguard Worker           /* read from user-supplied method */
1390*6236dae4SAndroid Build Coastguard Worker           n = data->state.fread_func(buffer, 1, buf_size, data->state.in);
1391*6236dae4SAndroid Build Coastguard Worker           if(n == CURL_READFUNC_ABORT) {
1392*6236dae4SAndroid Build Coastguard Worker             keepon = FALSE;
1393*6236dae4SAndroid Build Coastguard Worker             result = CURLE_READ_ERROR;
1394*6236dae4SAndroid Build Coastguard Worker             break;
1395*6236dae4SAndroid Build Coastguard Worker           }
1396*6236dae4SAndroid Build Coastguard Worker 
1397*6236dae4SAndroid Build Coastguard Worker           if(n == CURL_READFUNC_PAUSE)
1398*6236dae4SAndroid Build Coastguard Worker             break;
1399*6236dae4SAndroid Build Coastguard Worker 
1400*6236dae4SAndroid Build Coastguard Worker           if(n == 0)                        /* no bytes */
1401*6236dae4SAndroid Build Coastguard Worker             break;
1402*6236dae4SAndroid Build Coastguard Worker 
1403*6236dae4SAndroid Build Coastguard Worker           /* fall through with number of bytes read */
1404*6236dae4SAndroid Build Coastguard Worker           readfile_read = (DWORD)n;
1405*6236dae4SAndroid Build Coastguard Worker         }
1406*6236dae4SAndroid Build Coastguard Worker         else {
1407*6236dae4SAndroid Build Coastguard Worker           /* read from stdin */
1408*6236dae4SAndroid Build Coastguard Worker           if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1409*6236dae4SAndroid Build Coastguard Worker                             &readfile_read, NULL)) {
1410*6236dae4SAndroid Build Coastguard Worker             keepon = FALSE;
1411*6236dae4SAndroid Build Coastguard Worker             result = CURLE_READ_ERROR;
1412*6236dae4SAndroid Build Coastguard Worker             break;
1413*6236dae4SAndroid Build Coastguard Worker           }
1414*6236dae4SAndroid Build Coastguard Worker 
1415*6236dae4SAndroid Build Coastguard Worker           if(!readfile_read)
1416*6236dae4SAndroid Build Coastguard Worker             break;
1417*6236dae4SAndroid Build Coastguard Worker 
1418*6236dae4SAndroid Build Coastguard Worker           if(!ReadFile(stdin_handle, buffer, buf_size,
1419*6236dae4SAndroid Build Coastguard Worker                        &readfile_read, NULL)) {
1420*6236dae4SAndroid Build Coastguard Worker             keepon = FALSE;
1421*6236dae4SAndroid Build Coastguard Worker             result = CURLE_READ_ERROR;
1422*6236dae4SAndroid Build Coastguard Worker             break;
1423*6236dae4SAndroid Build Coastguard Worker           }
1424*6236dae4SAndroid Build Coastguard Worker         }
1425*6236dae4SAndroid Build Coastguard Worker 
1426*6236dae4SAndroid Build Coastguard Worker         result = send_telnet_data(data, buffer, readfile_read);
1427*6236dae4SAndroid Build Coastguard Worker         if(result) {
1428*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1429*6236dae4SAndroid Build Coastguard Worker           break;
1430*6236dae4SAndroid Build Coastguard Worker         }
1431*6236dae4SAndroid Build Coastguard Worker       }
1432*6236dae4SAndroid Build Coastguard Worker     }
1433*6236dae4SAndroid Build Coastguard Worker     break;
1434*6236dae4SAndroid Build Coastguard Worker 
1435*6236dae4SAndroid Build Coastguard Worker     case WAIT_OBJECT_0 + 1:
1436*6236dae4SAndroid Build Coastguard Worker     {
1437*6236dae4SAndroid Build Coastguard Worker       if(!ReadFile(stdin_handle, buffer, buf_size,
1438*6236dae4SAndroid Build Coastguard Worker                    &readfile_read, NULL)) {
1439*6236dae4SAndroid Build Coastguard Worker         keepon = FALSE;
1440*6236dae4SAndroid Build Coastguard Worker         result = CURLE_READ_ERROR;
1441*6236dae4SAndroid Build Coastguard Worker         break;
1442*6236dae4SAndroid Build Coastguard Worker       }
1443*6236dae4SAndroid Build Coastguard Worker 
1444*6236dae4SAndroid Build Coastguard Worker       result = send_telnet_data(data, buffer, readfile_read);
1445*6236dae4SAndroid Build Coastguard Worker       if(result) {
1446*6236dae4SAndroid Build Coastguard Worker         keepon = FALSE;
1447*6236dae4SAndroid Build Coastguard Worker         break;
1448*6236dae4SAndroid Build Coastguard Worker       }
1449*6236dae4SAndroid Build Coastguard Worker     }
1450*6236dae4SAndroid Build Coastguard Worker     break;
1451*6236dae4SAndroid Build Coastguard Worker 
1452*6236dae4SAndroid Build Coastguard Worker     case WAIT_OBJECT_0:
1453*6236dae4SAndroid Build Coastguard Worker     {
1454*6236dae4SAndroid Build Coastguard Worker       events.lNetworkEvents = 0;
1455*6236dae4SAndroid Build Coastguard Worker       if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) {
1456*6236dae4SAndroid Build Coastguard Worker         err = SOCKERRNO;
1457*6236dae4SAndroid Build Coastguard Worker         if(err != EINPROGRESS) {
1458*6236dae4SAndroid Build Coastguard Worker           infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1459*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1460*6236dae4SAndroid Build Coastguard Worker           result = CURLE_READ_ERROR;
1461*6236dae4SAndroid Build Coastguard Worker         }
1462*6236dae4SAndroid Build Coastguard Worker         break;
1463*6236dae4SAndroid Build Coastguard Worker       }
1464*6236dae4SAndroid Build Coastguard Worker       if(events.lNetworkEvents & FD_READ) {
1465*6236dae4SAndroid Build Coastguard Worker         /* read data from network */
1466*6236dae4SAndroid Build Coastguard Worker         result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
1467*6236dae4SAndroid Build Coastguard Worker         /* read would have blocked. Loop again */
1468*6236dae4SAndroid Build Coastguard Worker         if(result == CURLE_AGAIN)
1469*6236dae4SAndroid Build Coastguard Worker           break;
1470*6236dae4SAndroid Build Coastguard Worker         /* returned not-zero, this an error */
1471*6236dae4SAndroid Build Coastguard Worker         else if(result) {
1472*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1473*6236dae4SAndroid Build Coastguard Worker           break;
1474*6236dae4SAndroid Build Coastguard Worker         }
1475*6236dae4SAndroid Build Coastguard Worker         /* returned zero but actually received 0 or less here,
1476*6236dae4SAndroid Build Coastguard Worker            the server closed the connection and we bail out */
1477*6236dae4SAndroid Build Coastguard Worker         else if(nread <= 0) {
1478*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1479*6236dae4SAndroid Build Coastguard Worker           break;
1480*6236dae4SAndroid Build Coastguard Worker         }
1481*6236dae4SAndroid Build Coastguard Worker 
1482*6236dae4SAndroid Build Coastguard Worker         result = telrcv(data, (unsigned char *) buffer, nread);
1483*6236dae4SAndroid Build Coastguard Worker         if(result) {
1484*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1485*6236dae4SAndroid Build Coastguard Worker           break;
1486*6236dae4SAndroid Build Coastguard Worker         }
1487*6236dae4SAndroid Build Coastguard Worker 
1488*6236dae4SAndroid Build Coastguard Worker         /* Negotiate if the peer has started negotiating,
1489*6236dae4SAndroid Build Coastguard Worker            otherwise do not. We do not want to speak telnet with
1490*6236dae4SAndroid Build Coastguard Worker            non-telnet servers, like POP or SMTP. */
1491*6236dae4SAndroid Build Coastguard Worker         if(tn->please_negotiate && !tn->already_negotiated) {
1492*6236dae4SAndroid Build Coastguard Worker           negotiate(data);
1493*6236dae4SAndroid Build Coastguard Worker           tn->already_negotiated = 1;
1494*6236dae4SAndroid Build Coastguard Worker         }
1495*6236dae4SAndroid Build Coastguard Worker       }
1496*6236dae4SAndroid Build Coastguard Worker       if(events.lNetworkEvents & FD_CLOSE) {
1497*6236dae4SAndroid Build Coastguard Worker         keepon = FALSE;
1498*6236dae4SAndroid Build Coastguard Worker       }
1499*6236dae4SAndroid Build Coastguard Worker     }
1500*6236dae4SAndroid Build Coastguard Worker     break;
1501*6236dae4SAndroid Build Coastguard Worker 
1502*6236dae4SAndroid Build Coastguard Worker     }
1503*6236dae4SAndroid Build Coastguard Worker 
1504*6236dae4SAndroid Build Coastguard Worker     if(data->set.timeout) {
1505*6236dae4SAndroid Build Coastguard Worker       now = Curl_now();
1506*6236dae4SAndroid Build Coastguard Worker       if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1507*6236dae4SAndroid Build Coastguard Worker         failf(data, "Time-out");
1508*6236dae4SAndroid Build Coastguard Worker         result = CURLE_OPERATION_TIMEDOUT;
1509*6236dae4SAndroid Build Coastguard Worker         keepon = FALSE;
1510*6236dae4SAndroid Build Coastguard Worker       }
1511*6236dae4SAndroid Build Coastguard Worker     }
1512*6236dae4SAndroid Build Coastguard Worker   }
1513*6236dae4SAndroid Build Coastguard Worker 
1514*6236dae4SAndroid Build Coastguard Worker   /* We called WSACreateEvent, so call WSACloseEvent */
1515*6236dae4SAndroid Build Coastguard Worker   if(!WSACloseEvent(event_handle)) {
1516*6236dae4SAndroid Build Coastguard Worker     infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1517*6236dae4SAndroid Build Coastguard Worker   }
1518*6236dae4SAndroid Build Coastguard Worker #else
1519*6236dae4SAndroid Build Coastguard Worker   pfd[0].fd = sockfd;
1520*6236dae4SAndroid Build Coastguard Worker   pfd[0].events = POLLIN;
1521*6236dae4SAndroid Build Coastguard Worker 
1522*6236dae4SAndroid Build Coastguard Worker   if(data->set.is_fread_set) {
1523*6236dae4SAndroid Build Coastguard Worker     poll_cnt = 1;
1524*6236dae4SAndroid Build Coastguard Worker     interval_ms = 100; /* poll user-supplied read function */
1525*6236dae4SAndroid Build Coastguard Worker   }
1526*6236dae4SAndroid Build Coastguard Worker   else {
1527*6236dae4SAndroid Build Coastguard Worker     /* really using fread, so infile is a FILE* */
1528*6236dae4SAndroid Build Coastguard Worker     pfd[1].fd = fileno((FILE *)data->state.in);
1529*6236dae4SAndroid Build Coastguard Worker     pfd[1].events = POLLIN;
1530*6236dae4SAndroid Build Coastguard Worker     poll_cnt = 2;
1531*6236dae4SAndroid Build Coastguard Worker     interval_ms = 1 * 1000;
1532*6236dae4SAndroid Build Coastguard Worker     if(pfd[1].fd < 0) {
1533*6236dae4SAndroid Build Coastguard Worker       failf(data, "cannot read input");
1534*6236dae4SAndroid Build Coastguard Worker       result = CURLE_RECV_ERROR;
1535*6236dae4SAndroid Build Coastguard Worker       keepon = FALSE;
1536*6236dae4SAndroid Build Coastguard Worker     }
1537*6236dae4SAndroid Build Coastguard Worker   }
1538*6236dae4SAndroid Build Coastguard Worker 
1539*6236dae4SAndroid Build Coastguard Worker   while(keepon) {
1540*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt));
1541*6236dae4SAndroid Build Coastguard Worker     switch(Curl_poll(pfd, (unsigned int)poll_cnt, interval_ms)) {
1542*6236dae4SAndroid Build Coastguard Worker     case -1:                    /* error, stop reading */
1543*6236dae4SAndroid Build Coastguard Worker       keepon = FALSE;
1544*6236dae4SAndroid Build Coastguard Worker       continue;
1545*6236dae4SAndroid Build Coastguard Worker     case 0:                     /* timeout */
1546*6236dae4SAndroid Build Coastguard Worker       pfd[0].revents = 0;
1547*6236dae4SAndroid Build Coastguard Worker       pfd[1].revents = 0;
1548*6236dae4SAndroid Build Coastguard Worker       FALLTHROUGH();
1549*6236dae4SAndroid Build Coastguard Worker     default:                    /* read! */
1550*6236dae4SAndroid Build Coastguard Worker       if(pfd[0].revents & POLLIN) {
1551*6236dae4SAndroid Build Coastguard Worker         /* read data from network */
1552*6236dae4SAndroid Build Coastguard Worker         result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
1553*6236dae4SAndroid Build Coastguard Worker         /* read would have blocked. Loop again */
1554*6236dae4SAndroid Build Coastguard Worker         if(result == CURLE_AGAIN)
1555*6236dae4SAndroid Build Coastguard Worker           break;
1556*6236dae4SAndroid Build Coastguard Worker         /* returned not-zero, this an error */
1557*6236dae4SAndroid Build Coastguard Worker         if(result) {
1558*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1559*6236dae4SAndroid Build Coastguard Worker           /* TODO: in test 1452, macOS sees a ECONNRESET sometimes?
1560*6236dae4SAndroid Build Coastguard Worker            * Is this the telnet test server not shutting down the socket
1561*6236dae4SAndroid Build Coastguard Worker            * in a clean way? Seems to be timing related, happens more
1562*6236dae4SAndroid Build Coastguard Worker            * on slow debug build */
1563*6236dae4SAndroid Build Coastguard Worker           if(data->state.os_errno == ECONNRESET) {
1564*6236dae4SAndroid Build Coastguard Worker             DEBUGF(infof(data, "telnet_do, unexpected ECONNRESET on recv"));
1565*6236dae4SAndroid Build Coastguard Worker           }
1566*6236dae4SAndroid Build Coastguard Worker           break;
1567*6236dae4SAndroid Build Coastguard Worker         }
1568*6236dae4SAndroid Build Coastguard Worker         /* returned zero but actually received 0 or less here,
1569*6236dae4SAndroid Build Coastguard Worker            the server closed the connection and we bail out */
1570*6236dae4SAndroid Build Coastguard Worker         else if(nread <= 0) {
1571*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1572*6236dae4SAndroid Build Coastguard Worker           break;
1573*6236dae4SAndroid Build Coastguard Worker         }
1574*6236dae4SAndroid Build Coastguard Worker 
1575*6236dae4SAndroid Build Coastguard Worker         total_dl += nread;
1576*6236dae4SAndroid Build Coastguard Worker         result = Curl_pgrsSetDownloadCounter(data, total_dl);
1577*6236dae4SAndroid Build Coastguard Worker         if(!result)
1578*6236dae4SAndroid Build Coastguard Worker           result = telrcv(data, (unsigned char *)buffer, nread);
1579*6236dae4SAndroid Build Coastguard Worker         if(result) {
1580*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1581*6236dae4SAndroid Build Coastguard Worker           break;
1582*6236dae4SAndroid Build Coastguard Worker         }
1583*6236dae4SAndroid Build Coastguard Worker 
1584*6236dae4SAndroid Build Coastguard Worker         /* Negotiate if the peer has started negotiating,
1585*6236dae4SAndroid Build Coastguard Worker            otherwise do not. We do not want to speak telnet with
1586*6236dae4SAndroid Build Coastguard Worker            non-telnet servers, like POP or SMTP. */
1587*6236dae4SAndroid Build Coastguard Worker         if(tn->please_negotiate && !tn->already_negotiated) {
1588*6236dae4SAndroid Build Coastguard Worker           negotiate(data);
1589*6236dae4SAndroid Build Coastguard Worker           tn->already_negotiated = 1;
1590*6236dae4SAndroid Build Coastguard Worker         }
1591*6236dae4SAndroid Build Coastguard Worker       }
1592*6236dae4SAndroid Build Coastguard Worker 
1593*6236dae4SAndroid Build Coastguard Worker       nread = 0;
1594*6236dae4SAndroid Build Coastguard Worker       if(poll_cnt == 2) {
1595*6236dae4SAndroid Build Coastguard Worker         if(pfd[1].revents & POLLIN) { /* read from in file */
1596*6236dae4SAndroid Build Coastguard Worker           nread = read(pfd[1].fd, buffer, sizeof(buffer));
1597*6236dae4SAndroid Build Coastguard Worker         }
1598*6236dae4SAndroid Build Coastguard Worker       }
1599*6236dae4SAndroid Build Coastguard Worker       else {
1600*6236dae4SAndroid Build Coastguard Worker         /* read from user-supplied method */
1601*6236dae4SAndroid Build Coastguard Worker         nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer),
1602*6236dae4SAndroid Build Coastguard Worker                                             data->state.in);
1603*6236dae4SAndroid Build Coastguard Worker         if(nread == CURL_READFUNC_ABORT) {
1604*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1605*6236dae4SAndroid Build Coastguard Worker           break;
1606*6236dae4SAndroid Build Coastguard Worker         }
1607*6236dae4SAndroid Build Coastguard Worker         if(nread == CURL_READFUNC_PAUSE)
1608*6236dae4SAndroid Build Coastguard Worker           break;
1609*6236dae4SAndroid Build Coastguard Worker       }
1610*6236dae4SAndroid Build Coastguard Worker 
1611*6236dae4SAndroid Build Coastguard Worker       if(nread > 0) {
1612*6236dae4SAndroid Build Coastguard Worker         result = send_telnet_data(data, buffer, nread);
1613*6236dae4SAndroid Build Coastguard Worker         if(result) {
1614*6236dae4SAndroid Build Coastguard Worker           keepon = FALSE;
1615*6236dae4SAndroid Build Coastguard Worker           break;
1616*6236dae4SAndroid Build Coastguard Worker         }
1617*6236dae4SAndroid Build Coastguard Worker         total_ul += nread;
1618*6236dae4SAndroid Build Coastguard Worker         Curl_pgrsSetUploadCounter(data, total_ul);
1619*6236dae4SAndroid Build Coastguard Worker       }
1620*6236dae4SAndroid Build Coastguard Worker       else if(nread < 0)
1621*6236dae4SAndroid Build Coastguard Worker         keepon = FALSE;
1622*6236dae4SAndroid Build Coastguard Worker 
1623*6236dae4SAndroid Build Coastguard Worker       break;
1624*6236dae4SAndroid Build Coastguard Worker     } /* poll switch statement */
1625*6236dae4SAndroid Build Coastguard Worker 
1626*6236dae4SAndroid Build Coastguard Worker     if(data->set.timeout) {
1627*6236dae4SAndroid Build Coastguard Worker       now = Curl_now();
1628*6236dae4SAndroid Build Coastguard Worker       if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1629*6236dae4SAndroid Build Coastguard Worker         failf(data, "Time-out");
1630*6236dae4SAndroid Build Coastguard Worker         result = CURLE_OPERATION_TIMEDOUT;
1631*6236dae4SAndroid Build Coastguard Worker         keepon = FALSE;
1632*6236dae4SAndroid Build Coastguard Worker       }
1633*6236dae4SAndroid Build Coastguard Worker     }
1634*6236dae4SAndroid Build Coastguard Worker 
1635*6236dae4SAndroid Build Coastguard Worker     if(Curl_pgrsUpdate(data)) {
1636*6236dae4SAndroid Build Coastguard Worker       result = CURLE_ABORTED_BY_CALLBACK;
1637*6236dae4SAndroid Build Coastguard Worker       break;
1638*6236dae4SAndroid Build Coastguard Worker     }
1639*6236dae4SAndroid Build Coastguard Worker   }
1640*6236dae4SAndroid Build Coastguard Worker #endif
1641*6236dae4SAndroid Build Coastguard Worker   /* mark this as "no further transfer wanted" */
1642*6236dae4SAndroid Build Coastguard Worker   Curl_xfer_setup_nop(data);
1643*6236dae4SAndroid Build Coastguard Worker 
1644*6236dae4SAndroid Build Coastguard Worker   return result;
1645*6236dae4SAndroid Build Coastguard Worker }
1646*6236dae4SAndroid Build Coastguard Worker #endif
1647