77d8b7b6b59917ef5ba385ff938960521b340072
[platform/upstream/curl.git] / lib / telnet.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, 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->state.proto.telnet = (void *)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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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->state.proto.telnet;
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   unsigned short *pval;
714
715   if(data->set.verbose) {
716     if(direction) {
717       infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
718       if(length >= 3) {
719         int j;
720
721         i = pointer[length-2];
722         j = pointer[length-1];
723
724         if(i != CURL_IAC || j != CURL_SE) {
725           infof(data, "(terminated by ");
726           if(CURL_TELOPT_OK(i))
727             infof(data, "%s ", CURL_TELOPT(i));
728           else if(CURL_TELCMD_OK(i))
729             infof(data, "%s ", CURL_TELCMD(i));
730           else
731             infof(data, "%u ", i);
732           if(CURL_TELOPT_OK(j))
733             infof(data, "%s", CURL_TELOPT(j));
734           else if(CURL_TELCMD_OK(j))
735             infof(data, "%s", CURL_TELCMD(j));
736           else
737             infof(data, "%d", j);
738           infof(data, ", not IAC SE!) ");
739         }
740       }
741       length -= 2;
742     }
743     if(length < 1) {
744       infof(data, "(Empty suboption?)");
745       return;
746     }
747
748     if(CURL_TELOPT_OK(pointer[0])) {
749       switch(pointer[0]) {
750       case CURL_TELOPT_TTYPE:
751       case CURL_TELOPT_XDISPLOC:
752       case CURL_TELOPT_NEW_ENVIRON:
753       case CURL_TELOPT_NAWS:
754         infof(data, "%s", CURL_TELOPT(pointer[0]));
755         break;
756       default:
757         infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
758         break;
759       }
760     }
761     else
762       infof(data, "%d (unknown)", pointer[i]);
763
764     switch(pointer[0]) {
765     case CURL_TELOPT_NAWS:
766       pval = (unsigned short*)(pointer+1);
767       infof(data, "Width: %hu ; Height: %hu",
768             ntohs(pval[0]), ntohs(pval[1]));
769       break;
770     default:
771       switch(pointer[1]) {
772       case CURL_TELQUAL_IS:
773         infof(data, " IS");
774         break;
775       case CURL_TELQUAL_SEND:
776         infof(data, " SEND");
777         break;
778       case CURL_TELQUAL_INFO:
779         infof(data, " INFO/REPLY");
780         break;
781       case CURL_TELQUAL_NAME:
782         infof(data, " NAME");
783         break;
784       }
785
786       switch(pointer[0]) {
787       case CURL_TELOPT_TTYPE:
788       case CURL_TELOPT_XDISPLOC:
789         pointer[length] = 0;
790         infof(data, " \"%s\"", &pointer[2]);
791         break;
792       case CURL_TELOPT_NEW_ENVIRON:
793         if(pointer[1] == CURL_TELQUAL_IS) {
794           infof(data, " ");
795           for(i = 3;i < length;i++) {
796             switch(pointer[i]) {
797             case CURL_NEW_ENV_VAR:
798               infof(data, ", ");
799               break;
800             case CURL_NEW_ENV_VALUE:
801               infof(data, " = ");
802               break;
803             default:
804               infof(data, "%c", pointer[i]);
805               break;
806             }
807           }
808         }
809         break;
810       default:
811         for(i = 2; i < length; i++)
812           infof(data, " %.2x", pointer[i]);
813         break;
814       }
815     }
816     if(direction)
817       infof(data, "\n");
818   }
819 }
820
821 static CURLcode check_telnet_options(struct connectdata *conn)
822 {
823   struct curl_slist *head;
824   struct curl_slist *beg;
825   char option_keyword[128];
826   char option_arg[256];
827   struct SessionHandle *data = conn->data;
828   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
829   CURLcode result = CURLE_OK;
830   int binary_option;
831
832   /* Add the user name as an environment variable if it
833      was given on the command line */
834   if(conn->bits.user_passwd) {
835     snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
836     beg = curl_slist_append(tn->telnet_vars, option_arg);
837     if(!beg) {
838       curl_slist_free_all(tn->telnet_vars);
839       tn->telnet_vars = NULL;
840       return CURLE_OUT_OF_MEMORY;
841     }
842     tn->telnet_vars = beg;
843     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
844   }
845
846   for(head = data->set.telnet_options; head; head=head->next) {
847     if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
848               option_keyword, option_arg) == 2) {
849
850       /* Terminal type */
851       if(Curl_raw_equal(option_keyword, "TTYPE")) {
852         strncpy(tn->subopt_ttype, option_arg, 31);
853         tn->subopt_ttype[31] = 0; /* String termination */
854         tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
855         continue;
856       }
857
858       /* Display variable */
859       if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
860         strncpy(tn->subopt_xdisploc, option_arg, 127);
861         tn->subopt_xdisploc[127] = 0; /* String termination */
862         tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
863         continue;
864       }
865
866       /* Environment variable */
867       if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
868         beg = curl_slist_append(tn->telnet_vars, option_arg);
869         if(!beg) {
870           result = CURLE_OUT_OF_MEMORY;
871           break;
872         }
873         tn->telnet_vars = beg;
874         tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
875         continue;
876       }
877
878           /* Window Size */
879       if(Curl_raw_equal(option_keyword, "WS")) {
880         if(sscanf(option_arg, "%hu%*[xX]%hu",
881                   &tn->subopt_wsx, &tn->subopt_wsy) == 2)
882           tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
883         else {
884           failf(data, "Syntax error in telnet option: %s", head->data);
885           result = CURLE_TELNET_OPTION_SYNTAX;
886           break;
887         }
888         continue;
889       }
890
891       /* To take care or not of the 8th bit in data exchange */
892       if(Curl_raw_equal(option_keyword, "BINARY")) {
893         binary_option=atoi(option_arg);
894         if(binary_option!=1) {
895           tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
896           tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
897         }
898         continue;
899       }
900
901       failf(data, "Unknown telnet option %s", head->data);
902       result = CURLE_UNKNOWN_TELNET_OPTION;
903       break;
904     }
905     else {
906       failf(data, "Syntax error in telnet option: %s", head->data);
907       result = CURLE_TELNET_OPTION_SYNTAX;
908       break;
909     }
910   }
911
912   if(result) {
913     curl_slist_free_all(tn->telnet_vars);
914     tn->telnet_vars = NULL;
915   }
916
917   return result;
918 }
919
920 /*
921  * suboption()
922  *
923  * Look at the sub-option buffer, and try to be helpful to the other
924  * side.
925  */
926
927 static void suboption(struct connectdata *conn)
928 {
929   struct curl_slist *v;
930   unsigned char temp[2048];
931   ssize_t bytes_written;
932   size_t len;
933   size_t tmplen;
934   int err;
935   char varname[128];
936   char varval[128];
937   struct SessionHandle *data = conn->data;
938   struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
939
940   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
941   switch (CURL_SB_GET(tn)) {
942     case CURL_TELOPT_TTYPE:
943       len = strlen(tn->subopt_ttype) + 4 + 2;
944       snprintf((char *)temp, sizeof(temp),
945                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
946                CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
947       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
948       if(bytes_written < 0) {
949         err = SOCKERRNO;
950         failf(data,"Sending data failed (%d)",err);
951       }
952       printsub(data, '>', &temp[2], len-2);
953       break;
954     case CURL_TELOPT_XDISPLOC:
955       len = strlen(tn->subopt_xdisploc) + 4 + 2;
956       snprintf((char *)temp, sizeof(temp),
957                "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
958                CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
959       bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
960       if(bytes_written < 0) {
961         err = SOCKERRNO;
962         failf(data,"Sending data failed (%d)",err);
963       }
964       printsub(data, '>', &temp[2], len-2);
965       break;
966     case CURL_TELOPT_NEW_ENVIRON:
967       snprintf((char *)temp, sizeof(temp),
968                "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
969                CURL_TELQUAL_IS);
970       len = 4;
971
972       for(v = tn->telnet_vars;v;v = v->next) {
973         tmplen = (strlen(v->data) + 1);
974         /* Add the variable only if it fits */
975         if(len + tmplen < (int)sizeof(temp)-6) {
976           sscanf(v->data, "%127[^,],%127s", varname, varval);
977           snprintf((char *)&temp[len], sizeof(temp) - len,
978                    "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
979                    CURL_NEW_ENV_VALUE, varval);
980           len += tmplen;
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->state.proto.telnet;
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->state.proto.telnet;
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 != CURLE_OK)                                    \
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 rc = CURLE_OK;
1233
1234   while(rc == CURLE_OK && 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           rc = CURLE_SEND_ERROR;
1250           break;
1251         default:                    /* write! */
1252           bytes_written = 0;
1253           rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
1254                           out_count-total_written, &bytes_written);
1255           total_written += bytes_written;
1256           break;
1257       }
1258     /* handle partial write */
1259     } while(rc == CURLE_OK && total_written < out_count);
1260   }
1261   return rc;
1262 }
1263
1264 static CURLcode telnet_done(struct connectdata *conn,
1265                                  CURLcode status, bool premature)
1266 {
1267   struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
1268   (void)status; /* unused */
1269   (void)premature; /* not used */
1270
1271   if(!tn)
1272     return CURLE_OK;
1273
1274   curl_slist_free_all(tn->telnet_vars);
1275   tn->telnet_vars = NULL;
1276
1277   Curl_safefree(conn->data->state.proto.telnet);
1278
1279   return CURLE_OK;
1280 }
1281
1282 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1283 {
1284   CURLcode code;
1285   struct SessionHandle *data = conn->data;
1286   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1287 #ifdef USE_WINSOCK
1288   HMODULE wsock2;
1289   WSOCK2_FUNC close_event_func;
1290   WSOCK2_FUNC create_event_func;
1291   WSOCK2_FUNC event_select_func;
1292   WSOCK2_FUNC enum_netevents_func;
1293   WSAEVENT event_handle;
1294   WSANETWORKEVENTS events;
1295   HANDLE stdin_handle;
1296   HANDLE objs[2];
1297   DWORD  obj_count;
1298   DWORD  wait_timeout;
1299   DWORD waitret;
1300   DWORD readfile_read;
1301   int err;
1302 #else
1303   int interval_ms;
1304   struct pollfd pfd[2];
1305   int poll_cnt;
1306   curl_off_t total_dl = 0;
1307   curl_off_t total_ul = 0;
1308 #endif
1309   ssize_t nread;
1310   struct timeval now;
1311   bool keepon = TRUE;
1312   char *buf = data->state.buffer;
1313   struct TELNET *tn;
1314
1315   *done = TRUE; /* unconditionally */
1316
1317   code = init_telnet(conn);
1318   if(code)
1319     return code;
1320
1321   tn = (struct TELNET *)data->state.proto.telnet;
1322
1323   code = check_telnet_options(conn);
1324   if(code)
1325     return code;
1326
1327 #ifdef USE_WINSOCK
1328   /*
1329   ** This functionality only works with WinSock >= 2.0.  So,
1330   ** make sure have it.
1331   */
1332   code = check_wsock2(data);
1333   if(code)
1334     return code;
1335
1336   /* OK, so we have WinSock 2.0.  We need to dynamically */
1337   /* load ws2_32.dll and get the function pointers we need. */
1338   wsock2 = LoadLibrary(TEXT("WS2_32.DLL"));
1339   if(wsock2 == NULL) {
1340     failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
1341     return CURLE_FAILED_INIT;
1342   }
1343
1344   /* Grab a pointer to WSACreateEvent */
1345   create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
1346   if(create_event_func == NULL) {
1347     failf(data,"failed to find WSACreateEvent function (%d)",
1348           ERRNO);
1349     FreeLibrary(wsock2);
1350     return CURLE_FAILED_INIT;
1351   }
1352
1353   /* And WSACloseEvent */
1354   close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
1355   if(close_event_func == NULL) {
1356     failf(data,"failed to find WSACloseEvent function (%d)",
1357           ERRNO);
1358     FreeLibrary(wsock2);
1359     return CURLE_FAILED_INIT;
1360   }
1361
1362   /* And WSAEventSelect */
1363   event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
1364   if(event_select_func == NULL) {
1365     failf(data,"failed to find WSAEventSelect function (%d)",
1366           ERRNO);
1367     FreeLibrary(wsock2);
1368     return CURLE_FAILED_INIT;
1369   }
1370
1371   /* And WSAEnumNetworkEvents */
1372   enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
1373   if(enum_netevents_func == NULL) {
1374     failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
1375           ERRNO);
1376     FreeLibrary(wsock2);
1377     return CURLE_FAILED_INIT;
1378   }
1379
1380   /* We want to wait for both stdin and the socket. Since
1381   ** the select() function in winsock only works on sockets
1382   ** we have to use the WaitForMultipleObjects() call.
1383   */
1384
1385   /* First, create a sockets event object */
1386   event_handle = (WSAEVENT)create_event_func();
1387   if(event_handle == WSA_INVALID_EVENT) {
1388     failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
1389     FreeLibrary(wsock2);
1390     return CURLE_FAILED_INIT;
1391   }
1392
1393   /* Tell winsock what events we want to listen to */
1394   if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1395      SOCKET_ERROR) {
1396     close_event_func(event_handle);
1397     FreeLibrary(wsock2);
1398     return CURLE_OK;
1399   }
1400
1401   /* The get the Windows file handle for stdin */
1402   stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1403
1404   /* Create the list of objects to wait for */
1405   objs[0] = event_handle;
1406   objs[1] = stdin_handle;
1407
1408   /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1409      else use the old WaitForMultipleObjects() way */
1410   if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1411      data->set.is_fread_set) {
1412     /* Don't wait for stdin_handle, just wait for event_handle */
1413     obj_count = 1;
1414     /* Check stdin_handle per 100 milliseconds */
1415     wait_timeout = 100;
1416   }
1417   else {
1418     obj_count = 2;
1419     wait_timeout = 1000;
1420   }
1421
1422   /* Keep on listening and act on events */
1423   while(keepon) {
1424     waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1425     switch(waitret) {
1426     case WAIT_TIMEOUT:
1427     {
1428       for(;;) {
1429         if(obj_count == 1) {
1430           /* read from user-supplied method */
1431           code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1432           if(code == CURL_READFUNC_ABORT) {
1433             keepon = FALSE;
1434             code = CURLE_READ_ERROR;
1435             break;
1436           }
1437
1438           if(code == CURL_READFUNC_PAUSE)
1439             break;
1440
1441           if(code == 0)                        /* no bytes */
1442             break;
1443
1444           readfile_read = code; /* fall thru with number of bytes read */
1445         }
1446         else {
1447           /* read from stdin */
1448           if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1449                             &readfile_read, NULL)) {
1450             keepon = FALSE;
1451             code = CURLE_READ_ERROR;
1452             break;
1453           }
1454
1455           if(!readfile_read)
1456             break;
1457
1458           if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1459                        &readfile_read, NULL)) {
1460             keepon = FALSE;
1461             code = CURLE_READ_ERROR;
1462             break;
1463           }
1464         }
1465
1466         code = send_telnet_data(conn, buf, readfile_read);
1467         if(code) {
1468           keepon = FALSE;
1469           break;
1470         }
1471       }
1472     }
1473     break;
1474
1475     case WAIT_OBJECT_0 + 1:
1476     {
1477       if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1478                    &readfile_read, NULL)) {
1479         keepon = FALSE;
1480         code = CURLE_READ_ERROR;
1481         break;
1482       }
1483
1484       code = send_telnet_data(conn, buf, readfile_read);
1485       if(code) {
1486         keepon = FALSE;
1487         break;
1488       }
1489     }
1490     break;
1491
1492     case WAIT_OBJECT_0:
1493
1494       if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1495         if((err = SOCKERRNO) != EINPROGRESS) {
1496           infof(data,"WSAEnumNetworkEvents failed (%d)", err);
1497           keepon = FALSE;
1498           code = CURLE_READ_ERROR;
1499         }
1500         break;
1501       }
1502       if(events.lNetworkEvents & FD_READ) {
1503         /* read data from network */
1504         code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1505         /* read would've blocked. Loop again */
1506         if(code == CURLE_AGAIN)
1507           break;
1508         /* returned not-zero, this an error */
1509         else if(code) {
1510           keepon = FALSE;
1511           break;
1512         }
1513         /* returned zero but actually received 0 or less here,
1514            the server closed the connection and we bail out */
1515         else if(nread <= 0) {
1516           keepon = FALSE;
1517           break;
1518         }
1519
1520         code = telrcv(conn, (unsigned char *)buf, nread);
1521         if(code) {
1522           keepon = FALSE;
1523           break;
1524         }
1525
1526         /* Negotiate if the peer has started negotiating,
1527            otherwise don't. We don't want to speak telnet with
1528            non-telnet servers, like POP or SMTP. */
1529         if(tn->please_negotiate && !tn->already_negotiated) {
1530           negotiate(conn);
1531           tn->already_negotiated = 1;
1532         }
1533       }
1534       if(events.lNetworkEvents & FD_CLOSE) {
1535         keepon = FALSE;
1536       }
1537       break;
1538
1539     }
1540
1541     if(data->set.timeout) {
1542       now = Curl_tvnow();
1543       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1544         failf(data, "Time-out");
1545         code = CURLE_OPERATION_TIMEDOUT;
1546         keepon = FALSE;
1547       }
1548     }
1549   }
1550
1551   /* We called WSACreateEvent, so call WSACloseEvent */
1552   if(!close_event_func(event_handle)) {
1553     infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
1554   }
1555
1556   /* "Forget" pointers into the library we're about to free */
1557   create_event_func = NULL;
1558   close_event_func = NULL;
1559   event_select_func = NULL;
1560   enum_netevents_func = NULL;
1561
1562   /* We called LoadLibrary, so call FreeLibrary */
1563   if(!FreeLibrary(wsock2))
1564     infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
1565 #else
1566   pfd[0].fd = sockfd;
1567   pfd[0].events = POLLIN;
1568
1569   if(conn->fread_func != (curl_read_callback)fread) {
1570     poll_cnt = 1;
1571     interval_ms = 100; /* poll user-supplied read function */
1572   }
1573   else {
1574     /* really using fread, so infile is a FILE* */
1575     pfd[1].fd = fileno((FILE *)conn->fread_in);
1576     pfd[1].events = POLLIN;
1577     poll_cnt = 2;
1578     interval_ms = 1 * 1000;
1579   }
1580
1581   while(keepon) {
1582     switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1583     case -1:                    /* error, stop reading */
1584       keepon = FALSE;
1585       continue;
1586     case 0:                     /* timeout */
1587       pfd[0].revents = 0;
1588       pfd[1].revents = 0;
1589       /* fall through */
1590     default:                    /* read! */
1591       if(pfd[0].revents & POLLIN) {
1592         /* read data from network */
1593         code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1594         /* read would've blocked. Loop again */
1595         if(code == CURLE_AGAIN)
1596           break;
1597         /* returned not-zero, this an error */
1598         else if(code) {
1599           keepon = FALSE;
1600           break;
1601         }
1602         /* returned zero but actually received 0 or less here,
1603            the server closed the connection and we bail out */
1604         else if(nread <= 0) {
1605           keepon = FALSE;
1606           break;
1607         }
1608
1609         total_dl += nread;
1610         Curl_pgrsSetDownloadCounter(data, total_dl);
1611         code = telrcv(conn, (unsigned char *)buf, nread);
1612         if(code) {
1613           keepon = FALSE;
1614           break;
1615         }
1616
1617         /* Negotiate if the peer has started negotiating,
1618            otherwise don't. We don't want to speak telnet with
1619            non-telnet servers, like POP or SMTP. */
1620         if(tn->please_negotiate && !tn->already_negotiated) {
1621           negotiate(conn);
1622           tn->already_negotiated = 1;
1623         }
1624       }
1625
1626       nread = 0;
1627       if(poll_cnt == 2) {
1628         if(pfd[1].revents & POLLIN) { /* read from in file */
1629           nread = read(pfd[1].fd, buf, BUFSIZE - 1);
1630         }
1631       }
1632       else {
1633         /* read from user-supplied method */
1634         nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_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         code = send_telnet_data(conn, buf, nread);
1645         if(code) {
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         code = CURLE_OPERATION_TIMEDOUT;
1663         keepon = FALSE;
1664       }
1665     }
1666
1667     if(Curl_pgrsUpdate(conn)) {
1668       code = 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 code;
1677 }
1678 #endif