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