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