telnet.c: fix MSVC compiler warning
[platform/upstream/curl.git] / lib / telnet.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2011, 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   curl_slist_free_all(tn->telnet_vars);
1277   tn->telnet_vars = NULL;
1278
1279   free(conn->data->state.proto.telnet);
1280   conn->data->state.proto.telnet = NULL;
1281
1282   return CURLE_OK;
1283 }
1284
1285 static CURLcode telnet_do(struct connectdata *conn, bool *done)
1286 {
1287   CURLcode code;
1288   struct SessionHandle *data = conn->data;
1289   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1290 #ifdef USE_WINSOCK
1291   HMODULE wsock2;
1292   WSOCK2_FUNC close_event_func;
1293   WSOCK2_FUNC create_event_func;
1294   WSOCK2_FUNC event_select_func;
1295   WSOCK2_FUNC enum_netevents_func;
1296   WSAEVENT event_handle;
1297   WSANETWORKEVENTS events;
1298   HANDLE stdin_handle;
1299   HANDLE objs[2];
1300   DWORD  obj_count;
1301   DWORD  wait_timeout;
1302   DWORD waitret;
1303   DWORD readfile_read;
1304   int err;
1305 #else
1306   int interval_ms;
1307   struct pollfd pfd[2];
1308   int poll_cnt;
1309   curl_off_t total_dl = 0;
1310   curl_off_t total_ul = 0;
1311 #endif
1312   ssize_t nread;
1313   struct timeval now;
1314   bool keepon = TRUE;
1315   char *buf = data->state.buffer;
1316   struct TELNET *tn;
1317
1318   *done = TRUE; /* unconditionally */
1319
1320   code = init_telnet(conn);
1321   if(code)
1322     return code;
1323
1324   tn = (struct TELNET *)data->state.proto.telnet;
1325
1326   code = check_telnet_options(conn);
1327   if(code)
1328     return code;
1329
1330 #ifdef USE_WINSOCK
1331   /*
1332   ** This functionality only works with WinSock >= 2.0.  So,
1333   ** make sure have it.
1334   */
1335   code = check_wsock2(data);
1336   if(code)
1337     return code;
1338
1339   /* OK, so we have WinSock 2.0.  We need to dynamically */
1340   /* load ws2_32.dll and get the function pointers we need. */
1341   wsock2 = LoadLibrary("WS2_32.DLL");
1342   if(wsock2 == NULL) {
1343     failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
1344     return CURLE_FAILED_INIT;
1345   }
1346
1347   /* Grab a pointer to WSACreateEvent */
1348   create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
1349   if(create_event_func == NULL) {
1350     failf(data,"failed to find WSACreateEvent function (%d)",
1351           ERRNO);
1352     FreeLibrary(wsock2);
1353     return CURLE_FAILED_INIT;
1354   }
1355
1356   /* And WSACloseEvent */
1357   close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
1358   if(close_event_func == NULL) {
1359     failf(data,"failed to find WSACloseEvent function (%d)",
1360           ERRNO);
1361     FreeLibrary(wsock2);
1362     return CURLE_FAILED_INIT;
1363   }
1364
1365   /* And WSAEventSelect */
1366   event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
1367   if(event_select_func == NULL) {
1368     failf(data,"failed to find WSAEventSelect function (%d)",
1369           ERRNO);
1370     FreeLibrary(wsock2);
1371     return CURLE_FAILED_INIT;
1372   }
1373
1374   /* And WSAEnumNetworkEvents */
1375   enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
1376   if(enum_netevents_func == NULL) {
1377     failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
1378           ERRNO);
1379     FreeLibrary(wsock2);
1380     return CURLE_FAILED_INIT;
1381   }
1382
1383   /* We want to wait for both stdin and the socket. Since
1384   ** the select() function in winsock only works on sockets
1385   ** we have to use the WaitForMultipleObjects() call.
1386   */
1387
1388   /* First, create a sockets event object */
1389   event_handle = (WSAEVENT)create_event_func();
1390   if(event_handle == WSA_INVALID_EVENT) {
1391     failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
1392     FreeLibrary(wsock2);
1393     return CURLE_FAILED_INIT;
1394   }
1395
1396   /* Tell winsock what events we want to listen to */
1397   if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1398      SOCKET_ERROR) {
1399     close_event_func(event_handle);
1400     FreeLibrary(wsock2);
1401     return CURLE_OK;
1402   }
1403
1404   /* The get the Windows file handle for stdin */
1405   stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1406
1407   /* Create the list of objects to wait for */
1408   objs[0] = event_handle;
1409   objs[1] = stdin_handle;
1410
1411   /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1412      else use the old WaitForMultipleObjects() way */
1413   if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1414      data->set.is_fread_set) {
1415     /* Don't wait for stdin_handle, just wait for event_handle */
1416     obj_count = 1;
1417     /* Check stdin_handle per 100 milliseconds */
1418     wait_timeout = 100;
1419   }
1420   else {
1421     obj_count = 2;
1422     wait_timeout = 1000;
1423   }
1424
1425   /* Keep on listening and act on events */
1426   while(keepon) {
1427     waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
1428     switch(waitret) {
1429     case WAIT_TIMEOUT:
1430     {
1431       for(;;) {
1432         if(obj_count == 1) {
1433           /* read from user-supplied method */
1434           code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1435           if(code == CURL_READFUNC_ABORT) {
1436             keepon = FALSE;
1437             code = CURLE_READ_ERROR;
1438             break;
1439           }
1440
1441           if(code == CURL_READFUNC_PAUSE)
1442             break;
1443
1444           if(code == 0)                        /* no bytes */
1445             break;
1446
1447           readfile_read = code; /* fall thru with number of bytes read */
1448         }
1449         else {
1450           /* read from stdin */
1451           if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1452                             &readfile_read, NULL)) {
1453             keepon = FALSE;
1454             code = CURLE_READ_ERROR;
1455             break;
1456           }
1457
1458           if(!readfile_read)
1459             break;
1460
1461           if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1462                        &readfile_read, NULL)) {
1463             keepon = FALSE;
1464             code = CURLE_READ_ERROR;
1465             break;
1466           }
1467         }
1468
1469         code = send_telnet_data(conn, buf, readfile_read);
1470         if(code) {
1471           keepon = FALSE;
1472           break;
1473         }
1474       }
1475     }
1476     break;
1477
1478     case WAIT_OBJECT_0 + 1:
1479     {
1480       if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
1481                    &readfile_read, NULL)) {
1482         keepon = FALSE;
1483         code = CURLE_READ_ERROR;
1484         break;
1485       }
1486
1487       code = send_telnet_data(conn, buf, readfile_read);
1488       if(code) {
1489         keepon = FALSE;
1490         break;
1491       }
1492     }
1493     break;
1494
1495     case WAIT_OBJECT_0:
1496
1497       if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1498         if((err = SOCKERRNO) != EINPROGRESS) {
1499           infof(data,"WSAEnumNetworkEvents failed (%d)", err);
1500           keepon = FALSE;
1501           code = CURLE_READ_ERROR;
1502         }
1503         break;
1504       }
1505       if(events.lNetworkEvents & FD_READ) {
1506         /* read data from network */
1507         code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1508         /* read would've blocked. Loop again */
1509         if(code == CURLE_AGAIN)
1510           break;
1511         /* returned not-zero, this an error */
1512         else if(code) {
1513           keepon = FALSE;
1514           break;
1515         }
1516         /* returned zero but actually received 0 or less here,
1517            the server closed the connection and we bail out */
1518         else if(nread <= 0) {
1519           keepon = FALSE;
1520           break;
1521         }
1522
1523         code = telrcv(conn, (unsigned char *)buf, nread);
1524         if(code) {
1525           keepon = FALSE;
1526           break;
1527         }
1528
1529         /* Negotiate if the peer has started negotiating,
1530            otherwise don't. We don't want to speak telnet with
1531            non-telnet servers, like POP or SMTP. */
1532         if(tn->please_negotiate && !tn->already_negotiated) {
1533           negotiate(conn);
1534           tn->already_negotiated = 1;
1535         }
1536       }
1537       if(events.lNetworkEvents & FD_CLOSE) {
1538         keepon = FALSE;
1539       }
1540       break;
1541
1542     }
1543
1544     if(data->set.timeout) {
1545       now = Curl_tvnow();
1546       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1547         failf(data, "Time-out");
1548         code = CURLE_OPERATION_TIMEDOUT;
1549         keepon = FALSE;
1550       }
1551     }
1552   }
1553
1554   /* We called WSACreateEvent, so call WSACloseEvent */
1555   if(!close_event_func(event_handle)) {
1556     infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
1557   }
1558
1559   /* "Forget" pointers into the library we're about to free */
1560   create_event_func = NULL;
1561   close_event_func = NULL;
1562   event_select_func = NULL;
1563   enum_netevents_func = NULL;
1564
1565   /* We called LoadLibrary, so call FreeLibrary */
1566   if(!FreeLibrary(wsock2))
1567     infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
1568 #else
1569   pfd[0].fd = sockfd;
1570   pfd[0].events = POLLIN;
1571
1572   if(data->set.is_fread_set) {
1573     poll_cnt = 1;
1574     interval_ms = 100; /* poll user-supplied read function */
1575   }
1576   else {
1577     pfd[1].fd = 0;
1578     pfd[1].events = POLLIN;
1579     poll_cnt = 2;
1580     interval_ms = 1 * 1000;
1581   }
1582
1583   while(keepon) {
1584     switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
1585     case -1:                    /* error, stop reading */
1586       keepon = FALSE;
1587       continue;
1588     case 0:                     /* timeout */
1589       pfd[0].revents = 0;
1590       pfd[1].revents = 0;
1591       /* fall through */
1592     default:                    /* read! */
1593       if(pfd[0].revents & POLLIN) {
1594         /* read data from network */
1595         code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1596         /* read would've blocked. Loop again */
1597         if(code == CURLE_AGAIN)
1598           break;
1599         /* returned not-zero, this an error */
1600         else if(code) {
1601           keepon = FALSE;
1602           break;
1603         }
1604         /* returned zero but actually received 0 or less here,
1605            the server closed the connection and we bail out */
1606         else if(nread <= 0) {
1607           keepon = FALSE;
1608           break;
1609         }
1610
1611         total_dl += nread;
1612         Curl_pgrsSetDownloadCounter(data, total_dl);
1613         code = telrcv(conn, (unsigned char *)buf, nread);
1614         if(code) {
1615           keepon = FALSE;
1616           break;
1617         }
1618
1619         /* Negotiate if the peer has started negotiating,
1620            otherwise don't. We don't want to speak telnet with
1621            non-telnet servers, like POP or SMTP. */
1622         if(tn->please_negotiate && !tn->already_negotiated) {
1623           negotiate(conn);
1624           tn->already_negotiated = 1;
1625         }
1626       }
1627
1628       nread = 0;
1629       if(poll_cnt == 2) {
1630         if(pfd[1].revents & POLLIN) { /* read from stdin */
1631           nread = read(0, buf, BUFSIZE - 1);
1632         }
1633       }
1634       else {
1635         /* read from user-supplied method */
1636         nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
1637         if(nread == CURL_READFUNC_ABORT) {
1638           keepon = FALSE;
1639           break;
1640         }
1641         if(nread == CURL_READFUNC_PAUSE)
1642           break;
1643       }
1644
1645       if(nread > 0) {
1646         code = send_telnet_data(conn, buf, nread);
1647         if(code) {
1648           keepon = FALSE;
1649           break;
1650         }
1651         total_ul += nread;
1652         Curl_pgrsSetUploadCounter(data, total_ul);
1653       }
1654       else if(nread < 0)
1655         keepon = FALSE;
1656
1657       break;
1658     } /* poll switch statement */
1659
1660     if(data->set.timeout) {
1661       now = Curl_tvnow();
1662       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
1663         failf(data, "Time-out");
1664         code = CURLE_OPERATION_TIMEDOUT;
1665         keepon = FALSE;
1666       }
1667     }
1668
1669     if(Curl_pgrsUpdate(conn)) {
1670       code = CURLE_ABORTED_BY_CALLBACK;
1671       break;
1672     }
1673   }
1674 #endif
1675   /* mark this as "no further transfer wanted" */
1676   Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1677
1678   return code;
1679 }
1680 #endif