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