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