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