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