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