1 /* TN5250 - An implementation of the 5250 telnet protocol.
2 * Copyright (C) 1997-2008 Michael Madore
3 *
4 * This file is part of TN5250.
5 *
6 * TN5250 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1, or (at your option)
9 * any later version.
10 *
11 * TN5250 is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this software; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307 USA
20 *
21 */
22 #include "tn5250-private.h"
23
24 static int telnet_stream_get_next(Tn5250Stream * This, unsigned char *buf, int size);
25 static void telnet_stream_do_verb(Tn5250Stream * This, unsigned char verb, unsigned char what);
26 static int telnet_stream_host_verb(Tn5250Stream * This, unsigned char verb,
27 unsigned char what);
28 static void telnet_stream_sb_var_value(Tn5250Buffer * buf, unsigned char *var, unsigned char *value);
29 static void telnet_stream_sb(Tn5250Stream * This, unsigned char *sb_buf, int sb_len);
30 static void telnet_stream_escape(Tn5250Buffer * buffer);
31 static void telnet_stream_write(Tn5250Stream * This, unsigned char *data, int size);
32 static int telnet_stream_get_byte(Tn5250Stream * This);
33
34 static int telnet_stream_connect(Tn5250Stream * This, const char *to);
35 static int telnet_stream_accept(Tn5250Stream * This, SOCKET_TYPE masterSock);
36 static void telnet_stream_destroy(Tn5250Stream *This);
37 static void telnet_stream_disconnect(Tn5250Stream * This);
38 static int telnet_stream_handle_receive(Tn5250Stream * This);
39 static void telnet_stream_send_packet(Tn5250Stream * This, int length,
40 StreamHeader header,
41 unsigned char *data);
42 static void tn3270_stream_send_packet(Tn5250Stream * This, int length,
43 StreamHeader header,
44 unsigned char * data);
45
46 #define SEND 1
47 #define IS 0
48 #define INFO 2
49 #define VALUE 1
50 #define VAR 0
51 #define VALUE 1
52 #define USERVAR 3
53
54 #define TERMINAL 1
55 #define BINARY 2
56 #define RECORD 4
57 #define DONE 7
58 #define HOST 8
59
60 #define TRANSMIT_BINARY 0
61 #define END_OF_RECORD 25
62 #define TERMINAL_TYPE 24
63 #define TIMING_MARK 6
64 #define NEW_ENVIRON 39
65
66 #define TN3270E 40
67
68 /* Sub-Options for TN3270E negotiation */
69 #define TN3270E_ASSOCIATE 0
70 #define TN3270E_CONNECT 1
71 #define TN3270E_DEVICE_TYPE 2
72 #define TN3270E_FUNCTIONS 3
73 #define TN3270E_IS 4
74 #define TN3270E_REASON 5
75 #define TN3270E_REJECT 6
76 #define TN3270E_REQUEST 7
77 #define TN3270E_SEND 8
78
79 /* Reason codes for TN3270E negotiation */
80 #define TN3270E_CONN_PARTNER 0
81 #define TN3270E_DEVICE_IN_USE 1
82 #define TN3270E_INV_ASSOCIATE 2
83 #define TN3270E_INV_NAME 3
84 #define TN3270E_INV_DEVICE_TYPE 4
85 #define TN3270E_TYPE_NAME_ERROR 5
86 #define TN3270E_UNKNOWN_ERROR 6
87 #define TN3270E_UNSUPPORTED_REQ 7
88
89 /* Function names for TN3270E FUNCTIONS sub-option */
90 #define TN3270E_BIND_IMAGE 0
91 #define TN3270E_DATA_STREAM_CTL 1
92 #define TN3270E_RESPONSES 2
93 #define TN3270E_SCS_CTL_CODES 3
94 #define TN3270E_SYSREQ 4
95
96 #define EOR 239
97 #define SE 240
98 #define SB 250
99 #define WILL 251
100 #define WONT 252
101 #define DO 253
102 #define DONT 254
103 #define IAC 255
104
105 #define TN5250_STREAM_STATE_NO_DATA 0 /* Dummy state */
106 #define TN5250_STREAM_STATE_DATA 1
107 #define TN5250_STREAM_STATE_HAVE_IAC 2
108 #define TN5250_STREAM_STATE_HAVE_VERB 3 /* e.g. DO, DONT, WILL, WONT */
109 #define TN5250_STREAM_STATE_HAVE_SB 4 /* SB data */
110 #define TN5250_STREAM_STATE_HAVE_SB_IAC 5
111
112 /* Internal Telnet option settings (bit-wise flags) */
113 #define RECV_BINARY 1
114 #define SEND_BINARY 2
115 #define RECV_EOR 4
116 #define SEND_EOR 8
117
118 #ifndef HAVE_UCHAR
119 typedef unsigned char UCHAR;
120 #endif
121
122 static const UCHAR hostInitStr[] = {IAC,DO,NEW_ENVIRON,IAC,DO,TERMINAL_TYPE};
123 static const UCHAR hostDoEOR[] = {IAC,DO,END_OF_RECORD};
124 static const UCHAR hostDoBinary[] = {IAC,DO,TRANSMIT_BINARY};
125 static const UCHAR hostDoTN3270E[] = {IAC,DO,TN3270E};
126 static const UCHAR hostSBDevice[] = {IAC,SB,TN3270E,TN3270E_SEND,TN3270E_DEVICE_TYPE,
127 IAC,SE};
128 typedef struct doTable_t {
129 const UCHAR *cmd;
130 unsigned len;
131 } DOTABLE;
132
133 static const DOTABLE host5250DoTable[] = {
134 hostInitStr, sizeof(hostInitStr),
135 hostDoEOR, sizeof(hostDoEOR),
136 hostDoBinary, sizeof(hostDoBinary),
137 NULL, 0
138 };
139
140 static const DOTABLE host3270DoTable[] = {
141 hostInitStr, sizeof(hostInitStr),
142 hostDoEOR, sizeof(hostDoEOR),
143 hostDoBinary, sizeof(hostDoBinary),
144 NULL, 0
145 };
146
147 static const UCHAR SB_Str_NewEnv[]={IAC, SB, NEW_ENVIRON, SEND, USERVAR,
148 'I','B','M','R','S','E','E','D', 0,1,2,3,4,5,6,7,
149 VAR, USERVAR, IAC, SE};
150 static const UCHAR SB_Str_TermType[]={IAC, SB, TERMINAL_TYPE, SEND, IAC, SE};
151
152 #ifdef NDEBUG
153 #define IACVERB_LOG(tag,verb,what)
154 #define TNSB_LOG(sb_buf,sb_len)
155 #define LOGERROR(tag, ecode)
156 #else
157 #define IACVERB_LOG log_IAC_verb
158 #define TNSB_LOG log_SB_buf
159 #define LOGERROR logError
160
getTelOpt(what)161 static char *getTelOpt(what)
162 {
163 char *wcp;
164 static char wbuf[12];
165
166 switch (what) {
167 case TERMINAL_TYPE:
168 wcp = "<TERMTYPE>";
169 break;
170 case END_OF_RECORD:
171 wcp = "<END_OF_REC>";
172 break;
173 case TRANSMIT_BINARY:
174 wcp = "<BINARY>";
175 break;
176 case NEW_ENVIRON:
177 wcp = "<NEWENV>";
178 break;
179 case EOR:
180 wcp = "<EOR>";
181 break;
182 default:
183 snprintf(wcp=wbuf, sizeof(wbuf), "<%02X>", what);
184 break;
185 }
186 return wcp;
187 }
188
logError(char * tag,int ecode)189 static void logError(char *tag, int ecode)
190 {
191 FILE *errfp = tn5250_logfile ? tn5250_logfile : stderr;
192
193 fprintf(errfp,"%s: ERROR (code=%d) - %s\n", tag, ecode, strerror(ecode));
194 }
195
log_IAC_verb(char * tag,int verb,int what)196 static void log_IAC_verb(char *tag, int verb, int what)
197 {
198 char *vcp, vbuf[10];
199
200 if (!tn5250_logfile)
201 return;
202 switch (verb) {
203 case DO: vcp = "<DO>";
204 break;
205 case DONT:
206 vcp = "<DONT>";
207 break;
208 case WILL:
209 vcp = "<WILL>";
210 break;
211 case WONT:
212 vcp = "<WONT>";
213 break;
214 default:
215 sprintf(vcp=vbuf, "<%02X>", verb);
216 break;
217 }
218 fprintf(tn5250_logfile,"%s:<IAC>%s%s\n", tag, vcp, getTelOpt(what));
219 }
220
dumpVarVal(UCHAR * buf,int len)221 static int dumpVarVal(UCHAR *buf, int len)
222 {
223 int c, i;
224
225 for (c=buf[i=0]; i<len && c!=VAR && c!=VALUE && c!=USERVAR; c=buf[++i]) {
226 if (isprint(c))
227 putc(c, tn5250_logfile);
228 else
229 fprintf(tn5250_logfile,"<%02X>", c);
230 }
231 return i;
232 }
233
dumpNewEnv(unsigned char * buf,int len)234 static int dumpNewEnv(unsigned char *buf, int len)
235 {
236 int c, i=0, j;
237
238 while (i<len) {
239 switch (c=buf[i]) {
240 case IAC:
241 return i;
242 case VAR:
243 fputs("\n\t<VAR>",tn5250_logfile);
244 if (++i<len && buf[i]==USERVAR) {
245 fputs("<USERVAR>",tn5250_logfile);
246 return i+1;
247 }
248 j = dumpVarVal(buf+i, len-i);
249 i += j;
250 case USERVAR:
251 fputs("\n\t<USERVAR>",tn5250_logfile);
252 if (!memcmp("IBMRSEED", &buf[++i], 8)) {
253 fputs("IBMRSEED",tn5250_logfile);
254 putc('<',tn5250_logfile);
255 for (j=0, i+=8; j<8; i++, j++) {
256 if (j)
257 putc(' ',tn5250_logfile);
258 fprintf(tn5250_logfile,"%02X",buf[i]);
259 }
260 putc('>',tn5250_logfile);
261 } else {
262 j = dumpVarVal(buf+i, len-i);
263 i += j;
264 }
265 break;
266 case VALUE:
267 fputs("<VALUE>",tn5250_logfile);
268 i++;
269 j = dumpVarVal(buf+i, len-i);
270 i += j;
271 break;
272 default:
273 fputs(getTelOpt(c),tn5250_logfile);
274 } /* switch */
275 } /* while */
276 return i;
277 }
278
log_SB_buf(unsigned char * buf,int len)279 static void log_SB_buf(unsigned char *buf, int len)
280 {
281 int c, i, type;
282
283 if (!tn5250_logfile)
284 return;
285 fprintf(tn5250_logfile,getTelOpt(type=*buf++));
286 switch (c=*buf++) {
287 case IS:
288 fputs("<IS>",tn5250_logfile);
289 break;
290 case SEND:
291 fputs("<SEND>",tn5250_logfile);
292 break;
293 default:
294 fputs(getTelOpt(c),tn5250_logfile);
295 }
296 len -= 2;
297 i = (type==NEW_ENVIRON) ? dumpNewEnv(buf,len) : 0;
298 while (i<len) {
299 switch(c=buf[i++]) {
300 case IAC:
301 fputs("<IAC>",tn5250_logfile);
302 if (i<len)
303 fputs(getTelOpt(buf[i++]), tn5250_logfile);
304 break;
305 default:
306 if (isprint(c))
307 putc(c, tn5250_logfile);
308 else
309 fprintf(tn5250_logfile,"<%02X>", c);
310 }
311 }
312 }
313 #endif /* !NDEBUG */
314
315 /****f* lib5250/tn5250_telnet_stream_init
316 * NAME
317 * tn5250_telnet_stream_init
318 * SYNOPSIS
319 * ret = tn5250_telnet_stream_init (This);
320 * INPUTS
321 * Tn5250Stream * This -
322 * DESCRIPTION
323 * DOCUMENT ME!!!
324 *****/
tn5250_telnet_stream_init(Tn5250Stream * This)325 int tn5250_telnet_stream_init (Tn5250Stream *This)
326 {
327 This->connect = telnet_stream_connect;
328 This->accept = telnet_stream_accept;
329 This->disconnect = telnet_stream_disconnect;
330 This->handle_receive = telnet_stream_handle_receive;
331 This->send_packet = telnet_stream_send_packet;
332 This->destroy = telnet_stream_destroy;
333 This->streamtype = TN5250_STREAM;
334 return 0; /* Ok */
335 }
336
337 /****f* lib5250/tn3270_telnet_stream_init
338 * NAME
339 * tn3270_telnet_stream_init
340 * SYNOPSIS
341 * ret = tn3270_telnet_stream_init (This);
342 * INPUTS
343 * Tn5250Stream * This -
344 * DESCRIPTION
345 * DOCUMENT ME!!!
346 *****/
tn3270_telnet_stream_init(Tn5250Stream * This)347 int tn3270_telnet_stream_init (Tn5250Stream *This)
348 {
349 This->connect = telnet_stream_connect;
350 This->accept = telnet_stream_accept;
351 This->disconnect = telnet_stream_disconnect;
352 This->handle_receive = telnet_stream_handle_receive;
353 This->send_packet = tn3270_stream_send_packet;
354 This->destroy = telnet_stream_destroy;
355 This->streamtype = TN3270E_STREAM;
356 return 0; /* Ok */
357 }
358
359 /****i* lib5250/telnet_stream_connect
360 * NAME
361 * telnet_stream_connect
362 * SYNOPSIS
363 * ret = telnet_stream_connect (This, to);
364 * INPUTS
365 * Tn5250Stream * This -
366 * const char * to -
367 * DESCRIPTION
368 * Connects to server. The `to' parameter is in the form
369 * host[:port].
370 *****/
telnet_stream_connect(Tn5250Stream * This,const char * to)371 static int telnet_stream_connect(Tn5250Stream * This, const char *to)
372 {
373 struct sockaddr_in serv_addr;
374 u_long ioctlarg = 1;
375 char *address;
376 int r;
377
378 memset((char *) &serv_addr, 0, sizeof(serv_addr));
379 serv_addr.sin_family = AF_INET;
380
381 /* Figure out the internet address. */
382 address = (char *)malloc (strlen (to)+1);
383 strcpy (address, to);
384 if (strchr (address, ':'))
385 *strchr (address, ':') = '\0';
386
387 serv_addr.sin_addr.s_addr = inet_addr(address);
388 if (serv_addr.sin_addr.s_addr == INADDR_NONE) {
389 struct hostent *pent = TN_GETHOSTBYNAME(address);
390 if (pent != NULL)
391 serv_addr.sin_addr.s_addr = *((u_long *) (pent->h_addr));
392 }
393 free (address);
394 if (serv_addr.sin_addr.s_addr == INADDR_NONE)
395 return LAST_ERROR;
396
397 /* Figure out the port name. */
398 if (strchr (to, ':') != NULL) {
399 const char *port = strchr (to, ':') + 1;
400 serv_addr.sin_port = htons((u_short) atoi(port));
401 if (serv_addr.sin_port == 0) {
402 struct servent *pent = getservbyname(port, "tcp");
403 if (pent != NULL)
404 serv_addr.sin_port = pent->s_port;
405 }
406 if (serv_addr.sin_port == 0)
407 return LAST_ERROR;
408 } else {
409 /* No port specified ... use telnet port. */
410 struct servent *pent = getservbyname ("telnet", "tcp");
411 if (pent == NULL)
412 serv_addr.sin_port = htons(23);
413 else
414 serv_addr.sin_port = pent->s_port;
415 }
416
417 This->sockfd = socket(PF_INET, SOCK_STREAM, 0);
418 if (WAS_INVAL_SOCK(This->sockfd)) {
419 return LAST_ERROR;
420 }
421 r = TN_CONNECT(This->sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
422 if (WAS_ERROR_RET(r)) {
423 return LAST_ERROR;
424 }
425 /* Set socket to non-blocking mode. */
426 #ifdef FIONBIO
427 TN5250_LOG(("Non-Blocking\n"));
428 TN_IOCTL(This->sockfd, FIONBIO, &ioctlarg);
429 #endif
430
431 This->state = TN5250_STREAM_STATE_DATA;
432 return 0;
433 }
434
435 /****i* lib5250/telnet_stream_accept
436 * NAME
437 * telnet_stream_accept
438 * SYNOPSIS
439 * ret = telnet_stream_accept (This, masterSock);
440 * INPUTS
441 * Tn5250Stream * This -
442 * SOCKET masterSock -
443 * DESCRIPTION
444 * Accepts a connection from the client.
445 *****/
telnet_stream_accept(Tn5250Stream * This,SOCKET_TYPE masterfd)446 static int telnet_stream_accept(Tn5250Stream * This, SOCKET_TYPE masterfd)
447 {
448 int i, retCode;
449 /*
450 int len;
451 struct sockaddr_in serv_addr;
452 */
453 fd_set fdr;
454 struct timeval tv;
455
456 #ifndef WINELIB
457 u_long ioctlarg=1L;
458 #endif
459
460 /*
461 len = sizeof(serv_addr);
462 This->sockfd = accept(masterSock, (struct sockaddr *) &serv_addr, &len);
463 if (WAS_INVAL_SOCK(This->sockfd)) {
464 return LAST_ERROR;
465 }
466 */
467 printf("This->sockfd = %d\n", masterfd);
468 This->sockfd = masterfd;
469
470 /* Set socket to non-blocking mode. */
471 #ifndef WINELIB
472 TN_IOCTL(This->sockfd, FIONBIO, &ioctlarg);
473 #endif
474
475 This->state = TN5250_STREAM_STATE_DATA;
476 This->status = HOST;
477
478 /* Commence TN5250 negotiations...
479 Send DO options (New Environment, Terminal Type, etc.) */
480
481 if(This->streamtype == TN3270E_STREAM)
482 {
483 retCode = send(This->sockfd, hostDoTN3270E, sizeof(hostDoTN3270E), 0);
484 if (WAS_ERROR_RET(retCode)) {
485 perror("telnetstr");
486 return LAST_ERROR;
487 }
488
489 FD_ZERO(&fdr);
490 FD_SET(This->sockfd, &fdr);
491 tv.tv_sec = 5;
492 tv.tv_usec = 0;
493 TN_SELECT(This->sockfd + 1, &fdr, NULL, NULL, &tv);
494 if (FD_ISSET(This->sockfd, &fdr)) {
495
496 if (!telnet_stream_handle_receive(This)) {
497 retCode = LAST_ERROR;
498 return retCode ? retCode : -1;
499 }
500 } else {
501 return -1;
502 }
503
504 if(This->streamtype == TN3270E_STREAM)
505 {
506 retCode = send(This->sockfd, hostSBDevice, sizeof(hostSBDevice),0);
507
508 if (WAS_ERROR_RET(retCode)) {
509 perror("telnetstr");
510 return LAST_ERROR;
511 }
512
513 FD_ZERO(&fdr);
514 FD_SET(This->sockfd, &fdr);
515 tv.tv_sec = 5;
516 tv.tv_usec = 0;
517 TN_SELECT(This->sockfd + 1, &fdr, NULL, NULL, &tv);
518 if (FD_ISSET(This->sockfd, &fdr)) {
519
520 if (!telnet_stream_handle_receive(This)) {
521 retCode = LAST_ERROR;
522 return retCode ? retCode : -1;
523 }
524 } else {
525 return -1;
526 }
527
528 FD_ZERO(&fdr);
529 FD_SET(This->sockfd, &fdr);
530 tv.tv_sec = 5;
531 tv.tv_usec = 0;
532 TN_SELECT(This->sockfd + 1, &fdr, NULL, NULL, &tv);
533 if (FD_ISSET(This->sockfd, &fdr)) {
534
535 if (!telnet_stream_handle_receive(This)) {
536 retCode = LAST_ERROR;
537 return retCode ? retCode : -1;
538 }
539 } else {
540 return -1;
541 }
542 }
543 else
544 {
545 goto neg5250;
546 }
547 }
548 else
549 {
550 neg5250:
551 for (i=0; host5250DoTable[i].cmd; i++) {
552 retCode = send(This->sockfd, host5250DoTable[i].cmd,
553 host5250DoTable[i].len, 0);
554 if (WAS_ERROR_RET(retCode)) {
555 perror("telnetstr");
556 return LAST_ERROR;
557 }
558
559 FD_ZERO(&fdr);
560 FD_SET(This->sockfd, &fdr);
561 tv.tv_sec = 5;
562 tv.tv_usec = 0;
563 TN_SELECT(This->sockfd + 1, &fdr, NULL, NULL, &tv);
564 if (FD_ISSET(This->sockfd, &fdr)) {
565
566 if (!telnet_stream_handle_receive(This)) {
567 retCode = LAST_ERROR;
568 return retCode ? retCode : -1;
569 }
570 } else {
571 return -1;
572 }
573 }
574 }
575 return 0;
576 }
577
578 /****i* lib5250/telnet_stream_disconnect
579 * NAME
580 * telnet_stream_disconnect
581 * SYNOPSIS
582 * telnet_stream_disconnect (This);
583 * INPUTS
584 * Tn5250Stream * This -
585 * DESCRIPTION
586 * Disconnect from the remote host.
587 *****/
telnet_stream_disconnect(Tn5250Stream * This)588 static void telnet_stream_disconnect(Tn5250Stream * This)
589 {
590 printf("Closing...\n");
591 TN_CLOSE(This->sockfd);
592 }
593
594 /****i* lib5250/telnet_stream_destroy
595 * NAME
596 * telnet_stream_destroy
597 * SYNOPSIS
598 * telnet_stream_destroy (This);
599 * INPUTS
600 * Tn5250Stream * This -
601 * DESCRIPTION
602 * DOCUMENT ME!!!
603 *****/
telnet_stream_destroy(Tn5250Stream * This)604 static void telnet_stream_destroy(Tn5250Stream *This)
605 {
606 /* noop */
607 }
608
609 /****i* lib5250/telnet_stream_get_next
610 * NAME
611 * telnet_stream_get_next
612 * SYNOPSIS
613 * ret = telnet_stream_get_next (This, buf, size);
614 * INPUTS
615 * Tn5250Stream * This -
616 * unsigned char * buf -
617 * int size -
618 * DESCRIPTION
619 * Gets the next buffer of data from the socket. The
620 * return value is the length of the data received,
621 * or -1 for no data to receive, or -2 if disconnected
622 *****/
telnet_stream_get_next(Tn5250Stream * This,unsigned char * buf,int size)623 static int telnet_stream_get_next(Tn5250Stream * This, unsigned char *buf, int size)
624 {
625 int rc;
626 fd_set fdr;
627 struct timeval tv;
628
629 FD_ZERO(&fdr);
630 FD_SET(This->sockfd, &fdr);
631 tv.tv_sec = This->msec_wait/1000;
632 tv.tv_usec = (This->msec_wait%1000)*1000;
633 TN_SELECT(This->sockfd + 1, &fdr, NULL, NULL, &tv);
634 if (!FD_ISSET(This->sockfd, &fdr))
635 return -1; /* No data on socket. */
636
637 rc = TN_RECV(This->sockfd, buf, size, 0);
638 if (WAS_ERROR_RET(rc)) {
639 if (LAST_ERROR != ERR_AGAIN && LAST_ERROR != ERR_INTR) {
640 TN5250_LOG(("Error reading from socket: %s\n", strerror(LAST_ERROR)));
641 return -2;
642 } else
643 return -1;
644 }
645 /* If the socket was readable, but there is no data, that means that we
646 have been disconnected. */
647 if (rc == 0)
648 return -2;
649
650 return rc;
651 }
652
sendWill(SOCKET_TYPE sock,unsigned char what)653 static int sendWill(SOCKET_TYPE sock, unsigned char what)
654 {
655 UCHAR buff[3]={IAC,WILL};
656 buff[2] = what;
657 return send(sock, buff, 3, 0);
658 }
659
660 /****i* lib5250/telnet_stream_host_verb
661 * NAME
662 * telnet_stream_host_verb
663 * SYNOPSIS
664 * telnet_stream_host_verb (This, verb, what);
665 * INPUTS
666 * SOCKET_TYPE sock -
667 * unsigned char verb -
668 * unsigned char what -
669 * DESCRIPTION
670 * Process the telnet DO, DONT, WILL, or WONT escape sequence.
671 *****/
telnet_stream_host_verb(Tn5250Stream * This,unsigned char verb,unsigned char what)672 static int telnet_stream_host_verb(Tn5250Stream * This, unsigned char verb,
673 unsigned char what)
674 {
675 int len, option=0, retval=0;
676 SOCKET_TYPE sock;
677
678 sock = This->sockfd;
679
680 IACVERB_LOG("GotVerb(1)",verb,what);
681 switch (verb) {
682 case DO:
683 switch (what) {
684 case END_OF_RECORD:
685 option = SEND_EOR;
686 break;
687
688 case TRANSMIT_BINARY:
689 option = SEND_BINARY;
690 break;
691
692 default:
693 break;
694 } /* DO: switch (what) */
695 break;
696
697 case DONT:
698 case WONT:
699 if(what == TN3270E)
700 {
701 This->streamtype = TN3270_STREAM;
702 }
703 break;
704
705 case WILL:
706 switch (what) {
707 case NEW_ENVIRON:
708 len = sizeof(SB_Str_NewEnv);
709 TN5250_LOG(("Sending SB NewEnv..\n"));
710 retval = send(sock, SB_Str_NewEnv, len, 0);
711 break;
712
713 case TERMINAL_TYPE:
714 len = sizeof(SB_Str_TermType);
715 TN5250_LOG(("Sending SB TermType..\n"));
716 retval = send(sock, SB_Str_TermType, len, 0);
717 break;
718
719 case END_OF_RECORD:
720 option = RECV_EOR;
721 retval = sendWill(sock, what);
722 break;
723
724 case TRANSMIT_BINARY:
725 option = RECV_BINARY;
726 retval = sendWill(sock, what);
727 break;
728
729 default:
730 break;
731 } /* WILL: switch (what) */
732 break;
733
734 default:
735 break;
736 } /* switch (verb) */
737
738 return(WAS_ERROR_RET(retval) ? retval : option);
739 } /* telnet_stream_host_verb */
740
741
742 /****i* lib5250/telnet_stream_do_verb
743 * NAME
744 * telnet_stream_do_verb
745 * SYNOPSIS
746 * telnet_stream_do_verb (This, verb, what);
747 * INPUTS
748 * Tn5250Stream * This -
749 * unsigned char verb -
750 * unsigned char what -
751 * DESCRIPTION
752 * Process the telnet DO, DONT, WILL, or WONT escape sequence.
753 *****/
telnet_stream_do_verb(Tn5250Stream * This,unsigned char verb,unsigned char what)754 static void telnet_stream_do_verb(Tn5250Stream * This, unsigned char verb, unsigned char what)
755 {
756 unsigned char reply[3];
757 int ret;
758
759 IACVERB_LOG("GotVerb(2)", verb, what);
760 reply[0] = IAC;
761 reply[2] = what;
762 switch (verb) {
763 case DO:
764 switch (what) {
765 case TERMINAL_TYPE:
766 case END_OF_RECORD:
767 case TRANSMIT_BINARY:
768 case NEW_ENVIRON:
769 reply[1] = WILL;
770 break;
771
772 default:
773 reply[1] = WONT;
774 break;
775 }
776 break;
777
778 case DONT:
779 break;
780
781 case WILL:
782 switch (what) {
783 case TERMINAL_TYPE:
784 case END_OF_RECORD:
785 case TRANSMIT_BINARY:
786 case NEW_ENVIRON:
787 reply[1] = DO;
788 break;
789
790 case TIMING_MARK:
791 TN5250_LOG(("do_verb: IAC WILL TIMING_MARK received.\n"));
792 default:
793 reply[1] = DONT;
794 break;
795 }
796 break;
797
798 case WONT:
799 break;
800 }
801
802 /* We should really keep track of states here, but the code has been
803 * like this for some time, and no complaints.
804 *
805 * Actually, I don't even remember what that comment means -JMF */
806
807 IACVERB_LOG("GotVerb(3)",verb,what);
808 ret = TN_SEND(This->sockfd, (char *) reply, 3, 0);
809 if (WAS_ERROR_RET(ret)) {
810 printf("Error writing to socket: %s\n", strerror(LAST_ERROR));
811 exit(5);
812 }
813 }
814
telnet_stream_host_sb(Tn5250Stream * This,UCHAR * sb_buf,int sb_len)815 static void telnet_stream_host_sb(Tn5250Stream * This, UCHAR *sb_buf,
816 int sb_len)
817 {
818 int rc;
819 int i;
820 int sbType;
821 int sbParm;
822 Tn5250Buffer tbuf;
823 UCHAR deviceResponse[] = {IAC,SB,TN3270E,TN3270E_DEVICE_TYPE,TN3270E_IS};
824 UCHAR functionResponse[] = {IAC,SB,TN3270E,TN3270E_FUNCTIONS};
825 char * dummyname = "TN3E002";
826
827 if (sb_len <= 0)
828 return;
829
830 TN5250_LOG(("GotSB:<IAC><SB>"));
831 TNSB_LOG(sb_buf,sb_len);
832 TN5250_LOG(("<IAC><SE>\n"));
833 sbType = sb_buf[0];
834 switch (sbType)
835 {
836 case TN3270E:
837 sb_buf += 1;
838 sb_len -= 1;
839 sbParm = sb_buf[0];
840 switch (sbParm)
841 {
842 case TN3270E_DEVICE_TYPE:
843 sb_buf += 2; /* Device string follows DEVICE_TYPE IS parameter */
844 sb_len -= 2;
845 tn5250_buffer_init(&tbuf);
846 tn5250_buffer_append_data(&tbuf, deviceResponse,
847 sizeof(deviceResponse));
848 for(i=0; i<sb_len && sb_buf[i] != IAC; i++)
849 tn5250_buffer_append_byte(&tbuf, sb_buf[i]);
850 tn5250_buffer_append_byte(&tbuf, TN3270E_CONNECT);
851 tn5250_buffer_append_data(&tbuf, dummyname, strlen(dummyname));
852 tn5250_buffer_append_byte(&tbuf, IAC);
853 tn5250_buffer_append_byte(&tbuf, SE);
854 rc = TN_SEND(This->sockfd, (char *) tn5250_buffer_data(&tbuf),
855 tn5250_buffer_length(&tbuf), 0);
856 if (WAS_ERROR_RET(rc)) {
857 printf("Error writing to socket: %s\n", strerror(LAST_ERROR));
858 exit(5);
859 }
860 break;
861 case TN3270E_FUNCTIONS:
862 sb_buf += 2; /* Function list follows FUNCTIONS REQUEST parameter */
863 sb_len -= 2;
864 tn5250_buffer_init(&tbuf);
865 tn5250_buffer_append_data(&tbuf, functionResponse,
866 sizeof(functionResponse));
867
868 tn5250_buffer_append_byte(&tbuf, TN3270E_IS);
869 for(i=0; i<sb_len && sb_buf[i] != IAC; i++)
870 {
871 tn5250_buffer_append_byte(&tbuf, sb_buf[i]);
872 This->options = This->options | (1 << (sb_buf[i]+1));
873 }
874
875 tn5250_buffer_append_byte(&tbuf, IAC);
876 tn5250_buffer_append_byte(&tbuf, SE);
877 rc = TN_SEND(This->sockfd, (char *) tn5250_buffer_data(&tbuf),
878 tn5250_buffer_length(&tbuf), 0);
879 if (WAS_ERROR_RET(rc)) {
880 printf("Error writing to socket: %s\n", strerror(LAST_ERROR));
881 exit(5);
882 }
883 break;
884 default:
885 break;
886 }
887 break;
888 case TERMINAL_TYPE:
889 sb_buf += 2; /* Assume IS follows SB option type. */
890 sb_len -= 2;
891 tn5250_buffer_init(&tbuf);
892 for (i=0; i<sb_len && sb_buf[i]!=IAC; i++)
893 tn5250_buffer_append_byte(&tbuf, sb_buf[i]);
894 tn5250_buffer_append_byte(&tbuf, 0);
895 tn5250_stream_setenv(This, "TERM", (char *) tbuf.data);
896 tn5250_buffer_free(&tbuf);
897 break;
898 case NEW_ENVIRON:
899 /* TODO:
900 * setNewEnvVars(This, sb_buf, sb_len);
901 */
902 break;
903 default:
904 break;
905 } /* switch */
906 } /* telnet_stream_host_sb */
907
908 /****i* lib5250/telnet_stream_sb_var_value
909 * NAME
910 * telnet_stream_sb_var_value
911 * SYNOPSIS
912 * telnet_stream_sb_var_value (buf, var, value);
913 * INPUTS
914 * Tn5250Buffer * buf -
915 * unsigned char * var -
916 * unsigned char * value -
917 * DESCRIPTION
918 * Utility function for constructing replies to NEW_ENVIRON requests.
919 *****/
telnet_stream_sb_var_value(Tn5250Buffer * buf,unsigned char * var,unsigned char * value)920 static void telnet_stream_sb_var_value(Tn5250Buffer * buf, unsigned char *var, unsigned char *value)
921 {
922 tn5250_buffer_append_byte(buf, VAR);
923 tn5250_buffer_append_data(buf, var, strlen((char *) var));
924 tn5250_buffer_append_byte(buf, VALUE);
925 tn5250_buffer_append_data(buf, value, strlen((char *) value));
926 }
927
928 /****i* lib5250/telnet_stream_sb
929 * NAME
930 * telnet_stream_sb
931 * SYNOPSIS
932 * telnet_stream_sb (This, sb_buf, sb_len);
933 * INPUTS
934 * Tn5250Stream * This -
935 * unsigned char * sb_buf -
936 * int sb_len -
937 * DESCRIPTION
938 * Handle telnet SB escapes, which are the option-specific negotiations.
939 *****/
telnet_stream_sb(Tn5250Stream * This,unsigned char * sb_buf,int sb_len)940 static void telnet_stream_sb(Tn5250Stream * This, unsigned char *sb_buf, int sb_len)
941 {
942 Tn5250Buffer out_buf;
943 int ret;
944
945 TN5250_LOG(("GotSB:<IAC><SB>"));
946 TNSB_LOG(sb_buf,sb_len);
947 TN5250_LOG(("<IAC><SE>\n"));
948
949 tn5250_buffer_init(&out_buf);
950
951 if (sb_len <= 0)
952 return;
953
954 if (sb_buf[0] == TERMINAL_TYPE) {
955 unsigned char *termtype;
956
957 if (sb_buf[1] != SEND)
958 return;
959
960 termtype = (unsigned char *) tn5250_stream_getenv(This, "TERM");
961
962 tn5250_buffer_append_byte(&out_buf, IAC);
963 tn5250_buffer_append_byte(&out_buf, SB);
964 tn5250_buffer_append_byte(&out_buf, TERMINAL_TYPE);
965 tn5250_buffer_append_byte(&out_buf, IS);
966 tn5250_buffer_append_data(&out_buf, termtype, strlen((char *) termtype));
967 tn5250_buffer_append_byte(&out_buf, IAC);
968 tn5250_buffer_append_byte(&out_buf, SE);
969
970 ret = TN_SEND(This->sockfd, (char *) tn5250_buffer_data(&out_buf),
971 tn5250_buffer_length(&out_buf), 0);
972 if (WAS_ERROR_RET(ret)) {
973 printf("Error writing to socket: %s\n", strerror(LAST_ERROR));
974 exit(5);
975 }
976 TN5250_LOG(("SentSB:<IAC><SB><TERMTYPE><IS>%s<IAC><SE>\n", termtype));
977
978 This->status = This->status | TERMINAL;
979 } else if (sb_buf[0] == NEW_ENVIRON) {
980 Tn5250ConfigStr *iter;
981 tn5250_buffer_append_byte(&out_buf, IAC);
982 tn5250_buffer_append_byte(&out_buf, SB);
983 tn5250_buffer_append_byte(&out_buf, NEW_ENVIRON);
984 tn5250_buffer_append_byte(&out_buf, IS);
985
986 if (This->config != NULL) {
987 if ((iter = This->config->vars) != NULL) {
988 do {
989 if ((strlen (iter->name) > 4) && (!memcmp (iter->name, "env.", 4))) {
990 telnet_stream_sb_var_value(&out_buf,
991 (unsigned char *) iter->name + 4,
992 (unsigned char *) iter->value);
993 }
994 iter = iter->next;
995 } while (iter != This->config->vars);
996 }
997 }
998 tn5250_buffer_append_byte(&out_buf, IAC);
999 tn5250_buffer_append_byte(&out_buf, SE);
1000
1001 ret = TN_SEND(This->sockfd, (char *) tn5250_buffer_data(&out_buf),
1002 tn5250_buffer_length(&out_buf), 0);
1003 if (WAS_ERROR_RET(ret)) {
1004 printf("Error writing to socket: %s\n", strerror(LAST_ERROR));
1005 exit(5);
1006 }
1007 TN5250_LOG(("SentSB:<IAC><SB>"));
1008 TNSB_LOG(&out_buf.data[2], out_buf.len-4);
1009 TN5250_LOG(("<IAC><SE>\n"));
1010 }
1011 tn5250_buffer_free(&out_buf);
1012 }
1013
1014 /****i* lib5250/telnet_stream_get_byte
1015 * NAME
1016 * telnet_stream_get_byte
1017 * SYNOPSIS
1018 * ret = telnet_stream_get_byte (This);
1019 * INPUTS
1020 * Tn5250Stream * This -
1021 * DESCRIPTION
1022 * Returns the next byte from the 5250 data stream, or return -1 if no data
1023 * is waiting on the socket or -2 if disconnected, or -END_OF_RECORD if a
1024 * telnet EOR escape sequence was encountered.
1025 *****/
telnet_stream_get_byte(Tn5250Stream * This)1026 static int telnet_stream_get_byte(Tn5250Stream * This)
1027 {
1028 int temp;
1029 unsigned char verb;
1030
1031 do {
1032 if (This->state == TN5250_STREAM_STATE_NO_DATA)
1033 This->state = TN5250_STREAM_STATE_DATA;
1034
1035 This->rcvbufpos ++;
1036 if (This->rcvbufpos >= This->rcvbuflen) {
1037 This->rcvbufpos = 0;
1038 This->rcvbuflen = telnet_stream_get_next(This, This->rcvbuf, TN5250_RBSIZE);
1039 if (This->rcvbuflen<0)
1040 return This->rcvbuflen;
1041 }
1042 temp = This->rcvbuf[This->rcvbufpos];
1043
1044 switch (This->state) {
1045 case TN5250_STREAM_STATE_DATA:
1046 if (temp == IAC)
1047 This->state = TN5250_STREAM_STATE_HAVE_IAC;
1048 break;
1049
1050 case TN5250_STREAM_STATE_HAVE_IAC:
1051 switch(temp) {
1052 case IAC:
1053 This->state = TN5250_STREAM_STATE_DATA;
1054 break;
1055
1056 case DO:
1057 case DONT:
1058 case WILL:
1059 case WONT:
1060 verb = temp;
1061 This->state = TN5250_STREAM_STATE_HAVE_VERB;
1062 break;
1063
1064 case SB:
1065 This->state = TN5250_STREAM_STATE_HAVE_SB;
1066 tn5250_buffer_free(&(This->sb_buf));
1067 break;
1068
1069 case EOR:
1070 This->state = TN5250_STREAM_STATE_DATA;
1071 return -END_OF_RECORD;
1072
1073 default:
1074 TN5250_LOG(("GetByte: unknown escape 0x%02x in telnet stream.\n", temp));
1075 This->state = TN5250_STREAM_STATE_NO_DATA; /* Hopefully a good recovery. */
1076 }
1077 break;
1078
1079 case TN5250_STREAM_STATE_HAVE_VERB:
1080 TN5250_LOG(("HOST, This->status = %d %d\n", HOST, This->status));
1081 if (This->status&HOST) {
1082 temp = telnet_stream_host_verb(This, verb, (UCHAR) temp);
1083 if (WAS_ERROR_RET(temp)) {
1084 LOGERROR("send", LAST_ERROR);
1085 return -2;
1086 }
1087 /* Implement later...
1088 This->options |= temp;
1089 */
1090 } else
1091 telnet_stream_do_verb(This, verb, (UCHAR) temp);
1092 This->state = TN5250_STREAM_STATE_NO_DATA;
1093 break;
1094
1095 case TN5250_STREAM_STATE_HAVE_SB:
1096 if (temp == IAC)
1097 This->state = TN5250_STREAM_STATE_HAVE_SB_IAC;
1098 else
1099 tn5250_buffer_append_byte(&(This->sb_buf), (UCHAR) temp);
1100 break;
1101
1102 case TN5250_STREAM_STATE_HAVE_SB_IAC:
1103 switch (temp) {
1104 case IAC:
1105 tn5250_buffer_append_byte(&(This->sb_buf), IAC);
1106 /* Since the IAC code was escaped, shouldn't we be resetting the
1107 state as in the following statement? Please verify and
1108 uncomment if applicable. GJS 2/25/2000 */
1109 /* This->state = TN5250_STREAM_STATE_HAVE_SB; */
1110 break;
1111
1112 case SE:
1113 if (This->status&HOST)
1114 telnet_stream_host_sb(This, tn5250_buffer_data(&This->sb_buf),
1115 tn5250_buffer_length(&This->sb_buf));
1116 else
1117 telnet_stream_sb(This, tn5250_buffer_data(&(This->sb_buf)),
1118 tn5250_buffer_length(&(This->sb_buf)));
1119
1120 tn5250_buffer_free(&(This->sb_buf));
1121 This->state = TN5250_STREAM_STATE_NO_DATA;
1122 break;
1123
1124 default: /* Should never happen -- server error */
1125 TN5250_LOG(("GetByte: huh? Got IAC SB 0x%02X.\n", temp));
1126 This->state = TN5250_STREAM_STATE_HAVE_SB;
1127 break;
1128 }
1129 break;
1130
1131 default:
1132 TN5250_LOG(("GetByte: huh? Invalid state %d.\n", This->state));
1133 TN5250_ASSERT(0);
1134 break; /* Avoid compiler warning. */
1135 }
1136 } while (This->state != TN5250_STREAM_STATE_DATA);
1137 return (int) temp;
1138 }
1139
1140 /****i* lib5250/telnet_stream_write
1141 * NAME
1142 * telnet_stream_write
1143 * SYNOPSIS
1144 * telnet_stream_write (This, data, size);
1145 * INPUTS
1146 * Tn5250Stream * This -
1147 * unsigned char * data -
1148 * int size -
1149 * DESCRIPTION
1150 * Writes size bytes of data (pointed to by *data) to the 5250 data stream.
1151 * This is also a temporary method to aid in the conversion process.
1152 *****/
telnet_stream_write(Tn5250Stream * This,unsigned char * data,int size)1153 static void telnet_stream_write(Tn5250Stream * This, unsigned char *data, int size)
1154 {
1155 int r;
1156 int last_error = 0;
1157 fd_set fdw;
1158
1159 /* There was an easier way to do this, but I can't remember. This
1160 just makes sure that non blocking writes that don't have enough
1161 buffer space get completed anyway. */
1162 do {
1163 FD_ZERO(&fdw);
1164 FD_SET(This->sockfd, &fdw);
1165 r = TN_SELECT(This->sockfd + 1, NULL, &fdw, NULL, NULL);
1166 if (WAS_ERROR_RET(r)) {
1167 last_error = LAST_ERROR;
1168 switch (last_error) {
1169 case ERR_INTR:
1170 case ERR_AGAIN:
1171 r = 0;
1172 continue;
1173
1174 default:
1175 perror("select");
1176 exit(5);
1177 }
1178 }
1179 if (FD_ISSET(This->sockfd, &fdw)) {
1180 r = TN_SEND(This->sockfd, (char *) data, size, 0);
1181 if (WAS_ERROR_RET(r)) {
1182 last_error = LAST_ERROR;
1183 if (last_error != ERR_AGAIN) {
1184 perror("Error writing to socket");
1185 exit(5);
1186 }
1187 }
1188 if (r > 0) {
1189 data += r;
1190 size -= r;
1191 }
1192 }
1193 } while (size && (r >= 0 || last_error == ERR_AGAIN));
1194 }
1195
1196 /****i* lib5250/telnet_stream_send_packet
1197 * NAME
1198 * telnet_stream_send_packet
1199 * SYNOPSIS
1200 * telnet_stream_send_packet (This, length, flowtype, flags, opcode, data);
1201 * INPUTS
1202 * Tn5250Stream * This -
1203 * int length -
1204 * int flowtype -
1205 * unsigned char flags -
1206 * unsgined char opcode -
1207 * unsigned char * data -
1208 * DESCRIPTION
1209 * Send a packet, prepending a header and escaping any naturally
1210 * occuring IAC characters.
1211 *****/
telnet_stream_send_packet(Tn5250Stream * This,int length,StreamHeader header,unsigned char * data)1212 static void telnet_stream_send_packet(Tn5250Stream * This, int length,
1213 StreamHeader header, unsigned char *data)
1214 {
1215 Tn5250Buffer out_buf;
1216 int n;
1217 int flowtype;
1218 unsigned char flags;
1219 unsigned char opcode;
1220
1221 flowtype = header.h5250.flowtype;
1222 flags = header.h5250.flags;
1223 opcode = header.h5250.opcode;
1224
1225 length = length + 10;
1226
1227 /* Fixed length portion of header */
1228 tn5250_buffer_init(&out_buf);
1229 tn5250_buffer_append_byte(&out_buf, (UCHAR) (((short)length)>>8));
1230 tn5250_buffer_append_byte(&out_buf, (UCHAR) (length & 0xff));
1231 tn5250_buffer_append_byte(&out_buf, 0x12); /* Record type = General data stream (GDS) */
1232 tn5250_buffer_append_byte(&out_buf, 0xa0);
1233 tn5250_buffer_append_byte(&out_buf, (UCHAR)(flowtype >> 8));
1234 tn5250_buffer_append_byte(&out_buf, (UCHAR) (flowtype & 0xff));
1235
1236 /* Variable length portion of header */
1237 tn5250_buffer_append_byte(&out_buf, 4);
1238 tn5250_buffer_append_byte(&out_buf, flags);
1239 tn5250_buffer_append_byte(&out_buf, 0);
1240 tn5250_buffer_append_byte(&out_buf, opcode);
1241 tn5250_buffer_append_data(&out_buf, data, length - 10);
1242
1243 telnet_stream_escape(&out_buf);
1244
1245 tn5250_buffer_append_byte(&out_buf, IAC);
1246 tn5250_buffer_append_byte(&out_buf, EOR);
1247
1248 #ifndef NDEBUG
1249 TN5250_LOG(("SendPacket: length = %d\nSendPacket: data follows.",
1250 tn5250_buffer_length(&out_buf)));
1251 for (n = 0; n < tn5250_buffer_length(&out_buf); n++) {
1252 if ((n % 16) == 0) {
1253 TN5250_LOG(("\nSendPacket: data: "));
1254 }
1255 TN5250_LOG(("%02X ", tn5250_buffer_data(&out_buf)[n]));
1256 }
1257 TN5250_LOG(("\n"));
1258 #endif
1259
1260 telnet_stream_write(This, tn5250_buffer_data(&out_buf), tn5250_buffer_length(&out_buf));
1261 tn5250_buffer_free(&out_buf);
1262 }
1263
1264 void
tn3270_stream_send_packet(Tn5250Stream * This,int length,StreamHeader header,unsigned char * data)1265 tn3270_stream_send_packet(Tn5250Stream * This, int length,
1266 StreamHeader header,
1267 unsigned char * data)
1268 {
1269 Tn5250Buffer out_buf;
1270
1271 tn5250_buffer_init(&out_buf);
1272
1273 if(This->streamtype == TN3270E_STREAM)
1274 {
1275 tn5250_buffer_append_byte(&out_buf, header.h3270.data_type);
1276 tn5250_buffer_append_byte(&out_buf, header.h3270.request_flag);
1277 tn5250_buffer_append_byte(&out_buf, header.h3270.response_flag);
1278
1279 tn5250_buffer_append_byte(&out_buf, header.h3270.sequence >> 8);
1280 tn5250_buffer_append_byte(&out_buf, header.h3270.sequence & 0x00ff);
1281 }
1282
1283 tn5250_buffer_append_data(&out_buf, data, length);
1284
1285 telnet_stream_escape(&out_buf);
1286
1287 tn5250_buffer_append_byte(&out_buf, IAC);
1288 tn5250_buffer_append_byte(&out_buf, EOR);
1289
1290 telnet_stream_write(This, tn5250_buffer_data(&out_buf),
1291 tn5250_buffer_length(&out_buf));
1292
1293 tn5250_buffer_free(&out_buf);
1294
1295 }
1296
1297 /****f* lib5250/telnet_stream_handle_receive
1298 * NAME
1299 * telnet_stream_handle_receive
1300 * SYNOPSIS
1301 * ret = telnet_stream_handle_receive (This);
1302 * INPUTS
1303 * Tn5250Stream * This -
1304 * DESCRIPTION
1305 * Read as much data as possible in a non-blocking fasion, form it
1306 * into Tn5250Record structures and queue them for retrieval.
1307 *****/
telnet_stream_handle_receive(Tn5250Stream * This)1308 int telnet_stream_handle_receive(Tn5250Stream * This)
1309 {
1310 int c;
1311
1312 /* -1 = no more data, -2 = we've been disconnected */
1313 while ((c = telnet_stream_get_byte(This)) != -1 && c != -2) {
1314
1315 if (c == -END_OF_RECORD && This->current_record != NULL) {
1316 /* End of current packet. */
1317 #ifndef NDEBUG
1318 if (tn5250_logfile!=NULL)
1319 tn5250_record_dump(This->current_record);
1320 #endif
1321 This->records = tn5250_record_list_add(This->records, This->current_record);
1322 This->current_record = NULL;
1323 This->record_count++;
1324 continue;
1325 }
1326 if (This->current_record == NULL) {
1327 /* Start of new packet. */
1328 This->current_record = tn5250_record_new();
1329 }
1330 tn5250_record_append_byte(This->current_record, (unsigned char) c);
1331 }
1332
1333 return (c != -2);
1334 }
1335
1336 /****i* lib5250/telnet_stream_escape
1337 * NAME
1338 * telnet_stream_escape
1339 * SYNOPSIS
1340 * telnet_stream_escape (in);
1341 * INPUTS
1342 * Tn5250Buffer * in -
1343 * DESCRIPTION
1344 * Escape IACs in data before sending it to the host.
1345 *****/
telnet_stream_escape(Tn5250Buffer * in)1346 static void telnet_stream_escape(Tn5250Buffer * in)
1347 {
1348 Tn5250Buffer out;
1349 register unsigned char c;
1350 int n;
1351
1352 tn5250_buffer_init(&out);
1353 for (n = 0; n < tn5250_buffer_length(in); n++) {
1354 c = tn5250_buffer_data(in)[n];
1355 tn5250_buffer_append_byte(&out, c);
1356 if (c == IAC)
1357 tn5250_buffer_append_byte(&out, IAC);
1358 }
1359 tn5250_buffer_free(in);
1360 memcpy(in, &out, sizeof(Tn5250Buffer));
1361 }
1362
1363 /* vi:set sts=3 sw=3: */
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381