1 /***************************************************************************
3 * Project ___| | | | _ \| |
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 ***************************************************************************/
26 #ifndef CURL_DISABLE_TELNET
27 /* -- WIN32 approved -- */
33 #include <sys/types.h>
38 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
43 #ifdef HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
46 #include <netinet/in.h>
48 #include <sys/resource.h>
53 #ifdef HAVE_ARPA_INET_H
54 #include <arpa/inet.h>
59 #include <sys/ioctl.h>
62 #ifdef HAVE_SYS_PARAM_H
63 #include <sys/param.h>
66 #ifdef HAVE_SYS_SELECT_H
67 #include <sys/select.h>
74 #include <curl/curl.h>
78 #define _MPRINTF_REPLACE /* use our functions only */
79 #include <curl/mprintf.h>
84 #include "arpa_telnet.h"
86 /* The last #include file should be: */
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)
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 */
132 * Telnet receiver states for fsm
143 TS_SB
, /* sub-option collection */
144 TS_SE
/* looking for sub-option end */
148 int please_negotiate
;
149 int already_negotiated
;
152 int us_preferred
[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 */
161 char subbuffer
[SUBBUFSIZE
];
162 char *subpointer
, *subend
; /* buffer for sub-options */
164 TelnetReceive telrcv_state
;
168 CURLcode
init_telnet(struct connectdata
*conn
)
172 tn
= (struct TELNET
*)malloc(sizeof(struct TELNET
));
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 */
185 /* Set all options to NO */
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);
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
;
204 static void negotiate(struct connectdata
*conn
)
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
)
225 if (data
->set
.verbose
)
229 if (TELCMD_OK(option
))
230 Curl_infof(data
, "%s IAC %s\n", direction
, TELCMD(option
));
232 Curl_infof(data
, "%s IAC %d\n", direction
, option
);
236 fmt
= (cmd
== WILL
) ? "WILL" : (cmd
== WONT
) ? "WONT" :
237 (cmd
== DO
) ? "DO" : (cmd
== DONT
) ? "DONT" : 0;
240 if (TELOPT_OK(option
))
241 opt
= TELOPT(option
);
242 else if (option
== TELOPT_EXOPL
)
248 Curl_infof(data
, "%s %s %s\n", direction
, fmt
, opt
);
250 Curl_infof(data
, "%s %s %d\n", direction
, fmt
, option
);
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];
266 swrite(conn
->firstsocket
, buf
, 3);
268 printoption(conn
->data
, "SENT", cmd
, option
);
272 void set_remote_option(struct connectdata
*conn
, int option
, int newstate
)
274 struct TELNET
*tn
= (struct TELNET
*)conn
->proto
.telnet
;
277 switch(tn
->him
[option
])
280 tn
->him
[option
] = WANTYES
;
281 send_negotiation(conn
, DO
, option
);
285 /* Already enabled */
289 switch(tn
->himq
[option
])
292 /* Already negotiating for YES, queue the request */
293 tn
->himq
[option
] = OPPOSITE
;
296 /* Error: already queued an enable request */
302 switch(tn
->himq
[option
])
305 /* Error: already negotiating for enable */
308 tn
->himq
[option
] = EMPTY
;
316 switch(tn
->him
[option
])
319 /* Already disabled */
323 tn
->him
[option
] = WANTNO
;
324 send_negotiation(conn
, DONT
, option
);
328 switch(tn
->himq
[option
])
331 /* Already negotiating for NO */
334 tn
->himq
[option
] = EMPTY
;
340 switch(tn
->himq
[option
])
343 tn
->himq
[option
] = OPPOSITE
;
354 void rec_will(struct connectdata
*conn
, int option
)
356 struct TELNET
*tn
= (struct TELNET
*)conn
->proto
.telnet
;
357 switch(tn
->him
[option
])
360 if(tn
->him_preferred
[option
] == YES
)
362 tn
->him
[option
] = YES
;
363 send_negotiation(conn
, DO
, option
);
367 send_negotiation(conn
, DONT
, option
);
372 /* Already enabled */
376 switch(tn
->himq
[option
])
379 /* Error: DONT answered by WILL */
380 tn
->him
[option
] = NO
;
383 /* Error: DONT answered by WILL */
384 tn
->him
[option
] = YES
;
385 tn
->himq
[option
] = EMPTY
;
391 switch(tn
->himq
[option
])
394 tn
->him
[option
] = YES
;
397 tn
->him
[option
] = WANTNO
;
398 tn
->himq
[option
] = EMPTY
;
399 send_negotiation(conn
, DONT
, option
);
407 void rec_wont(struct connectdata
*conn
, int option
)
409 struct TELNET
*tn
= (struct TELNET
*)conn
->proto
.telnet
;
410 switch(tn
->him
[option
])
413 /* Already disabled */
417 tn
->him
[option
] = NO
;
418 send_negotiation(conn
, DONT
, option
);
422 switch(tn
->himq
[option
])
425 tn
->him
[option
] = NO
;
429 tn
->him
[option
] = WANTYES
;
430 tn
->himq
[option
] = EMPTY
;
431 send_negotiation(conn
, DO
, option
);
437 switch(tn
->himq
[option
])
440 tn
->him
[option
] = NO
;
443 tn
->him
[option
] = NO
;
444 tn
->himq
[option
] = EMPTY
;
451 void set_local_option(struct connectdata
*conn
, int option
, int newstate
)
453 struct TELNET
*tn
= (struct TELNET
*)conn
->proto
.telnet
;
456 switch(tn
->us
[option
])
459 tn
->us
[option
] = WANTYES
;
460 send_negotiation(conn
, WILL
, option
);
464 /* Already enabled */
468 switch(tn
->usq
[option
])
471 /* Already negotiating for YES, queue the request */
472 tn
->usq
[option
] = OPPOSITE
;
475 /* Error: already queued an enable request */
481 switch(tn
->usq
[option
])
484 /* Error: already negotiating for enable */
487 tn
->usq
[option
] = EMPTY
;
495 switch(tn
->us
[option
])
498 /* Already disabled */
502 tn
->us
[option
] = WANTNO
;
503 send_negotiation(conn
, WONT
, option
);
507 switch(tn
->usq
[option
])
510 /* Already negotiating for NO */
513 tn
->usq
[option
] = EMPTY
;
519 switch(tn
->usq
[option
])
522 tn
->usq
[option
] = OPPOSITE
;
533 void rec_do(struct connectdata
*conn
, int option
)
535 struct TELNET
*tn
= (struct TELNET
*)conn
->proto
.telnet
;
536 switch(tn
->us
[option
])
539 if(tn
->us_preferred
[option
] == YES
)
541 tn
->us
[option
] = YES
;
542 send_negotiation(conn
, WILL
, option
);
546 send_negotiation(conn
, WONT
, option
);
551 /* Already enabled */
555 switch(tn
->usq
[option
])
558 /* Error: DONT answered by WILL */
562 /* Error: DONT answered by WILL */
563 tn
->us
[option
] = YES
;
564 tn
->usq
[option
] = EMPTY
;
570 switch(tn
->usq
[option
])
573 tn
->us
[option
] = YES
;
576 tn
->us
[option
] = WANTNO
;
577 tn
->himq
[option
] = EMPTY
;
578 send_negotiation(conn
, WONT
, option
);
586 void rec_dont(struct connectdata
*conn
, int option
)
588 struct TELNET
*tn
= (struct TELNET
*)conn
->proto
.telnet
;
589 switch(tn
->us
[option
])
592 /* Already disabled */
597 send_negotiation(conn
, WONT
, option
);
601 switch(tn
->usq
[option
])
608 tn
->us
[option
] = WANTYES
;
609 tn
->usq
[option
] = EMPTY
;
610 send_negotiation(conn
, WILL
, option
);
616 switch(tn
->usq
[option
])
623 tn
->usq
[option
] = EMPTY
;
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 */
638 if (data
->set
.verbose
)
642 Curl_infof(data
, "%s IAC SB ", (direction
== '<')? "RCVD":"SENT");
647 i
= pointer
[length
-2];
648 j
= pointer
[length
-1];
650 if (i
!= IAC
|| j
!= SE
)
652 Curl_infof(data
, "(terminated by ");
654 Curl_infof(data
, "%s ", TELOPT(i
));
655 else if (TELCMD_OK(i
))
656 Curl_infof(data
, "%s ", TELCMD(i
));
658 Curl_infof(data
, "%d ", i
);
660 Curl_infof(data
, "%s", TELOPT(j
));
661 else if (TELCMD_OK(j
))
662 Curl_infof(data
, "%s", TELCMD(j
));
664 Curl_infof(data
, "%d", j
);
665 Curl_infof(data
, ", not IAC SE!) ");
672 Curl_infof(data
, "(Empty suboption?)");
676 if (TELOPT_OK(pointer
[0])) {
679 case TELOPT_XDISPLOC
:
680 case TELOPT_NEW_ENVIRON
:
681 Curl_infof(data
, "%s", TELOPT(pointer
[0]));
684 Curl_infof(data
, "%s (unsupported)", TELOPT(pointer
[0]));
689 Curl_infof(data
, "%d (unknown)", pointer
[i
]);
693 Curl_infof(data
, " IS");
696 Curl_infof(data
, " SEND");
699 Curl_infof(data
, " INFO/REPLY");
702 Curl_infof(data
, " NAME");
708 case TELOPT_XDISPLOC
:
710 Curl_infof(data
, " \"%s\"", &pointer
[2]);
712 case TELOPT_NEW_ENVIRON
:
713 if(pointer
[1] == TELQUAL_IS
) {
714 Curl_infof(data
, " ");
715 for(i
= 3;i
< length
;i
++) {
718 Curl_infof(data
, ", ");
721 Curl_infof(data
, " = ");
724 Curl_infof(data
, "%c", pointer
[i
]);
731 for (i
= 2; i
< length
; i
++)
732 Curl_infof(data
, " %.2x", pointer
[i
]);
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];
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) {
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
;
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
;
783 /* Environment variable */
784 if(strequal(option_keyword
, "NEW_ENV")) {
785 buf
= strdup(option_arg
);
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
;
793 failf(data
, "Unknown telnet option %s", head
->data
);
794 return CURLE_UNKNOWN_TELNET_OPTION
;
796 failf(data
, "Syntax error in telnet option: %s", head
->data
);
797 return CURLE_TELNET_OPTION_SYNTAX
;
807 * Look at the sub-option buffer, and try to be helpful to the other
811 static void suboption(struct connectdata
*conn
)
813 struct curl_slist
*v
;
814 unsigned char subchar
;
815 unsigned char temp
[2048];
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
)) {
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);
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);
841 case TELOPT_NEW_ENVIRON
:
842 snprintf((char *)temp
, sizeof(temp
),
843 "%c%c%c%c", IAC
, SB
, TELOPT_NEW_ENVIRON
, TELQUAL_IS
);
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
);
857 snprintf((char *)&temp
[len
], sizeof(temp
) - len
,
860 swrite(conn
->firstsocket
, temp
, len
);
861 printsub(data
, '>', &temp
[2], len
-2);
868 void telrcv(struct connectdata
*conn
,
869 unsigned char *inbuf
, /* Data received from socket */
870 int count
) /* Number of bytes received */
874 struct SessionHandle
*data
= conn
->data
;
875 struct TELNET
*tn
= (struct TELNET
*)conn
->proto
.telnet
;
881 switch (tn
->telrcv_state
)
884 tn
->telrcv_state
= TS_DATA
;
887 break; /* Ignore \0 after CR */
890 Curl_client_write(data
, CLIENTWRITE_BODY
, (char *)&c
, 1);
896 tn
->telrcv_state
= TS_IAC
;
901 tn
->telrcv_state
= TS_CR
;
904 Curl_client_write(data
, CLIENTWRITE_BODY
, (char *)&c
, 1);
912 tn
->telrcv_state
= TS_WILL
;
915 tn
->telrcv_state
= TS_WONT
;
918 tn
->telrcv_state
= TS_DO
;
921 tn
->telrcv_state
= TS_DONT
;
925 tn
->telrcv_state
= TS_SB
;
928 Curl_client_write(data
, CLIENTWRITE_BODY
, (char *)&c
, 1);
934 printoption(data
, "RCVD", IAC
, c
);
937 tn
->telrcv_state
= TS_DATA
;
941 printoption(data
, "RCVD", WILL
, c
);
942 tn
->please_negotiate
= 1;
944 tn
->telrcv_state
= TS_DATA
;
948 printoption(data
, "RCVD", WONT
, c
);
949 tn
->please_negotiate
= 1;
951 tn
->telrcv_state
= TS_DATA
;
955 printoption(data
, "RCVD", DO
, c
);
956 tn
->please_negotiate
= 1;
958 tn
->telrcv_state
= TS_DATA
;
962 printoption(data
, "RCVD", DONT
, c
);
963 tn
->please_negotiate
= 1;
965 tn
->telrcv_state
= TS_DATA
;
971 tn
->telrcv_state
= TS_SE
;
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
);
1001 printoption(data
, "In SUBOPTION processing, RCVD", IAC
, c
);
1002 suboption(conn
); /* handle sub-option */
1003 tn
->telrcv_state
= TS_IAC
;
1007 tn
->telrcv_state
= TS_SB
;
1011 SB_ACCUM(tn
, (unsigned char)IAC
);
1012 SB_ACCUM(tn
, (unsigned char)SE
);
1013 tn
->subpointer
-= 2;
1015 suboption(conn
); /* handle sub-option */
1016 tn
->telrcv_state
= TS_DATA
;
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
;
1034 CURLcode
Curl_telnet(struct connectdata
*conn
)
1037 struct SessionHandle
*data
= conn
->data
;
1038 int sockfd
= conn
->firstsocket
;
1040 WSAEVENT event_handle
;
1041 WSANETWORKEVENTS events
;
1042 HANDLE stdin_handle
;
1050 char *buf
= data
->state
.buffer
;
1053 struct timeval now
; /* current time */
1055 code
= init_telnet(conn
);
1059 tn
= (struct TELNET
*)conn
->proto
.telnet
;
1061 code
= check_telnet_options(conn
);
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
) {
1086 /* Keep on listening and act on events */
1088 waitret
= WaitForMultipleObjects(2, objs
, FALSE
, INFINITE
);
1089 switch(waitret
- WAIT_OBJECT_0
)
1093 unsigned char outbuf
[2];
1095 ssize_t bytes_written
;
1098 if(!ReadFile(stdin_handle
, buf
, 255, &nread
, NULL
)) {
1104 outbuf
[0] = *buffer
++;
1106 if(outbuf
[0] == IAC
)
1107 outbuf
[out_count
++] = IAC
;
1109 Curl_write(conn
, conn
->firstsocket
, outbuf
,
1110 out_count
, &bytes_written
);
1116 if(WSAEnumNetworkEvents(sockfd
, event_handle
, &events
)
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
);
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
) {
1133 tn
->already_negotiated
= 1;
1137 if(events
.lNetworkEvents
& FD_CLOSE
)
1146 FD_ZERO (&readfd
); /* clear it */
1147 FD_SET (sockfd
, &readfd
);
1148 FD_SET (0, &readfd
);
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 */
1163 case 0: /* timeout */
1165 default: /* read! */
1166 if(FD_ISSET(0, &readfd
)) { /* read from stdin */
1167 unsigned char outbuf
[2];
1169 ssize_t bytes_written
;
1172 nread
= read(0, buf
, 255);
1175 outbuf
[0] = *buffer
++;
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! */
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
) {
1203 tn
->already_negotiated
= 1;
1207 if(data
->set
.timeout
) {
1209 if(Curl_tvdiff(now
, conn
->created
)/1000 >= data
->set
.timeout
) {
1210 failf(data
, "Time-out");
1211 code
= CURLE_OPERATION_TIMEOUTED
;
1217 /* mark this as "no further transfer wanted" */
1218 Curl_Transfer(conn
, -1, -1, FALSE
, NULL
, -1, NULL
);
1225 * eval: (load-file "../curl-mode.el")
1227 * vim600: fdm=marker
1228 * vim: et sw=2 ts=2 sts=2 tw=78