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