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