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