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