somebody is playing with the contributions :)
[cmake.git] / Source / CTest / Curl / telnet.c
blobaa841501db206e8943dffec31cc2926c35149ae3
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: telnet.c,v 1.3 2003-01-14 14:12:37 andy Exp $
22 ***************************************************************************/
24 #include "setup.h"
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 #include <sys/types.h>
34 #include <sys/stat.h>
36 #include <errno.h>
38 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
39 #include <winsock2.h>
40 #include <time.h>
41 #include <io.h>
42 #else
43 #ifdef HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
45 #endif
46 #include <netinet/in.h>
47 #include <sys/time.h>
48 #include <sys/resource.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>
62 #ifdef HAVE_SYS_PARAM_H
63 #include <sys/param.h>
64 #endif
66 #ifdef HAVE_SYS_SELECT_H
67 #include <sys/select.h>
68 #endif
71 #endif
73 #include "urldata.h"
74 #include <curl/curl.h>
75 #include "transfer.h"
76 #include "sendf.h"
78 #define _MPRINTF_REPLACE /* use our functions only */
79 #include <curl/mprintf.h>
81 #define TELOPTS
82 #define TELCMDS
84 #include "arpa_telnet.h"
86 /* The last #include file should be: */
87 #ifdef MALLOCDEBUG
88 #include "memdebug.h"
89 #endif
91 #define SUBBUFSIZE 512
93 #define SB_CLEAR(x) x->subpointer = x->subbuffer;
94 #define SB_TERM(x) { x->subend = x->subpointer; SB_CLEAR(x); }
95 #define SB_ACCUM(x,c) if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
96 *x->subpointer++ = (c); \
99 #define SB_GET(x) ((*x->subpointer++)&0xff)
100 #define SB_PEEK(x) ((*x->subpointer)&0xff)
101 #define SB_EOF(x) (x->subpointer >= x->subend)
102 #define SB_LEN(x) (x->subend - x->subpointer)
104 static
105 void telrcv(struct connectdata *,
106 unsigned char *inbuf, /* Data received from socket */
107 int count); /* Number of bytes received */
109 static void printoption(struct SessionHandle *data,
110 const char *direction,
111 int cmd, int option);
113 static void negotiate(struct connectdata *);
114 static void send_negotiation(struct connectdata *, int cmd, int option);
115 static void set_local_option(struct connectdata *, int cmd, int option);
116 static void set_remote_option(struct connectdata *, int cmd, int option);
118 static void printsub(struct SessionHandle *data,
119 int direction, unsigned char *pointer, int length);
120 static void suboption(struct connectdata *);
122 /* For negotiation compliant to RFC 1143 */
123 #define NO 0
124 #define YES 1
125 #define WANTYES 2
126 #define WANTNO 3
128 #define EMPTY 0
129 #define OPPOSITE 1
132 * Telnet receiver states for fsm
134 typedef enum
136 TS_DATA = 0,
137 TS_IAC,
138 TS_WILL,
139 TS_WONT,
140 TS_DO,
141 TS_DONT,
142 TS_CR,
143 TS_SB, /* sub-option collection */
144 TS_SE /* looking for sub-option end */
145 } TelnetReceive;
147 struct TELNET {
148 int please_negotiate;
149 int already_negotiated;
150 int us[256];
151 int usq[256];
152 int us_preferred[256];
153 int him[256];
154 int himq[256];
155 int him_preferred[256];
156 char subopt_ttype[32]; /* Set with suboption TTYPE */
157 char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
158 struct curl_slist *telnet_vars; /* Environment variables */
160 /* suboptions */
161 char subbuffer[SUBBUFSIZE];
162 char *subpointer, *subend; /* buffer for sub-options */
164 TelnetReceive telrcv_state;
167 static
168 CURLcode init_telnet(struct connectdata *conn)
170 struct TELNET *tn;
172 tn = (struct TELNET *)malloc(sizeof(struct TELNET));
173 if(!tn)
174 return CURLE_OUT_OF_MEMORY;
176 conn->proto.telnet = (void *)tn; /* make us known */
178 memset(tn, 0, sizeof(struct TELNET));
180 tn->telrcv_state = TS_DATA;
182 /* Init suboptions */
183 SB_CLEAR(tn);
185 /* Set all options to NO */
186 #if 0
187 /* NO is zero => default fill pattern */
188 memset(tn->us, NO, 256);
189 memset(tn->usq, NO, 256);
190 memset(tn->us_preferred, NO, 256);
191 memset(tn->him, NO, 256);
192 memset(tn->himq, NO, 256);
193 memset(tn->him_preferred, NO, 256);
194 #endif
195 /* Set the options we want by default */
196 tn->us_preferred[TELOPT_BINARY] = YES;
197 tn->us_preferred[TELOPT_SGA] = YES;
198 tn->him_preferred[TELOPT_BINARY] = YES;
199 tn->him_preferred[TELOPT_SGA] = YES;
201 return CURLE_OK;
204 static void negotiate(struct connectdata *conn)
206 int i;
207 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
209 for(i = 0;i < NTELOPTS;i++)
211 if(tn->us_preferred[i] == YES)
212 set_local_option(conn, i, YES);
214 if(tn->him_preferred[i] == YES)
215 set_remote_option(conn, i, YES);
219 static void printoption(struct SessionHandle *data,
220 const char *direction, int cmd, int option)
222 const char *fmt;
223 const char *opt;
225 if (data->set.verbose)
227 if (cmd == IAC)
229 if (TELCMD_OK(option))
230 Curl_infof(data, "%s IAC %s\n", direction, TELCMD(option));
231 else
232 Curl_infof(data, "%s IAC %d\n", direction, option);
234 else
236 fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
237 (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
238 if (fmt)
240 if (TELOPT_OK(option))
241 opt = TELOPT(option);
242 else if (option == TELOPT_EXOPL)
243 opt = "EXOPL";
244 else
245 opt = NULL;
247 if(opt)
248 Curl_infof(data, "%s %s %s\n", direction, fmt, opt);
249 else
250 Curl_infof(data, "%s %s %d\n", direction, fmt, option);
252 else
253 Curl_infof(data, "%s %d %d\n", direction, cmd, option);
258 static void send_negotiation(struct connectdata *conn, int cmd, int option)
260 unsigned char buf[3];
262 buf[0] = IAC;
263 buf[1] = cmd;
264 buf[2] = option;
266 swrite(conn->firstsocket, buf, 3);
268 printoption(conn->data, "SENT", cmd, option);
271 static
272 void set_remote_option(struct connectdata *conn, int option, int newstate)
274 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
275 if(newstate == YES)
277 switch(tn->him[option])
279 case NO:
280 tn->him[option] = WANTYES;
281 send_negotiation(conn, DO, option);
282 break;
284 case YES:
285 /* Already enabled */
286 break;
288 case WANTNO:
289 switch(tn->himq[option])
291 case EMPTY:
292 /* Already negotiating for YES, queue the request */
293 tn->himq[option] = OPPOSITE;
294 break;
295 case OPPOSITE:
296 /* Error: already queued an enable request */
297 break;
299 break;
301 case WANTYES:
302 switch(tn->himq[option])
304 case EMPTY:
305 /* Error: already negotiating for enable */
306 break;
307 case OPPOSITE:
308 tn->himq[option] = EMPTY;
309 break;
311 break;
314 else /* NO */
316 switch(tn->him[option])
318 case NO:
319 /* Already disabled */
320 break;
322 case YES:
323 tn->him[option] = WANTNO;
324 send_negotiation(conn, DONT, option);
325 break;
327 case WANTNO:
328 switch(tn->himq[option])
330 case EMPTY:
331 /* Already negotiating for NO */
332 break;
333 case OPPOSITE:
334 tn->himq[option] = EMPTY;
335 break;
337 break;
339 case WANTYES:
340 switch(tn->himq[option])
342 case EMPTY:
343 tn->himq[option] = OPPOSITE;
344 break;
345 case OPPOSITE:
346 break;
348 break;
353 static
354 void rec_will(struct connectdata *conn, int option)
356 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
357 switch(tn->him[option])
359 case NO:
360 if(tn->him_preferred[option] == YES)
362 tn->him[option] = YES;
363 send_negotiation(conn, DO, option);
365 else
367 send_negotiation(conn, DONT, option);
369 break;
371 case YES:
372 /* Already enabled */
373 break;
375 case WANTNO:
376 switch(tn->himq[option])
378 case EMPTY:
379 /* Error: DONT answered by WILL */
380 tn->him[option] = NO;
381 break;
382 case OPPOSITE:
383 /* Error: DONT answered by WILL */
384 tn->him[option] = YES;
385 tn->himq[option] = EMPTY;
386 break;
388 break;
390 case WANTYES:
391 switch(tn->himq[option])
393 case EMPTY:
394 tn->him[option] = YES;
395 break;
396 case OPPOSITE:
397 tn->him[option] = WANTNO;
398 tn->himq[option] = EMPTY;
399 send_negotiation(conn, DONT, option);
400 break;
402 break;
406 static
407 void rec_wont(struct connectdata *conn, int option)
409 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
410 switch(tn->him[option])
412 case NO:
413 /* Already disabled */
414 break;
416 case YES:
417 tn->him[option] = NO;
418 send_negotiation(conn, DONT, option);
419 break;
421 case WANTNO:
422 switch(tn->himq[option])
424 case EMPTY:
425 tn->him[option] = NO;
426 break;
428 case OPPOSITE:
429 tn->him[option] = WANTYES;
430 tn->himq[option] = EMPTY;
431 send_negotiation(conn, DO, option);
432 break;
434 break;
436 case WANTYES:
437 switch(tn->himq[option])
439 case EMPTY:
440 tn->him[option] = NO;
441 break;
442 case OPPOSITE:
443 tn->him[option] = NO;
444 tn->himq[option] = EMPTY;
445 break;
447 break;
451 void set_local_option(struct connectdata *conn, int option, int newstate)
453 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
454 if(newstate == YES)
456 switch(tn->us[option])
458 case NO:
459 tn->us[option] = WANTYES;
460 send_negotiation(conn, WILL, option);
461 break;
463 case YES:
464 /* Already enabled */
465 break;
467 case WANTNO:
468 switch(tn->usq[option])
470 case EMPTY:
471 /* Already negotiating for YES, queue the request */
472 tn->usq[option] = OPPOSITE;
473 break;
474 case OPPOSITE:
475 /* Error: already queued an enable request */
476 break;
478 break;
480 case WANTYES:
481 switch(tn->usq[option])
483 case EMPTY:
484 /* Error: already negotiating for enable */
485 break;
486 case OPPOSITE:
487 tn->usq[option] = EMPTY;
488 break;
490 break;
493 else /* NO */
495 switch(tn->us[option])
497 case NO:
498 /* Already disabled */
499 break;
501 case YES:
502 tn->us[option] = WANTNO;
503 send_negotiation(conn, WONT, option);
504 break;
506 case WANTNO:
507 switch(tn->usq[option])
509 case EMPTY:
510 /* Already negotiating for NO */
511 break;
512 case OPPOSITE:
513 tn->usq[option] = EMPTY;
514 break;
516 break;
518 case WANTYES:
519 switch(tn->usq[option])
521 case EMPTY:
522 tn->usq[option] = OPPOSITE;
523 break;
524 case OPPOSITE:
525 break;
527 break;
532 static
533 void rec_do(struct connectdata *conn, int option)
535 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
536 switch(tn->us[option])
538 case NO:
539 if(tn->us_preferred[option] == YES)
541 tn->us[option] = YES;
542 send_negotiation(conn, WILL, option);
544 else
546 send_negotiation(conn, WONT, option);
548 break;
550 case YES:
551 /* Already enabled */
552 break;
554 case WANTNO:
555 switch(tn->usq[option])
557 case EMPTY:
558 /* Error: DONT answered by WILL */
559 tn->us[option] = NO;
560 break;
561 case OPPOSITE:
562 /* Error: DONT answered by WILL */
563 tn->us[option] = YES;
564 tn->usq[option] = EMPTY;
565 break;
567 break;
569 case WANTYES:
570 switch(tn->usq[option])
572 case EMPTY:
573 tn->us[option] = YES;
574 break;
575 case OPPOSITE:
576 tn->us[option] = WANTNO;
577 tn->himq[option] = EMPTY;
578 send_negotiation(conn, WONT, option);
579 break;
581 break;
585 static
586 void rec_dont(struct connectdata *conn, int option)
588 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
589 switch(tn->us[option])
591 case NO:
592 /* Already disabled */
593 break;
595 case YES:
596 tn->us[option] = NO;
597 send_negotiation(conn, WONT, option);
598 break;
600 case WANTNO:
601 switch(tn->usq[option])
603 case EMPTY:
604 tn->us[option] = NO;
605 break;
607 case OPPOSITE:
608 tn->us[option] = WANTYES;
609 tn->usq[option] = EMPTY;
610 send_negotiation(conn, WILL, option);
611 break;
613 break;
615 case WANTYES:
616 switch(tn->usq[option])
618 case EMPTY:
619 tn->us[option] = NO;
620 break;
621 case OPPOSITE:
622 tn->us[option] = NO;
623 tn->usq[option] = EMPTY;
624 break;
626 break;
631 static void printsub(struct SessionHandle *data,
632 int direction, /* '<' or '>' */
633 unsigned char *pointer, /* where suboption data is */
634 int length) /* length of suboption data */
636 int i = 0;
638 if (data->set.verbose)
640 if (direction)
642 Curl_infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
643 if (length >= 3)
645 int j;
647 i = pointer[length-2];
648 j = pointer[length-1];
650 if (i != IAC || j != SE)
652 Curl_infof(data, "(terminated by ");
653 if (TELOPT_OK(i))
654 Curl_infof(data, "%s ", TELOPT(i));
655 else if (TELCMD_OK(i))
656 Curl_infof(data, "%s ", TELCMD(i));
657 else
658 Curl_infof(data, "%d ", i);
659 if (TELOPT_OK(j))
660 Curl_infof(data, "%s", TELOPT(j));
661 else if (TELCMD_OK(j))
662 Curl_infof(data, "%s", TELCMD(j));
663 else
664 Curl_infof(data, "%d", j);
665 Curl_infof(data, ", not IAC SE!) ");
668 length -= 2;
670 if (length < 1)
672 Curl_infof(data, "(Empty suboption?)");
673 return;
676 if (TELOPT_OK(pointer[0])) {
677 switch(pointer[0]) {
678 case TELOPT_TTYPE:
679 case TELOPT_XDISPLOC:
680 case TELOPT_NEW_ENVIRON:
681 Curl_infof(data, "%s", TELOPT(pointer[0]));
682 break;
683 default:
684 Curl_infof(data, "%s (unsupported)", TELOPT(pointer[0]));
685 break;
688 else
689 Curl_infof(data, "%d (unknown)", pointer[i]);
691 switch(pointer[1]) {
692 case TELQUAL_IS:
693 Curl_infof(data, " IS");
694 break;
695 case TELQUAL_SEND:
696 Curl_infof(data, " SEND");
697 break;
698 case TELQUAL_INFO:
699 Curl_infof(data, " INFO/REPLY");
700 break;
701 case TELQUAL_NAME:
702 Curl_infof(data, " NAME");
703 break;
706 switch(pointer[0]) {
707 case TELOPT_TTYPE:
708 case TELOPT_XDISPLOC:
709 pointer[length] = 0;
710 Curl_infof(data, " \"%s\"", &pointer[2]);
711 break;
712 case TELOPT_NEW_ENVIRON:
713 if(pointer[1] == TELQUAL_IS) {
714 Curl_infof(data, " ");
715 for(i = 3;i < length;i++) {
716 switch(pointer[i]) {
717 case NEW_ENV_VAR:
718 Curl_infof(data, ", ");
719 break;
720 case NEW_ENV_VALUE:
721 Curl_infof(data, " = ");
722 break;
723 default:
724 Curl_infof(data, "%c", pointer[i]);
725 break;
729 break;
730 default:
731 for (i = 2; i < length; i++)
732 Curl_infof(data, " %.2x", pointer[i]);
733 break;
736 if (direction)
738 Curl_infof(data, "\n");
743 static int check_telnet_options(struct connectdata *conn)
745 struct curl_slist *head;
746 char option_keyword[128];
747 char option_arg[256];
748 char *buf;
749 struct SessionHandle *data = conn->data;
750 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
752 /* Add the user name as an environment variable if it
753 was given on the command line */
754 if(conn->bits.user_passwd)
756 char *buf = malloc(256);
757 sprintf(buf, "USER,%s", data->state.user);
758 tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
760 tn->us_preferred[TELOPT_NEW_ENVIRON] = YES;
763 for(head = data->set.telnet_options; head; head=head->next) {
764 if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
765 option_keyword, option_arg) == 2) {
767 /* Terminal type */
768 if(strequal(option_keyword, "TTYPE")) {
769 strncpy(tn->subopt_ttype, option_arg, 31);
770 tn->subopt_ttype[31] = 0; /* String termination */
771 tn->us_preferred[TELOPT_TTYPE] = YES;
772 continue;
775 /* Display variable */
776 if(strequal(option_keyword, "XDISPLOC")) {
777 strncpy(tn->subopt_xdisploc, option_arg, 127);
778 tn->subopt_xdisploc[127] = 0; /* String termination */
779 tn->us_preferred[TELOPT_XDISPLOC] = YES;
780 continue;
783 /* Environment variable */
784 if(strequal(option_keyword, "NEW_ENV")) {
785 buf = strdup(option_arg);
786 if(!buf)
787 return CURLE_OUT_OF_MEMORY;
788 tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
789 tn->us_preferred[TELOPT_NEW_ENVIRON] = YES;
790 continue;
793 failf(data, "Unknown telnet option %s", head->data);
794 return CURLE_UNKNOWN_TELNET_OPTION;
795 } else {
796 failf(data, "Syntax error in telnet option: %s", head->data);
797 return CURLE_TELNET_OPTION_SYNTAX;
801 return CURLE_OK;
805 * suboption()
807 * Look at the sub-option buffer, and try to be helpful to the other
808 * side.
811 static void suboption(struct connectdata *conn)
813 struct curl_slist *v;
814 unsigned char subchar;
815 unsigned char temp[2048];
816 int len;
817 int tmplen;
818 char varname[128];
819 char varval[128];
820 struct SessionHandle *data = conn->data;
821 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
823 printsub(data, '<', (unsigned char *)tn->subbuffer, SB_LEN(tn)+2);
824 switch (subchar = SB_GET(tn)) {
825 case TELOPT_TTYPE:
826 len = strlen(tn->subopt_ttype) + 4 + 2;
827 snprintf((char *)temp, sizeof(temp),
828 "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
829 TELQUAL_IS, tn->subopt_ttype, IAC, SE);
830 swrite(conn->firstsocket, temp, len);
831 printsub(data, '>', &temp[2], len-2);
832 break;
833 case TELOPT_XDISPLOC:
834 len = strlen(tn->subopt_xdisploc) + 4 + 2;
835 snprintf((char *)temp, sizeof(temp),
836 "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
837 TELQUAL_IS, tn->subopt_xdisploc, IAC, SE);
838 swrite(conn->firstsocket, temp, len);
839 printsub(data, '>', &temp[2], len-2);
840 break;
841 case TELOPT_NEW_ENVIRON:
842 snprintf((char *)temp, sizeof(temp),
843 "%c%c%c%c", IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_IS);
844 len = 4;
846 for(v = tn->telnet_vars;v;v = v->next) {
847 tmplen = (strlen(v->data) + 1);
848 /* Add the variable only if it fits */
849 if(len + tmplen < (int)sizeof(temp)-6) {
850 sscanf(v->data, "%127[^,],%s", varname, varval);
851 snprintf((char *)&temp[len], sizeof(temp) - len,
852 "%c%s%c%s", NEW_ENV_VAR, varname,
853 NEW_ENV_VALUE, varval);
854 len += tmplen;
857 snprintf((char *)&temp[len], sizeof(temp) - len,
858 "%c%c", IAC, SE);
859 len += 2;
860 swrite(conn->firstsocket, temp, len);
861 printsub(data, '>', &temp[2], len-2);
862 break;
864 return;
867 static
868 void telrcv(struct connectdata *conn,
869 unsigned char *inbuf, /* Data received from socket */
870 int count) /* Number of bytes received */
872 unsigned char c;
873 int index = 0;
874 struct SessionHandle *data = conn->data;
875 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
877 while(count--)
879 c = inbuf[index++];
881 switch (tn->telrcv_state)
883 case TS_CR:
884 tn->telrcv_state = TS_DATA;
885 if (c == '\0')
887 break; /* Ignore \0 after CR */
890 Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
891 continue;
893 case TS_DATA:
894 if (c == IAC)
896 tn->telrcv_state = TS_IAC;
897 break;
899 else if(c == '\r')
901 tn->telrcv_state = TS_CR;
904 Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
905 continue;
907 case TS_IAC:
908 process_iac:
909 switch (c)
911 case WILL:
912 tn->telrcv_state = TS_WILL;
913 continue;
914 case WONT:
915 tn->telrcv_state = TS_WONT;
916 continue;
917 case DO:
918 tn->telrcv_state = TS_DO;
919 continue;
920 case DONT:
921 tn->telrcv_state = TS_DONT;
922 continue;
923 case SB:
924 SB_CLEAR(tn);
925 tn->telrcv_state = TS_SB;
926 continue;
927 case IAC:
928 Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
929 break;
930 case DM:
931 case NOP:
932 case GA:
933 default:
934 printoption(data, "RCVD", IAC, c);
935 break;
937 tn->telrcv_state = TS_DATA;
938 continue;
940 case TS_WILL:
941 printoption(data, "RCVD", WILL, c);
942 tn->please_negotiate = 1;
943 rec_will(conn, c);
944 tn->telrcv_state = TS_DATA;
945 continue;
947 case TS_WONT:
948 printoption(data, "RCVD", WONT, c);
949 tn->please_negotiate = 1;
950 rec_wont(conn, c);
951 tn->telrcv_state = TS_DATA;
952 continue;
954 case TS_DO:
955 printoption(data, "RCVD", DO, c);
956 tn->please_negotiate = 1;
957 rec_do(conn, c);
958 tn->telrcv_state = TS_DATA;
959 continue;
961 case TS_DONT:
962 printoption(data, "RCVD", DONT, c);
963 tn->please_negotiate = 1;
964 rec_dont(conn, c);
965 tn->telrcv_state = TS_DATA;
966 continue;
968 case TS_SB:
969 if (c == IAC)
971 tn->telrcv_state = TS_SE;
973 else
975 SB_ACCUM(tn,c);
977 continue;
979 case TS_SE:
980 if (c != SE)
982 if (c != IAC)
985 * This is an error. We only expect to get
986 * "IAC IAC" or "IAC SE". Several things may
987 * have happend. An IAC was not doubled, the
988 * IAC SE was left off, or another option got
989 * inserted into the suboption are all possibilities.
990 * If we assume that the IAC was not doubled,
991 * and really the IAC SE was left off, we could
992 * get into an infinate loop here. So, instead,
993 * we terminate the suboption, and process the
994 * partial suboption if we can.
996 SB_ACCUM(tn, (unsigned char)IAC);
997 SB_ACCUM(tn, c);
998 tn->subpointer -= 2;
999 SB_TERM(tn);
1001 printoption(data, "In SUBOPTION processing, RCVD", IAC, c);
1002 suboption(conn); /* handle sub-option */
1003 tn->telrcv_state = TS_IAC;
1004 goto process_iac;
1006 SB_ACCUM(tn,c);
1007 tn->telrcv_state = TS_SB;
1009 else
1011 SB_ACCUM(tn, (unsigned char)IAC);
1012 SB_ACCUM(tn, (unsigned char)SE);
1013 tn->subpointer -= 2;
1014 SB_TERM(tn);
1015 suboption(conn); /* handle sub-option */
1016 tn->telrcv_state = TS_DATA;
1018 break;
1023 CURLcode Curl_telnet_done(struct connectdata *conn)
1025 struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
1026 curl_slist_free_all(tn->telnet_vars);
1028 free(conn->proto.telnet);
1029 conn->proto.telnet = NULL;
1031 return CURLE_OK;
1034 CURLcode Curl_telnet(struct connectdata *conn)
1036 CURLcode code;
1037 struct SessionHandle *data = conn->data;
1038 int sockfd = conn->firstsocket;
1039 #ifdef WIN32
1040 WSAEVENT event_handle;
1041 WSANETWORKEVENTS events;
1042 HANDLE stdin_handle;
1043 HANDLE objs[2];
1044 DWORD waitret;
1045 #else
1046 fd_set readfd;
1047 fd_set keepfd;
1048 #endif
1049 bool keepon = TRUE;
1050 char *buf = data->state.buffer;
1051 ssize_t nread;
1052 struct TELNET *tn;
1053 struct timeval now; /* current time */
1055 code = init_telnet(conn);
1056 if(code)
1057 return code;
1059 tn = (struct TELNET *)conn->proto.telnet;
1061 code = check_telnet_options(conn);
1062 if(code)
1063 return code;
1065 #ifdef WIN32
1066 /* We want to wait for both stdin and the socket. Since
1067 ** the select() function in winsock only works on sockets
1068 ** we have to use the WaitForMultipleObjects() call.
1071 /* First, create a sockets event object */
1072 event_handle = WSACreateEvent();
1074 /* The get the Windows file handle for stdin */
1075 stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1077 /* Create the list of objects to wait for */
1078 objs[0] = stdin_handle;
1079 objs[1] = event_handle;
1081 /* Tell winsock what events we want to listen to */
1082 if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
1083 return 0;
1086 /* Keep on listening and act on events */
1087 while(keepon) {
1088 waitret = WaitForMultipleObjects(2, objs, FALSE, INFINITE);
1089 switch(waitret - WAIT_OBJECT_0)
1091 case 0:
1093 unsigned char outbuf[2];
1094 int out_count = 0;
1095 ssize_t bytes_written;
1096 char *buffer = buf;
1098 if(!ReadFile(stdin_handle, buf, 255, &nread, NULL)) {
1099 keepon = FALSE;
1100 break;
1103 while(nread--) {
1104 outbuf[0] = *buffer++;
1105 out_count = 1;
1106 if(outbuf[0] == IAC)
1107 outbuf[out_count++] = IAC;
1109 Curl_write(conn, conn->firstsocket, outbuf,
1110 out_count, &bytes_written);
1113 break;
1115 case 1:
1116 if(WSAEnumNetworkEvents(sockfd, event_handle, &events)
1117 != SOCKET_ERROR)
1119 if(events.lNetworkEvents & FD_READ)
1121 /* This reallu OUGHT to check its return code. */
1122 Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1124 telrcv(conn, (unsigned char *)buf, nread);
1126 fflush(stdout);
1128 /* Negotiate if the peer has started negotiating,
1129 otherwise don't. We don't want to speak telnet with
1130 non-telnet servers, like POP or SMTP. */
1131 if(tn->please_negotiate && !tn->already_negotiated) {
1132 negotiate(conn);
1133 tn->already_negotiated = 1;
1137 if(events.lNetworkEvents & FD_CLOSE)
1139 keepon = FALSE;
1142 break;
1145 #else
1146 FD_ZERO (&readfd); /* clear it */
1147 FD_SET (sockfd, &readfd);
1148 FD_SET (0, &readfd);
1150 keepfd = readfd;
1152 while (keepon) {
1153 struct timeval interval;
1155 readfd = keepfd; /* set this every lap in the loop */
1156 interval.tv_sec = 1;
1157 interval.tv_usec = 0;
1159 switch (select (sockfd + 1, &readfd, NULL, NULL, &interval)) {
1160 case -1: /* error, stop reading */
1161 keepon = FALSE;
1162 continue;
1163 case 0: /* timeout */
1164 break;
1165 default: /* read! */
1166 if(FD_ISSET(0, &readfd)) { /* read from stdin */
1167 unsigned char outbuf[2];
1168 int out_count = 0;
1169 ssize_t bytes_written;
1170 char *buffer = buf;
1172 nread = read(0, buf, 255);
1174 while(nread--) {
1175 outbuf[0] = *buffer++;
1176 out_count = 1;
1177 if(outbuf[0] == IAC)
1178 outbuf[out_count++] = IAC;
1180 Curl_write(conn, conn->firstsocket, outbuf,
1181 out_count, &bytes_written);
1185 if(FD_ISSET(sockfd, &readfd)) {
1186 /* This OUGHT to check the return code... */
1187 Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
1189 /* if we receive 0 or less here, the server closed the connection and
1190 we bail out from this! */
1191 if (nread <= 0) {
1192 keepon = FALSE;
1193 break;
1196 telrcv(conn, (unsigned char *)buf, nread);
1198 /* Negotiate if the peer has started negotiating,
1199 otherwise don't. We don't want to speak telnet with
1200 non-telnet servers, like POP or SMTP. */
1201 if(tn->please_negotiate && !tn->already_negotiated) {
1202 negotiate(conn);
1203 tn->already_negotiated = 1;
1207 if(data->set.timeout) {
1208 now = Curl_tvnow();
1209 if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) {
1210 failf(data, "Time-out");
1211 code = CURLE_OPERATION_TIMEOUTED;
1212 keepon = FALSE;
1216 #endif
1217 /* mark this as "no further transfer wanted" */
1218 Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1220 return code;
1224 * local variables:
1225 * eval: (load-file "../curl-mode.el")
1226 * end:
1227 * vim600: fdm=marker
1228 * vim: et sw=2 ts=2 sts=2 tw=78
1230 #endif