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