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