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