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