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