applied 050_ck_patch.patch
[ckermit.git] / ckcnet.c
1 char *cknetv = "Network support, 8.0.283, 7 Feb 2004";
2
3 /*  C K C N E T  --  Network support  */
4
5 /*
6   Copyright (C) 1985, 2004,
7     Trustees of Columbia University in the City of New York.
8     All rights reserved.  See the C-Kermit COPYING.TXT file or the
9     copyright text in the ckcmai.c module for disclaimer and permissions.
10 */
11
12 /*
13   REMINDER: Any changes made to this file that other modules depend must
14   also be made to cklnet.c (for VOS) until such time as cklnet.c and this
15   module are merged back together.
16
17   NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
18   C-Kermit source files, must be compatible with C preprocessors that support
19   only #ifdef, #else, #endif, #define, and #undef.  Please do not use #if,
20   logical operators, or other preprocessor features in this module.  Also,
21   don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif.
22
23   Authors:
24
25   Frank da Cruz (fdc@columbia.edu),
26     Columbia University Academic Information Systems, New York City.
27   Jeffrey E Altman (jaltman@secure-endpoints.com) -- Primary 
28     maintainer/developer since about 1996.
29   netopen() routine for TCP/IP originally by Ken Yap, Rochester University
30     (ken@cs.rochester.edu) (no longer at that address).
31   Missing pieces for Excelan sockets library from William Bader.
32   Telnet protocol by Frank da Cruz and Jeffrey Altman.
33   Rlogin protocol by Jeffrey E Altman.
34   SSL support adapted by Jeffrey E Altman from work done by
35     Tim Hudson <tjh@cryptosoft.com> +61 7 32781581
36   TLS support by Jeffrey E Altman.
37   HTTP support by Jeffrey E Altman.
38   TGV MultiNet code by Frank da Cruz.
39   MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
40   MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
41   TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
42   CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
43   X.25 support by Marcello Frutig, Catholic University,
44     Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
45     Stefaan Eeckels, Eurokom, Luxembourg.
46     David Lane added support for Stratus VOS X.25 1996.
47     Stephen Riehm added support for IBM AIX X.25 in April 1998.
48   Other contributions as indicated in the code.
49 */
50 #define CKCNET_C
51 #include "ckcsym.h"
52 #include "ckcdeb.h"
53 #include "ckcker.h"
54 #include "ckcasc.h"
55 #ifdef I386IX                           /* Has to come before ckcnet.h in */
56 #include <errno.h>                      /* this version, but after in others */
57 #endif /* I386IX */
58 #include "ckcnet.h"                     /* which includes ckctel.h */
59 #ifdef CK_SSL
60 #include "ck_ssl.h"
61 #endif /* CK_SSL */
62
63 #ifdef CK_DNS_SRV
64 #ifdef OS2
65 #ifdef NT
66 #include <wshelper.h>
67 #else /* NT */
68 /* !Error OS/2 does not support DNS Service Records. */
69 #endif /* NT */
70 #else /* OS2 */
71 #include <arpa/inet.h>
72 #ifdef USE_NAMESER_COMPAT
73 #include <arpa/nameser_compat.h>
74 #endif  /* USE_NAMESER_COMPAT */
75 #include <arpa/nameser.h>
76 #include <resolv.h>
77 #ifndef PS2AIX10
78 #ifndef BSD4
79 #ifndef I386IX
80 #ifndef RTAIX
81 #include <netdb.h>
82 #endif /* RTAIX */
83 #endif /* I386IX */
84 #endif /* BSD4 */
85 #endif /* PS2AIX10 */
86 #endif /* OS2 */
87 #ifndef T_SRV
88 #define T_SRV 33
89 #endif /* T_SRV */
90 #ifndef T_TXT
91 #define T_TXT 16
92 #endif /* T_TXT */
93
94 /* for old Unixes and friends ... */
95 #ifndef MAXHOSTNAMELEN
96 #define MAXHOSTNAMELEN 64
97 #endif /* MAXHOSTNAMELEN */
98
99 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
100 #endif /* CK_DNS_SRV */
101
102 #ifdef NONET
103 #ifdef TCPIPLIB
104 #undef TCPIPLIB
105 #endif /* TCPIPLIB */
106 #endif /* NONET */
107
108 #ifndef NOMHHOST
109 #ifdef datageneral
110 #define NOMHHOST
111 #else
112 #ifdef HPUX5WINTCP
113 #define NOMHHOST
114 #endif /* HPUX5WINTCP */
115 #endif /* datageneral */
116 #endif /* NOMHHOST */
117
118 #ifdef INADDRX
119   struct in_addr inaddrx;
120 #endif /* INADDRX */
121
122 int ttnet = NET_NONE;                   /* Network type */
123 int ttnproto = NP_DEFAULT;              /* Network virtual terminal protocol */
124
125 /* 0 = don't lowercase username for Rlogin/Telnet protocol */
126 /* nonzero = do lowercase it.  Add a SET command if necessary... */
127 #ifdef VMS
128 int ck_lcname = 1;
129 #else
130 int ck_lcname = 0;
131 #endif /* VMS */
132
133 extern int                              /* External variables */
134   duplex, debses, seslog, sessft, wasclosed,
135   ttyfd, quiet, msgflg, what, nettype, ttmdm;
136 #ifdef IKSD
137 extern int inserver;
138 #endif /* IKSD */
139
140 char myipaddr[20] = { '\0' };           /* Global copy of my IP address */
141
142 #ifdef NETCONN
143 /* Don't need any of this if there is no network support. */
144
145 /*
146   NETLEBUF is (must be) defined for those platforms that call this
147   module to do network i/o (e.g. netinc(), nettchk(), etc) rather
148   than doing it themselves (ttinc(), ttchk(), etc).  In this case
149   the Telnet local-echo buffers and routines are defined and referenced
150   here, rather than in the ck?tio.c module.
151 */
152 #ifdef NETLEBUF
153 #define LEBUFSIZ 4096
154 int ttpush = -1, le_data = 0;           /* These are seen from outside */
155 static CHAR le_buf[LEBUFSIZ];           /* These are used internally */
156 static int le_start = 0, le_end = 0;
157 int tt_push_inited = 0;
158 #endif /* NETLEBUF */
159
160 #ifdef CK_SOCKS                         /* SOCKS Internet relay package */
161 #ifdef CK_SOCKS5                        /* SOCKS 5 */
162 #define accept  SOCKSaccept
163 #define bind    SOCKSbind
164 #define connect SOCKSconnect
165 #define getsockname SOCKSgetsockname
166 #define listen SOCKSlisten
167 #else  /* Not SOCKS 5 */
168 #define accept  Raccept
169 #define bind    Rbind
170 #define connect Rconnect
171 #define getsockname Rgetsockname
172 #define listen Rlisten
173 #endif /* CK_SOCKS5 */
174 #endif /* CK_SOCKS */
175
176 #ifdef DEC_TCPIP
177 #include <time.h>
178 #include <inet.h>
179 #endif /* DEC_TCPIP */
180
181 /* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */
182
183 #ifdef HPUX
184 #ifndef HPUX7                           /* HPUX 7.00 doesn't have it */
185 #include <arpa/inet.h>                  /* For inet_ntoa() prototype */
186 #endif /* HPUX7 */
187 #endif /* HPUX */
188
189 #ifdef CMU_TCPIP
190 #include <time.h>
191 #endif /* CMU_TCPIP */
192
193 #ifndef NODCLTIMEVAL
194 #ifdef DCLTIMEVAL                       /* UnixWare 7 */
195 struct timeval {                        /* And define these ourselves. */
196     long tv_sec;                        /* (see comments in ckutio.c) */
197     long tv_usec;
198 };
199 struct timezone {
200     int tz_minuteswest;
201     int tz_dsttime;
202 };
203 #endif /* DCLTIMEVAL */
204 #endif /* NODCLTIMEVAL */
205
206 #ifdef WINTCP
207
208 #include <setjmp.h>
209 #include <signal.h>
210 #include <sys/time.h>
211 /*
212   The WIN/TCP code path is the same as that for MultiNet.
213   Only the routine names have changed ...
214 */
215 #define socket_read     netread
216 #define socket_ioctl    ioctl
217 #define socket_write    netwrite
218 #define socket_close    netclose
219
220 #ifdef OLD_TWG                         /* some routines have evolved */
221         extern int vmserrno, uerrno;
222 #define socket_errno    uerrno
223 #define socket_perror   perror         /* which uses errno, not uerrno! */
224 #else
225 #define socket_errno    errno
226 #define socket_perror   win$perror
227 #endif /* OLD_TWG */
228
229 #else /* Not WINTCP */
230
231 #ifdef OSF13
232 #ifdef CK_ANSIC
233 #ifdef _NO_PROTO
234 #undef _NO_PROTO
235 #endif /* _NO_PROTO */
236 #endif /* CK_ANSIC */
237 #endif /* OSF13 */
238
239 #ifndef I386IX
240 #include <errno.h>                      /* Already included above */
241 #endif /* I386IX */
242
243 #include <signal.h>                     /* Everybody needs this */
244
245 #ifdef ZILOG                            /* Zilog has different name for this */
246 #include <setret.h>
247 #else
248 #include <setjmp.h>
249 #endif /* ZILOG */
250
251 #endif /* WINTCP */
252
253 #ifdef datageneral                      /* Data General AOS/VS */
254 #include <:usr:include:vs_tcp_errno.h>
255 #include <:usr:include:sys:vs_tcp_types.h>
256 #ifdef SELECT
257 /*
258   NOTE: This can be compiled and linked OK with SELECT defined
259   but it doesn't work at all.  Anybody who cares and knows how
260   to fix it, feel free.
261 */
262 #include <:usr:include:sys:vs_tcp_time.h>
263 #endif /* SELECT */
264 #include <:usr:include:sys:socket.h>
265 #include <:usr:include:netinet:in.h>
266 #include <:usr:include:netdb.h>
267 #endif /* datageneral */
268
269 #ifndef socket_errno
270 #define socket_errno errno
271 #endif /* socket_errno */
272
273 #ifdef TNCODE
274 extern int tn_deb;
275 #endif /* TNCODE */
276
277 int tcp_rdns =                          /* Reverse DNS lookup */
278 #ifdef DEC_TCPIP_OLD
279     SET_OFF                             /* Doesn't seem to work in UCX */
280 #else
281      SET_AUTO
282 #endif /* DEC_TCPIP */
283       ;
284 #ifdef CK_DNS_SRV
285 int tcp_dns_srv = SET_OFF;
286 #endif /* CK_DNS_SRV */
287
288 _PROTOTYP( char * cmcvtdate, (char *, int) );
289
290 #ifdef RLOGCODE
291 _PROTOTYP( int rlog_ctrl, (CHAR *, int) );
292 _PROTOTYP( static int rlog_oob, (CHAR *, int) );
293 #ifndef TCPIPLIB
294 _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
295 #endif /* TCPIPLIB */
296 _PROTOTYP( static int rlog_ini, (CHAR *, int,
297                                  struct sockaddr_in *,
298                                  struct sockaddr_in *) );
299 int rlog_mode = RL_COOKED;
300 int rlog_stopped = 0;
301 int rlog_inband = 0;
302 #endif /* RLOGCODE */
303
304 #ifndef NOICP
305 extern int doconx;                      /* CONNECT-class command active */
306 #endif /* NOICP */
307
308 #ifdef IBMX25
309 /* This variable should probably be generalised for true client/server
310  * support - ie: the fd of the listening server, accepted calls should
311  * be forked or at least handled via a second fd (for IBM's X.25 -
312  * ttyfd always holds the active fd - ie the server becomes inactive
313  * as long as a client is connected, and becomes active again when the
314  * connection is closed)
315  */
316 int x25serverfd = 0;            /* extern in ckcnet.h */
317 int x25seqno = 0;               /* Connection sequence number */
318 int x25lastmsg = -1;            /* A cheapskate's state table */
319
320 #define X25_CLOSED      0       /* Default state: no connection, no STREAM */
321 #define X25_SETUP       1       /* X.25 has been set up (no connection) */
322 #define X25_CONNECTED   2       /* X.25 connection has been established */
323 int x25_state = X25_CLOSED;     /* Default state */
324 #endif /* IBMX25 */
325
326 #ifndef DEBUG
327 #define deblog 0
328 #endif /* DEBUG */
329
330 #ifdef CK_NAWS                          /* Negotiate About Window Size */
331 #ifdef RLOGCODE
332 _PROTOTYP( int rlog_naws, (void) );
333 #endif /* RLOGCODE */
334 #endif /* CK_NAWS */
335
336 #ifdef OS2                              /* For terminal type name string */
337 #include "ckuusr.h"
338 #ifndef NT
339 #include <os2.h>
340 #undef COMMENT
341 #endif /* NT */
342 #include "ckocon.h"
343 extern int tt_type, max_tt;
344 extern struct tt_info_rec tt_info[];
345 extern char ttname[];
346 #else
347 #ifdef CK_AUTHENTICATION
348 #include "ckuusr.h"
349 #endif /* CK_AUTHENTICATION */
350 #endif /* OS2 */
351
352 #ifdef NT
353 extern int winsock_version;
354 #endif /* NT */
355
356 #ifdef CK_AUTHENTICATION
357 #include "ckuath.h"
358 #endif /* CK_AUTHENTICATION */
359
360 #include "ckcsig.h"
361
362 #ifndef OS2                             /* For timeout longjumps */
363 static ckjmpbuf njbuf;
364 #endif /* OS2 */
365
366 #define NAMECPYL 1024                   /* Local copy of hostname */
367 char namecopy[NAMECPYL];                /* Referenced by ckctel.c */
368 char namecopy2[NAMECPYL];               /* Referenced by ckctel.c */
369 #ifndef NOHTTP
370 char http_host_port[NAMECPYL];          /* orig host/port necessary for http */
371 char http_ip[20] = { '\0' };            /* ip address of host */
372 char http_port = 0;
373 int  http_ssl = 0;
374 char * http_agent = 0;
375 int  httpfd = -1;                       /* socket for http connections */
376 int  http_code = 0;
377 #define HTTPBUFLEN  1024
378 char http_reply_str[HTTPBUFLEN] = "";
379 #endif /* NOHTTP */
380
381 char ipaddr[20] = { '\0' };             /* Global copy of IP address */
382 unsigned long myxipaddr = 0L;           /* Ditto as a number */
383 #endif /* NETCONN */
384
385 char *tcp_address = NULL;               /* Preferred IP Address */
386 extern char uidbuf[];                   /* User ID buffer */
387 extern char pwbuf[];                    /* Password buffer */
388
389 #ifndef NOHTTP
390 char * tcp_http_proxy = NULL;           /* Name[:port] of http proxy server */
391 int    tcp_http_proxy_errno = 0;
392 char * tcp_http_proxy_user = NULL;
393 char * tcp_http_proxy_pwd  = NULL;
394 char * tcp_http_proxy_agent = NULL;
395 #define HTTPCPYL 1024
396 static char proxycopy[HTTPCPYL];
397 #endif /* NOHTTP */
398
399 #ifdef OS2
400 extern int tt_rows[], tt_cols[];
401 extern int tt_status[VNUM];
402 #else /* OS2 */
403 extern int tt_rows, tt_cols;            /* Everybody has this */
404 #endif /* OS2 */
405
406 extern int cmd_cols, cmd_rows;
407
408 #ifdef STREAMING                        /* Use blocking writes for streaming */
409 extern int streaming;
410 #endif /* STREAMING */
411
412 #ifdef NT
413 extern int WSASafeToCancel;
414 int win95selectbug = 0;                 /* For TCP/IP stacks whose select() */
415 /* always fails on write requests such as Cisco and Quarterdeck */
416 #define stricmp _stricmp
417 #endif /* NT */
418
419 #ifndef NOTCPOPTS
420
421 /* Skip all this if NOTCPOPTS specified. */
422
423 #ifdef SOL_SOCKET
424
425 #ifdef TCP_NODELAY
426 int tcp_nodelay = 0;                    /* Nagle algorithm TCP_NODELAY */
427 #endif /* TCP_NODELAY */
428
429 #ifdef SO_DONTROUTE
430 int tcp_dontroute = 0;
431 #endif /* SO_DONTROUTE */
432
433 #ifdef SO_LINGER
434 int tcp_linger  = 0;                    /* SO_LINGER */
435 int tcp_linger_tmo = 0;                 /* SO_LINGER timeout */
436 #endif /* SO_LINGER */
437
438 #ifdef HPUX                             /* But the data structures */
439 #ifndef HPUX8                           /* needed for linger are not */
440 #ifndef HPUX9                           /* defined in HP-UX versions */
441 #ifndef HPUX10                          /* prior to 8.00. */
442 #ifdef SO_LINGER
443 #undef SO_LINGER
444 #endif /* SO_LINGER */
445 #endif /* HPUX10 */
446 #endif /* HPUX9 */
447 #endif /* HPUX8 */
448 #endif /* HPUX */
449
450 #ifndef SO_OOBINLINE                    /* Hopefully only HP-UX 7.0 */
451 #define SO_OOBINLINE 0x0100
452 #endif /* SO_OOBINLINE */
453
454 #ifndef TCPSNDBUFSIZ
455 #ifdef VMS
456 #ifdef __alpha
457 #define TCPSNDBUFSIZ 16384
458 #endif /* __alpha */
459 #endif /* VMS */
460 #endif /* TCPSNDBUFSIZ */
461
462 #ifndef TCPSNDBUFSIZ
463 #define TCPSNDBUFSIZ -1
464 #endif /* TCPSNDBUFSIZ */
465
466 #ifdef SO_SNDBUF
467 int tcp_sendbuf = TCPSNDBUFSIZ;
468 #endif /* SO_SNDBUF */
469
470 #ifdef SO_RCVBUF
471 int tcp_recvbuf = -1;
472 #endif /* SO_RCVBUF */
473
474 #ifdef SO_KEEPALIVE
475 int tcp_keepalive = 1;
476 #endif /* SO_KEEPALIVE */
477
478 #endif /* SOL_SOCKET */
479 #endif /* NOTCPOPTS */
480
481 #ifndef NETCONN
482 /*
483   Network support not defined.
484   Dummy functions here in case #ifdef's forgotten elsewhere.
485 */
486 int                                     /* Open network connection */
487 netopen(name, lcl, nett) char *name; int *lcl, nett; {
488     return(-1);
489 }
490 int                                     /* Close network connection */
491 netclos() {
492     return(-1);
493 }
494 int                                     /* Check network input buffer */
495 nettchk() {
496     return(-1);
497 }
498 int                                     /* Flush network input buffer */
499 netflui() {
500     return(-1);
501 }
502 int                                     /* Send network BREAK */
503 netbreak() {
504     return(-1);
505 }
506 int                                     /* Input character from network */
507 netinc(timo) int timo; {
508     return(-1);
509 }
510 int                                     /* Output character to network */
511 #ifdef CK_ANSIC
512 nettoc(CHAR c)
513 #else
514 nettoc(c) CHAR c;
515 #endif /* CK_ANSIC */
516 /* nettoc */ {
517     return(-1);
518 }
519 int
520 nettol(s,n) CHAR *s; int n; {
521     return(-1);
522 }
523
524 #else /* NETCONN is defined (much of this module...) */
525
526 #ifdef NETLEBUF
527 VOID
528 le_init() {                             /* LocalEchoInit() */
529     int i;
530     for (i = 0; i < LEBUFSIZ; i++)
531       le_buf[i] = '\0';
532     le_start = 0;
533     le_end = 0;
534     le_data = 0;
535     tt_push_inited = 1;
536 }
537
538 VOID
539 le_clean() {                            /* LocalEchoCleanup() */
540     le_init();
541     return;
542 }
543
544 int
545 le_inbuf() {
546     int rc = 0;
547     if (le_start != le_end) {
548         rc = (le_end -
549               le_start +
550               LEBUFSIZ) % LEBUFSIZ;
551     }
552     return(rc);
553 }
554
555 int
556 #ifdef CK_ANSIC
557 le_putchar(CHAR ch)
558 #else
559 le_putchar(ch) CHAR ch;
560 #endif /* CK_ANSIC */
561 /* le_putchar */ {
562     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
563         debug(F110,"le_putchar","buffer is full",0);
564         return(-1);
565     }
566     le_buf[le_end++] = ch;
567     if (le_end == LEBUFSIZ)
568       le_end = 0;
569     le_data = 1;
570     return(0);
571 }
572
573 int
574 #ifdef CK_ANSIC
575 le_puts(CHAR * s, int n)
576 #else
577 le_puts(s,n) CHAR * s; int n;
578 #endif /* CK_ANSIC */
579 /* le_puts */ {
580     int rc = 0;
581     int i = 0;
582     CHAR * p = (CHAR *)"le_puts";
583     hexdump(p,s,n);
584     for (i = 0; i < n; i++)
585       rc = le_putchar((char)s[i]);
586     debug(F101,"le_puts","",rc);
587     return(rc);
588 }
589
590 int
591 #ifdef CK_ANSIC
592 le_putstr(CHAR * s)
593 #else
594 le_putstr(s) CHAR * s;
595 #endif /* CK_ANSIC */
596 /* le_puts */ {
597     CHAR * p;
598     int rc = 0;
599     p = (CHAR *)"le_putstr";
600     hexdump(p,s,(int)strlen((char *)s));
601     for (p = s; *p && !rc; p++)
602       rc = le_putchar(*p);
603     return(rc);
604 }
605
606 int
607 #ifdef CK_ANSIC
608 le_getchar(CHAR * pch)
609 #else /* CK_ANSIC */
610 le_getchar(pch) CHAR * pch;
611 #endif /* CK_ANSIC */
612 /* le_gatchar */ {
613     int rc = 0;
614     if (le_start != le_end) {
615         *pch = le_buf[le_start];
616         le_buf[le_start] = 0;
617         le_start++;
618
619         if (le_start == LEBUFSIZ)
620           le_start = 0;
621
622         if (le_start == le_end) {
623             le_data = 0;
624         }
625         rc++;
626     } else {
627         *pch = 0;
628     }
629     return(rc);
630 }
631 #endif /* NETLEBUF */
632
633 #ifdef VMS
634 /*
635   In edit 190, we moved tn_ini() to be called from within netopen().
636   But tn_ini() calls ttol(), and ttol() checks to see if it's a net
637   connection, but the flag for that isn't set until after netopen()
638   is finished.  Since, in this module, we are always doing network
639   output anyway, we just call nettol() directly, instead of going thru
640   ttol().  Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
641   net connections just like regular connections in ttol(), and OS/2
642   has a special routine for this.
643 */
644 #define ttol nettol
645 #endif /* VMS */
646
647 int tcpsrfd = -1;
648
649 #ifdef CK_KERBEROS
650
651 char * krb5_d_principal = NULL;         /* Default principal */
652 char * krb5_d_instance = NULL;          /* Default instance */
653 char * krb5_d_realm = NULL;             /* Default realm */
654 char * krb5_d_cc = NULL;                /* Default credentials cache */
655 char * krb5_d_srv   = NULL;             /* Default Service */
656 int    krb5_d_lifetime = 600;           /* Default lifetime (10 hours) */
657 int    krb5_d_forwardable = 0;          /* creds not forwardable */
658 int    krb5_d_proxiable = 0;            /* creds not proxiable */
659 int    krb5_d_renewable = 0;            /* creds not renewable (0 min) */
660 int    krb5_autoget = 1;                /* Autoget TGTs */
661 int    krb5_autodel = 0;                /* Auto delete TGTs */
662 int    krb5_d_getk4 = 0;                /* K5 Kinit gets K4 TGTs */
663 int    krb5_checkaddrs = 1;             /* Check TGT Addrs */
664 int    krb5_d_no_addresses = 0;         /* Do not include IP Addresses */
665 char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
666 int    krb5_errno = 0;                  /* Last K5 errno */
667 char * krb5_errmsg = NULL;              /* Last K5 errmsg */
668 char * k5_keytab = NULL;
669
670 char * krb4_d_principal = NULL;         /* Default principal */
671 char * krb4_d_realm = NULL;             /* Default realm */
672 char * krb4_d_srv   = NULL;             /* Default Service */
673 int    krb4_d_lifetime = 600;           /* Default lifetime (10 hours) */
674 int    krb4_d_preauth = 1;              /* Use preauth requests */
675 char * krb4_d_instance = NULL;          /* Default instance */
676 int    krb4_autoget = 1;                /* Autoget TGTs */
677 int    krb4_autodel = 0;                /* Auto delete TGTs */
678 int    krb4_checkaddrs = 1;             /* Check TGT Addrs */
679 char * k4_keytab = NULL;
680
681 int    krb4_errno = 0;                  /* Last K4 errno */
682 char * krb4_errmsg = NULL;              /* Last K4 errmsg */
683
684 struct krb_op_data krb_op = {           /* Operational data structure */
685     0, NULL                             /* (version, cachefile) */
686 };
687
688 struct krb4_init_data krb4_init = {     /* Kerberos 4 INIT data structure */
689     0, NULL, NULL, NULL, NULL
690 };
691
692 struct krb5_init_data krb5_init = {     /* Kerberos 5 INIT data structure */
693     0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
694     { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
695       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
696     0
697 };
698
699 struct krb5_list_cred_data krb5_lc = {  /* List Credentials data structure */
700     0, 0, 0
701 };
702
703 int krb_action = -1;                    /* Kerberos action to perform */
704
705 #ifndef CK_AUTHENTICATION
706 char *
707 ck_krb4_getrealm() {
708     return("");
709 }
710 char *
711 ck_krb5_getrealm(cc) char * cc; {
712     return("");
713 }
714 char *
715 ck_krb4_getprincipal() {
716     return("");
717 }
718 char *
719 ck_krb5_getprincipal(cc) char * cc; {
720     return("");
721 }
722 #endif /* CK_AUTHENTICATION */
723
724 /*  I N I _ K E R B  --  Initialize Kerberos data  */
725
726 VOID
727 ini_kerb() {
728     int i;
729
730     krb_action = -1;                    /* No action specified */
731
732     krb_op.version = 0;                 /* Kerberos version (none) */
733     krb_op.cache = NULL;                /* Cache file (none) */
734
735 /* Kerberos 5 */
736
737     krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
738     krb5_init.proxiable   = krb5_d_proxiable;
739     krb5_init.lifetime    = krb5_d_lifetime;
740     krb5_init.renew       = 0;
741     krb5_init.renewable   = krb5_d_renewable;
742     krb5_init.validate    = 0;
743     krb5_init.no_addresses = krb5_d_no_addresses;
744     krb5_init.getk4       = krb5_d_getk4;
745     if (krb5_init.postdate) {
746         free(krb5_init.postdate);
747         krb5_init.postdate = NULL;
748     }
749     if (krb5_init.service) {
750         free(krb5_init.service);
751         krb5_init.service = NULL;
752     }
753     if (!krb5_d_cc || !krb5_d_cc[0]) {  /* Set default cache */
754         char * p;
755         p = ck_krb5_get_cc_name();
756         makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
757     }
758     if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
759         char * p;
760         p = ck_krb5_getrealm(krb5_d_cc);
761         makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
762     }
763     makestr(&krb5_init.instance,krb5_d_instance);
764     makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
765     if (krb5_init.password) {
766         memset(krb5_init.password,0xFF,strlen(krb5_init.password));
767         free(krb5_init.password);
768         krb5_init.password = NULL;
769     }
770     if (!krb5_d_principal) {            /* Default principal */
771         /* a Null principal indicates the user should be prompted */
772         char * p = ck_krb5_getprincipal(krb5_d_cc);
773         if (!p || !(*p))
774           p = (char *)uidbuf;           /* Principal = user */
775                 makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
776     }
777     makestr(&krb5_init.principal,krb5_d_principal);
778     for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
779         if (krb5_init.addrs[i])
780           free(krb5_init.addrs[i]);
781         krb5_init.addrs[i] = NULL;
782     }
783     for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
784         makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
785     }
786
787     /* Kerberos 4 */
788
789     krb4_init.lifetime = krb4_d_lifetime;
790     krb4_init.preauth  = krb4_d_preauth;
791     makestr(&krb4_init.instance,krb4_d_instance);
792     if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
793         char * p;
794         p = ck_krb4_getrealm();
795                 makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
796     }
797     makestr(&krb4_init.realm,krb4_d_realm);
798     if (krb4_init.password) {
799         memset(krb4_init.password,0xFF,strlen(krb4_init.password));
800         free(krb4_init.password);
801         krb4_init.password = NULL;
802     }
803     if (!krb4_d_principal) {            /* Default principal */
804         /* a Null principal indicates the user should be prompted */
805         char * p = ck_krb4_getprincipal();
806         if (!p || !(*p))
807           p = (char *)uidbuf;           /* Principal = user */
808         makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
809     }
810     makestr(&(krb4_init.principal),krb4_d_principal);
811 }
812
813 /*  D O A U T H  --  AUTHENTICATE action routine  */
814
815 int
816 doauth(cx) int cx; {                    /* AUTHENTICATE action routine */
817     int rc = 0;                         /* Return code */
818
819 #ifdef CK_AUTHENTICATION
820 #ifdef OS2
821     if (!ck_security_loaddll())         /* Load various DLLs */
822       return(rc);
823 #endif /* OS2 */
824     if (krb_op.version == 4) {          /* Version = 4 */
825 #ifdef COMMENT
826         sho_auth(AUTHTYPE_KERBEROS_V4);
827 #endif /* COMMENT */
828         if (!ck_krb4_is_installed()) {
829             printf("?Kerberos 4 is not installed\n");
830             return(0);
831         }
832         switch (krb_action) {           /* Perform V4 functions */
833           case KRB_A_IN:                /* INIT */
834             rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
835             break;
836           case KRB_A_DE:                /* DESTROY */
837             rc |= !(ck_krb4_destroy(&krb_op) < 0);
838             break;
839           case KRB_A_LC:                /* LIST-CREDENTIALS */
840             rc |= !(ck_krb4_list_creds(&krb_op) < 0);
841             break;
842         }
843     }
844     if (krb_op.version == 5) {          /* V5 functions */
845 #ifdef COMMENT
846         sho_auth(AUTHTYPE_KERBEROS_V5);
847 #endif /* COMMENT */
848         if (!ck_krb5_is_installed()) {
849             printf("?Kerberos 5 is not installed\n");
850             return(0);
851         }
852         switch (krb_action) {
853           case KRB_A_IN:                /* INIT */
854             rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
855                                      krb5_init.getk4 ? &krb4_init : 0) < 0);
856             break;
857           case KRB_A_DE:                /* DESTROY */
858             rc |= !(ck_krb5_destroy(&krb_op) < 0);
859             break;
860           case KRB_A_LC:                /* LIST-CREDENTIALS */
861             if (krb_op.version == 0)
862               printf("\n");
863             rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
864             break;
865         }
866     }
867 #else
868 #ifndef NOICP
869 #ifndef NOSHOW
870     rc = sho_auth(0);                   /* Show all */
871 #endif /* NOSHOW */
872 #endif /* NOICP */
873 #endif /* CK_AUTHENTICATION */
874     return(rc);
875 }
876 #endif /* CK_KERBEROS */
877
878 #ifdef TCPSOCKET
879 #ifndef OS2
880 #ifndef NOLISTEN                        /* For incoming connections */
881
882 #ifndef INADDR_ANY
883 #define INADDR_ANY 0
884 #endif /* INADDR_ANY */
885
886 _PROTOTYP( int ttbufr, ( VOID ) );
887 _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
888
889 static unsigned short tcpsrv_port = 0;
890
891 #endif /* NOLISTEN */
892 #endif /* OS2 */
893
894 static char svcbuf[80];                 /* TCP service string */
895 static int svcnum = 0;                  /* TCP port number */
896
897 #endif /* TCPSOCKET */
898
899 /*
900   TCPIPLIB means use separate socket calls for i/o, while on UNIX the
901   normal file system calls are used for TCP/IP sockets too.
902   Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
903 */
904
905 #ifdef TCPIPLIB
906
907 /* For buffered network reads... */
908 /*
909   If the buffering code is written right, it shouldn't matter
910   how long this buffer is.
911 */
912 #ifdef OS2
913 #ifdef NT
914 #define TTIBUFL 64240                   /* 44 * 1460 (MSS) */
915 #else
916 #define TTIBUFL 32120                   /* 22 * 1460 (MSS) */
917 #endif /* NT */
918 #else /* OS2 */
919 #define TTIBUFL 8191                    /* Let's use 8K. */
920 #endif /* OS2 */
921
922 CHAR ttibuf[TTIBUFL+1];
923
924 /*
925   select() is used in preference to alarm()/signal(), but different systems
926   use different forms of select()...
927 */
928 #ifndef NOSELECT         /* Option to override BSDSELECT */
929 #ifdef BELLV10
930 /*
931   Note: Although BELLV10 does have TCP/IP support, and does use the unique
932   form of select() that is evident in this module (and in ckutio.c), it does
933   not have a sockets library and so we can't build Kermit TCP/IP support for
934   it.  For this, somebody would have to write TCP/IP streams code.
935 */
936 #define BELLSELECT
937 #ifndef FD_SETSIZE
938 #define FD_SETSIZE 128
939 #endif /* FD_SETSIZE */
940 #else
941 #ifdef WINTCP                           /* VMS with Wollongong WIN/TCP */
942 #ifndef OLD_TWG                         /* TWG 3.2 has only select(read) */
943 #define BSDSELECT
944 #endif /* OLD_TWG */
945 #else
946 #ifdef CMU_TCPIP                        /* LIBCMU can do select */
947 #define BSDSELECT
948 #else
949 #ifdef DEC_TCPIP
950 #define BSDSELECT
951 #else
952 #ifdef OS2                              /* OS/2 with TCP/IP */
953 #ifdef NT
954 #define BSDSELECT
955 #else /* NT */
956 #define IBMSELECT
957 #endif /* NT */
958 #endif /* OS2 */
959 #endif /* DEC_TCPIP */
960 #endif /* CMU_TCPIP */
961 #endif /* WINTCP */
962 #endif /* BELLV10 */
963 #endif /* NOSELECT */
964 /*
965   Others (TGV, TCPware, ...) use alarm()/signal().  The BSDSELECT case does not
966   compile at all; the IBMSELECT case compiles and links but crashes at runtime.
967   NOTE: If any of these can be converted to select(), they should be for two
968   reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
969   their socket_read() calls to be interrupted; subsequent socket_read()'s tend
970   to fail with EBUSY.  This happened in the UCX case before it was converted
971   to use select().
972 */
973 #ifndef OS2
974 #ifndef VMS
975 static                                  /* These are used in CKVTIO.C */
976 #endif /* VMS */                        /* And in CKONET.C            */
977 #endif /* OS2 */
978 int
979   ttibp = 0,
980   ttibn = 0;
981 /*
982   Read bytes from network into internal buffer ttibuf[].
983   To be called when input buffer is empty, i.e. when ttibn == 0.
984
985   Other network reading routines, like ttinc, ttinl, ttxin, should check the
986   internal buffer first, and call this routine for a refill if necessary.
987
988   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
989   returns number of bytes read, and sets global ttibn to that number and
990   ttibp (the buffer pointer) to zero.
991 */
992 _PROTOTYP( int ttbufr, ( VOID ) );
993 int
994 ttbufr() {                              /* TT Buffer Read */
995     int count;
996
997     if (ttnet != NET_TCPB)              /* First make sure current net is */
998       return(-1);                       /* TCP/IP; if not, do nothing. */
999
1000 #ifdef OS2
1001     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1002 #endif /* OS2 */
1003
1004     if (ttibn > 0) {                    /* Our internal buffer is not empty, */
1005 #ifdef OS2
1006         ReleaseTCPIPMutex();
1007 #endif /* OS2 */
1008         return(ttibn);                  /* so keep using it. */
1009     }
1010
1011     if (ttyfd == -1) {                  /* No connection, error */
1012 #ifdef OS2
1013         ReleaseTCPIPMutex();
1014 #endif /* OS2 */
1015         return(-2);
1016     }
1017
1018     ttibp = 0;                          /* Else reset pointer to beginning */
1019
1020 #ifdef WINTCP
1021     count = 512;                        /* This works for WIN/TCP */
1022 #else
1023 #ifdef DEC_TCPIP
1024     count = 512;                        /* UCX */
1025 #else
1026 #ifdef OS2
1027     count = TTIBUFL;
1028 #else                                   /* Multinet, etc. */
1029     count = ttchk();                    /* Check network input buffer, */
1030     if (ttibn > 0) {                    /* which can put a char there! */
1031         debug(F111,"ttbufr","ttchk() returns",count);
1032 #ifdef OS2
1033         ReleaseTCPIPMutex();
1034 #endif /* OS2 */
1035         return(ttibn);
1036     }
1037     if (count < 0) {                     /* Read error - connection closed */
1038 #ifdef OS2
1039         ReleaseTCPIPMutex();
1040 #endif /* OS2 */
1041         return(-2);
1042     }
1043     else if (count > TTIBUFL)           /* Too many to read */
1044       count = TTIBUFL;
1045     else if (count == 0)                /* None, so force blocking read */
1046       count = 1;
1047 #endif /* OS2 */
1048 #endif /* DEC_TCPIP */
1049 #endif /* WINTCP */
1050     debug(F101,"ttbufr count 1","",count);
1051
1052 #ifdef CK_SSL
1053     if (ssl_active_flag || tls_active_flag) {
1054         int error;
1055       ssl_read:
1056         if (ssl_active_flag)
1057           count = SSL_read(ssl_con, ttibuf, count);
1058         else
1059           count = SSL_read(tls_con, ttibuf, count);
1060         error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
1061         switch (error) {
1062           case SSL_ERROR_NONE:
1063             debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
1064             if (count > 0) {
1065                 ttibp = 0;              /* Reset buffer pointer. */
1066                 ttibn = count;
1067 #ifdef OS2
1068                 ReleaseTCPIPMutex();
1069 #endif /* OS2 */
1070                 return(ttibn);          /* Return buffer count. */
1071             } else if (count < 0) {
1072 #ifdef OS2
1073                 ReleaseTCPIPMutex();
1074 #endif /* OS2 */
1075                 return(-1);
1076             } else {
1077                 netclos();
1078 #ifdef OS2
1079                 ReleaseTCPIPMutex();
1080 #endif /* OS2 */
1081                 return(-2);
1082             }
1083           case SSL_ERROR_WANT_WRITE:
1084             debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
1085 #ifdef OS2
1086               ReleaseTCPIPMutex();
1087 #endif /* OS2 */
1088             return(-1);
1089           case SSL_ERROR_WANT_READ:
1090             debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
1091 #ifdef OS2
1092             ReleaseTCPIPMutex();
1093 #endif /* OS2 */
1094             return(-1);
1095           case SSL_ERROR_SYSCALL:
1096               if ( count == 0 ) { /* EOF */
1097                   netclos();
1098 #ifdef OS2
1099                   ReleaseTCPIPMutex();
1100 #endif /* OS2 */
1101                   return(-2);
1102               } else {
1103                   int rc = -1;
1104 #ifdef NT
1105                   int gle = GetLastError();
1106                   debug(F111,"ttbufr SSL_ERROR_SYSCALL",
1107                          "GetLastError()",gle);
1108                   rc = os2socketerror(gle);
1109                   if (rc == -1)
1110                       rc = -2;
1111                   else if ( rc == -2 )
1112                       rc = -1;
1113 #endif /* NT */
1114 #ifdef OS2
1115                   ReleaseTCPIPMutex();
1116 #endif /* OS2 */
1117                   return(rc);
1118               }
1119           case SSL_ERROR_WANT_X509_LOOKUP:
1120             debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
1121             netclos();
1122 #ifdef OS2
1123               ReleaseTCPIPMutex();
1124 #endif /* OS2 */
1125             return(-2);
1126           case SSL_ERROR_SSL:
1127               if (bio_err!=NULL) {
1128                   int len;
1129                   extern char ssl_err[];
1130                   BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
1131                   ERR_print_errors(bio_err);
1132                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
1133                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
1134                   debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
1135                   if (ssl_debug_flag)                  
1136                       printf(ssl_err);
1137               } else if (ssl_debug_flag) {
1138                   debug(F100,"ttbufr SSL_ERROR_SSL","",0);
1139                   fflush(stderr);
1140                   fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
1141                   ERR_print_errors_fp(stderr);
1142               }
1143 #ifdef COMMENT
1144               netclos();
1145 #endif /* COMMENT */
1146 #ifdef OS2
1147               ReleaseTCPIPMutex();
1148 #endif /* OS2 */
1149             return(-2);
1150           case SSL_ERROR_ZERO_RETURN:
1151             debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
1152             netclos();
1153 #ifdef OS2
1154               ReleaseTCPIPMutex();
1155 #endif /* OS2 */
1156             return(-2);
1157           default:
1158               debug(F100,"ttbufr SSL_ERROR_?????","",0);
1159               netclos();
1160 #ifdef OS2
1161               ReleaseTCPIPMutex();
1162 #endif /* OS2 */
1163               return(-2);
1164           }
1165     }
1166 #endif /* CK_SSL */
1167
1168 #ifdef COMMENT
1169 /*
1170  This is for nonblocking reads, which we don't do any more.  This code didn't
1171  work anyway, in the sense that a broken connection was never sensed.
1172 */
1173     if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
1174         if (count == -1 && socket_errno == EWOULDBLOCK) {
1175             debug(F100,"ttbufr finds nothing","",0);
1176 #ifdef OS2
1177             ReleaseTCPIPMutex();
1178 #endif /* OS2 */
1179             return(0);
1180         } else {
1181             debug(F101,"ttbufr socket_read error","",socket_errno);
1182 #ifdef OS2
1183             ReleaseTCPIPMutex();
1184 #endif /* OS2 */
1185             return(-1);
1186         }
1187
1188     } else if (count == 0) {
1189         debug(F100,"ttbufr socket eof","",0);
1190 #ifdef OS2
1191         ReleaseTCPIPMutex();
1192 #endif /* OS2 */
1193         return(-1);
1194     }
1195 #else /* COMMENT */
1196
1197 /* This is for blocking reads */
1198
1199 #ifndef VMS
1200 #ifdef SO_OOBINLINE
1201     {
1202         int outofband = 0;
1203 #ifdef BELLSELECT
1204         if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
1205           outofband = 1;
1206 #else
1207 #ifdef BSDSELECT
1208         fd_set efds;
1209         struct timeval tv;
1210         FD_ZERO(&efds);
1211         FD_SET(ttyfd, &efds);
1212         tv.tv_sec  = tv.tv_usec = 0L;
1213         debug(F100,"Out-of-Band BSDSELECT","",0);
1214 #ifdef NT
1215         WSASafeToCancel = 1;
1216 #endif /* NT */
1217         if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
1218             FD_ISSET(ttyfd, &efds))
1219           outofband = 1;
1220 #ifdef NT
1221         WSASafeToCancel = 0;
1222 #endif /* NT */
1223 #else /* !BSDSELECT */
1224 #ifdef IBMSELECT
1225 /* Is used by OS/2 ... */
1226 /* ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set */
1227 /* and timeval stuff since this is the only place where it is used. */
1228         int socket = ttyfd;
1229         debug(F100,"Out-of-Band IBMSELECT","",0);
1230         if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
1231           outofband = 1;
1232 #else /* !IBMSELECT */
1233 /*
1234   If we can't use select(), then we use the regular alarm()/signal()
1235   timeout mechanism.
1236 */
1237       debug(F101,"Out-of-Band data not supported","",0);
1238       outofband = 0;
1239
1240 #endif /* IBMSELECT */
1241 #endif /* BSDSELECT */
1242 #endif /* BELLSELECT */
1243       if (outofband) {
1244          /* Get the Urgent Data */
1245          /* if OOBINLINE is disabled this should be only a single byte      */
1246          /* MS Winsock has a bug in Windows 95.  Extra bytes are delivered  */
1247          /* That were never sent.                                           */
1248 #ifdef OS2
1249           RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1250 #endif /* OS2 */
1251           count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
1252 #ifdef OS2
1253           ReleaseTCPIPMutex();
1254 #endif /* OS2 */
1255           if (count <= 0) {
1256               int s_errno = socket_errno;
1257               debug(F101, "ttbufr socket_recv MSG_OOB","",count);
1258               debug(F101, "ttbufr socket_errno","",s_errno);
1259 #ifdef OS2ONLY
1260               if (count < 0 && (s_errno == 0 || s_errno == 23)) {
1261                   /* These appear in OS/2 - don't know why   */
1262                   /* ignore it and read as normal data       */
1263                   /* and break, then we will attempt to read */
1264                   /* the port using normal read() techniques */
1265                   debug(F100,"ttbufr handing as in-band data","",0);
1266                   count = 1;
1267               } else {
1268                   netclos();                    /* *** *** */
1269 #ifdef OS2
1270                   ReleaseTCPIPMutex();
1271 #endif /* OS2 */
1272                   return(-2);
1273               }
1274 #else /* OS2ONLY */
1275               netclos();                        /* *** *** */
1276 #ifdef OS2
1277               ReleaseTCPIPMutex();
1278 #endif /* OS2 */
1279               return(-2);
1280 #endif /* OS2ONLY */
1281           } else {                      /* we got out-of-band data */
1282               hexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
1283 #ifdef BETADEBUG
1284               bleep(BP_NOTE);
1285 #endif /* BETADEBUG */
1286 #ifdef RLOGCODE                         /* blah */
1287               if (ttnproto == NP_RLOGIN  ||
1288                   ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
1289                   ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) && 
1290                   !rlog_inband)
1291                    )
1292               {
1293                   /*
1294                     When urgent data is read with MSG_OOB and not OOBINLINE
1295                     then urgent data and normal data are not mixed.  So
1296                     treat the entire buffer as urgent data.
1297                   */
1298                   rlog_oob(&ttibuf[ttibp+ttibn], count);
1299 #ifdef OS2
1300                   ReleaseTCPIPMutex();
1301 #endif /* OS2 */
1302                   return ttbufr();
1303               } else
1304 #endif /* RLOGCODE */ /* blah */
1305 #ifdef COMMENT
1306             /*
1307                I haven't written this yet, nor do I know what it should do
1308              */
1309                 if (ttnproto == NP_TELNET) {
1310                     tn_oob();
1311 #ifdef OS2
1312                     ReleaseTCPIPMutex();
1313 #endif /* OS2 */
1314                     return 0;
1315               } else
1316 #endif /* COMMENT */
1317               {
1318                   /* For any protocols we don't have a special out-of-band  */
1319                   /* handler for, just put the bytes in the normal buffer   */
1320                   /* and return                                             */
1321
1322                   ttibp += 0;       /* Reset buffer pointer. */
1323                   ttibn += count;
1324 #ifdef DEBUG
1325                   /* Got some bytes. */
1326                   debug(F101,"ttbufr count 2","",count);
1327                   if (count > 0)
1328                       ttibuf[ttibp+ttibn] = '\0';
1329                   debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
1330 #endif /* DEBUG */
1331 #ifdef OS2
1332                   ReleaseTCPIPMutex();
1333 #endif /* OS2 */
1334                   return(ttibn);    /* Return buffer count. */
1335               }
1336           }
1337       }
1338     }
1339 #endif /* SO_OOBINLINE */
1340 #endif /* VMS */
1341
1342     count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
1343     if (count <= 0) {
1344         int s_errno = socket_errno;
1345         debug(F101,"ttbufr socket_read","",count);
1346         debug(F101,"ttbufr socket_errno","",s_errno);
1347 #ifdef OS2
1348         if (count == 0 || os2socketerror(s_errno) < 0) {
1349             netclos();
1350             ReleaseTCPIPMutex();
1351             return(-2);
1352         }
1353         ReleaseTCPIPMutex();
1354         return(-1);
1355 #else /* OS2 */
1356         netclos();                      /* *** *** */
1357         return(-2);
1358 #endif /* OS2 */
1359     }
1360 #endif /* COMMENT */ /* (blocking vs nonblock reads...) */
1361     else {
1362         ttibp = 0;                      /* Reset buffer pointer. */
1363         ttibn += count;
1364 #ifdef DEBUG
1365         debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
1366         if (count > 0)
1367           ttibuf[ttibp+ttibn] = '\0';
1368         debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
1369 #endif /* DEBUG */
1370
1371 #ifdef OS2
1372         ReleaseTCPIPMutex();
1373 #endif /* OS2 */
1374         return(ttibn);                  /* Return buffer count. */
1375     }
1376 }
1377 #endif /* TCPIPLIB */
1378
1379 #ifndef IBMSELECT
1380 #ifndef BELLSELECT
1381 #ifndef BSDSELECT               /* Non-TCPIPLIB case */
1382 #ifdef SELECT
1383 #define BSDSELECT
1384 #endif /* SELECT */
1385 #endif /* BSDSELECT */
1386 #endif /* BELLSELECT */
1387 #endif /* IBMSELECT */
1388
1389 #define TELNET_PORT 23          /* Should do lookup, but it won't change */
1390 #define RLOGIN_PORT 513
1391 #define KERMIT_PORT 1649
1392 #define KLOGIN_PORT 543
1393 #define EKLOGIN_PORT 2105
1394
1395 #ifndef NONET
1396 /*
1397   C-Kermit network open/close functions for BSD-sockets.
1398   Much of this code shared by SunLink X.25, which also uses the socket library.
1399 */
1400
1401 /*  N E T O P N  --  Open a network connection.  */
1402 /*
1403   Call with:
1404     name of host (or host:service),
1405     lcl - local-mode flag to be set if this function succeeds,
1406     network type - value defined in ckunet.h.
1407 */
1408 #ifdef TCPSOCKET
1409 struct hostent *
1410 #ifdef CK_ANSIC
1411 ck_copyhostent(struct hostent * h)
1412 #else /* CK_ANSIC */
1413 ck_copyhostent(h) struct hostent * h;
1414 #endif /* CK_ANSIC */
1415 {
1416     /*
1417      *  The hostent structure is dynamic in nature.
1418      *  struct  hostent {
1419      *  char    * h_name;
1420      *  char    * * h_aliases;
1421      *  short   h_addrtype;
1422      *  short   h_length;
1423      *  char    * * h_addr_list;
1424      *  #define h_addr  h_addr_list[0]
1425      */
1426 #define HOSTENTCNT 5
1427     static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
1428                                                {NULL,NULL,0,0,NULL},
1429                                                {NULL,NULL,0,0,NULL},
1430                                                {NULL,NULL,0,0,NULL},
1431                                                {NULL,NULL,0,0,NULL}};
1432     static int    next = 0;
1433     int    i,cnt;
1434     char ** pp;
1435
1436     if ( h == NULL )
1437         return(NULL);
1438
1439     if (next == HOSTENTCNT)
1440         next = 0;
1441
1442     if ( hosts[next].h_name ) {
1443         free(hosts[next].h_name);
1444         hosts[next].h_name = NULL;
1445     }
1446     if ( hosts[next].h_aliases ) {
1447         pp = hosts[next].h_aliases;
1448         while ( *pp ) {
1449             free(*pp);
1450             pp++;
1451         }
1452         free(hosts[next].h_aliases);
1453     }
1454 #ifdef HADDRLIST
1455     if ( hosts[next].h_addr_list ) {
1456         pp = hosts[next].h_addr_list;
1457         while ( *pp ) {
1458             free(*pp);
1459             pp++;
1460         }
1461         free(hosts[next].h_addr_list);
1462     }
1463 #endif /* HADDRLIST */
1464
1465     makestr(&hosts[next].h_name,h->h_name);
1466     if (h->h_aliases) {
1467         for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
1468         /* The following can give warnings in non-ANSI builds */
1469         hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
1470         for ( i=0; i<cnt; i++) {
1471             hosts[next].h_aliases[i] = NULL;
1472             makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
1473         }
1474         hosts[next].h_aliases[i] = NULL;
1475     } else
1476         hosts[next].h_aliases = NULL;
1477
1478     hosts[next].h_addrtype = h->h_addrtype;
1479     hosts[next].h_length = h->h_length;
1480
1481 #ifdef HADDRLIST
1482 #ifdef h_addr
1483     if (h->h_addr_list) {
1484         for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
1485         /* The following can give warnings non-ANSI builds */
1486         hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
1487         for ( i=0; i<cnt; i++) {
1488             hosts[next].h_addr_list[i] = malloc(h->h_length);
1489             bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
1490         }
1491         hosts[next].h_addr_list[i] = NULL;
1492     } else
1493         hosts[next].h_addr_list = NULL;
1494 #else
1495     bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1496 #endif /* h_addr */
1497 #else /* HADDRLIST */
1498     bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1499 #endif /* HADDRLIST */
1500
1501     return(&hosts[next++]);
1502 }
1503
1504 #ifdef EXCELAN
1505 /*
1506   Most other BSD sockets implementations define these in header files
1507   and libraries.
1508 */
1509 struct servent {
1510     unsigned short s_port;
1511 };
1512
1513 struct hostent {
1514     short h_addrtype;
1515     struct in_addr h_addr;
1516     int h_length;
1517 };
1518
1519 struct servent *
1520 getservbyname(service, connection) char *service,*connection; {
1521     static struct servent servrec;
1522     int port;
1523
1524     port = 0;
1525     if (strcmp(service, "telnet") == 0) port = 23;
1526     else if (strcmp(service, "smtp") == 0) port = 25;
1527     else port = atoi(service);
1528
1529     debug(F101,"getservbyname return port ","",port);
1530
1531     if (port > 0) {
1532         servrec.s_port = htons(port);
1533         return(&servrec);
1534     }
1535     return((struct servent *) NULL);
1536 }
1537
1538 struct hostent *
1539 gethostbyname(hostname) char *hostname; {
1540     return((struct hostent *) NULL);
1541 }
1542
1543 unsigned long
1544 inet_addr(name) char *name; {
1545     unsigned long addr;
1546
1547     addr = rhost(&name);
1548     debug(F111,"inet_addr ",name,(int)addr);
1549     return(addr);
1550 }
1551
1552 char *
1553 inet_ntoa(in) struct in_addr in; {
1554     static char name[80];
1555     ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
1556                ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
1557     return(name);
1558 }
1559 #else
1560 #ifdef DEC_TCPIP                        /* UCX */
1561
1562 int ucx_port_bug = 0;                   /* Explained below */
1563
1564 #ifndef __DECC                          /* VAXC or GCC */
1565
1566 #define getservbyname my_getservbyname
1567
1568 #ifdef CK_ANSIC
1569 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1570 extern void C$$TRANSLATE();
1571 extern void C$$SOCK_TRANSLATE();
1572 #else
1573 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1574 extern VOID C$$TRANSLATE();
1575 extern VOID C$$SOCK_TRANSLATE();
1576 #endif /* CK_ANSIC */
1577
1578 struct servent *
1579 my_getservbyname (service, proto) char *service, *proto; {
1580     static struct servent sent;
1581     struct iosb {
1582         union {
1583             unsigned long status;
1584             unsigned short st[2];
1585         } sb;
1586         unsigned long spare;
1587     } s;
1588     struct {
1589         struct iosb *s;
1590         char *serv;
1591         char *prot;
1592     } par;
1593     unsigned long e;
1594     char sbuf[30], pbuf[30];
1595     char *p;
1596
1597     debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
1598
1599     p = sbuf;
1600     ckstrncpy(p, service, 29);
1601     while (*p = toupper(*p), *p++) {}
1602     p = pbuf;
1603     ckstrncpy(p, proto, 29);
1604     while (*p = toupper(*p), *p++) {}
1605
1606     par.s = &s;
1607
1608     par.serv = "";
1609     par.prot = "";
1610     /* reset file pointer or something like that!?!? */
1611     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1612     par.serv = sbuf;
1613     par.prot = pbuf;            /* that is don't care */
1614     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1615     if ((long)e == -1L)
1616       return NULL;
1617     if ((e & 1) == 0L) {
1618         C$$TRANSLATE(e);
1619         return NULL;
1620     }
1621     if ((s.sb.st[0] & 1) == 0) {
1622         C$$SOCK_TRANSLATE(&s.sb.st[0]);
1623         return NULL;
1624     }
1625 /*
1626   sent.s_port is supposed to be returned by UCX in network byte order.
1627   However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
1628   But there is no way of knowing which UCX version, so we have a user-settable
1629   runtime variable.  Note: UCX 2.0 was only for the VAX.
1630 */
1631     debug(F101,"UCX getservbyname port","",sent.s_port);
1632     debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
1633     if (ucx_port_bug) {
1634         sent.s_port = htons(sent.s_port);
1635         debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
1636         debug(F101,"UCX swapped port","",sent.s_port);
1637         debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
1638     }
1639     return &sent;
1640 }
1641 #endif /* __DECC */
1642 #endif /* DEC_TCPIP */
1643 #endif /* EXCELAN */
1644 #endif /* TCPSOCKET */
1645
1646 #ifndef NOTCPOPTS
1647 #ifndef datageneral
1648 int
1649 ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
1650 /*
1651   The following, from William Bader, turns off the socket linger parameter,
1652   which makes a close() block until all data is sent.  "I don't think that
1653   disabling linger can ever cause kermit to lose data, but you telnet to a
1654   flaky server (or to our modem server when the modem is in use), disabling
1655   linger prevents kermit from hanging on the close if you try to exit."
1656
1657   Modified by Jeff Altman to be generally useful.
1658 */
1659 #ifdef SOL_SOCKET
1660 #ifdef SO_LINGER
1661     struct linger set_linger_opt;
1662     struct linger get_linger_opt;
1663     SOCKOPT_T x;
1664
1665 #ifdef IKSD
1666     if (!inserver)
1667 #endif /* IKSD */
1668       if (sock == -1 ||
1669         nettype != NET_TCPA && nettype != NET_TCPB &&
1670         nettype != NET_SSH || ttmdm >= 0) {
1671         tcp_linger = onoff;
1672         tcp_linger_tmo = timo;
1673         return(1);
1674     }
1675     x = sizeof(get_linger_opt);
1676     if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
1677                     (char *)&get_linger_opt, &x)) {
1678         debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1679     } else if (x != sizeof(get_linger_opt)) {
1680 #ifdef OS2
1681         struct _linger16 {
1682             short s_linger;
1683             short s_onoff;
1684         } get_linger_opt16, set_linger_opt16;
1685         if ( x == sizeof(get_linger_opt16) ) {
1686             debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
1687             if (getsockopt(sock,
1688                            SOL_SOCKET, SO_LINGER,
1689                            (char *)&get_linger_opt16, &x)
1690                 ) {
1691                 debug(F111,
1692                       "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1693             } else if (get_linger_opt16.s_onoff != onoff ||
1694                        get_linger_opt16.s_linger != timo)
1695             {
1696                 set_linger_opt16.s_onoff  = onoff;
1697                 set_linger_opt16.s_linger = timo;
1698                 if (setsockopt(sock,
1699                                SOL_SOCKET,
1700                                SO_LINGER,
1701                                (char *)&set_linger_opt16,
1702                                sizeof(set_linger_opt16))
1703                     ) {
1704                     debug(F111,
1705                           "TCP ck_linger can't set SO_LINGER",
1706                           ck_errstr(),
1707                           errno
1708                           );
1709                     tcp_linger = get_linger_opt16.s_onoff;
1710                     tcp_linger_tmo = get_linger_opt16.s_linger;
1711                 } else {
1712                     debug(F101,
1713                           "TCP ck_linger new SO_LINGER","",
1714                           set_linger_opt16.s_onoff);
1715                     tcp_linger = set_linger_opt16.s_onoff;
1716                     tcp_linger_tmo = set_linger_opt16.s_linger;
1717                     return 1;
1718                 }
1719             } else {
1720                 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1721                        get_linger_opt16.s_onoff);
1722                 tcp_linger = get_linger_opt16.s_onoff;
1723                 tcp_linger_tmo = get_linger_opt16.s_linger;
1724                 return 1;
1725             }
1726             return(0);
1727         }
1728 #endif /* OS2 */
1729         debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
1730         debug(F111,"TCP ck_linger SO_LINGER",
1731               "expected len",sizeof(get_linger_opt));
1732         debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
1733               get_linger_opt.l_onoff);
1734         debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
1735                get_linger_opt.l_linger);
1736     } else if (get_linger_opt.l_onoff != onoff ||
1737                get_linger_opt.l_linger != timo) {
1738         set_linger_opt.l_onoff  = onoff;
1739         set_linger_opt.l_linger = timo;
1740         if (setsockopt(sock,
1741                        SOL_SOCKET,
1742                        SO_LINGER,
1743                        (char *)&set_linger_opt,
1744                        sizeof(set_linger_opt))) {
1745             debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
1746             tcp_linger = get_linger_opt.l_onoff;
1747             tcp_linger_tmo = get_linger_opt.l_linger;
1748          } else {
1749              debug(F101,
1750                    "TCP ck_linger new SO_LINGER",
1751                    "",
1752                    set_linger_opt.l_onoff
1753                    );
1754              tcp_linger = set_linger_opt.l_onoff;
1755              tcp_linger_tmo = set_linger_opt.l_linger;
1756              return 1;
1757          }
1758     } else {
1759         debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1760               get_linger_opt.l_onoff);
1761         tcp_linger = get_linger_opt.l_onoff;
1762         tcp_linger_tmo = get_linger_opt.l_linger;
1763         return 1;
1764     }
1765 #else
1766     debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
1767 #endif /* SO_LINGER */
1768 #else
1769     debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
1770 #endif /* SOL_SOCKET */
1771     return(0);
1772 }
1773
1774 int
1775 sendbuf(sock,size) int sock; int size; {
1776 /*
1777   The following, from William Bader, allows changing of socket buffer sizes,
1778   in case that might affect performance.
1779
1780   Modified by Jeff Altman to be generally useful.
1781 */
1782 #ifdef SOL_SOCKET
1783 #ifdef SO_SNDBUF
1784     int i, j;
1785     SOCKOPT_T x;
1786
1787 #ifdef IKSD
1788     if (!inserver)
1789 #endif /* IKSD */
1790       if (sock == -1 ||
1791         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1792                 || ttmdm >= 0) {
1793         tcp_sendbuf = size;
1794         return 1;
1795     }
1796     x = sizeof(i);
1797     if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
1798         debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
1799     } else if (x != sizeof(i)) {
1800 #ifdef OS2
1801         short i16,j16;
1802         if (x == sizeof(i16)) {
1803             debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
1804             if (getsockopt(sock,
1805                            SOL_SOCKET, SO_SNDBUF,
1806                            (char *)&i16, &x)
1807                 ) {
1808                 debug(F111,"TCP sendbuf can't get SO_SNDBUF",
1809                       ck_errstr(),errno);
1810             } else if (size <= 0) {
1811                 tcp_sendbuf = i16;
1812                 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
1813                 return 1;
1814             } else if (i16 != size) {
1815                 j16 = size;
1816                 if (setsockopt(sock,
1817                                SOL_SOCKET,
1818                                SO_SNDBUF,
1819                                (char *)&j16,
1820                                sizeof(j16))
1821                     ) {
1822                     debug(F111,"TCP sendbuf can't set SO_SNDBUF",
1823                           ck_errstr(),errno);
1824                 } else {
1825                     debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
1826                     debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
1827                     tcp_sendbuf = size;
1828                     return 1;
1829                 }
1830             } else {
1831                 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
1832                 tcp_sendbuf = size;
1833                 return 1;
1834             }
1835             return(0);
1836         }
1837 #endif /* OS2 */
1838         debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
1839         debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
1840         debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
1841     } else if (size <= 0) {
1842         tcp_sendbuf = i;
1843         debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
1844         return 1;
1845     } else if (i != size) {
1846         j = size;
1847         if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
1848             debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
1849             tcp_sendbuf = i;
1850         } else {
1851             debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
1852             debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
1853             tcp_sendbuf = size;
1854             return 1;
1855         }
1856     } else {
1857         debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
1858         tcp_sendbuf = size;
1859         return 1;
1860     }
1861 #else
1862     debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
1863 #endif /* SO_SNDBUF */
1864 #else
1865     debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
1866 #endif /* SOL_SOCKET */
1867     return(0);
1868 }
1869
1870 int
1871 recvbuf(sock,size) int sock; int size; {
1872 /*
1873   The following, from William Bader, allows changing of socket buffer sizes,
1874   in case that might affect performance.
1875
1876   Modified by Jeff Altman to be generally useful.
1877 */
1878 #ifdef SOL_SOCKET
1879 #ifdef SO_RCVBUF
1880     int i, j;
1881     SOCKOPT_T x;
1882
1883 #ifdef IKSD
1884     if (!inserver)
1885 #endif /* IKSD */
1886       if (sock == -1 ||
1887           nettype != NET_TCPA && nettype != NET_TCPB &&
1888           nettype != NET_SSH || ttmdm >= 0) {
1889         tcp_recvbuf = size;
1890         return(1);
1891     }
1892     x = sizeof(i);
1893     if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
1894         debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
1895     } else if (x != sizeof(i)) {
1896 #ifdef OS2
1897         short i16,j16;
1898         if ( x == sizeof(i16) ) {
1899             debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
1900             if (getsockopt(sock,
1901                            SOL_SOCKET, SO_RCVBUF,
1902                            (char *)&i16, &x)
1903                 ) {
1904                 debug(F111,"TCP recvbuf can't get SO_RCVBUF",
1905                       ck_errstr(),errno);
1906             } else if (size <= 0) {
1907                 tcp_recvbuf = i16;
1908                 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
1909                 return 1;
1910             } else if (i16 != size) {
1911                 j16 = size;
1912                 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
1913                                sizeof(j16))) {
1914                     debug(F111,"TCP recvbuf can' set SO_RCVBUF",
1915                           ck_errstr(),errno);
1916                 } else {
1917                     debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
1918                     debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
1919                     tcp_recvbuf = size;
1920                     return 1;
1921                 }
1922             } else {
1923                 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
1924                 tcp_recvbuf = size;
1925                 return 1;
1926             }
1927             return(0);
1928         }
1929 #endif /* OS2 */
1930         debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
1931         debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
1932         debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
1933     } else if (size <= 0) {
1934         tcp_recvbuf = i;
1935         debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
1936         return 1;
1937     } else if (i != size) {
1938         j = size;
1939         if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
1940             debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
1941             tcp_recvbuf = i;
1942         } else {
1943             debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
1944             debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
1945             tcp_recvbuf = size;
1946             return 1;
1947         }
1948     } else {
1949         debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
1950         tcp_recvbuf = size;
1951         return 1;
1952     }
1953 #else
1954     debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
1955 #endif /* SO_RCVBUF */
1956 #else
1957     debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
1958 #endif /* SOL_SOCKET */
1959     return 0;
1960 }
1961
1962 int
1963 keepalive(sock,onoff) int sock; int onoff; {
1964 #ifdef SOL_SOCKET
1965 #ifdef SO_KEEPALIVE
1966     int get_keepalive_opt;
1967     int set_keepalive_opt;
1968     SOCKOPT_T x;
1969
1970     debug(F111,"TCP keepalive","sock",sock);
1971     debug(F111,"TCP keepalive","nettype",nettype);
1972     debug(F111,"TCP keepalive","ttmdm",ttmdm);
1973
1974 #ifdef IKSD
1975     if (!inserver)
1976 #endif /* IKSD */
1977       if (sock == -1 ||
1978         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1979                 || ttmdm >= 0) {
1980         tcp_keepalive = onoff;
1981         return 1;
1982     }
1983     x = sizeof(get_keepalive_opt);
1984     if (getsockopt(sock,
1985                    SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
1986         debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
1987     } else if (x != sizeof(get_keepalive_opt)) {
1988 #ifdef OS2
1989         short get_keepalive_opt16;
1990         short set_keepalive_opt16;
1991         if (x == sizeof(get_keepalive_opt16)) {
1992             debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
1993                   "len is 16-bit",x);
1994             if (getsockopt(sock,
1995                            SOL_SOCKET, SO_KEEPALIVE,
1996                            (char *)&get_keepalive_opt16, &x)
1997                 ) {
1998                 debug(F111,
1999                       "TCP keepalive can't get SO_KEEPALIVE",
2000                       ck_errstr(),
2001                       errno
2002                       );
2003             } else if (get_keepalive_opt16 != onoff) {
2004                 set_keepalive_opt16 = onoff;
2005                 if (setsockopt(sock,
2006                                SOL_SOCKET,
2007                                SO_KEEPALIVE,
2008                                (char *)&set_keepalive_opt16,
2009                                sizeof(set_keepalive_opt16))
2010                     ) {
2011                     debug(F111,
2012                           "TCP keepalive can't clear SO_KEEPALIVE",
2013                           ck_errstr(),
2014                           errno
2015                           );
2016                     tcp_keepalive = get_keepalive_opt16;
2017                 } else {
2018                     debug(F101,
2019                           "TCP keepalive new SO_KEEPALIVE","",
2020                           set_keepalive_opt16);
2021                     tcp_keepalive = set_keepalive_opt16;
2022                     return 1;
2023                 }
2024             } else {
2025                 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
2026                       get_keepalive_opt16);
2027                 tcp_keepalive = onoff;
2028                 return 1;
2029             }
2030             return(0);
2031         }
2032 #endif /* OS2 */
2033         debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
2034         debug(F111,
2035               "TCP keepalive SO_KEEPALIVE",
2036               "expected len",
2037               sizeof(get_keepalive_opt)
2038               );
2039         debug(F111,
2040               "TCP keepalive SO_KEEPALIVE",
2041               "keepalive_opt",
2042               get_keepalive_opt
2043               );
2044     } else if (get_keepalive_opt != onoff) {
2045             set_keepalive_opt = onoff;
2046             if (setsockopt(sock,
2047                             SOL_SOCKET,
2048                             SO_KEEPALIVE,
2049                             (char *)&set_keepalive_opt,
2050                             sizeof(set_keepalive_opt))
2051                 ) {
2052                 debug(F111,
2053                       "TCP keepalive can't clear SO_KEEPALIVE",
2054                       ck_errstr(),
2055                       errno
2056                       );
2057                 tcp_keepalive = get_keepalive_opt;
2058             } else {
2059                 debug(F101,
2060                       "TCP keepalive new SO_KEEPALIVE",
2061                       "",
2062                       set_keepalive_opt
2063                       );
2064                 tcp_keepalive = onoff;
2065                 return 1;
2066             }
2067         } else {
2068             debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
2069                   "",
2070                   get_keepalive_opt
2071                   );
2072             tcp_keepalive = onoff;
2073             return 1;
2074     }
2075 #else
2076     debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
2077 #endif /* SO_KEEPALIVE */
2078 #else
2079     debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
2080 #endif /* SOL_SOCKET */
2081     return(0);
2082 }
2083
2084 int
2085 dontroute(sock,onoff) int sock; int onoff; {
2086 #ifdef SOL_SOCKET
2087 #ifdef SO_DONTROUTE
2088     int get_dontroute_opt;
2089     int set_dontroute_opt;
2090     SOCKOPT_T x;
2091
2092 #ifdef IKSD
2093     if (!inserver)
2094 #endif /* IKSD */
2095       if (sock == -1 ||
2096         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2097                 || ttmdm >= 0) {
2098         tcp_dontroute = onoff;
2099         return 1;
2100     }
2101     x = sizeof(get_dontroute_opt);
2102     if (getsockopt(sock,
2103                    SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
2104         debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
2105     } else if (x != sizeof(get_dontroute_opt)) {
2106 #ifdef OS2
2107         short get_dontroute_opt16;
2108         short set_dontroute_opt16;
2109         if (x == sizeof(get_dontroute_opt16)) {
2110             debug(F111,"TCP dontroute warning: SO_DONTROUTE",
2111                   "len is 16-bit",x);
2112             if (getsockopt(sock,
2113                            SOL_SOCKET, SO_DONTROUTE,
2114                            (char *)&get_dontroute_opt16, &x)
2115                 ) {
2116                 debug(F111,
2117                       "TCP dontroute can't get SO_DONTROUTE",
2118                       ck_errstr(),
2119                       errno
2120                       );
2121             } else if (get_dontroute_opt16 != onoff) {
2122                 set_dontroute_opt16 = onoff;
2123                 if (setsockopt(sock,
2124                                SOL_SOCKET,
2125                                SO_DONTROUTE,
2126                                (char *)&set_dontroute_opt16,
2127                                sizeof(set_dontroute_opt16))
2128                     ) {
2129                     debug(F111,
2130                           "TCP dontroute can't clear SO_DONTROUTE",
2131                           ck_errstr(),
2132                           errno
2133                           );
2134                     tcp_dontroute = get_dontroute_opt16;
2135                 } else {
2136                     debug(F101,
2137                           "TCP dontroute new SO_DONTROUTE","",
2138                           set_dontroute_opt16);
2139                     tcp_dontroute = set_dontroute_opt16;
2140                     return 1;
2141                 }
2142             } else {
2143                 debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
2144                       get_dontroute_opt16);
2145                 tcp_dontroute = onoff;
2146                 return 1;
2147             }
2148             return(0);
2149         }
2150 #endif /* OS2 */
2151         debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
2152         debug(F111,
2153               "TCP dontroute SO_DONTROUTE",
2154               "expected len",
2155               sizeof(get_dontroute_opt)
2156               );
2157         debug(F111,
2158               "TCP dontroute SO_DONTROUTE",
2159               "dontroute_opt",
2160               get_dontroute_opt
2161               );
2162     } else if (get_dontroute_opt != onoff) {
2163             set_dontroute_opt = onoff;
2164             if (setsockopt(sock,
2165                             SOL_SOCKET,
2166                             SO_DONTROUTE,
2167                             (char *)&set_dontroute_opt,
2168                             sizeof(set_dontroute_opt))
2169                 ) {
2170                 debug(F111,
2171                       "TCP dontroute can't clear SO_DONTROUTE",
2172                       ck_errstr(),
2173                       errno
2174                       );
2175                 tcp_dontroute = get_dontroute_opt;
2176             } else {
2177                 debug(F101,
2178                       "TCP dontroute new SO_DONTROUTE",
2179                       "",
2180                       set_dontroute_opt
2181                       );
2182                 tcp_dontroute = onoff;
2183                 return 1;
2184             }
2185         } else {
2186             debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
2187                   "",
2188                   get_dontroute_opt
2189                   );
2190             tcp_dontroute = onoff;
2191             return 1;
2192     }
2193 #else
2194     debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
2195 #endif /* SO_DONTROUTE */
2196 #else
2197     debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
2198 #endif /* SOL_SOCKET */
2199     return(0);
2200 }
2201
2202 int
2203 no_delay(sock,onoff)  int sock; int onoff; {
2204 #ifdef SOL_SOCKET
2205 #ifdef TCP_NODELAY
2206     int get_nodelay_opt;
2207     int set_nodelay_opt;
2208     SOCKOPT_T x;
2209
2210 #ifdef IKSD
2211     if (!inserver)
2212 #endif /* IKSD */
2213       if (sock == -1 ||
2214         nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2215                 || ttmdm >= 0) {
2216         tcp_nodelay = onoff;
2217         return(1);
2218     }
2219     x = sizeof(get_nodelay_opt);
2220     if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
2221                    (char *)&get_nodelay_opt,&x)) {
2222         debug(F111,
2223               "TCP no_delay can't get TCP_NODELAY",
2224               ck_errstr(),
2225               errno);
2226     } else if (x != sizeof(get_nodelay_opt)) {
2227 #ifdef OS2
2228         short get_nodelay_opt16;
2229         short set_nodelay_opt16;
2230         if (x == sizeof(get_nodelay_opt16)) {
2231             debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
2232             if (getsockopt(sock,
2233                            IPPROTO_TCP, TCP_NODELAY,
2234                            (char *)&get_nodelay_opt16, &x)
2235                 ) {
2236                 debug(F111,
2237                       "TCP no_delay can't get TCP_NODELAY",
2238                       ck_errstr(),
2239                       errno);
2240             } else if (get_nodelay_opt16 != onoff) {
2241                 set_nodelay_opt16 = onoff;
2242                 if (setsockopt(sock,
2243                                IPPROTO_TCP,
2244                                TCP_NODELAY,
2245                                (char *)&set_nodelay_opt16,
2246                                sizeof(set_nodelay_opt16))
2247                     ) {
2248                     debug(F111,
2249                           "TCP no_delay can't clear TCP_NODELAY",
2250                           ck_errstr(),
2251                           errno);
2252                     tcp_nodelay = get_nodelay_opt16;
2253                 } else {
2254                     debug(F101,
2255                           "TCP no_delay new TCP_NODELAY",
2256                           "",
2257                           set_nodelay_opt16);
2258                     tcp_nodelay = onoff;
2259                     return 1;
2260                 }
2261             } else {
2262                 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
2263                       get_nodelay_opt16);
2264                 tcp_nodelay = onoff;
2265                 return 1;
2266             }
2267             return(0);
2268         }
2269 #endif /* OS2 */
2270         debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
2271         debug(F111,"TCP no_delay TCP_NODELAY","expected len",
2272               sizeof(get_nodelay_opt));
2273         debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
2274     } else if (get_nodelay_opt != onoff) {
2275         set_nodelay_opt = onoff;
2276         if (setsockopt(sock,
2277                        IPPROTO_TCP,
2278                        TCP_NODELAY,
2279                        (char *)&set_nodelay_opt,
2280                        sizeof(set_nodelay_opt))) {
2281             debug(F111,
2282                   "TCP no_delay can't clear TCP_NODELAY",
2283                   ck_errstr(),
2284                   errno
2285                   );
2286             tcp_nodelay = get_nodelay_opt;
2287         } else {
2288             debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
2289             tcp_nodelay = onoff;
2290             return 1;
2291         }
2292     } else {
2293         debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
2294         tcp_nodelay = onoff;
2295         return(1);
2296     }
2297 #else
2298     debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
2299 #endif /* TCP_NODELAY */
2300 #else
2301     debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
2302 #endif /* SOL_SOCKET */
2303     return 0;
2304 }
2305 #endif /* datageneral */
2306 #endif /* NOTCPOPTS */
2307
2308 #ifdef SUNX25
2309 #ifndef X25_WR_FACILITY
2310 /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
2311 void
2312 bzero(s,n) char *s; int n; {
2313     memset(s,0,n);
2314 }
2315 #endif /* X25_WR_FACILITY */
2316 #endif /* SUNX25 */
2317
2318 #ifdef TCPSOCKET
2319 #ifndef OS2
2320 #ifndef NOLISTEN
2321
2322 #ifdef BSDSELECT
2323 #ifndef VMS
2324 #ifndef BELLV10
2325 #ifndef datageneral
2326 #ifdef hp9000s500                       /* HP-9000/500 HP-U 5.21 */
2327 #include <time.h>
2328 #else
2329
2330 /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
2331 *       ------------------------------------------------------
2332 *
2333 *       Due to OS9's Lack of a select() call, the following seems to be
2334 *       enough to fool the rest of the code into compiling. The only
2335 *       effect that I can see is using control L to refresh the status
2336 *       display gets qued up until some network packets arrive.
2337 *
2338 *       This solution is by no means elegant but works enough to be
2339 *       a (the) solution.
2340 *
2341 *       Also with the defines I had specified in my makefile I had to
2342 *       have an #endif right at the end of the file when compiling.
2343 *       I did not bother speding time to find out why.
2344 *
2345 *       COPTS   = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
2346 *          -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
2347 *          -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
2348 *          -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
2349 *          -l=termlib.l -l=math.l -l=sys_clib.l
2350 *
2351 *       stever@ozemail.com.au
2352 */
2353
2354 #ifdef  OSK
2355 #define BSDSELECT                       /* switch on BSD select code */
2356 #define FD_SETSIZE 32                   /* Max # of paths in OS9 */
2357 #define FD_ZERO(p)                      ((*p)=0)
2358 #define FD_SET(n,b)                     ((*b)|=(1<<(n)))
2359 #define FD_ISSET(n,b)           1       /* always say data is ready */
2360 #define select(a,b,c,d,e)       1       /* always say 1 path has data */
2361 typedef int     fd_set;                 /* keep BSD Code Happy */
2362 struct timeval {int tv_sec,tv_usec;};   /* keep BSD Code Happy */
2363
2364 /****** END OF OS9 MODS FROM STEVE RANCE **************************/
2365 #endif /* OSK */
2366
2367 #include <sys/time.h>
2368 #endif /* hp9000s500 */
2369 #endif /* datageneral */
2370 #endif /* BELLV10 */
2371 #endif /* VMS */
2372 #ifdef SELECT_H
2373 #include <sys/select.h>
2374 #endif /* SELECT_H */
2375 #endif /* BSDSELECT */
2376
2377 #ifdef SELECT
2378 #ifdef CK_SCOV5
2379 #include <sys/select.h>
2380 #endif /* CK_SCOV5 */
2381 #endif /* SELECT */
2382
2383 #ifdef NOTUSED
2384 /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
2385
2386 int
2387 tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
2388     int on = 1;
2389     static struct servent *service, servrec;
2390     static struct hostent *host;
2391     static struct sockaddr_in saddr;
2392     static
2393 #ifdef UCX50
2394       unsigned
2395 #endif /* UCX50 */
2396       int saddrlen;
2397 #ifdef BSDSELECT
2398     fd_set rfds;
2399     struct timeval tv;
2400 #else
2401 #ifdef BELLSELECT
2402     fd_set rfds;
2403 #else
2404     fd_set rfds;
2405     fd_set rfds;
2406     struct timeval {
2407         long tv_sec;
2408         long tv_usec;
2409     } tv;
2410 #endif /* BELLSELECT */
2411 #endif /* BSDSELECT */
2412
2413     debug(F101,"tcpsocket_open nett","",nett);
2414     *ipaddr = '\0';
2415
2416     if (nett != NET_TCPB)
2417       return(-1);                       /* BSD socket support */
2418
2419     netclos();                          /* Close any previous connection. */
2420     ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2421     if (ttnproto != NP_TCPRAW)
2422       ttnproto = NP_NONE;               /* No protocol selected yet. */
2423     debug(F110,"tcpsocket_open namecopy",namecopy,0);
2424
2425     /* Assign the socket number to ttyfd and then fill in tcp structures */
2426     ttyfd = atoi(&name[1]);
2427     debug(F111,"tcpsocket_open","ttyfd",ttyfd);
2428
2429 #ifndef NOTCPOPTS
2430 #ifdef SOL_SOCKET
2431     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2432
2433 #ifndef datageneral
2434 #ifdef TCP_NODELAY
2435     no_delay(ttyfd,tcp_nodelay);
2436 #endif /* TCP_NODELAY */
2437 #ifdef SO_KEEPALIVE
2438     keepalive(ttyfd,tcp_keepalive);
2439 #endif /* SO_KEEPALIVE */
2440 #ifdef SO_LINGER
2441     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2442 #endif /* SO_LINGER */
2443 #ifdef SO_SNDBUF
2444     sendbuf(ttyfd,tcp_sendbuf);
2445 #endif /* SO_SNDBUF */
2446 #ifdef SO_RCVBUF
2447     recvbuf(ttyfd,tcp_recvbuf);
2448 #endif /* SO_RCVBUF */
2449 #endif /* datageneral */
2450 #endif /* SOL_SOCKET */
2451 #endif /* NOTCPOPTS */
2452
2453 #ifdef NT_TCP_OVERLAPPED
2454     OverlappedWriteInit();
2455     OverlappedReadInit();
2456 #endif /* NT_TCP_OVERLAPPED */
2457
2458
2459     /* Get the name of the host we are connected to */
2460
2461     saddrlen = sizeof(saddr);
2462     getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
2463
2464     ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2465
2466     if (tcp_rdns == SET_ON
2467 #ifdef CK_KERBEROS
2468         || tcp_rdns == SET_AUTO &&
2469          (ck_krb5_is_installed() || ck_krb4_is_installed())
2470 #endif /* CK_KERBEROS */
2471 #ifndef NOHTTP
2472           && (tcp_http_proxy == NULL)
2473 #endif /* NOHTTP */
2474 #ifdef CK_SSL
2475           && !(ssl_only_flag || tls_only_flag)
2476 #endif /* CK_SSL */
2477          ) {                            /* Reverse DNS */
2478         if (!quiet) {
2479             printf(" Reverse DNS Lookup... ");
2480             fflush(stdout);
2481         }
2482         host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
2483         debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
2484         if (host) {
2485             host = ck_copyhostent(host);
2486             debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
2487             if (!quiet) {
2488                 printf("(OK)\n");
2489                 fflush(stdout);
2490             }
2491             ckstrncpy(name, host->h_name, 80);
2492             ckstrncat(name, ":", 80);
2493             ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
2494             if (!quiet
2495 #ifndef NOICP
2496                 && !doconx
2497 #endif /* NOICP */
2498                 )
2499               printf("%s connected on port %d\n",
2500                    host->h_name,
2501                    ntohs(saddr.sin_port)
2502                    );
2503         } else if (!quiet)
2504           printf("Failed\n");
2505     } else if (!quiet)
2506       printf("(OK)\n");
2507
2508     if (tcp_rdns != SET_ON || !host) {
2509         ckstrncpy(name,ipaddr,80);
2510         ckstrncat(name,":",80);
2511         ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2512         if (!quiet
2513 #ifdef NOICP
2514             && !doconx
2515 #endif /* NOICP */
2516             )
2517           printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2518     }
2519     if (!quiet) fflush(stdout);
2520     ttnet = nett;                       /* TCP/IP (sockets) network */
2521
2522 #ifdef RLOGCODE
2523     if (ntohs(saddr.sin_port) == 513)
2524         ttnproto = NP_LOGIN;
2525     else
2526 #endif /* RLOGCODE */
2527     /* Assume the service is TELNET. */
2528     if (ttnproto != NP_TCPRAW)
2529         ttnproto = NP_TELNET;           /* Yes, set global flag. */
2530 #ifdef CK_SECURITY
2531     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2532     ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2533                 host->h_name : ipaddr,
2534                 ipaddr,
2535                 uidbuf,
2536                 ttyfd
2537                 );
2538 #endif /* CK_SECURITY */
2539     if (tn_ini() < 0)                   /* Start/Reset TELNET negotiations */
2540       if (ttchk() < 0)                  /* Did it fail due to connect loss? */
2541         return(-1);
2542
2543     if (*lcl < 0) *lcl = 1;             /* Local mode. */
2544
2545     return(0);                          /* Done. */
2546 }
2547 #endif /* NOTUSED */
2548
2549 /*  T C P S R V _ O P E N  --  Open a TCP/IP Server connection  */
2550 /*
2551   Calling conventions same as ttopen(), except third argument is network
2552   type rather than modem type.
2553 */
2554 int
2555 tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
2556     char *p;
2557     int i, x;
2558     SOCKOPT_T on = 1;
2559     int ready_to_accept = 0;
2560     static struct servent *service, *service2, servrec;
2561     static struct hostent *host;
2562     static struct sockaddr_in saddr;
2563     struct sockaddr_in l_addr;
2564     GSOCKNAME_T l_slen;
2565 #ifdef UCX50
2566     static u_int saddrlen;
2567 #else
2568     static SOCKOPT_T saddrlen;
2569 #endif /* UCX50 */
2570
2571 #ifdef BSDSELECT
2572     fd_set rfds;
2573     struct timeval tv;
2574 #else
2575 #ifdef BELLSELCT
2576     fd_set rfds;
2577 #else
2578     fd_set rfds;
2579     struct timeval {
2580         long tv_sec;
2581         long tv_usec;
2582     } tv;
2583 #endif /* BELLSELECT */
2584 #endif /* BSDSELECT */
2585 #ifdef CK_SSL
2586     int ssl_failed = 0;
2587 #endif /* CK_SSL */
2588
2589     debug(F101,"tcpsrv_open nett","",nett);
2590     *ipaddr = '\0';
2591
2592     if (nett != NET_TCPB)
2593       return(-1);                       /* BSD socket support */
2594
2595     netclos();                          /* Close any previous connection. */
2596     ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2597 #ifdef COMMENT
2598     /* Don't do this. */
2599     if (ttnproto != NP_TCPRAW)
2600       ttnproto = NP_NONE;               /* No protocol selected yet. */
2601 #endif /* COMMENT */
2602     debug(F110,"tcpsrv_open namecopy",namecopy,0);
2603
2604     p = namecopy;                       /* Was a service requested? */
2605     while (*p != '\0' && *p != ':')
2606       p++; /* Look for colon */
2607     if (*p == ':') {                    /* Have a colon */
2608         *p++ = '\0';                    /* Get service name or number */
2609     } else {                            /* Otherwise use kermit */
2610         p = "kermit";
2611     }
2612     debug(F110,"tcpsrv_open service requested",p,0);
2613     if (isdigit(*p)) {                  /* Use socket number without lookup */
2614         service = &servrec;
2615         service->s_port = htons((unsigned short)atoi(p));
2616     } else {                            /* Otherwise lookup the service name */
2617         service = getservbyname(p, "tcp");
2618     }
2619     if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
2620         service = &servrec;
2621         service->s_port = htons(1649);
2622     }
2623 #ifdef RLOGCODE
2624     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
2625         fprintf(stderr,
2626                 "  Warning: login service on port %d instead of port 513\n",
2627                  ntohs(service->s_port));
2628         fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
2629         debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
2630     }
2631 #endif /* RLOGCODE */
2632     if (!service) {
2633         fprintf(stderr, "Cannot find port for service: %s\n", p);
2634         debug(F111,"tcpsrv_open can't get service",p,errno);
2635         errno = 0;                      /* rather than mislead */
2636         return(-1);
2637     }
2638
2639     /* If we currently have a listen active but port has changed then close */
2640
2641     debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
2642     debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
2643     if (tcpsrfd != -1 &&
2644         tcpsrv_port != ntohs((unsigned short)service->s_port)) {
2645         debug(F100,"tcpsrv_open closing previous connection","",0);
2646 #ifdef TCPIPLIB
2647         socket_close(tcpsrfd);
2648 #else
2649         close(tcpsrfd);
2650 #endif /* TCPIPLIB */
2651         tcpsrfd = -1;
2652     }
2653     debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
2654     if (tcpsrfd == -1) {
2655
2656         /* Set up socket structure and get host address */
2657
2658         bzero((char *)&saddr, sizeof(saddr));
2659         debug(F100,"tcpsrv_open bzero ok","",0);
2660         saddr.sin_family = AF_INET;
2661         if (tcp_address) {
2662 #ifdef INADDRX
2663             inaddrx = inet_addr(tcp_address);
2664             saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
2665 #else
2666             saddr.sin_addr.s_addr = inet_addr(tcp_address);
2667 #endif /* INADDRX */
2668         } else
2669           saddr.sin_addr.s_addr = INADDR_ANY;
2670
2671         /* Get a file descriptor for the connection. */
2672
2673         saddr.sin_port = service->s_port;
2674         ipaddr[0] = '\0';
2675
2676         debug(F100,"tcpsrv_open calling socket","",0);
2677         if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2678             perror("TCP socket error");
2679             debug(F101,"tcpsrv_open socket error","",errno);
2680             return (-1);
2681         }
2682         errno = 0;
2683
2684         /* Specify the Port may be reused */
2685
2686         debug(F100,"tcpsrv_open calling setsockopt","",0);
2687         x = setsockopt(tcpsrfd,
2688                        SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
2689         debug(F101,"tcpsrv_open setsockopt","",x);
2690
2691        /* Now bind to the socket */
2692         printf("\nBinding socket to port %d ...\n",
2693                ntohs((unsigned short)service->s_port));
2694         if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
2695             i = errno;                  /* Save error code */
2696 #ifdef TCPIPLIB
2697             socket_close(tcpsrfd);
2698 #else /* TCPIPLIB */
2699             close(tcpsrfd);
2700 #endif /* TCPIPLIB */
2701             tcpsrfd = -1;
2702             tcpsrv_port = 0;
2703             ttyfd = -1;
2704             wasclosed = 1;
2705             errno = i;                  /* and report this error */
2706             debug(F101,"tcpsrv_open bind errno","",errno);
2707             printf("?Unable to bind to socket (errno = %d)\n",errno);
2708             return(-1);
2709         }
2710         debug(F100,"tcpsrv_open bind OK","",0);
2711         printf("Listening ...\n");
2712         if (listen(tcpsrfd, 15) < 0) {
2713             i = errno;                  /* Save error code */
2714 #ifdef TCPIPLIB
2715             socket_close(tcpsrfd);
2716 #else /* TCPIPLIB */
2717             close(tcpsrfd);
2718 #endif /* TCPIPLIB */
2719             tcpsrfd = -1;
2720             tcpsrv_port = 0;
2721             ttyfd = -1;
2722             wasclosed = 1;
2723             errno = i;                  /* And report this error */
2724             debug(F101,"tcpsrv_open listen errno","",errno);
2725             return(-1);
2726         }
2727         debug(F100,"tcpsrv_open listen OK","",0);
2728         tcpsrv_port = ntohs((unsigned short)service->s_port);
2729     }
2730
2731 #ifdef CK_SSL
2732     if (ck_ssleay_is_installed()) {
2733         if (!ssl_tn_init(SSL_SERVER)) {
2734             ssl_failed = 1;
2735             if (bio_err!=NULL) {
2736                 BIO_printf(bio_err,"do_ssleay_init() failed\n");
2737                 ERR_print_errors(bio_err);
2738             } else {
2739                 fflush(stderr);
2740                 fprintf(stderr,"do_ssleay_init() failed\n");
2741                 ERR_print_errors_fp(stderr);
2742             }
2743             if (tls_only_flag || ssl_only_flag) {
2744 #ifdef TCPIPLIB
2745                 socket_close(ttyfd);
2746                 socket_close(tcpsrfd);
2747 #else /* TCPIPLIB */
2748                 close(ttyfd);
2749                 close(tcpsrfd);
2750 #endif /* TCPIPLIB */
2751                 ttyfd = -1;
2752                 wasclosed = 1;
2753                 tcpsrfd = -1;
2754                 tcpsrv_port = 0;
2755                 return(-1);
2756             }
2757             /* we will continue to accept the connection   */
2758             /* without SSL or TLS support unless required. */
2759             if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2760                 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2761             if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2762                 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2763             if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2764                 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2765             if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2766                 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2767         }
2768     }
2769 #endif /* CK_SSL */
2770
2771     printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
2772            ntohs((unsigned short)service->s_port));
2773     saddrlen = sizeof(saddr);
2774
2775 #ifdef BSDSELECT
2776     tv.tv_sec  = tv.tv_usec = 0L;
2777     if (timo < 0)
2778       tv.tv_usec = (long) -timo * 10000L;
2779     else
2780       tv.tv_sec = timo;
2781     debug(F101,"tcpsrv_open BSDSELECT","",timo);
2782 #else
2783     debug(F101,"tcpsrv_open not BSDSELECT","",timo);
2784 #endif /* BSDSELECT */
2785
2786     if (timo) {
2787         while (!ready_to_accept) {
2788 #ifdef BSDSELECT
2789             FD_ZERO(&rfds);
2790             FD_SET(tcpsrfd, &rfds);
2791             ready_to_accept =
2792               ((select(FD_SETSIZE,
2793 #ifdef HPUX
2794 #ifdef HPUX1010
2795                        (fd_set *)
2796 #else
2797
2798                        (int *)
2799 #endif /* HPUX1010 */
2800 #else
2801 #ifdef __DECC
2802                        (fd_set *)
2803 #endif /* __DECC */
2804 #endif /* HPUX */
2805                        &rfds, NULL, NULL, &tv) > 0) &&
2806                FD_ISSET(tcpsrfd, &rfds));
2807 #else /* BSDSELECT */
2808 #ifdef IBMSELECT
2809 #define ck_sleepint 250
2810             ready_to_accept =
2811               (select(&tcpsrfd, 1, 0, 0,
2812                       timo < 0 ? -timo :
2813                       (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
2814                );
2815 #else
2816 #ifdef BELLSELECT
2817             FD_ZERO(rfds);
2818             FD_SET(tcpsrfd, rfds);
2819             ready_to_accept =
2820               ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
2821                       (timo > 0 ? timo * 1000L)) > 0) &&
2822                FD_ISSET(tcpsrfd, rfds));
2823 #else
2824 /* Try this - what's the worst that can happen... */
2825
2826             FD_ZERO(&rfds);
2827             FD_SET(tcpsrfd, &rfds);
2828             ready_to_accept =
2829               ((select(FD_SETSIZE,
2830                        (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
2831                FD_ISSET(tcpsrfd, &rfds));
2832
2833 #endif /* BELLSELECT */
2834 #endif /* IBMSELECT */
2835 #endif /* BSDSELECT */
2836         }
2837     }
2838     if (ready_to_accept || timo == 0) {
2839         if ((ttyfd = accept(tcpsrfd,
2840                             (struct sockaddr *)&saddr,&saddrlen)) < 0) {
2841             i = errno;                  /* save error code */
2842 #ifdef TCPIPLIB
2843             socket_close(tcpsrfd);
2844 #else /* TCPIPLIB */
2845             close(tcpsrfd);
2846 #endif /* TCPIPLIB */
2847             ttyfd = -1;
2848             wasclosed = 1;
2849             tcpsrfd = -1;
2850             tcpsrv_port = 0;
2851             errno = i;                  /* and report this error */
2852             debug(F101,"tcpsrv_open accept errno","",errno);
2853             return(-1);
2854         }
2855         setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2856
2857 #ifndef NOTCPOPTS
2858 #ifndef datageneral
2859 #ifdef SOL_SOCKET
2860 #ifdef TCP_NODELAY
2861         no_delay(ttyfd,tcp_nodelay);
2862         debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
2863 #endif /* TCP_NODELAY */
2864 #ifdef SO_KEEPALIVE
2865         keepalive(ttyfd,tcp_keepalive);
2866         debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
2867 #endif /* SO_KEEPALIVE */
2868 #ifdef SO_LINGER
2869         ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2870         debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
2871 #endif /* SO_LINGER */
2872 #ifdef SO_SNDBUF
2873         sendbuf(ttyfd,tcp_sendbuf);
2874 #endif /* SO_SNDBUF */
2875 #ifdef SO_RCVBUF
2876         recvbuf(ttyfd,tcp_recvbuf);
2877 #endif /* SO_RCVBUF */
2878 #endif /* SOL_SOCKET */
2879 #endif /* datageneral */
2880 #endif /* NOTCPOPTS */
2881
2882         ttnet = nett;                   /* TCP/IP (sockets) network */
2883         tcp_incoming = 1;               /* This is an incoming connection */
2884         sstelnet = 1;                   /* Do server-side Telnet protocol */
2885
2886         /* See if the service is TELNET. */
2887         x = (unsigned short)service->s_port;
2888         service2 = getservbyname("telnet", "tcp");
2889         if (service2 && x == service2->s_port) {
2890             if (ttnproto != NP_TCPRAW)  /* Yes and if raw port not requested */
2891               ttnproto = NP_TELNET;     /* Set protocol to TELNET. */
2892         }
2893
2894         ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2895         if (tcp_rdns) {
2896             if (!quiet) {
2897                 printf(" Reverse DNS Lookup... ");
2898                 fflush(stdout);
2899             }
2900             if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
2901                 host = ck_copyhostent(host);
2902                 debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
2903                 if (!quiet) {
2904                     printf("(OK)\n");
2905                     fflush(stdout);
2906                 }
2907                 name[0] = '*';
2908                 ckstrncpy(&name[1],host->h_name,78);
2909                 strncat(name,":",80-strlen(name));
2910                 strncat(name,p,80-strlen(name));
2911                 if (!quiet
2912 #ifndef NOICP
2913                     && !doconx
2914 #endif /* NOICP */
2915                     )
2916                   printf("%s connected on port %s\n",host->h_name,p);
2917             } else {
2918                 if (!quiet) printf("Failed.\n");
2919             }
2920         } else if (!quiet) printf("(OK)\n");
2921
2922         if (!tcp_rdns || !host) {
2923             ckstrncpy(name,ipaddr,80);
2924             ckstrncat(name,":",80);
2925             ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2926             if (!quiet
2927 #ifndef NOICP
2928                 && !doconx
2929 #endif /* NOICP */
2930                 )
2931               printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2932         }
2933         if (!quiet) fflush(stdout);
2934
2935 #ifdef CK_SECURITY
2936         /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2937         ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2938                      (char *)host->h_name : ipaddr,
2939                      ipaddr,
2940                      uidbuf,
2941                      ttyfd
2942                      );
2943 #endif /* CK_SECURITY */
2944
2945 #ifdef CK_SSL
2946         if (ck_ssleay_is_installed() && !ssl_failed) {
2947             if (ck_ssl_incoming(ttyfd) < 0) {
2948 #ifdef TCPIPLIB
2949                     socket_close(ttyfd);
2950                     socket_close(tcpsrfd);
2951 #else /* TCPIPLIB */
2952                     close(ttyfd);
2953                     close(tcpsrfd);
2954 #endif /* TCPIPLIB */
2955                     ttyfd = -1;
2956                     wasclosed = 1;
2957                     tcpsrfd = -1;
2958                     tcpsrv_port = 0;
2959                     return(-1);
2960             }
2961         }
2962 #endif /* CK_SSL */
2963
2964 #ifndef datageneral
2965         /* Find out our own IP address. */
2966         l_slen = sizeof(l_addr);
2967         bzero((char *)&l_addr, l_slen);
2968 #ifndef EXCELAN
2969         if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
2970             char * s = (char *)inet_ntoa(l_addr.sin_addr);
2971             ckstrncpy(myipaddr, s,20);
2972             debug(F110,"getsockname",myipaddr,0);
2973         }
2974 #endif /* EXCELAN */
2975 #endif /* datageneral */
2976
2977         if (tn_ini() < 0)               /* Start TELNET negotiations. */
2978           if (ttchk() < 0) {            /* Disconnected? */
2979               i = errno;                /* save error code */
2980 #ifdef TCPIPLIB
2981               socket_close(tcpsrfd);
2982 #else /* TCPIPLIB */
2983               close(tcpsrfd);
2984 #endif /* TCPIPLIB */
2985               ttyfd = -1;
2986               wasclosed = 1;
2987               tcpsrfd = -1;
2988               tcpsrv_port = 0;
2989               errno = i;                /* and report this error */
2990               debug(F101,"tcpsrv_open accept errno","",errno);
2991               return(-1);
2992           }
2993         debug(F101,"tcpsrv_open service","",x);
2994         if (*lcl < 0)                   /* Set local mode. */
2995           *lcl = 1;
2996
2997 #ifdef CK_KERBEROS
2998 #ifdef KRB5_U2U
2999         if ( ttnproto == NP_K5U2U ) {
3000             if (k5_user_to_user_server_auth() != 0) {
3001                 i = errno;                /* save error code */
3002 #ifdef TCPIPLIB
3003                 socket_close(tcpsrfd);
3004 #else /* TCPIPLIB */
3005                 close(tcpsrfd);
3006 #endif /* TCPIPLIB */
3007                 ttyfd = -1;
3008                 wasclosed = 1;
3009                 tcpsrfd = -1;
3010                 tcpsrv_port = 0;
3011                 errno = i;                /* and report this error */
3012                 debug(F101,"tcpsrv_open accept errno","",errno);
3013                 return(-1);
3014             }
3015         }
3016 #endif /* KRB5_U2U */
3017 #endif /* CK_KERBEROS */
3018         return(0);                      /* Done. */
3019     } else {
3020         i = errno;                      /* save error code */
3021 #ifdef TCPIPLIB
3022         socket_close(tcpsrfd);
3023 #else /* TCPIPLIB */
3024         close(tcpsrfd);
3025 #endif /* TCPIPLIB */
3026         ttyfd = -1;
3027         wasclosed = 1;
3028         tcpsrfd = -1;
3029         tcpsrv_port = 0;
3030         errno = i;                      /* and report this error */
3031         debug(F101,"tcpsrv_open accept errno","",errno);
3032         return(-1);
3033     }
3034 }
3035 #endif /* NOLISTEN */
3036 #endif /* OS2 */
3037 #endif /* TCPSOCKET */
3038 #endif /* NONET */
3039
3040 #ifdef TCPSOCKET
3041 char *
3042 ckname2addr(name) char * name;
3043 {
3044 #ifdef HPUX5
3045     return("");
3046 #else
3047     struct hostent *host;
3048
3049     if (name == NULL || *name == '\0')
3050         return("");
3051
3052     host = gethostbyname(name);
3053     if ( host ) {
3054         host = ck_copyhostent(host);
3055         return(inet_ntoa(*((struct in_addr *) host->h_addr)));
3056     }
3057     return("");
3058 #endif /* HPUX5 */
3059 }
3060
3061 char *
3062 ckaddr2name(addr) char * addr;
3063 {
3064 #ifdef HPUX5
3065     return("");
3066 #else
3067     struct hostent *host;
3068     struct in_addr sin_addr;
3069
3070     if (addr == NULL || *addr == '\0')
3071         return("");
3072
3073     sin_addr.s_addr = inet_addr(addr);
3074     host = gethostbyaddr((char *)&sin_addr,4,AF_INET);
3075     if (host) {
3076         host = ck_copyhostent(host);
3077         return((char *)host->h_name);
3078     }
3079     return("");
3080 #endif /* HPUX5 */
3081 }
3082 #endif /* TCPSOCKET */
3083
3084 unsigned long peerxipaddr = 0L;
3085
3086 char *
3087 ckgetpeer() {
3088 #ifdef TCPSOCKET
3089     static char namebuf[256];
3090     static struct hostent *host;
3091     static struct sockaddr_in saddr;
3092 #ifdef PTX
3093     static size_t saddrlen;
3094 #else
3095 #ifdef AIX42
3096     /* It's size_t in 4.2 but int in 4.1 and earlier. */
3097     /* Note: the 4.2 man page lies; believe socket.h. */
3098     static size_t saddrlen;
3099 #else
3100 #ifdef UNIXWARE
3101     static size_t saddrlen;
3102 #else  /* UNIXWARE */
3103 #ifdef DEC_TCPIP
3104     static unsigned int saddrlen;
3105 #else
3106     static int saddrlen;
3107 #endif /* VMS */
3108 #endif /* UNIXWARE */
3109 #endif /* AIX42 */
3110 #endif /* PTX */
3111     saddrlen = sizeof(saddr);
3112     if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
3113         debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
3114         return(NULL);
3115     }
3116     host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
3117     if (host) {
3118         host = ck_copyhostent(host);
3119         ckstrncpy(namebuf,(char *)host->h_name,80);
3120     } else {
3121         ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
3122     }
3123     peerxipaddr = ntohl(saddr.sin_addr.s_addr);
3124     debug(F111,"ckgetpeer",namebuf,peerxipaddr);
3125     return(namebuf);
3126 #else
3127     return(NULL);
3128 #endif /* TCPSOCKET */
3129 }
3130
3131 /* Get fully qualified IP hostname */
3132
3133 #ifndef NONET
3134 char *
3135 #ifdef CK_ANSIC
3136 ckgetfqhostname(char * name)
3137 #else
3138 ckgetfqhostname(name) char * name;
3139 #endif /* CK_ANSIC */
3140 {
3141 #ifdef NOCKGETFQHOST
3142
3143     return(name);
3144
3145 #else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */
3146
3147     static char namebuf[256];
3148     struct hostent *host=NULL;
3149     struct sockaddr_in r_addr;
3150     int i;
3151
3152     debug(F110,"ckgetfqhn()",name,0);
3153
3154     ckstrncpy(namebuf,name,256);
3155     namebuf[255] = '\0';
3156     i = ckindex(":",namebuf,0,0,0);
3157     if (i)
3158       namebuf[i-1] = '\0';
3159
3160     bzero((char *)&r_addr, sizeof(r_addr));
3161
3162     host = gethostbyname(namebuf);
3163     if (host) {
3164         host = ck_copyhostent(host);
3165         debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
3166         r_addr.sin_family = host->h_addrtype;
3167 #ifdef HADDRLIST
3168 #ifdef h_addr
3169         /* This is for trying multiple IP addresses - see <netdb.h> */
3170         if (!(host->h_addr_list))
3171           goto exit_func;
3172         bcopy(host->h_addr_list[0],
3173               (caddr_t)&r_addr.sin_addr,
3174               host->h_length
3175               );
3176 #else
3177         bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3178 #endif /* h_addr */
3179 #else  /* HADDRLIST */
3180         bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3181 #endif /* HADDRLIST */
3182 #ifndef EXCELAN
3183         debug(F111,"BCOPY","host->h_addr",host->h_addr);
3184 #endif /* EXCELAN */
3185         debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
3186               (caddr_t)&r_addr.sin_addr);
3187         debug(F111,"BCOPY","host->h_length",host->h_length);
3188
3189 #ifdef NT
3190         /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
3191         /* provided DNS functions.  Otherwise, the TTL of the DNS response */
3192         /* is ignored. */
3193         if (isWin95())
3194           sleep(1);
3195 #endif /* NT */
3196         host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
3197         if (host) {
3198             host = ck_copyhostent(host);
3199             debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
3200             ckstrncpy(namebuf, host->h_name, 256);
3201         }
3202     }
3203
3204 #ifdef HADDRLIST
3205 #ifdef h_addr
3206   exit_func:
3207 #endif /* h_addr */
3208 #endif /* HADDRLIST */
3209
3210     if (i > 0)
3211       strncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
3212     debug(F110,"ckgetfqhn()",namebuf,0);
3213     return(namebuf);
3214 #endif /* NOCKGETFQHOST */
3215 }
3216
3217 VOID
3218 #ifdef CK_ANSIC
3219 setnproto(char * p)
3220 #else
3221 setnproto(p) char * p;
3222 #endif /* CK_ANSIC */
3223 {
3224     if (!isdigit(*p)) {
3225         if (!strcmp("kermit",p))
3226           ttnproto = NP_KERMIT;
3227         else if (!strcmp("telnet",p))
3228           ttnproto = NP_TELNET;
3229         else if (!strcmp("http",p))
3230           ttnproto = NP_TCPRAW;
3231 #ifdef RLOGCODE
3232         else if (!strcmp("login",p))
3233           ttnproto = NP_RLOGIN;
3234 #endif /* RLOGCODE */
3235 #ifdef CK_SSL
3236         /* Commonly used SSL ports (might not be in services file) */
3237         else if (!strcmp("https",p)) {
3238           ttnproto = NP_SSL;
3239           ssl_only_flag = 1;
3240         } else if (!strcmp("ssl-telnet",p)) {
3241           ttnproto = NP_TELNET;
3242           ssl_only_flag = 1;
3243         } else if (!strcmp("telnets",p)) {
3244           ttnproto = NP_TELNET;
3245           ssl_only_flag = 1;
3246         }
3247 #endif /* CK_SSL */
3248 #ifdef CK_KERBEROS
3249 #ifdef RLOGCODE
3250         else if (!strcmp("klogin",p)) {
3251             if (ck_krb5_is_installed())
3252               ttnproto = NP_K5LOGIN;
3253             else if (ck_krb4_is_installed())
3254               ttnproto = NP_K4LOGIN;
3255             else
3256               ttnproto = NP_RLOGIN;
3257         } else if (!strcmp("eklogin",p)) {
3258             if (ck_krb5_is_installed())
3259               ttnproto = NP_EK5LOGIN;
3260             else if (ck_krb4_is_installed())
3261               ttnproto = NP_EK4LOGIN;
3262             else
3263               ttnproto = NP_RLOGIN;
3264         }
3265 #endif /* RLOGCODE */
3266 #endif /* CK_KERBEROS */
3267         else
3268           ttnproto = NP_NONE;
3269     } else {
3270         switch (atoi(p)) {
3271           case 23:                      /* Telnet */
3272             ttnproto = NP_TELNET;
3273             break;
3274           case 513:
3275             ttnproto = NP_RLOGIN;
3276             break;
3277           case 1649:
3278             ttnproto = NP_KERMIT;
3279             break;
3280 #ifdef CK_SSL
3281           case 443:
3282             ttnproto = NP_SSL;
3283             ssl_only_flag = 1;
3284             break;
3285           case 151:
3286           case 992:
3287             ttnproto = NP_TELNET;
3288             ssl_only_flag = 1;
3289             break;
3290 #endif /* CK_SSL */
3291 #ifdef CK_KERBEROS
3292           case 543:
3293             if (ck_krb5_is_installed())
3294               ttnproto = NP_K5LOGIN;
3295             else if (ck_krb4_is_installed())
3296               ttnproto = NP_K4LOGIN;
3297             else
3298               ttnproto = NP_RLOGIN;
3299             break;
3300           case 2105:
3301             if (ck_krb5_is_installed())
3302               ttnproto = NP_EK5LOGIN;
3303             else if (ck_krb4_is_installed())
3304               ttnproto = NP_EK4LOGIN;
3305             else
3306               ttnproto = NP_RLOGIN;
3307             break;
3308 #endif /* CK_KERBEROS */
3309           case 80:                      /* HTTP */
3310             ttnproto = NP_TCPRAW;
3311             break;
3312           default:
3313             ttnproto = NP_NONE;
3314             break;
3315         }
3316     }
3317 }
3318
3319 /* ckgetservice() is used to determine the port number for a given */
3320 /* service taking into account the use of DNS SRV records.         */
3321
3322 static struct servent servrec;
3323 static struct servent *
3324 ckgetservice(hostname, servicename, ip, iplen)
3325     char *hostname; char * servicename; char * ip; int iplen;
3326 {
3327     struct servent * service = NULL;
3328 #ifdef CK_DNS_SRV
3329     struct sockaddr * dns_addrs = NULL;
3330     int dns_naddrs = 0;
3331 #endif /* CK_DNS_SRV */
3332
3333     if (isdigit(*servicename)) {        /* Use socket number without lookup */
3334         service = &servrec;
3335         service->s_port = htons((unsigned short)atoi(servicename));
3336     } else {                            /* Otherwise lookup the service name */
3337 #ifdef CK_DNS_SRV
3338         if (tcp_dns_srv && !quiet) {
3339             printf(" DNS SRV Lookup... ");
3340             fflush(stdout);
3341         }
3342         if (tcp_dns_srv &&
3343             locate_srv_dns(hostname,
3344                            servicename,
3345                            "tcp",
3346                            &dns_addrs,
3347                            &dns_naddrs
3348                            )
3349             ) {
3350             /* Use the first one.  Eventually we should cycle through all */
3351             /* the returned IP addresses and port numbers. */
3352             struct sockaddr_in *sin = NULL;
3353 #ifdef BETADEBUG
3354             int i;
3355             printf("\r\n");
3356             for ( i=0;i<dns_naddrs;i++ ) {
3357                 sin = (struct sockaddr_in *) &dns_addrs[i];
3358                 printf("dns_addrs[%d] = %s %d\r\n", i,
3359                         (char *)inet_ntoa(sin->sin_addr),
3360                         ntohs(sin->sin_port));
3361             }
3362 #endif /* BETADEBUG */
3363             sin = (struct sockaddr_in *) &dns_addrs[0];
3364             if ( ip && iplen > 0 )
3365                 ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen);
3366             service = &servrec;
3367             service->s_port = sin->sin_port;
3368
3369             free(dns_addrs);
3370             dns_addrs = NULL;
3371             dns_naddrs = 0;
3372         } else
3373 #endif /* CK_DNS_SRV */
3374             service = getservbyname(servicename, "tcp");
3375     }
3376     if (!service) {
3377         if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */
3378             service = &servrec;
3379             service->s_port = htons(1649);
3380         } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */
3381             service = &servrec;
3382             service->s_port = htons(23);
3383         } else if (!ckstrcmp("http",servicename,-1,0)) {
3384             service = &servrec;
3385             service->s_port = htons(80);
3386         }
3387 #ifdef RLOGCODE
3388         else if (!ckstrcmp("login",servicename,-1,0)) {
3389             service = &servrec;
3390             service->s_port = htons(513);
3391         }
3392 #endif /* RLOGCODE */
3393 #ifdef CK_SSL
3394         /* Commonly used SSL ports (might not be in services file) */
3395         else if (!ckstrcmp("https",servicename,-1,0)) {
3396             service = &servrec;
3397             service->s_port = htons(443);
3398         } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) {
3399             service = &servrec;
3400             service->s_port = htons(151);
3401         } else if (!ckstrcmp("telnets",servicename,-1,0)) {
3402             service = &servrec;
3403             service->s_port = htons(992);
3404         }
3405 #endif /* CK_SSL */
3406 #ifdef CK_KERBEROS
3407 #ifdef RLOGCODE
3408         else if (!ckstrcmp("klogin",servicename,-1,0)) {
3409             service = &servrec;
3410             service->s_port = htons(543);
3411         } else if (!ckstrcmp("eklogin",servicename,-1,0)) {
3412             service = &servrec;
3413             service->s_port = htons(2105);
3414         }
3415 #endif /* RLOGCODE */
3416 #endif /* CK_KERBEROS */
3417     }
3418     return(service);
3419 }
3420
3421 /*  N E T O P E N  --  Open a network connection  */
3422 /*
3423   Calling conventions same as ttopen(), except third argument is network
3424   type rather than modem type.  Designed to be called from within ttopen.
3425 */
3426
3427 int
3428 netopen(name, lcl, nett) char *name; int *lcl, nett; {
3429     char *p;
3430     int i, x, dns = 0;
3431 #ifdef TCPSOCKET
3432     int isconnect = 0;
3433 #ifdef SO_OOBINLINE
3434     int on = 1;
3435 #endif /* SO_OOBINLINE */
3436     struct servent *service=NULL;
3437     struct hostent *host=NULL;
3438     struct sockaddr_in r_addr;
3439     struct sockaddr_in sin;
3440     struct sockaddr_in l_addr;
3441     GSOCKNAME_T l_slen;
3442 #ifdef EXCELAN
3443     struct sockaddr_in send_socket;
3444 #endif /* EXCELAN */
3445
3446 #ifdef INADDRX
3447 /* inet_addr() is of type struct in_addr */
3448 #ifdef datageneral
3449     extern struct in_addr inet_addr();
3450 #else
3451 #ifdef HPUX5WINTCP
3452     extern struct in_addr inet_addr();
3453 #endif /* HPUX5WINTCP */
3454 #endif /* datageneral */
3455     struct in_addr iax;
3456 #else
3457 #ifdef INADDR_NONE
3458     struct in_addr iax;
3459 #else /* INADDR_NONE */
3460     long iax;
3461 #endif /* INADDR_NONE */
3462 #endif /* INADDRX */
3463 #endif /* TCPSOCKET */
3464
3465 #ifdef COMMENT
3466 /* This causes big trouble */
3467 #ifndef INADDR_NONE
3468 #define INADDR_NONE 0xffffffff
3469 #endif /* INADDR_NONE */
3470 #endif /* COMMENT */
3471
3472 #ifdef SUNX25                           /* Code for SunLink X.25 support */
3473 #define X29PID 1                        /* X.29 Protocol ID */
3474 _PROTOTYP(SIGTYP x25oobh, (int) );
3475     CONN_DB x25host;
3476 #ifndef X25_WR_FACILITY
3477     FACILITY x25facil;
3478 #else
3479     FACILITY_DB x25facil;
3480 #endif /* X25_WR_FACILITY */
3481     static int needh = 1;
3482     PID_T pid;
3483     extern int linkid, lcn, x25ver;
3484 #endif /* SUNX25 */
3485 #ifdef ANYX25
3486     extern int revcall, closgr, cudata;
3487     extern char udata[];
3488 #endif /* ANYX25 */
3489
3490 #ifdef IBMX25                           /* Variables for IBM X25 */
3491     extern int x25port;                 /* Logical port to use */
3492     extern x25addr_t local_nua;         /* Local X.25 address */
3493     extern x25addr_t remote_nua;        /* Remote X.25 address */
3494     extern char x25name[];              /* X25 device name (sx25a0) */
3495     extern char x25dev[];               /* X25 device file /dev/x25pkt */
3496     ulong bind_flags = 0;               /* Flags for binding the X25 stream */
3497     ulong token = 0;                    /* Temporary return code */
3498 #endif /* IBMX25 */
3499
3500     debug(F101,"netopen nett","",nett);
3501     *ipaddr = '\0';                     /* Initialize IP address string */
3502
3503 #ifdef SUNX25
3504     if (nett == NET_SX25) {             /* If network type is X.25 */
3505         netclos();                      /* Close any previous net connection */
3506         ttnproto = NP_NONE;             /* No protocol selected yet */
3507
3508         /* Set up host structure */
3509         bzero((char *)&x25host,sizeof(x25host));
3510         if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
3511             fprintf (stderr,"Invalid X.121 host address %s\n",name);
3512             errno = 0;
3513             return (-1);
3514         }
3515         x25host.datalen = X29PIDLEN;
3516         x25host.data[0] = X29PID;
3517
3518         /* Set call user data if specified */
3519         if (cudata) {
3520             ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
3521             x25host.datalen += (int)strlen(udata);
3522         }
3523
3524         /* Open SunLink X.25 socket */
3525         if (!quiet && *name) {
3526             printf(" Trying %s... ", name);
3527             fflush(stdout);
3528         }
3529         if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
3530             debug(F101,"netopen socket error","",errno);
3531             perror ("X.25 socket error");
3532             return (-1);
3533         }
3534
3535         /* Setting X.25 out-of-band data handler */
3536         pid = getpid();
3537         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
3538             perror("X.25 set process group id error");
3539             return(-1);
3540         }
3541         (VOID) signal(SIGURG,x25oobh);
3542
3543         /* Set reverse charge call and closed user group if requested */
3544         bzero ((char *)&x25facil,sizeof(x25facil));
3545
3546 #ifndef X25_WR_FACILITY
3547 /*  New SunLink (7.0 or 8.0, not sure which)... */
3548         x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
3549         x25facil.f_reverse_charge = revcall ? 1 : 0;
3550         if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3551             perror ("Setting X.25 reverse charge");
3552             return (-1);
3553         }
3554         if (closgr > -1) {              /* Closed User Group (Outgoing) */
3555             bzero ((char *)&x25facil,sizeof(x25facil));
3556             x25facil.type = T_CUG;
3557             x25facil.f_cug_req = CUG_REQ_ACS;
3558             x25facil.f_cug_index = closgr;
3559             if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3560                 perror ("Setting X.25 closed user group");
3561                 return (-1);
3562             }
3563         }
3564 #else
3565 /*  Old SunLink 6.0 (or 7.0?)... */
3566         if (revcall) x25facil.reverse_charge = revcall;
3567         if (closgr > -1) {
3568             x25facil.cug_req = 1;
3569             x25facil.cug_index = closgr;
3570         }
3571         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
3572             perror ("Setting X.25 facilities");
3573             return (-1);
3574         }
3575 #endif /* X25_WR_FACILITY */
3576
3577         /*  Need X.25 header with bits Q and M */
3578         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
3579             perror ("Setting X.25 header");
3580             return (-1);
3581         }
3582
3583         /* Connects to remote host via SunLink X.25 */
3584         if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
3585             i = errno;
3586             debug(F101,"netopen connect errno","",i);
3587             if (i) {
3588                 perror("netopen x25 connect");
3589                 x25diag();
3590             }
3591             (VOID) netclos();
3592             ttyfd = -1;
3593             wasclosed = 1;
3594             ttnproto = NP_NONE;
3595             errno = i;
3596             return (-1);
3597         }
3598
3599         /* Get X.25 link identification used for the connection */
3600         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
3601             perror ("Getting X.25 link id");
3602             return (-1);
3603         }
3604
3605         /* Get X.25 logical channel number used for the connection */
3606         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
3607             perror ("Getting X.25 lcn");
3608             return (-1);
3609         }
3610
3611         /* Get SunLink X.25 version */
3612         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
3613             perror ("Getting SunLink X.25 version");
3614             return (-1);
3615         }
3616         ttnet = nett;                   /* Sunlink X.25 network */
3617         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
3618         if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3619         return(0);
3620     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
3621 #endif /* SUNX25 */
3622
3623 #ifdef IBMX25
3624     /* riehm */
3625     if (nett == NET_IX25) {             /* IBM AIX X.25 */
3626         netclos();                      /* Close any previous net connection */
3627         ttnproto = NP_NONE;             /* No protocol selected yet */
3628
3629         /* find out who we are - this is not so easy on AIX */
3630         /* riehm: need to write the code that finds this out
3631          * automatically, or at least allow it to be configured
3632          * somehow
3633          */
3634         if (!local_nua[0] && !x25local_nua(local_nua)) {
3635             return(-1);
3636         }
3637
3638         /* Initialise the X25 API (once per process? once per connection?) */
3639
3640         debug(F110, "Opening ", x25dev, 0 );
3641         /* set O_NDELAY to allow polling? */
3642         if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
3643             perror ("X.25 device open error");
3644             debug(F101,"netopen: device open error","",errno);
3645             return (-1);
3646         }
3647
3648         /* push the NPI onto the STREAM */
3649         if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
3650             close(ttyfd);
3651             ttyfd = -1;
3652             wasclosed = 1;
3653             perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
3654             debug(F101,"netopen: can't push npi on the X25 stream","",errno);
3655             return (-1);
3656         }
3657
3658         /* set up server mode - bind the x25 port and wait for
3659          * incoming connections
3660          */
3661         if (name[0] == '*') {           /* Server */
3662             /* set up a server - see the warning in x25bind() */
3663             bind_flags |= TOKEN_REQUEST;
3664
3665             /* bind kermit to the local X25 address */
3666             token = x25bind(ttyfd,
3667                             local_nua,
3668                             udata,
3669                             (int)strlen( udata ),
3670                             1,
3671                             x25port,
3672                             bind_flags
3673                             );
3674             if (token < 0) {
3675                 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3676                 netclos();
3677                 return(-1);
3678             }
3679             /* Currently not connected to a remote host */
3680
3681             remote_nua[0] = '\0';
3682
3683             /* store the fd so that incoming calls can have their own fd
3684              * This is almost support for a true server (ie: a'la ftpd)
3685              * but we're not quite there yet.
3686              * used in netclos()
3687              */
3688             x25serverfd = ttyfd;
3689             /*
3690              * wait for an incoming call
3691              * this should happen in the "server" command and not in
3692              * the "set host *" command.
3693              */
3694             if ((ttyfd = x25getcall(ttyfd)) < 0) {
3695                 netclos();
3696                 return(-1);
3697             }
3698         } else {                        /* Client */
3699             /* Bind kermit to the local X25 address */
3700             token = x25bind(
3701                             ttyfd,
3702                             local_nua,
3703                             (char *)NULL,
3704                             0,
3705                             0,
3706                             x25port,
3707                             bind_flags
3708                             );
3709             if (token < 0) {
3710                 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3711                 netclos();
3712                 return(-1);
3713             }
3714 /* riehm: this should be done via the CONNECT command, not HOST! */
3715             {
3716                 x25serverfd = 0;
3717                 /* call the remote host */
3718                 /* name == address of remote host as char* */
3719                 if (x25call(ttyfd, name, udata) < 0 ) {
3720                     debug(F100,
3721                           "netopen: couldn't connect to remote X25 address",
3722                           "", 0);
3723                     netclos();
3724                     return(-1);
3725                 }
3726                 strcpy(remote_nua, name);
3727             }
3728         }
3729         ttnet = nett;                   /* AIX X.25 network */
3730         if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3731         return(0);
3732
3733     } else /* Note that IBMX25 support can coexist with TCP/IP support. */
3734 #endif /* IBMX25 */
3735
3736 /*   Add support for other networks here. */
3737
3738       if (nett != NET_TCPB) return(-1); /* BSD socket support */
3739
3740 #ifdef TCPSOCKET
3741     netclos();                          /* Close any previous connection. */
3742     ckstrncpy(namecopy, name, NAMECPYL);        /* Copy the hostname. */
3743     debug(F110,"netopen namecopy",namecopy,0);
3744
3745 #ifndef NOLISTEN
3746     if (name[0] == '*')
3747       return(tcpsrv_open(name, lcl, nett, 0));
3748 #endif /* NOLISTEN */
3749
3750     p = namecopy;                       /* Was a service requested? */
3751     while (*p != '\0' && *p != ':') p++; /* Look for colon */
3752     if (*p == ':') {                    /* Have a colon */
3753         debug(F110,"netopen name has colon",namecopy,0);
3754         *p++ = '\0';                    /* Get service name or number */
3755 #ifdef CK_URL
3756         /*
3757            Here we have to check for various popular syntaxes:
3758            host:port (our original syntax)
3759            URL such as telnet:host or telnet://host/
3760            Or even telnet://user:password@host:port/path/
3761            Or a malformed URL such as generated by Netscape 4.0 like:
3762            telnet:telnet or telnet::host.
3763         */
3764
3765         /*
3766          * REPLACE THIS CODE WITH urlparse() but not on the day of the
3767          * C-Kermit 8.0 RELEASE.
3768          */
3769
3770         if (*p == ':')                  /* a second colon */
3771           *p++ = '\0';                  /* get rid of that one too */
3772         while (*p == '/') *p++ = '\0';  /* and slashes */
3773         x = strlen(p);                  /* Length of remainder */
3774         if (p[x-1] == '/')              /* If there is a trailing slash */
3775           p[x-1] = '\0';                /* remove it. */
3776         debug(F110,"netopen namecopy after stripping",namecopy,0);
3777         debug(F110,"netopen p after stripping",p,0);
3778         service = getservbyname(namecopy,"tcp");
3779         if (service ||
3780 #ifdef RLOGCODE
3781             !ckstrcmp("rlogin",namecopy,NAMECPYL,0) ||
3782 #endif /* RLOGCODE */
3783 #ifdef CK_SSL
3784             !ckstrcmp("telnets",namecopy,NAMECPYL,0) ||
3785 #endif /* CK_SSL */
3786             !ckstrcmp("iksd",namecopy,NAMECPYL,0)
3787             ) {
3788             char temphost[256], tempservice[80], temppath[256];
3789             char * q = p, *r = p, *w = p;
3790             int uidfound=0;
3791             extern char pwbuf[];
3792             extern int pwflg, pwcrypt;
3793
3794             if (ttnproto == NP_DEFAULT)
3795               setnproto(namecopy);
3796
3797             /* Check for userid and possibly password */
3798             while (*p != '\0' && *p != '@')
3799                 p++; /* look for @ */
3800             if (*p == '@') {
3801                 /* found username and perhaps password */
3802                 debug(F110,"netopen namecopy found @","",0);
3803                 *p = '\0';
3804                 p++;
3805                 while (*w != '\0' && *w != ':')
3806                   w++;
3807                 if (*w == ':')
3808                   *w++ = '\0';
3809                 /* r now points to username, save it and the password */
3810                 debug(F110,"netopen namecopy username",r,0);
3811                 debug(F110,"netopen namecopy password",w,0);
3812                 uidfound=1;
3813                 if ( strcmp(uidbuf,r) || *w )
3814                     ckstrncpy(pwbuf,w,PWBUFL+1);
3815                 ckstrncpy(uidbuf,r,UIDBUFLEN);
3816                 pwflg = 1;
3817                 pwcrypt = 0;
3818                 q = p;                  /* Host after user and pwd */
3819             } else {
3820                 p = q;                  /* No username or password */
3821             }
3822             /* Now we must look for the optional port. */
3823             debug(F110,"netopen x p",p,0);
3824             debug(F110,"netopen x q",q,0);
3825
3826             /* Look for the port/service or a file/directory path */
3827             while (*p != '\0' && *p != ':' && *p != '/')
3828               p++;
3829             if (*p == ':') {
3830                 debug(F110,"netopen found port",q,0);
3831                 *p++ = '\0';            /* Found a port name or number */
3832                 r = p;
3833
3834                 /* Look for the end of port/service or a file/directory path */
3835                 while (*p != '\0' && *p != '/')
3836                     p++;
3837                 if (*p == '/')
3838                     *p++ = '\0';
3839
3840                 debug(F110,"netopen port",r,0);
3841                 ckstrncpy(tempservice,r,80);
3842                 ckstrncpy(temphost,q,256);
3843                 ckstrncpy(temppath,p,256);
3844                 ckstrncpy(namecopy,temphost,NAMECPYL);
3845                 debug(F110,"netopen tempservice",tempservice,0);
3846                 debug(F110,"netopen temphost",temphost,0);
3847                 debug(F110,"netopen temppath",temppath,0);
3848
3849                 /* move port/service to a buffer that won't go away */
3850                 x = strlen(namecopy);
3851                 p = namecopy + x + 1;
3852                 ckstrncpy(p, tempservice, NAMECPYL - x);
3853             } else {
3854                 /* Handle a path if we found one */
3855                 if (*p == '/')
3856                     *p++ = '\0';
3857                 ckstrncpy(temppath,p,256);
3858
3859                 /* We didn't find another port, but if q is a service */
3860                 /* then assume that namecopy is actually a host.      */
3861                 if (getservbyname(q,"tcp")) {
3862                     p = q;
3863                 } else {
3864 #ifdef RLOGCODE
3865                     /* rlogin is not a valid service */
3866                     if (!ckstrcmp("rlogin",namecopy,6,0)) {
3867                         ckstrncpy(namecopy,"login",NAMECPYL);
3868                     }
3869 #endif /* RLOGCODE */
3870                     /* iksd is not a valid service */
3871                     if (!ckstrcmp("iksd",namecopy,6,0)) {
3872                         ckstrncpy(namecopy,"kermit",NAMECPYL);
3873                     }
3874                     /* Reconstruct namecopy */
3875                     ckstrncpy(tempservice,namecopy,80);
3876                     ckstrncpy(temphost,q,256);
3877                     ckstrncpy(namecopy,temphost,NAMECPYL);
3878                     debug(F110,"netopen tempservice",tempservice,0);
3879                     debug(F110,"netopen temphost",temphost,0);
3880                     debug(F110,"netopen temppath",temppath,0);
3881
3882                     /* move port/service to a buffer that won't go away */
3883                     x = strlen(namecopy);
3884                     p = namecopy + x + 1;
3885                     ckstrncpy(p, tempservice, NAMECPYL - x - 1);
3886                 }
3887             }
3888             debug(F110,"netopen URL result: host",namecopy,0);
3889             debug(F110,"netopen URL result: service",p,0);
3890             debug(F110,"netopen URL result: path",temppath,0);
3891
3892 #ifdef IKS_GET
3893             /* If we have set a path specified, we need to try to GET it */
3894             /* But we have another problem, we have to login first.  How */
3895             /* do we specify that a login must be done before the GET?   */
3896             /* The user's name if specified is in 'userid' and the       */
3897             /* password if any is in 'pwbuf'.                            */
3898             if ( temppath[0] ) {
3899                 extern int action;
3900                 extern char * cmarg;
3901
3902                 if ( !uidfound ) {
3903                     /* If no userid was specified as part of the URL but
3904                      * a path was specified, then we
3905                      * set the user name to anonymous and the password
3906                      * to the current userid.
3907                      */
3908                     ckstrncpy(pwbuf,uidbuf,PWBUFL);
3909                     ckstrncat(pwbuf,"@",PWBUFL);
3910                     pwflg = 1;
3911                     pwcrypt = 0;
3912                     ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
3913                 }
3914
3915                 /*
3916                  * If a file path was specified we perform the GET
3917                  * operation and then terminate the connection.
3918                  *
3919                  * If a directory was given instead of a file, then
3920                  * we should REMOTE CD to the directory and list its
3921                  * contents.  But how do we tell the difference?
3922                  */
3923                 makestr(&cmarg,temppath);
3924                 action = 'r';
3925             }
3926 #endif /* IKS_GET */
3927         }
3928 #endif /* CK_URL */
3929     } else {                            /* Otherwise use telnet */
3930         p = "telnet";
3931     }
3932 /*
3933   By the time we get here, namecopy[] should hold the null-terminated
3934   hostname or address, and p should point to the service name or number.
3935 */
3936     debug(F110,"netopen host",namecopy,0);
3937     debug(F110,"netopen service requested",p,0);
3938
3939    /* Use the service port to set the default protocol type if necessary */
3940     if (ttnproto == NP_DEFAULT)
3941        setnproto(p);
3942
3943     ckstrncpy(namecopy2,namecopy,NAMECPYL);
3944     service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
3945     if (!service) {
3946         fprintf(stderr, "Can't find port for service %s\n", p);
3947 #ifdef TGVORWIN
3948         debug(F101,"netopen can't get service","",socket_errno);
3949 #else
3950         debug(F101,"netopen can't get service","",errno);
3951 #endif /* TGVORWIN */
3952         errno = 0;                  /* (rather than mislead) */
3953         return(-1);
3954     } else {
3955         if (!ckstrcmp(namecopy,namecopy2,-1,0))
3956           namecopy2[0] = '\0';
3957         ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf));
3958         debug(F110,"netopen service ok",svcbuf,0);
3959     }
3960
3961 #ifdef RLOGCODE
3962     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
3963         fprintf(stderr,
3964                 "  Warning: login service on port %d instead of port 513\n",
3965                  ntohs(service->s_port)
3966                 );
3967         fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
3968         debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
3969     }
3970 #endif /* RLOGCODE */
3971
3972 #ifndef NOHTTP
3973    /* For HTTP connections we must preserve the original hostname and */
3974    /* service requested so we can include them in the Host header.    */
3975     ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":",
3976               ckitoa(ntohs(service->s_port)),NULL);
3977
3978     /* 'namecopy' contains the name of the host to which we want to connect */
3979     /* 'svcbuf'   contains the service name                                 */
3980     /* 'service->s_port' contains the port number in network byte order     */
3981
3982     /* If we are using an http proxy, we need to create a buffer containing */
3983     /*   hostname:port-number                                               */
3984     /* to pass to the http_connect() function.  Then we need to replace     */
3985     /* 'namecopy' with the name of the proxy server and the service->s_port */
3986     /* with the port number of the proxy (default port 80).                 */
3987
3988     if ( tcp_http_proxy ) {
3989         ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":",
3990                  ckuitoa(ntohs(service->s_port)),NULL);
3991         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
3992
3993         p = namecopy;                       /* Was a service requested? */
3994         while (*p != '\0' && *p != ':') p++; /* Look for colon */
3995         if (*p == ':') {                    /* Have a colon */
3996             debug(F110,"netopen name has colon",namecopy,0);
3997             *p++ = '\0';                    /* Get service name or number */
3998         } else {
3999             strcpy(++p,"http");
4000         }
4001
4002         service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4003         if (!service) {
4004             fprintf(stderr, "Can't find port for service %s\n", p);
4005 #ifdef TGVORWIN
4006             debug(F101,"netopen can't get service for proxy","",socket_errno);
4007 #else
4008             debug(F101,"netopen can't get service for proxy","",errno);
4009 #endif /* TGVORWIN */
4010             errno = 0;                  /* (rather than mislead) */
4011             return(-1);
4012         }
4013         ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy));
4014
4015     }
4016 #endif /* NOHTTP */
4017
4018     /* Set up socket structure and get host address */
4019
4020     bzero((char *)&r_addr, sizeof(r_addr));
4021     debug(F100,"netopen bzero ok","",0);
4022 /*
4023    NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
4024    all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
4025    address without going through the multihomed host sequence and winding up
4026    at a different place than the one requested.
4027 */
4028 #ifdef INADDR_NONE
4029     debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
4030 #else /* INADDR_NONE */
4031     debug(F100,"netopen INADDR_NONE not defined","",0);
4032 #endif /* INADDR_NONE */
4033 #ifdef INADDRX
4034     debug(F100,"netopen INADDRX defined","",0);
4035 #else /* INADDRX */
4036     debug(F100,"netopen INADDRX not defined","",0);
4037 #endif /* INADDRX */
4038
4039 #ifndef NOMHHOST
4040 #ifdef INADDRX
4041     iax = inet_addr(namecopy);
4042     debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4043 #else /* INADDRX */
4044 #ifdef INADDR_NONE
4045     iax.s_addr = inet_addr(namecopy);
4046     debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4047 #else /* INADDR_NONE */
4048 #ifndef datageneral
4049     iax = (unsigned int) inet_addr(namecopy);
4050 #else
4051     iax = -1L;
4052 #endif /* datageneral */
4053     debug(F111,"netopen inet_addr",namecopy,iax);
4054 #endif /* INADDR_NONE */
4055 #endif /* INADDRX */
4056
4057     dns = 0;
4058     if (
4059 #ifdef INADDR_NONE
4060 /* This might give warnings on 64-bit platforms but they should be harmless */
4061 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
4062 /* probably superfluous -- not sure why it's even there, maybe it should be */
4063 /* removed. */
4064         iax.s_addr == INADDR_NONE || iax.s_addr == (unsigned long) -1L
4065 #else /* INADDR_NONE */
4066         iax < 0
4067 #endif /* INADDR_NONE */
4068         ) {
4069         if (!quiet) {
4070             printf(" DNS Lookup... ");
4071             fflush(stdout);
4072         }
4073         if ((host = gethostbyname(namecopy)) != NULL) {
4074             debug(F100,"netopen gethostbyname != NULL","",0);
4075             host = ck_copyhostent(host);
4076             dns = 1;                    /* Remember we performed dns lookup */
4077             r_addr.sin_family = host->h_addrtype;
4078             if (tcp_rdns && host->h_name && host->h_name[0]
4079 #ifndef NOHTTP
4080                  && (tcp_http_proxy == NULL)
4081 #endif /* NOHTTP */
4082                  ) {                   /* Copying into our argument? */
4083                 ckstrncpy(name,host->h_name,80);  /* Bad Bad Bad */
4084                 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4085                     strncat(name,":",80-strlen(name));
4086                     strncat(name,svcbuf,80-strlen(name));
4087                 }
4088             }
4089
4090 #ifdef HADDRLIST
4091 #ifdef h_addr
4092             /* This is for trying multiple IP addresses - see <netdb.h> */
4093             if (!(host->h_addr_list))
4094               return(-1);
4095             bcopy(host->h_addr_list[0],
4096                   (caddr_t)&r_addr.sin_addr,
4097                   host->h_length
4098                   );
4099 #else
4100             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4101 #endif /* h_addr */
4102 #else  /* HADDRLIST */
4103             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4104 #endif /* HADDRLIST */
4105 #ifndef EXCELAN
4106             debug(F111,"BCOPY","host->h_addr",host->h_addr);
4107 #endif /* EXCELAN */
4108             debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
4109                   (caddr_t)&r_addr.sin_addr);
4110             debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
4111                   r_addr.sin_addr.s_addr);
4112             debug(F111,"BCOPY","host->h_length",host->h_length);
4113         }
4114     }
4115 #endif /* NOMHHOST */
4116
4117     if (!dns) {
4118 #ifdef INADDRX
4119 /* inet_addr() is of type struct in_addr */
4120         struct in_addr ina;
4121         unsigned long uu;
4122         debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
4123         ina = inet_addr(namecopy);
4124         uu = *(unsigned int *)&ina;
4125 #else /* Not INADDRX */
4126 /* inet_addr() is unsigned long */
4127         unsigned long uu;
4128         debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
4129         uu = inet_addr(namecopy);
4130 #endif /* INADDRX */
4131         debug(F101,"netopen uu","",uu);
4132         if (
4133 #ifdef INADDR_NONE
4134             !(uu == INADDR_NONE || uu == (unsigned int) -1L)
4135 #else   /* INADDR_NONE */
4136             uu != ((unsigned long)-1)
4137 #endif /* INADDR_NONE */
4138             ) {
4139             r_addr.sin_addr.s_addr = uu;
4140             r_addr.sin_family = AF_INET;
4141         } else {
4142 #ifdef VMS
4143             fprintf(stdout, "\r\n");    /* complete any previous message */
4144 #endif /* VMS */
4145             fprintf(stderr, "Can't get address for %s\n", namecopy);
4146 #ifdef TGVORWIN
4147             debug(F101,"netopen can't get address","",socket_errno);
4148 #else
4149             debug(F101,"netopen can't get address","",errno);
4150 #endif /* TGVORWIN */
4151             errno = 0;                  /* Rather than mislead */
4152             return(-1);
4153         }
4154     }
4155
4156     /* Get a file descriptor for the connection. */
4157
4158     r_addr.sin_port = service->s_port;
4159     ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4160     debug(F110,"netopen trying",ipaddr,0);
4161     if (!quiet && *ipaddr) {
4162         printf(" Trying %s... ", ipaddr);
4163         fflush(stdout);
4164     }
4165
4166     /* Loop to try additional IP addresses, if any. */
4167
4168     do {
4169 #ifdef EXCELAN
4170         send_socket.sin_family = AF_INET;
4171         send_socket.sin_addr.s_addr = 0;
4172         send_socket.sin_port = 0;
4173         if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
4174                             &send_socket, SO_REUSEADDR)) < 0)
4175 #else  /* EXCELAN */
4176 #ifdef NT
4177 #ifdef COMMENT_X
4178        /*
4179          Must make sure that all sockets are opened in
4180          Non-overlapped mode since we use the standard
4181          C RTL functions to read and write data.
4182          But it doesn't seem to work as planned.
4183        */
4184           {
4185               int optionValue = SO_SYNCHRONOUS_NONALERT;
4186               if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
4187                              (char *) &optionValue, sizeof(optionValue))
4188                   != NO_ERROR)
4189                 return(-1);
4190           }
4191 #endif /* COMMENT */
4192 #endif /* NT */
4193
4194         if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
4195 #endif /* EXCELAN */
4196             {
4197 #ifdef EXCELAN
4198                 experror("TCP socket error");
4199 #else
4200 #ifdef VMS
4201                 fprintf(stdout, "\r\n"); /* complete any previous stdout */
4202 #endif /* VMS */
4203 #ifdef TGVORWIN
4204 #ifdef OLD_TWG
4205                 errno = socket_errno;
4206 #endif /* OLD_TWG */
4207                 socket_perror("TCP socket error");
4208                 debug(F101,"netopen socket error","",socket_errno);
4209 #else
4210                 perror("TCP socket error");
4211                 debug(F101,"netopen socket error","",errno);
4212 #endif /* TGVORWIN */
4213 #endif /* EXCELAN */
4214                 return (-1);
4215             }
4216         errno = 0;
4217
4218 #ifdef RLOGCODE
4219        /* Not part of the RLOGIN RFC, but the BSD implementation     */
4220        /* requires that the client port be a priviliged port (<1024) */
4221        /* on a Unix system this would require SuperUser permissions  */
4222        /* thereby saying that the root of the Unix system has given  */
4223        /* permission for this connection to be created               */
4224        if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
4225            static unsigned short lport = 1024;  /* max reserved port */
4226 #ifdef OS2
4227            int s_errno;
4228 #endif /* OS2 */
4229
4230            lport--;                     /* Make sure we do not reuse a port */
4231            if (lport == 512)
4232              lport = 1023;
4233
4234            sin.sin_family = AF_INET;
4235            if (tcp_address) {
4236 #ifdef INADDRX
4237                inaddrx = inet_addr(tcp_address);
4238                sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4239 #else
4240                sin.sin_addr.s_addr = inet_addr(tcp_address);
4241 #endif /* INADDRX */
4242            } else
4243              sin.sin_addr.s_addr = INADDR_ANY;
4244            while (1) {
4245                sin.sin_port = htons(lport);
4246                if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
4247                  break;
4248 #ifdef OS2
4249                s_errno = socket_errno;
4250                if (s_errno && /* OS2 bind fails with 0, if already in use */
4251 #ifdef NT
4252                    s_errno != WSAEADDRINUSE
4253 #else
4254                    s_errno != SOCEADDRINUSE &&
4255                    s_errno != (SOCEADDRINUSE - SOCBASEERR)
4256 #endif /* NT */
4257                    )
4258 #else /* OS2 */
4259 #ifdef TGVORWIN
4260                  if (socket_errno != EADDRINUSE)
4261 #else
4262                  if (errno != EADDRINUSE)
4263 #endif /* TGVORWIN */
4264 #endif /* OS2 */
4265                    {
4266 #ifdef COMMENT
4267                        printf("\nBind failed with errno %d  for port %d.\n",
4268 #ifdef OS2
4269                               s_errno
4270 #else
4271 #ifdef TGVORWIN
4272                               socket_errno
4273 #else
4274                               errno
4275 #endif /* TGVORWIN */
4276 #endif /* OS2 */
4277                               , lport
4278                               );
4279 #ifdef OS2
4280                        debug(F101,"rlogin bind failed","",s_errno);
4281 #else
4282 #ifdef TGVORWIN
4283                        debug(F101,"rlogin bind failed","",socket_errno);
4284 #ifdef OLD_TWG
4285                        errno = socket_errno;
4286 #endif /* OLD_TWG */
4287                        socket_perror("rlogin bind");
4288 #else
4289                        debug(F101,"rlogin bind failed","",errno);
4290                        perror("rlogin bind");
4291 #endif /* TGVORWIN */
4292 #endif /* OS2 */
4293 #else  /* COMMENT */
4294 #ifdef OS2
4295                        debug(F101,"rlogin bind s_errno","",s_errno);
4296                        perror("rlogin bind");
4297 #else
4298 #ifdef VMS
4299                        printf("\r\n");  /* complete any previous message */
4300 #endif /* VMS */
4301 #ifdef TGVORWIN
4302                        debug(F101,"rlogin bind socket_errno","",socket_errno);
4303 #ifdef OLD_TWG
4304                        errno = socket_errno;
4305 #endif /* OLD_TWG */
4306                        socket_perror("rlogin bind");
4307 #else
4308                        debug(F101,"rlogin bind errno","",errno);
4309                        perror("rlogin bind");
4310 #endif /* TGVORWIN */
4311 #endif /* OS2 */
4312                        debug(F101,"rlogin local port","",lport);
4313 #endif /* COMMENT */
4314                        netclos();
4315                        return -1;
4316                    }
4317                lport--;
4318                if (lport == 512 /* lowest reserved port to use */ ) {
4319                    printf("\nNo reserved ports available.\n");
4320                    netclos();
4321                    return -1;
4322                }
4323            }
4324            debug(F101,"rlogin lport","",lport);
4325            ttnproto = NP_RLOGIN;
4326        } else
4327 #endif /* RLOGCODE  */
4328
4329        /* If a specific TCP address on the local host is desired we */
4330        /* must bind it to the socket.                               */
4331 #ifndef datageneral
4332          if (tcp_address) {
4333              int s_errno;
4334
4335              debug(F110,"netopen binding socket to",tcp_address,0);
4336              bzero((char *)&sin,sizeof(sin));
4337              sin.sin_family = AF_INET;
4338 #ifdef INADDRX
4339              inaddrx = inet_addr(tcp_address);
4340              sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4341 #else
4342              sin.sin_addr.s_addr = inet_addr(tcp_address);
4343 #endif /* INADDRX */
4344              sin.sin_port = 0;
4345              if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
4346                  s_errno = socket_errno; /* Save error code */
4347 #ifdef TCPIPLIB
4348                  socket_close(ttyfd);
4349 #else /* TCPIPLIB */
4350                  close(ttyfd);
4351 #endif /* TCPIPLIB */
4352                  ttyfd = -1;
4353                  wasclosed = 1;
4354                  errno = s_errno;       /* and report this error */
4355                  debug(F101,"netopen bind errno","",errno);
4356                  return(-1);
4357              }
4358          }
4359 #endif /* datageneral */
4360
4361 /* Now connect to the socket on the other end. */
4362
4363 #ifdef EXCELAN
4364         if (connect(ttyfd, &r_addr) < 0)
4365 #else
4366 #ifdef NT
4367           WSASafeToCancel = 1;
4368 #endif /* NT */
4369         if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
4370 #endif /* EXCELAN */
4371           {
4372 #ifdef NT
4373               WSASafeToCancel = 0;
4374 #endif /* NT */
4375 #ifdef OS2
4376               i = socket_errno;
4377 #else /* OS2 */
4378 #ifdef TGVORWIN
4379               i = socket_errno;
4380 #else
4381               i = errno;                /* Save error code */
4382 #endif /* TGVORWIN */
4383 #endif /* OS2 */
4384 #ifdef RLOGCODE
4385               if (
4386 #ifdef OS2
4387                  i && /* OS2 bind fails with 0, if already in use */
4388 #ifdef NT
4389                  i == WSAEADDRINUSE
4390 #else
4391                  (i == SOCEADDRINUSE ||
4392                  i == (SOCEADDRINUSE - SOCBASEERR))
4393 #endif /* NT */
4394 #else /* OS2 */
4395 #ifdef TGVORWIN
4396                   socket_errno == EADDRINUSE
4397 #else
4398                   errno == EADDRINUSE
4399 #endif /* TGVORWIN */
4400 #endif /* OS2 */
4401                   && ttnproto == NP_RLOGIN) {
4402 #ifdef TCPIPLIB
4403                    socket_close(ttyfd); /* Close it. */
4404 #else
4405                    close(ttyfd);
4406 #endif /* TCPIPLIB */
4407                    continue;            /* Try a different lport */
4408                }
4409 #endif /* RLOGCODE */
4410 #ifdef HADDRLIST
4411 #ifdef h_addr
4412               if (host && host->h_addr_list && host->h_addr_list[1]) {
4413                   perror("");
4414                   host->h_addr_list++;
4415                   bcopy(host->h_addr_list[0],
4416                         (caddr_t)&r_addr.sin_addr,
4417                         host->h_length);
4418
4419                   ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4420                   debug(F110,"netopen h_addr_list",ipaddr,0);
4421                   if (!quiet && *ipaddr) {
4422                       printf(" Trying %s... ", ipaddr);
4423                       fflush(stdout);
4424                   }
4425 #ifdef TCPIPLIB
4426                   socket_close(ttyfd); /* Close it. */
4427 #else
4428                   close(ttyfd);
4429 #endif /* TCPIPLIB */
4430                   continue;
4431               }
4432 #endif /* h_addr */
4433 #endif  /* HADDRLIST */
4434               netclos();
4435               ttyfd = -1;
4436               wasclosed = 1;
4437               ttnproto = NP_NONE;
4438               errno = i;                /* And report this error */
4439 #ifdef EXCELAN
4440               if (errno) experror("netopen connect");
4441 #else
4442 #ifdef TGVORWIN
4443               debug(F101,"netopen connect error","",socket_errno);
4444               /* if (errno) socket_perror("netopen connect"); */
4445 #ifdef OLD_TWG
4446               errno = socket_errno;
4447 #endif /* OLD_TWG */
4448               if (!quiet)
4449                 socket_perror("netopen connect");
4450 #else /* TGVORWIN */
4451               debug(F101,"netopen connect errno","",errno);
4452 #ifdef VMS
4453               if (!quiet)
4454                 perror("\r\nFailed");
4455 #else
4456               if (!quiet)
4457                 perror("Failed");
4458 #endif /* VMS */
4459 #ifdef DEC_TCPIP
4460               if (!quiet)
4461                 perror("netopen connect");
4462 #endif /* DEC_TCPIP */
4463 #ifdef CMU_TCPIP
4464               if (!quiet)
4465                 perror("netopen connect");
4466 #endif /* CMU_TCPIP */
4467 #endif /* TGVORWIN */
4468 #endif /* EXCELAN */
4469               return(-1);
4470           }
4471 #ifdef NT
4472         WSASafeToCancel = 0;
4473 #endif /* NT */
4474         isconnect = 1;
4475     } while (!isconnect);
4476
4477 #ifdef NON_BLOCK_IO
4478     on = 1;
4479     x = socket_ioctl(ttyfd,FIONBIO,&on);
4480     debug(F101,"netopen FIONBIO","",x);
4481 #endif /* NON_BLOCK_IO */
4482
4483 #ifdef NT_TCP_OVERLAPPED
4484     OverlappedWriteInit();
4485     OverlappedReadInit();
4486 #endif /* NT_TCP_OVERLAPPED */
4487
4488     ttnet = nett;                       /* TCP/IP (sockets) network */
4489
4490 #ifndef NOHTTP
4491     /* We have succeeded in connecting to the HTTP PROXY.  So now we   */
4492     /* need to attempt to connect through the proxy to the actual host */
4493     /* If that is successful, we have to pretend that we made a direct */
4494     /* connection to the actual host.                                  */
4495
4496     if ( tcp_http_proxy ) {
4497 #ifdef OS2
4498         char * agent = "Kermit 95";             /* Default user agent */
4499 #else
4500         char * agent = "C-Kermit";
4501 #endif /* OS2 */
4502
4503         if (http_connect(ttyfd,
4504                          tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
4505                          NULL,
4506                          tcp_http_proxy_user,
4507                          tcp_http_proxy_pwd,
4508                          0,
4509                          proxycopy
4510                          ) < 0) {
4511             netclos();
4512             return(-1);
4513         }
4514
4515         ckstrncpy(namecopy,proxycopy,NAMECPYL);
4516         p = namecopy;                       /* Was a service requested? */
4517         while (*p != '\0' && *p != ':') p++; /* Look for colon */
4518         *p = '\0';
4519     }
4520 #endif /* NOHTTP */
4521
4522     /* Jeff - Does this next block of code that set's the protocol */
4523     /* need to be here anymore?  5/10/2000                         */
4524
4525     /* There are certain magic port numbers that when used require */
4526     /* the use of specific protocols.  Check this now before we    */
4527     /* set the SO_OOBINLINE state or we might get it wrong.        */
4528     x = ntohs((unsigned short)service->s_port);
4529     svcnum = x;
4530     /* See if the service is TELNET. */
4531     if (x == TELNET_PORT) {
4532         /* Yes, so if raw port not requested */
4533         if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
4534           ttnproto = NP_TELNET;         /* Select TELNET protocol. */
4535     }
4536 #ifdef RLOGCODE
4537     else if (x == RLOGIN_PORT) {
4538         ttnproto = NP_RLOGIN;
4539     }
4540 #ifdef CK_KERBEROS
4541     /* There is no good way to do this.  If the user didn't tell    */
4542     /* which one to use up front.  We may guess wrong if the user   */
4543     /* has both Kerberos versions installed and valid TGTs for each */
4544     else if (x == KLOGIN_PORT &&
4545              ttnproto != NP_K4LOGIN &&
4546              ttnproto != NP_K5LOGIN) {
4547         if (ck_krb5_is_installed() &&
4548             ck_krb5_is_tgt_valid())
4549           ttnproto = NP_K5LOGIN;
4550         else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4551           ttnproto = NP_K4LOGIN;
4552         else
4553           ttnproto = NP_K4LOGIN;
4554     } else if (x == EKLOGIN_PORT &&
4555                ttnproto != NP_EK4LOGIN &&
4556                ttnproto != NP_EK5LOGIN) {
4557         if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
4558           ttnproto = NP_EK5LOGIN;
4559         else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4560           ttnproto = NP_EK4LOGIN;
4561         else
4562           ttnproto = NP_EK4LOGIN;
4563     }
4564 #endif /* CK_KERBEROS */
4565 #endif /* RLOGCODE */
4566 #ifdef IKS_OPTION
4567     else if (x == KERMIT_PORT) {        /* IKS uses Telnet protocol */
4568         if (ttnproto == NP_NONE)
4569           ttnproto = NP_KERMIT;
4570     }
4571 #endif /* IKS_OPTION */
4572
4573 #ifdef SO_OOBINLINE
4574 /*
4575   The symbol SO_OOBINLINE is not known to Ultrix 2.0.
4576   It means "leave out of band data inline".  The normal value is 0x0100,
4577   but don't try this on systems where the symbol is undefined.
4578 */
4579 /*
4580   Note from Jeff Altman: 12/13/95
4581   In implementing rlogin protocol I have come to the conclusion that it is
4582   a really bad idea to read out-of-band data inline.
4583   At least Windows and OS/2 does not handle this well.
4584   And if you need to know that data is out-of-band, then it becomes
4585   absolutely pointless.
4586
4587   Therefore, at least on OS2 and Windows (NT) I have changed the value of
4588   on to 0, so that out-of-band data stays out-of-band.
4589
4590   12/18/95
4591   Actually, OOB data should be read inline when possible.  Especially with
4592   protocols that don't care about the Urgent flag.  This is true with Telnet.
4593   With Rlogin, you need to be able to catch OOB data.  However, the best
4594   way to do this is to set a signal handler on SIGURG.  This isn't possible
4595   on OS/2 and Windows.  But it is in UNIX.  We will also need OOB data for
4596   FTP so better create a general mechanism.
4597
4598   The reason for making OOB data be inline is that the standard ttinc/ttoc
4599   calls can be used for reading that data on UNIX systems.  If we didn't
4600   have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
4601   to read it.
4602 */
4603 #ifdef RLOGCODE
4604 #ifdef TCPIPLIB
4605     if (ttnproto == NP_RLOGIN
4606 #ifdef CK_KERBEROS
4607         || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4608         || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4609 #endif /* CK_KERBEROS */
4610       )
4611       on = 0;
4612 #else /* TCPIPLIB */
4613     if (ttnproto == NP_RLOGIN
4614 #ifdef CK_KERBEROS
4615          || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4616          || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4617 #endif /* CK_KERBEROS */
4618          ) {
4619         debug(F100,"Installing rlogoobh on SIGURG","",0);
4620         signal(SIGURG, rlogoobh);
4621         on = 0;
4622     } else {
4623         debug(F100,"Ignoring SIGURG","",0);
4624         signal(SIGURG, SIG_DFL);
4625     }
4626 #endif /* TCPIPLIB */
4627 #endif /* RLOGCODE */
4628
4629 #ifdef datageneral
4630     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4631 #else
4632 #ifdef BSD43
4633     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4634 #else
4635 #ifdef OSF1
4636     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4637 #else
4638 #ifdef POSIX
4639     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4640 #else
4641 #ifdef MOTSV88R4
4642     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4643 #else
4644 #ifdef SOLARIS
4645 /*
4646   Maybe this applies to all SVR4 versions, but the other (else) way has been
4647   compiling and working fine on all the others, so best not to change it.
4648 */
4649     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4650 #else
4651 #ifdef OSK
4652     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4653 #else
4654 #ifdef OS2
4655     {
4656         int rc;
4657         rc = setsockopt(ttyfd,
4658                         SOL_SOCKET,
4659                         SO_OOBINLINE,
4660                         (char *) &on,
4661                         sizeof on
4662                         );
4663         debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
4664     }
4665 #else
4666 #ifdef VMS /* or, at least, VMS with gcc */
4667     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4668 #else
4669 #ifdef CLIX
4670     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4671 #else
4672     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
4673 #endif /* CLIX */
4674 #endif /* VMS */
4675 #endif /* OS2 */
4676 #endif /* OSK */
4677 #endif /* SOLARIS */
4678 #endif /* MOTSV88R4 */
4679 #endif /* POSIX */
4680 #endif /* BSD43 */
4681 #endif /* OSF1 */
4682 #endif /* datageneral */
4683 #endif /* SO_OOBINLINE */
4684
4685 #ifndef NOTCPOPTS
4686 #ifndef datageneral
4687 #ifdef SOL_SOCKET
4688 #ifdef TCP_NODELAY
4689     no_delay(ttyfd,tcp_nodelay);
4690 #endif /* TCP_NODELAY */
4691 #ifdef SO_KEEPALIVE
4692     keepalive(ttyfd,tcp_keepalive);
4693 #endif /* SO_KEEPALIVE */
4694 #ifdef SO_LINGER
4695     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
4696 #endif /* SO_LINGER */
4697 #ifdef SO_SNDBUF
4698     sendbuf(ttyfd,tcp_sendbuf);
4699 #endif /* SO_SNDBUF */
4700 #ifdef SO_RCVBUF
4701     recvbuf(ttyfd,tcp_recvbuf);
4702 #endif /* SO_RCVBUF */
4703 #endif /* SOL_SOCKET */
4704 #endif /* datageneral */
4705 #endif /* NOTCPOPTS */
4706
4707 #ifndef datageneral
4708     /* Find out our own IP address. */
4709     /* We need the l_addr structure for [E]KLOGIN. */
4710     l_slen = sizeof(l_addr);
4711     bzero((char *)&l_addr, l_slen);
4712 #ifndef EXCELAN
4713     if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
4714         char * s = (char *)inet_ntoa(l_addr.sin_addr);
4715         ckstrncpy(myipaddr, s, 20);
4716         debug(F110,"getsockname",myipaddr,0);
4717     }
4718 #endif /* EXCELAN */
4719 #endif /* datageneral */
4720
4721 /*
4722   This is really only needed for Kerberos IV but is useful information in any
4723   case.  If we connect to a name that is really a pool, we need to get the
4724   name of the machine we are actually connecting to for K4 to authenticate
4725   properly.  This way we also update the names properly.
4726
4727   However, it is a security hole when used with insecure DNS.
4728
4729   Note: This does not work on Windows 95 or Windows NT 3.5x.  This is because
4730   of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
4731   and Winsock 2.0 on those platforms.  Their algorithm is:
4732
4733   1. Check the HOSTENT cache.
4734   2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
4735   3. Do a DNS query if the DNS server is configured for name resolution.
4736   4. Do an additional NetBIOS remote adapter status to an IP address for its
4737      NetBIOS name table. This step is specific only to the Windows NT version
4738      3.51 implementation.
4739
4740   The problem is the use of the HOSTENT cache.  It means that gethostbyaddr()
4741   can not be used to resolve the real name of machine if it was originally
4742   accessed by an alias used to represent a cluster.
4743 */
4744      if ((tcp_rdns && dns || tcp_rdns == SET_ON
4745 #ifdef CK_KERBEROS
4746          || tcp_rdns == SET_AUTO &&
4747           (ck_krb5_is_installed() || ck_krb4_is_installed())
4748 #endif /* CK_KERBEROS */
4749          )
4750 #ifndef NOHTTP
4751           && (tcp_http_proxy == NULL)
4752 #endif /* NOHTTP */
4753 #ifdef CK_SSL
4754           && !(ssl_only_flag || tls_only_flag)
4755 #endif /* CK_SSL */
4756          ) {
4757 #ifdef NT
4758         if (isWin95())
4759           sleep(1);
4760 #endif /* NT */
4761         if (!quiet) {
4762             printf(" Reverse DNS Lookup... ");
4763             fflush(stdout);
4764         }
4765         if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
4766             char * s;
4767             host = ck_copyhostent(host);
4768             debug(F100,"netopen gethostbyname != NULL","",0);
4769             if (!quiet) {
4770                 printf("(OK)\n");
4771                 fflush(stdout);
4772             }
4773             s = host->h_name;
4774             if (!s) {                   /* This can happen... */
4775                 debug(F100,"netopen host->h_name is NULL","",0);
4776                 s = "";
4777             }
4778             /* Something is wrong with inet_ntoa() on HPUX 10.xx */
4779             /* The compiler says "Integral value implicitly converted to */
4780             /* pointer in assignment."  The prototype is right there */
4781             /* in <arpa/inet.h> so what's the problem? */
4782             /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
4783             if (!*s) {                  /* No name so substitute the address */
4784                 debug(F100,"netopen host->h_name is empty","",0);
4785                 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
4786                 if (!s)                 /* Trust No 1 */
4787                   s = "";
4788                 if (*s) {               /* If it worked, use this string */
4789                     ckstrncpy(ipaddr,s,20);
4790                 }
4791                 s = ipaddr;             /* Otherwise stick with the IP */
4792                 if (!*s)                /* or failing that */
4793                   s = namecopy;         /* the name we were called with. */
4794             }
4795             if (*s) {                   /* Copying into our argument? */
4796                 ckstrncpy(name,s,80);   /* Bad Bad Bad */
4797                 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4798                     strncat(name,":",80-strlen(name));
4799                     strncat(name,svcbuf,80-strlen(name));
4800                 }
4801             }
4802             if (!quiet && *s
4803 #ifndef NOICP
4804                 && !doconx
4805 #endif /* NOICP */
4806                 ) {
4807                 printf(" %s connected on port %s\n",s,p);
4808 #ifdef BETADEBUG
4809                 /* This is simply for testing the DNS entries */
4810                 if (host->h_aliases) {
4811                     char ** a = host->h_aliases;
4812                     while (*a) {
4813                         printf(" alias => %s\n",*a);
4814                         a++;
4815                     }
4816                 }
4817 #endif /* BETADEBUG */
4818             }
4819         } else {
4820             if (!quiet) printf("Failed.\n");
4821         }
4822     } else if (!quiet) printf("(OK)\n");
4823     if (!quiet) fflush(stdout);
4824
4825     /* This should already have been done but just in case */
4826     ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4827
4828 #ifdef CK_SECURITY
4829
4830     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
4831 #ifndef NOHTTP
4832     if (tcp_http_proxy) {
4833         for (i=strlen(proxycopy); i >= 0 ; i--)
4834             if ( proxycopy[i] == ':' )
4835                 proxycopy[i] = '\0';
4836     }
4837 #endif /* NOHTTP */
4838     ck_auth_init(
4839 #ifndef NOHTTP
4840                  tcp_http_proxy ? proxycopy :
4841 #endif /* NOHTTP */
4842                  (tcp_rdns && host && host->h_name && host->h_name[0]) ?
4843                  (char *)host->h_name : (namecopy2[0] ? namecopy2 : 
4844                                         (namecopy[0] ? namecopy : ipaddr)),
4845                  ipaddr,
4846                  uidbuf,
4847                  ttyfd
4848                  );
4849 #endif /* CK_SECURITY */
4850 #ifdef CK_SSL
4851     if (ck_ssleay_is_installed()) {
4852         if (!ssl_tn_init(SSL_CLIENT)) {
4853             debug(F100,"netopen ssl_tn_init() failed","",0);
4854             if (bio_err!=NULL) {
4855                 BIO_printf(bio_err,"ssl_tn_init() failed\n");
4856                 ERR_print_errors(bio_err);
4857             } else {
4858                 fflush(stderr);
4859                 fprintf(stderr,"ssl_tn_init() failed\n");
4860                 ERR_print_errors_fp(stderr);
4861             }
4862             if (tls_only_flag || ssl_only_flag) {
4863                 debug(F100,"netopen ssl/tls required","",0);
4864                 netclos();
4865                 return(-1);
4866             }
4867
4868             /* we will continue to accept the connection   */
4869             /* without SSL or TLS support unless required. */
4870             if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
4871                 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
4872             if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
4873                 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
4874             if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
4875                 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
4876             if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
4877                 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
4878         } else if ( ck_ssl_outgoing(ttyfd) < 0 ) {
4879             debug(F100,"ck_ssl_outgoing() failed","",0);
4880             netclos();
4881             return(-1);
4882         }
4883     }
4884 #endif /* CK_SSL */
4885
4886 #ifdef RLOGCODE
4887     if (ttnproto == NP_RLOGIN
4888 #ifdef CK_KERBEROS
4889         || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4890         || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4891 #endif /* CK_KERBEROS */
4892         ) {                             /* Similar deal for rlogin */
4893         if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ?
4894                       (CHAR *)host->h_name : (CHAR *)ipaddr),
4895                      service->s_port,
4896                      &l_addr,&r_addr
4897                      ) < 0) {
4898             debug(F100,"rlogin initialization failed","",0);
4899             netclos();
4900             return(-1);
4901         }
4902     } else
4903 #endif /* RLOGCODE */
4904     if (tn_ini() < 0) {                 /* Start Telnet negotiations. */
4905         netclos();
4906         return(-1);                     /* Gone, so open failed.  */
4907     }
4908     if (ttchk() < 0) {
4909         netclos();
4910         return(-1);
4911     }
4912 #ifdef CK_KERBEROS
4913 #ifdef KRB5_U2U
4914    if ( ttnproto == NP_K5U2U ) {
4915        if (k5_user_to_user_client_auth()) {
4916            netclos();
4917            return(-1);
4918        }
4919    }
4920 #endif /* KRB5_U2U */
4921 #endif /* CK_KERBEROS */
4922
4923     debug(F101,"netopen service","",svcnum);
4924     debug(F110,"netopen name",name,0);
4925
4926     if (lcl) if (*lcl < 0)              /* Local mode. */
4927       *lcl = 1;
4928 #endif /* TCPSOCKET */
4929     return(0);                          /* Done. */
4930 }
4931
4932 /*  N E T C L O S  --  Close current network connection.  */
4933
4934 #ifndef NOLOCAL
4935 _PROTOTYP(VOID slrestor,(VOID));
4936 #ifdef CK_SSL
4937 int tls_norestore = 0;
4938 #endif /* CK_SSL */
4939 #endif /* NOLOCAL */
4940
4941 int
4942 netclos() {
4943     static int close_in_progress = 0;
4944     int x = 0, y, z;
4945     debug(F101,"netclos","",ttyfd);
4946
4947 #ifdef NETLEBUF
4948     if (!tt_push_inited)
4949       le_init();
4950 #endif /* NETLEBUF */
4951
4952     if (ttyfd == -1)                    /* Was open? */
4953       return(0);                        /* Wasn't. */
4954
4955     if (close_in_progress)
4956       return(0);
4957     close_in_progress = 1;              /* Remember */
4958
4959 #ifndef NOLOCAL
4960     /* This function call should not be here since this is a direct call */
4961     /* from an I/O routine to a user interface level function.  However, */
4962     /* the reality is that we do not have pure interfaces.  If we ever   */
4963     /* decide to clean this up the UI level should assign this function  */
4964     /* via a pointer assignment.  - Jeff 9/10/1999                       */
4965 #ifdef CK_SSL
4966     if (!tls_norestore)
4967 #endif /* CK_SSL */
4968       slrestor();
4969 #endif /* NOLOCAL */
4970 #ifdef OS2
4971     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
4972 #else /* OS2 */
4973     if (ttyfd > -1)                     /* Was. */
4974 #endif /* OS2 */
4975       {
4976 #ifdef VMS
4977           y = 1;                          /* Turn on nonblocking reads */
4978           z = socket_ioctl(ttyfd,FIONBIO,&y);
4979           debug(F111,"netclos FIONBIO","on",z);
4980 #endif /* VMS */
4981 #ifdef TNCODE
4982           if (ttnproto == NP_TELNET) {
4983             if ( !TELOPT_ME(TELOPT_LOGOUT) ) {
4984                 /* Send LOGOUT option before close */
4985                 if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) {
4986                     TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
4987                     /* It would be nice to call tn_wait but we can't */
4988                 }
4989             }
4990             tn_push();                  /* Place any waiting data into input*/
4991           }
4992 #endif /* TNCODE */
4993 #ifdef CK_SSL
4994           if (ssl_active_flag) {
4995               if (ssl_debug_flag)
4996                 BIO_printf(bio_err,"calling SSL_shutdown\n");
4997               SSL_shutdown(ssl_con);
4998               ssl_active_flag = 0;
4999           }
5000           if (tls_active_flag) {
5001               if (ssl_debug_flag)
5002                 BIO_printf(bio_err,"calling SSL_shutdown\n");
5003               SSL_shutdown(tls_con);
5004               tls_active_flag = 0;
5005           }
5006 #endif /* CK_SSL */
5007 #ifdef VMS
5008           ck_cancio();                  /* Cancel any outstanding reads. */
5009 #endif /* VMS */
5010 #ifdef TCPIPLIB
5011           x = socket_close(ttyfd);      /* Close it. */
5012 #else
5013 #ifndef OS2
5014 #ifdef IBMX25
5015         if (ttnet == NET_IX25) {
5016             /* riehm: should send a disc_req - but only if link is still OK */
5017             x = x25clear();
5018             close(ttyfd);
5019             if (x25serverfd) {
5020                   /* we were the passive client of a server, now we
5021                    * go back to being the normal client.
5022                    * I hope that kermit can cope with the logic that
5023                    * there can still be a connection after netclos
5024                    * has been called.
5025                    */
5026                   ttyfd = x25serverfd;
5027                   x25serverfd = 0;
5028                   /*
5029                    * need to close the server connection too - because
5030                    * all file descriptors connected to the NPI have the
5031                    * same status.
5032                    *
5033                    * The problem is that any waiting connections get
5034                    * lost, the client doesn't realise, and hangs.
5035                    */
5036                   netclos();
5037               }
5038             x25_state = X25_CLOSED;     /* riehm: dead code? */
5039         } else
5040 #endif /* IBMX25 */
5041           x = close(ttyfd);
5042 #endif /* OS2 */
5043 #endif /* TCPIPLIB */
5044       }
5045     ttyfd = -1;                         /* Mark it as closed. */
5046     wasclosed = 1;
5047 #ifdef OS2
5048     ReleaseTCPIPMutex();
5049 #endif /* OS2 */
5050 #ifdef TNCODE
5051 #ifdef CK_FORWARD_X
5052     fwdx_close_all();                   /* Shut down any Forward X sockets */
5053 #endif /* CK_FORWARD_X */
5054     tn_reset();                   /* The Reset Telnet Option table.  */
5055     debug(F100,"netclose setting tn_init = 0","",0);
5056     tn_init = 0;                        /* Remember about telnet protocol... */
5057     sstelnet = 0;                       /* Client-side Telnet */
5058 #endif /* TNCODE */
5059     *ipaddr = '\0';                     /* Zero the IP address string */
5060     tcp_incoming = 0;                   /* No longer incoming */
5061     /* Don't reset ttnproto so that we can remember which protocol is in use */
5062
5063 #ifdef TCPIPLIB
5064 /*
5065   Empty the internal buffers so they won't be used as invalid input on
5066   the next connect attempt (rlogin).
5067 */
5068     ttibp = 0;
5069     ttibn = 0;
5070 #endif /* TCPIPLIB */
5071 #ifdef CK_KERBEROS
5072     /* If we are automatically destroying Kerberos credentials on Close */
5073     /* do it now. */
5074 #ifdef KRB4
5075     if (krb4_autodel == KRB_DEL_CL) {
5076         extern struct krb_op_data krb_op;
5077         krb_op.version = 4;
5078         krb_op.cache = NULL;
5079         ck_krb4_destroy(&krb_op);
5080     }
5081 #endif /* KRB4 */
5082 #ifdef KRB5
5083     if (krb5_autodel == KRB_DEL_CL) {
5084         extern struct krb_op_data krb_op;
5085         extern char * krb5_d_cc;
5086         krb_op.version = 5;
5087         krb_op.cache = krb5_d_cc;
5088         ck_krb5_destroy(&krb_op);
5089     }
5090 #endif /* KRB5 */
5091 #endif /* CK_KERBEROS */
5092     close_in_progress = 0;              /* Remember we are done. */
5093     return(x);
5094 }
5095
5096 #ifdef OS2
5097 int
5098 os2socketerror( int s_errno ) {
5099 #ifdef OS2ONLY
5100     if (s_errno > 0 && s_errno <= SOCBASEERR) {
5101         /* in OS/2, there is a problem with threading in that
5102          * the value of errno is not thread safe.  It can be
5103          * set to a value from a previous library call and if
5104          * it was not cleared it will appear here.  Only treat
5105          * valid socket error codes as errors in this function.
5106          */
5107         debug(F100,"os2socketerror errno.h","",0);
5108         socket_errno = 0;
5109         return(0);
5110     }
5111 #endif /* OS2ONLY */
5112
5113     switch (s_errno) {
5114       case 0:                           /* NO ERROR */
5115         debug(F100,"os2socketerror NOERROR","",0);
5116         return(0);
5117 #ifdef NT
5118       case WSAECONNRESET:
5119 #else /* NT */
5120       case SOCECONNRESET:
5121       case SOCECONNRESET - SOCBASEERR:
5122 #endif /* NT */
5123         debug(F100,"os2socketerror ECONRESET","",0);
5124         tn_debug("ECONRESET");
5125         netclos();              /* *** *** */
5126         return(-1);             /* Connection is broken. */
5127 #ifdef NT
5128       case WSAECONNABORTED:
5129 #else /* NT */
5130       case SOCECONNABORTED:
5131       case SOCECONNABORTED - SOCBASEERR:
5132 #endif /* NT */
5133         debug(F100,"os2socketerror ECONNABORTED","",0);
5134         tn_debug("ECONNABORTED");
5135         netclos();              /* *** *** */
5136         return(-1);             /* Connection is broken. */
5137 #ifdef NT
5138       case WSAENETRESET:
5139 #else /* NT */
5140       case SOCENETRESET:
5141       case SOCENETRESET - SOCBASEERR:
5142 #endif /* NT */
5143         debug(F100,"os2socketerror ENETRESET","",0);
5144         tn_debug("ENETRESET");
5145         netclos();              /* *** *** */
5146         return(-1);             /* Connection is broken. */
5147 #ifdef NT
5148       case WSAENOTCONN:
5149 #else /* NT */
5150       case SOCENOTCONN:
5151       case SOCENOTCONN - SOCBASEERR:
5152 #endif /* NT */
5153         debug(F100,"os2socketerror ENOTCONN","",0);
5154         tn_debug("ENOTCONN");
5155         netclos();                      /* *** *** */
5156         return(-1);                     /* Connection is broken. */
5157 #ifdef NT
5158       case WSAESHUTDOWN:
5159         debug(F100,"os2socketerror ESHUTDOWN","",0);
5160         tn_debug("ESHUTDOWN");
5161         netclos();                      /* *** *** */
5162         return(-1);                     /* Connection is broken. */
5163 #endif /* NT */
5164 #ifdef NT
5165       case WSAEWOULDBLOCK:
5166 #else
5167       case SOCEWOULDBLOCK:
5168       case SOCEWOULDBLOCK - SOCBASEERR:
5169 #endif /* NT */
5170         debug(F100,"os2socketerror EWOULDBLOCK","",0);
5171         return(0);
5172 #ifdef NT
5173       case ERROR_IO_INCOMPLETE:
5174       case ERROR_IO_PENDING:
5175       case ERROR_OPERATION_ABORTED:
5176         return(0);
5177 #endif /* NT */
5178       default:
5179         return(-2);
5180     }
5181     return(0);
5182 }
5183 #endif /* OS2 */
5184
5185 /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
5186 /*
5187   Returns number of bytes waiting, or -1 if connection has been dropped.
5188 */
5189 int                                     /* Check how many bytes are ready */
5190 nettchk() {                             /* for reading from network */
5191 #ifdef TCPIPLIB
5192     long count = 0;
5193     int x = 0, z;
5194     long y;
5195     char c;
5196     int rc;
5197 #ifdef NT
5198     extern int ionoblock;               /* For Overlapped I/O */
5199 #endif /* NT */
5200
5201     debug(F101,"nettchk entry ttibn","",ttibn);
5202     debug(F101,"nettchk entry ttibp","",ttibp);
5203
5204 #ifdef NETLEBUF
5205     {
5206         int n = 0;
5207         if (ttpush >= 0)
5208           n++;
5209         n += le_inbuf();
5210         if (n > 0)
5211           return(n);
5212     }
5213 #endif /* NETLEBUF */
5214
5215 #ifndef OS2
5216 #ifndef BEBOX
5217     socket_errno = 0; /* This is a function call in NT, and BeOS */
5218 #endif /* BEBOX */
5219 #endif /* OS2 */
5220
5221     if (ttyfd == -1) {
5222         debug(F100,"nettchk socket is closed","",0);
5223         return(-1);
5224     }
5225 /*
5226   Note: this socket_ioctl() call does NOT return an error if the
5227   connection has been broken.  (At least not in MultiNet.)
5228 */
5229 #ifdef COMMENT
5230 /*  Another trick that can be tried here is something like this: */
5231
5232     if (ttnet == NET_TCPB) {
5233         char dummy;
5234         x = read(ttyfd,&dummy,0);       /* Try to read nothing */
5235         if (x < 0) {                    /* "Connection reset by peer" */
5236             perror("TCP/IP");           /* or somesuch... */
5237             ttclos(0);                  /* Close our end too. */
5238             return(-1);
5239         }
5240     }
5241 #endif /* COMMENT */
5242
5243
5244 #ifdef CK_SSL
5245     if (ssl_active_flag) {
5246 #ifndef IKSDONLY
5247 #ifdef OS2
5248         if ( IsConnectMode() ) {
5249             debug(F101,"nettchk (ssl_active_flag) returns","",count);
5250             return(0);
5251         }
5252 #endif /* OS2 */
5253 #endif /* IKSDONLY */
5254         count = SSL_pending(ssl_con);
5255         if (count < 0) {
5256             debug(F111,"nettchk","SSL_pending error",count);
5257             netclos();
5258             return(-1);
5259         }
5260         if ( count > 0 )
5261             return(count);                  /* Don't perform a read */
5262     } else if (tls_active_flag) {
5263 #ifndef IKSDONLY
5264 #ifdef OS2
5265         if ( IsConnectMode() ) {
5266             debug(F101,"nettchk (tls_active_flag) returns","",count);
5267             return(0);
5268         }
5269 #endif /* OS2 */
5270 #endif /* IKSDONLY */
5271         count = SSL_pending(tls_con);
5272         if (count < 0) {
5273             debug(F111,"nettchk","TLS_pending error",count);
5274             netclos();
5275             return(-1);
5276         }
5277         if ( count > 0 )
5278             return(count);                  /* Don't perform a read */
5279     } else
5280 #endif /* CK_SSL */
5281
5282     if (socket_ioctl(ttyfd,FIONREAD,
5283 #ifdef COMMENT
5284     /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
5285 #ifdef __DECC
5286     /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
5287                      /* Cast needed for DECC 4.1 & later? */
5288                      /* Maybe, but __DECC_VER only exists in 5.0 and later */
5289                      (char *)
5290 #endif /* __DECC */
5291 #endif /* COMMENT */
5292                      &count
5293                      ) < 0) {
5294         debug(F101,"nettchk socket_ioctl error","",socket_errno);
5295         /* If the connection is gone, the connection is gone. */
5296         netclos();
5297 #ifdef NT_TCP_OVERLAPPED
5298         /* Is there anything in the overlapped I/O buffers? */
5299         count += OverlappedDataWaiting();
5300 #endif /* NT_TCP_OVERLAPPED */
5301         count += ttibn;
5302         return(count>0?count:-1);
5303     }
5304     debug(F101,"nettchk count","",count);
5305 #ifdef NT_TCP_OVERLAPPED
5306     /* Is there anything in the overlapped I/O buffers? */
5307     count += OverlappedDataWaiting();
5308     debug(F101,"nettchk count w/overlapped","",count);
5309 #endif /* NT_TCP_OVERLAPPED */
5310
5311 #ifdef OS2
5312 #ifndef IKSDONLY
5313     if ( IsConnectMode() ) {
5314         debug(F101,"nettchk (FIONREAD) returns","",count);
5315         return(count);
5316     }
5317 #endif /* IKSDONLY */
5318 #endif /* OS2 */
5319
5320 /* For the sake of efficiency, if there is still data in the ttibuf */
5321 /* do not go to the bother of checking to see of the connection is  */
5322 /* still valid.  The handle is still good, so just return the count */
5323 /* of the bytes that we already have left to process.               */
5324 #ifdef OS2
5325     if ( count > 0 || ttibn > 0 ) {
5326         count+=ttibn;
5327         debug(F101,"nettchk (count+ttibn > 0) returns","",count);
5328         return(count);
5329     } else {
5330         RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5331         if ( ttibn == 0 )
5332             ttibp = 0;      /* reset for next read */
5333     }
5334 #else /* OS2 */
5335     if ( count > 0 || ttibn > 0 ) {
5336         debug(F101,"nettchk returns","",count+ttibn);
5337         return(count+ttibn);
5338     }
5339     ttibn = ttibp = 0;
5340 #endif /* OS2 */
5341
5342 /*
5343   The following code works well in most settings, but messes things up in
5344   others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
5345   make it impossible to ever make a new connection to the same host again with
5346   CONNECT, once it has been logged out from the first time.  Not even if you
5347   HANGUP first, or SET HOST<CR>, or SET LINE<CR>.  Reportedly, however, it
5348   does work OK in later releases of UCX.  But there is no way we can
5349   accommodate both old and new -- we might have static linking or dynamic
5350   linking, etc etc.  If we have static, I only have access to 2.0, where this
5351   doesn't work, etc etc blah blah.
5352
5353   In the following lines, we define a symbol NOCOUNT for builds where we want
5354   to omit this code.  By default, it is omitted for CMU/Tek.  You can force
5355   omission of it for other combinations by defining NOCOUNT in CFLAGS.  You
5356   can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
5357   in CFLAGS.
5358 */
5359 #ifdef NONOCOUNT
5360 #ifdef NOCOUNT
5361 #undef NOCOUNT
5362 #endif /* NOCOUNT */
5363 #else
5364 #ifndef NOCOUNT
5365 #ifdef CMU_TCPIP
5366 #define NOCOUNT
5367 #endif /* CMU_TCPIP */
5368 #endif /* NOCOUNT */
5369 #endif /* NONOCOUNT */
5370
5371
5372     /* From this point forward we have a possible race condition in K95
5373      * due to its use of multiple threads.  Therefore, we must ensure
5374      * that only one thread attempt to read/write from the socket at a
5375      * time.  Otherwise, it is possible for a buffer to be overwritten.
5376      */
5377     /* we know now that count >= 0 and that ttibn == 0 */
5378
5379     if (count == 0
5380 #ifdef RLOGCODE
5381 #ifdef CK_KERBEROS
5382         && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
5383 #endif /* CK_KERBEROS */
5384 #endif /* RLOGCODE */
5385         ) {
5386         int s_errno = 0;
5387 #ifndef NOCOUNT
5388 /*
5389   Here we need to tell the difference between a 0 count on an active
5390   connection, and a 0 count because the remote end of the socket broke the
5391   connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
5392   the status of the connection, so we have to do a read.  -1 means there was
5393   no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
5394   down.  But if, by chance, we actually get a character, we have to put it
5395   where it won't be lost.
5396 */
5397 #ifndef NON_BLOCK_IO
5398 #ifdef OS2
5399 #ifdef CK_SSL
5400         RequestSSLMutex(SEM_INDEFINITE_WAIT);
5401 #endif /* CK_SSL */
5402 #endif /* OS2 */
5403         y = 1;                          /* Turn on nonblocking reads */
5404         z = socket_ioctl(ttyfd,FIONBIO,&y);
5405         debug(F111,"nettchk FIONBIO","on",z);
5406 #ifdef OS2
5407 #ifdef CK_SSL
5408         ReleaseSSLMutex();
5409 #endif /* CK_SSL */
5410 #endif /* OS2 */
5411 #endif /* NON_BLOCK_IO */
5412 #ifdef NT_TCP_OVERLAPPED
5413         ionoblock = 1;                  /* For Overlapped I/O */
5414 #endif /* NT_TCP_OVERLAPPED */
5415 #ifdef CK_SSL
5416         if ( ssl_active_flag || tls_active_flag ) {
5417 #ifdef OS2
5418           ssl_read:
5419             x = SSL_read( ssl_active_flag?ssl_con:tls_con,
5420                           &ttibuf[ttibp+ttibn],
5421                           TTIBUFL-ttibp-ttibn );
5422             switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
5423             case SSL_ERROR_NONE:
5424                 debug(F111,"nettchk SSL_ERROR_NONE","x",x);
5425                 break;
5426             case SSL_ERROR_WANT_WRITE:
5427                 debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0);
5428                 x = -1;
5429                 break;
5430             case SSL_ERROR_WANT_READ:
5431                 debug(F100,"nettchk SSL_ERROR_WANT_READ","",0);
5432                 x = -1;
5433                 break;
5434             case SSL_ERROR_SYSCALL:
5435                 if ( x == 0 ) { /* EOF */
5436                     netclos();
5437                     rc = -1;
5438                     goto nettchk_return;
5439               } else {
5440 #ifdef NT
5441                   int gle = GetLastError();
5442 #endif /* NT */
5443 #ifndef NON_BLOCK_IO
5444 #ifdef OS2
5445 #ifdef CK_SSL
5446                   RequestSSLMutex(SEM_INDEFINITE_WAIT);
5447 #endif /* CK_SSL */
5448 #endif /* OS2 */
5449                   y = 0;                          /* Turn off nonblocking reads */
5450                   z = socket_ioctl(ttyfd,FIONBIO,&y);
5451                   debug(F111,"nettchk FIONBIO","off",z);
5452 #ifdef OS2
5453 #ifdef CK_SSL
5454                   ReleaseSSLMutex();
5455 #endif /* CK_SSL */
5456 #endif /* OS2 */
5457 #endif /* NON_BLOCK_IO */
5458 #ifdef NT_TCP_OVERLAPPED
5459                   ionoblock = 0;                  /* For Overlapped I/O */
5460 #endif /* NT_TCP_OVERLAPPED */
5461 #ifdef NT
5462                   debug(F111,"nettchk SSL_ERROR_SYSCALL",
5463                          "GetLastError()",gle);
5464                   rc = os2socketerror(gle);
5465                   if (rc == -1)
5466                       rc = -2;
5467                   else if ( rc == -2 )
5468                       rc = -1;
5469                   goto nettchk_return;
5470 #endif /* NT */
5471                   break;
5472               }
5473           case SSL_ERROR_WANT_X509_LOOKUP:
5474                 debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0);
5475                 break;
5476             case SSL_ERROR_SSL:
5477                 if (bio_err!=NULL) {
5478                     int len;
5479                     extern char ssl_err[];
5480                     BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n");
5481                     ERR_print_errors(bio_err);
5482                     len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
5483                     ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
5484                     debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0);
5485                     if (ssl_debug_flag)
5486                         printf(ssl_err);
5487                 } else if (ssl_debug_flag) {
5488                     debug(F100,"nettchk SSL_ERROR_SSL","",0);
5489                     fflush(stderr);
5490                     fprintf(stderr,"nettchk() SSL_ERROR_SSL\n");
5491                     ERR_print_errors_fp(stderr);
5492                 }
5493 #ifdef COMMENT
5494                 netclos();
5495                 rc = -1;
5496                 goto nettchk_return;
5497 #else
5498                 x = -1;
5499                 break;
5500 #endif
5501           case SSL_ERROR_ZERO_RETURN:
5502                 debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0);
5503                 netclos();
5504                 rc = -1;
5505                 goto nettchk_return;
5506             default:
5507                 debug(F100,"nettchk SSL_ERROR_?????","",0);
5508                 netclos();
5509                 rc = -1;
5510                 goto nettchk_return;
5511             }
5512 #else /* OS2 */
5513             /* Do not block */
5514             x = -1;
5515 #endif /* OS2 */
5516         } else
5517 #endif /* CK_SSL */
5518         {
5519 #ifdef OS2
5520         x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
5521                          TTIBUFL-ttibp-ttibn);  /* Returns -1 if no data */
5522 #else /* OS2 */
5523         x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
5524 #endif /* OS2 */
5525         }
5526         s_errno = socket_errno;         /* socket_errno may be a function */
5527         debug(F101,"nettchk socket_read","",x);
5528
5529 #ifndef NON_BLOCK_IO
5530 #ifdef OS2
5531 #ifdef CK_SSL
5532         RequestSSLMutex(SEM_INDEFINITE_WAIT);
5533 #endif /* CK_SSL */
5534 #endif /* OS2 */
5535         y = 0;                          /* Turn off nonblocking reads */
5536         z = socket_ioctl(ttyfd,FIONBIO,&y);
5537         debug(F111,"nettchk FIONBIO","off",z);
5538 #ifdef OS2
5539 #ifdef CK_SSL
5540         ReleaseSSLMutex();
5541 #endif /* CK_SSL */
5542 #endif /* OS2 */
5543 #endif /* NON_BLOCK_IO */
5544 #ifdef NT_TCP_OVERLAPPED
5545         ionoblock = 0;                  /* For Overlapped I/O */
5546 #endif /* NT_TCP_OVERLAPPED */
5547
5548         if (x == -1) {
5549             debug(F101,"nettchk socket_read errno","",s_errno);
5550 #ifdef OS2
5551             if (os2socketerror(s_errno) < 0) {
5552                 rc = -1;
5553                 goto nettchk_return;
5554             }
5555 #endif /* OS2 */
5556         } else if (x == 0) {
5557             debug(F100,"nettchk connection closed","",0);
5558             netclos();                  /* *** *** */
5559             rc = -1;
5560             goto nettchk_return;
5561         }
5562         if (x >= 1) {                   /* Oops, actually got a byte? */
5563 #ifdef OS2
5564             /* In OS/2 we read directly into ttibuf[] */
5565             hexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5566             ttibn += x;
5567 #else /* OS2 */
5568 #ifdef CK_SSL
5569             if ( ssl_active_flag || tls_active_flag ) {
5570                 hexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5571                 ttibn += x;
5572             } else 
5573 #endif /* CK_SSL */
5574             {
5575                 debug(F101,"nettchk socket_read char","",c);
5576                 debug(F101,"nettchk ttibp","",ttibp);
5577                 debug(F101,"nettchk ttibn","",ttibn);
5578 /*
5579   In the case of Overlapped I/O the character would have come from
5580   the beginning of the buffer, so put it back.
5581 */
5582                 if (ttibp > 0) {
5583                     ttibp--;
5584                     ttibuf[ttibp] = c;
5585                     ttibn++;
5586                 } else {
5587                     ttibuf[ttibp+ttibn] = c;
5588                     ttibn++;
5589                 }
5590             }
5591 #endif /* OS2 */
5592         }
5593 #else /* NOCOUNT */
5594         if (ttnet == NET_TCPB) {
5595             char dummy;
5596             x = read(ttyfd,&dummy,0);   /* Try to read nothing */
5597             if (x < 0) {                /* "Connection reset by peer" */
5598                 perror("TCP/IP");       /* or somesuch... */
5599                 ttclos(0);              /* Close our end too. */
5600                 rc = -1;
5601                 goto nettchk_return;
5602             }
5603         }
5604 #endif /* NOCOUNT */
5605     }
5606 #ifdef CK_KERBEROS
5607 #ifdef KRB4
5608 #ifdef RLOGCODE
5609     if (ttnproto == NP_EK4LOGIN)
5610       count += krb4_des_avail(ttyfd);
5611 #endif /* RLOGCODE */
5612 #endif /* KRB4 */
5613 #ifdef KRB5
5614 #ifdef RLOGCODE
5615     if (ttnproto == NP_EK5LOGIN)
5616       count += krb5_des_avail(ttyfd);
5617 #endif /* RLOGCODE */
5618 #ifdef KRB5_U2U
5619     if (ttnproto == NP_K5U2U)
5620       count += krb5_u2u_avail(ttyfd);
5621 #endif /* KRB5_U2U */
5622 #endif /* KRB5 */
5623 #endif /* CK_KERBEROS */
5624
5625     debug(F101,"nettchk returns","",count+ttibn);
5626     rc = count + ttibn;
5627
5628   nettchk_return:
5629 #ifdef OS2
5630     ReleaseTCPIPMutex();
5631 #endif /* OS2 */
5632     return(rc);
5633
5634 #else /* Not TCPIPLIB */
5635 /*
5636   UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
5637   seem to work OK.
5638 */
5639     return(ttchk());
5640 #endif /* TCPIPLIB */
5641 /*
5642   But what about X.25?
5643 */
5644 }
5645
5646 #ifndef OS2
5647 VOID
5648 nettout(i) int i; {                     /* Catch the alarm interrupts */
5649     debug(F100,"nettout caught timeout","",0);
5650     ttimoff();
5651     cklongjmp(njbuf, -1);
5652 }
5653 #endif /* !OS2 */
5654
5655 #ifdef TCPIPLIB
5656
5657 VOID
5658 #ifdef CK_ANSIC
5659 donetinc(void * threadinfo)
5660 #else /* CK_ANSIC */
5661 donetinc(threadinfo) VOID * threadinfo;
5662 #endif /* CK_ANSIC */
5663 /* donetinc */ {
5664 #ifdef NTSIG
5665     extern int TlsIndex;
5666     setint();
5667     if (threadinfo) {                   /* Thread local storage... */
5668         TlsSetValue(TlsIndex,threadinfo);
5669     }
5670 #endif /* NTSIG */
5671 #ifdef CK_LOGIN
5672 #ifdef NT
5673 #ifdef IKSD
5674     if (inserver)
5675       setntcreds();
5676 #endif /* IKSD */
5677 #endif /* NT */
5678 #endif /* CK_LOGIN */
5679     while (1) {
5680         if (ttbufr() < 0)               /* Keep trying to refill it. */
5681           break;                        /* Till we get an error. */
5682         if (ttibn > 0)                  /* Or we get a character. */
5683           break;
5684     }
5685 }
5686 #endif /* TCPIPLIB */
5687
5688 VOID
5689 #ifdef CK_ANSIC
5690 failnetinc(void * threadinfo)
5691 #else /* CK_ANSIC */
5692 failnetinc(threadinfo) VOID * threadinfo;
5693 #endif /* CK_ANSIC */
5694 /* failnetinc */ {
5695     ; /* Nothing to do on an error */
5696 }
5697
5698 /* N E T X I N -- Input block of characters from network */
5699
5700 int
5701 netxin(n,buf) int n; CHAR * buf; {
5702     int len, i, j;
5703 #ifdef TCPIPLIB
5704     int rc;
5705 #endif /* TCPIPLIB */
5706
5707     if (ttyfd == -1) {
5708         debug(F100,"netxin socket is closed","",0);
5709         return(-2);
5710     }
5711 #ifdef CK_KERBEROS
5712 #ifdef KRB4
5713 #ifdef RLOGCODE
5714     if (ttnproto == NP_EK4LOGIN) {
5715         if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
5716           return(-1);
5717         else
5718           return(len);
5719     }
5720 #endif /* RLOGCODE */
5721 #endif /* KRB4 */
5722 #ifdef KRB5
5723 #ifdef RLOGCODE
5724     if (ttnproto == NP_EK5LOGIN) {
5725         if ((len = krb5_des_read(ttyfd,buf,n,0)) < 0)
5726           return(-1);
5727         else
5728           return(len);
5729     }
5730 #endif /* RLOGCODE */
5731 #ifdef KRB5_U2U
5732     if (ttnproto == NP_K5U2U) {
5733         if ((len = krb5_u2u_read(ttyfd,buf,n)) < 0)
5734           return(-1);
5735         else
5736           return(len);
5737     }
5738 #endif /* KRB5_U2U */
5739 #endif /* KRB5 */
5740 #endif /* CK_KERBEROS */
5741
5742 #ifdef TCPIPLIB
5743 #ifdef OS2
5744     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5745 #endif /* OS2 */
5746     if (ttibn == 0)
5747       if ((rc = ttbufr()) <= 0) {
5748 #ifdef OS2
5749         ReleaseTCPIPMutex();
5750 #endif /* OS2 */
5751         return(rc);
5752       }
5753
5754     if (ttibn <= n) {
5755         len = ttibn;
5756         memcpy(buf,&ttibuf[ttibp],len);         /* safe */
5757         ttibp += len;
5758         ttibn = 0;
5759     } else {
5760         memcpy(buf,&ttibuf[ttibp],n);           /* safe */
5761         ttibp += n;
5762         ttibn -= n;
5763         len = n;
5764     }
5765 #ifdef OS2
5766     ReleaseTCPIPMutex();
5767 #endif /* OS2 */
5768 #else /* TCPIPLIB */
5769     for (i = 0; i < n; i++) {
5770         if ((j = netinc(0)) < 0) {
5771             if (j < -1)
5772               return(j);
5773             else
5774               break;
5775         }
5776         buf[i] = j;
5777     }
5778     len = i;
5779 #endif /* TCPIPLIB */
5780
5781 #ifdef COMMENT
5782 #ifdef CK_ENCRYPTION
5783     /* This would be great if it worked.  But what if the buffer we read  */
5784     /* contains a telnet negotiation that changes the state of the        */
5785     /* encryption.  If so, we would be either decrypting unencrypted text */
5786     /* or not decrypting encrypted text.  So we must move this call to    */
5787     /* all functions that call ttxin().  In OS2 that means os2_netxin()   */
5788     /* where the Telnet Negotiations are handled.                         */
5789     if (u_encrypt)
5790       ck_tn_decrypt(buf,len);
5791 #endif /* CK_ENCRYPTION */
5792 #endif /* COMMENT */
5793
5794     return(len);
5795 }
5796
5797 /*  N E T I N C --  Input character from network */
5798
5799 #ifdef NETLEBUF
5800 #define LEBUF
5801 #endif /* NETLEBUF */
5802 #ifdef TTLEBUF
5803 #define LEBUF
5804 #endif /* TTLEBUF */
5805 #ifndef LEBUF
5806 #ifdef OS2
5807 #define LEBUF
5808 #endif /* OS2 */
5809 #endif /* LEBUF */
5810
5811 int
5812 netinc(timo) int timo; {
5813 #ifdef TCPIPLIB
5814     int x; unsigned char c;             /* The locals. */
5815
5816 #ifdef NETLEBUF
5817     if (ttpush >= 0) {
5818         debug(F111,"netinc","ttpush",ttpush);
5819         c = ttpush;
5820         ttpush = -1;
5821         return(c);
5822     }
5823     if (le_data) {
5824         if (le_getchar((CHAR *)&c) > 0) {
5825             debug(F111,"netinc le_getchar","c",c);
5826             return(c);
5827         }
5828     }
5829 #endif /* NETLEBUF */
5830
5831     if (ttyfd == -1) {
5832         debug(F100,"netinc socket is closed","",0);
5833         return(-2);
5834     }
5835
5836 #ifdef CK_KERBEROS
5837 #ifdef KRB4
5838 #ifdef RLOGCODE
5839     if (ttnproto == NP_EK4LOGIN) {
5840         if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
5841           return(-1);
5842         else if (x < 0)
5843           return(-2);
5844         else
5845           return(c);
5846     }
5847 #endif /* RLOGCODE */
5848 #endif /* KRB4 */
5849 #ifdef KRB5
5850 #ifdef RLOGCODE
5851     if (ttnproto == NP_EK5LOGIN) {
5852         if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0)
5853           return(-1);
5854         else if (x < 0)
5855           return(-2);
5856         else
5857           return(c);
5858     }
5859 #endif /* RLOGCODE */
5860 #ifdef KRB5_U2U
5861     if (ttnproto == NP_K5U2U) {
5862         if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0)
5863           return(-1);
5864         else if (x < 0)
5865           return(-2);
5866         else
5867           return(c);
5868     }
5869 #endif /* KRB5_U2U */
5870 #endif /* KRB5 */
5871 #endif /* CK_KERBEROS */
5872
5873 #ifdef OS2
5874     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5875 #endif /* OS2 */
5876     if (ttibn > 0) {                    /* Something in internal buffer? */
5877 #ifdef COMMENT
5878         debug(F100,"netinc char in buf","",0); /* Yes. */
5879 #endif /* COMMENT */
5880         x = 0;                          /* Success. */
5881     } else {                            /* Else must read from network. */
5882         x = -1;                         /* Assume failure. */
5883 #ifdef DEBUG
5884         debug(F101,"netinc goes to net, timo","",timo);
5885 #endif /* DEBUG */
5886 #ifdef CK_SSL
5887         /*
5888          * In the case of OpenSSL, it is possible that there is still
5889          * data waiting in the SSL session buffers that has not yet
5890          * been read by Kermit.  If this is the case we must process
5891          * it without calling select() because select() will not return
5892          * with an indication that there is data to be read from the
5893          * socket.  If there is no data pending in the SSL session
5894          * buffers then fall through to the select() code and wait for
5895          * some data to arrive.
5896          */
5897         if (ssl_active_flag) {
5898             x = SSL_pending(ssl_con);
5899             if (x < 0) {
5900                 debug(F111,"netinc","SSL_pending error",x);
5901                 netclos();
5902 #ifdef OS2
5903                 ReleaseTCPIPMutex();
5904 #endif /* OS2 */
5905                 return(-1);
5906             } else if ( x > 0 ) {
5907                 if ( ttbufr() >= 0 ) {
5908                     x = netinc(timo);
5909 #ifdef OS2
5910                     ReleaseTCPIPMutex();
5911 #endif /* OS2 */
5912                     return(x);
5913                 }
5914             }
5915             x = -1;
5916         } else if (tls_active_flag) {
5917             x = SSL_pending(tls_con);
5918             if (x < 0) {
5919                 debug(F111,"netinc","TLS_pending error",x);
5920                 netclos();
5921 #ifdef OS2
5922                 ReleaseTCPIPMutex();
5923 #endif /* OS2 */
5924                 return(-1);
5925             } else if ( x > 0 ) {
5926                 if ( ttbufr() >= 0 ) {
5927                     x = netinc(timo);
5928 #ifdef OS2
5929                     ReleaseTCPIPMutex();
5930 #endif /* OS2 */
5931                     return(x);
5932                 }
5933             }
5934             x = -1;
5935         }
5936 #endif /* CK_SSL */
5937 #ifndef LEBUF
5938         if (timo == 0) {                /* Untimed case. */
5939             while (1) {                 /* Wait forever if necessary. */
5940                 if (ttbufr() < 0)       /* Refill buffer. */
5941                   break;                /* Error, fail. */
5942                 if (ttibn > 0) {        /* Success. */
5943                     x = 0;
5944                     break;
5945                 }
5946             }
5947         } else                          /* Timed case... */
5948 #endif /* LEBUF */
5949           {
5950 #ifdef NT_TCP_OVERLAPPED
5951             /* This code is for use on NT when we are using */
5952             /* Overlapped I/O to handle reads.  In the case */
5953             /* of outstanding reads select() doesn't work   */
5954
5955             if (WaitForOverlappedReadData(timo)) {
5956                 while (1) {
5957                     if (ttbufr() < 0)   /* Keep trying to refill it. */
5958                         break;          /* Till we get an error. */
5959                     if (ttibn > 0) {    /* Or we get a character. */
5960                         x = 0;
5961                         break;
5962                     }
5963                 }
5964             }
5965 #else /* NT_TCP_OVERLAPPED */
5966 #ifdef BSDSELECT
5967             fd_set rfds;
5968             struct timeval tv;
5969             int timeout = timo < 0 ? -timo : 1000 * timo;
5970             debug(F101,"netinc BSDSELECT","",timo);
5971
5972             for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
5973                 int rc;
5974                 debug(F111,"netinc","timeout",timeout);
5975                 /* Don't move select() initialization out of the loop. */
5976                 FD_ZERO(&rfds);
5977                 FD_SET(ttyfd, &rfds);
5978                 tv.tv_sec  = tv.tv_usec = 0L;
5979                 if (timo)
5980                   tv.tv_usec = (long) 100000L;
5981                 else
5982                   tv.tv_sec = 30;
5983 #ifdef NT
5984                 WSASafeToCancel = 1;
5985 #endif /* NT */
5986                 rc = select(FD_SETSIZE,
5987 #ifndef __DECC
5988                             (fd_set *)
5989 #endif /* __DECC */
5990                             &rfds, NULL, NULL, &tv);
5991                 if (rc < 0) {
5992                     int s_errno = socket_errno;
5993                     debug(F111,"netinc","select",rc);
5994                     debug(F111,"netinc","socket_errno",s_errno);
5995                     if (s_errno) {
5996 #ifdef OS2
5997                         ReleaseTCPIPMutex();
5998 #endif /* OS2 */
5999                         return(-1);
6000                     }
6001                 }
6002                 debug(F111,"netinc","select",rc);
6003 #ifdef NT
6004                 WSASafeToCancel = 0;
6005 #endif /* NT */
6006                 if (!FD_ISSET(ttyfd, &rfds)) {
6007 #ifdef LEBUF
6008                     if (le_inbuf() > 0) {
6009                         timeout = -1;
6010                         break;
6011                     }
6012 #endif /* LEBUF */
6013                     /* If waiting forever we have no way of knowing if the */
6014                     /* socket closed so try writing a 0-length TCP packet  */
6015                     /* which should force an error if the socket is closed */
6016                     if (!timo) {
6017                         if ((rc = socket_write(ttyfd,"",0)) < 0) {
6018                             int s_errno = socket_errno;
6019                             debug(F101,"netinc socket_write error","",s_errno);
6020 #ifdef OS2
6021                             if (os2socketerror(s_errno) < 0) {
6022                               ReleaseTCPIPMutex();
6023                               return(-2);
6024                             }
6025                             ReleaseTCPIPMutex();
6026 #endif /* OS2 */
6027                             return(-1); /* Call it an i/o error */
6028                         }
6029                     }
6030                     continue;
6031                 }
6032                 while (1) {
6033                     if (ttbufr() < 0) { /* Keep trying to refill it. */
6034                         timeout = -1;
6035                         break;          /* Till we get an error. */
6036                     }
6037                     if (ttibn > 0) {    /* Or we get a character. */
6038                         x = 0;
6039                         timeout = -1;
6040                         break;
6041                     }
6042                 }
6043             }
6044 #ifdef NT
6045             WSASafeToCancel = 0;
6046 #endif /* NT */
6047 #else /* !BSDSELECT */
6048 #ifdef IBMSELECT
6049 /*
6050   Was used by OS/2, currently not used, but might come in handy some day...
6051   ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
6052   and timeval stuff since this is the only place where it is used.
6053 */
6054             int socket = ttyfd;
6055             int timeout = timo < 0 ? -timo : 1000 * timo;
6056
6057             debug(F101,"netinc IBMSELECT","",timo);
6058             for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6059                 if (select(&socket, 1, 0, 0, 100L) == 1) {
6060                     while (1) {
6061                         if (ttbufr() < 0) { /* Keep trying to refill it. */
6062                             timeout = -1;
6063                             break;      /* Till we get an error. */
6064                         }
6065                         if (ttibn > 0) { /* Or we get a character. */
6066                             x = 0;
6067                             timeout = -1;
6068                             break;
6069                         }
6070                     }
6071                 }
6072 #ifdef LEBUF
6073                 else if (le_inbuf() > 0)  {
6074                     timeout = -1;
6075                     break;
6076                 }
6077 #endif /* LEBUF */
6078             }
6079 #else /* !IBMSELECT */
6080 #ifdef WINSOCK
6081        /* Actually, under WinSock we have a better mechanism than select() */
6082        /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
6083             SOCKET socket = ttyfd;
6084             debug(F101,"netinc NTSELECT","",timo);
6085             if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
6086                             sizeof(timo))  == NO_ERROR)
6087               while (1) {
6088                   if (ttbufr() < 0)     /* Keep trying to refill it. */
6089                     break;              /* Till we get an error. */
6090                   if (ttibn > 0) {      /* Or we get a character. */
6091                       x = 0;
6092                       break;
6093                   }
6094               }
6095 #else /* WINSOCK */
6096 /*
6097   If we can't use select(), then we use the regular alarm()/signal()
6098   timeout mechanism.
6099 */
6100             debug(F101,"netinc alarm","",timo);
6101             x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
6102             ttimoff();                  /* Timer off. */
6103 #endif /* WINSOCK */
6104 #endif /* IBMSELECT */
6105 #endif /* BSDSELECT */
6106 #endif /* NT_TCP_OVERLAPPED */
6107         }
6108     }
6109
6110 #ifdef LEBUF
6111     if (le_inbuf() > 0) {               /* If data was inserted into the */
6112         if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the   */
6113 #ifdef OS2                               /* was taking place do not mix   */
6114           ReleaseTCPIPMutex();           /* the le data with the net data */
6115 #endif /* OS2 */
6116           return(c);
6117         }
6118     }
6119 #endif /* LEBUF */
6120     if (x < 0) {                        /* Return -1 if we failed. */
6121         debug(F100,"netinc timed out","",0);
6122 #ifdef OS2
6123         ReleaseTCPIPMutex();
6124 #endif /* OS2 */
6125         return(-1);
6126     } else {                            /* Otherwise */
6127         c = ttibuf[ttibp];              /* Return the first char in ttibuf[] */
6128         if (deblog) {
6129 #ifndef COMMENT
6130             debug(F101,"netinc returning","",c);
6131 #endif /* COMMENT */
6132             if (c == 0) {
6133                 debug(F101,"netinc 0 ttibn","",ttibn);
6134                 debug(F101,"netinc 0 ttibp","",ttibp);
6135 #ifdef BETADEBUG
6136                 {
6137 #ifdef OS2
6138                     extern int tt_type_mode;
6139                     if ( !ISVTNT(tt_type_mode) )
6140 #endif /* OS2 */
6141                     hexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
6142                 }
6143 #endif /* BETADEBUG */
6144             }
6145         }
6146         ttibp++;
6147         ttibn--;
6148 #ifdef OS2
6149         ReleaseTCPIPMutex();
6150 #endif /* OS2 */
6151 #ifdef CK_ENCRYPTION
6152         if (TELOPT_U(TELOPT_ENCRYPTION))
6153           ck_tn_decrypt(&c,1);
6154 #endif /* CK_ENCRYPTION */
6155         return(c);
6156     }
6157 #else /* Not using TCPIPLIB */
6158     return(-1);
6159 #endif /* TCPIPLIB */
6160 }
6161
6162 /*  N E T T O L  --  Output a string of bytes to the network  */
6163 /*
6164   Call with s = pointer to string, n = length.
6165   Returns number of bytes actually written on success, or
6166   -1 on i/o error, -2 if called improperly.
6167 */
6168
6169 int
6170 nettol(s,n) CHAR *s; int n; {
6171 #ifdef TCPIPLIB
6172     int count = 0;
6173     int len = n;
6174     int try = 0;
6175
6176     if (ttyfd == -1) {
6177         debug(F100,"nettol socket is closed","",0);
6178         return -1;
6179     }
6180     debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
6181 #ifdef COMMENT
6182     hexdump("nettol",s,n);
6183 #endif /* COMMENT */
6184
6185 #ifdef CK_KERBEROS
6186 #ifdef KRB4
6187 #ifdef RLOGCODE
6188     if (ttnproto == NP_EK4LOGIN) {
6189         return(krb4_des_write(ttyfd,s,n));
6190     }
6191 #endif /* RLOGCODE */
6192 #endif /* KRB4 */
6193 #ifdef KRB5
6194 #ifdef RLOGCODE
6195     if (ttnproto == NP_EK5LOGIN) {
6196         return(krb5_des_write(ttyfd,s,n,0));
6197     }
6198 #endif /* RLOGCODE */
6199 #ifdef KRB5_U2U
6200     if (ttnproto == NP_K5U2U) {
6201         return(krb5_u2u_write(ttyfd,s,n));
6202     }
6203 #endif /* KRB5_U2U */
6204 #endif /* KRB5 */
6205 #endif /* CK_KERBEROS */
6206
6207 #ifdef CK_ENCRYPTION
6208     if (TELOPT_ME(TELOPT_ENCRYPTION))
6209       ck_tn_encrypt(s,n);
6210 #endif /* CK_ENCRYPTION */
6211
6212 #ifdef CK_SSL
6213     if (ssl_active_flag || tls_active_flag) {
6214         int error, r;
6215         /* Write using SSL */
6216       ssl_retry:
6217         if (ssl_active_flag)
6218           r = SSL_write(ssl_con, s, len /* >1024?1024:len */);
6219         else
6220           r = SSL_write(tls_con, s, len /* >1024?1024:len */);
6221         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) {
6222           case SSL_ERROR_NONE:
6223             debug(F111,"nettol","SSL_write",r);
6224             if ( r == len )
6225                 return(n);
6226              s += r;
6227              len -= r;
6228              goto ssl_retry;
6229           case SSL_ERROR_WANT_WRITE:
6230             debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
6231             return(-1);
6232           case SSL_ERROR_WANT_READ:
6233             debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
6234             return(-1);
6235           case SSL_ERROR_SYSCALL:
6236               if ( r == 0 ) { /* EOF */
6237                   netclos();
6238                   return(-2);
6239               } else {
6240                   int rc = -1;
6241 #ifdef NT
6242                   int gle = GetLastError();
6243                   debug(F111,"nettol SSL_ERROR_SYSCALL",
6244                          "GetLastError()",gle);
6245                   rc = os2socketerror(gle);
6246                   if (rc == -1)
6247                       rc = -2;
6248                   else if ( rc == -2 )
6249                       rc = -1;
6250 #endif /* NT */
6251                   return(rc);
6252               }
6253           case SSL_ERROR_WANT_X509_LOOKUP:
6254             debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
6255             netclos();
6256             return(-2);
6257           case SSL_ERROR_SSL:
6258             debug(F100,"nettol SSL_ERROR_SSL","",0);
6259               if (bio_err!=NULL) {
6260                   int len;
6261                   extern char ssl_err[];
6262                   BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n");
6263                   ERR_print_errors(bio_err);
6264                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6265                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6266                   debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0);
6267                   if (ssl_debug_flag)
6268                       printf(ssl_err);
6269               } else if (ssl_debug_flag) {
6270                   debug(F100,"nettol SSL_ERROR_SSL","",0);
6271                   fflush(stderr);
6272                   fprintf(stderr,"nettol() SSL_ERROR_SSL\n");
6273                   ERR_print_errors_fp(stderr);
6274               }
6275 #ifdef COMMENT
6276               netclos();
6277               return(-2);
6278 #else
6279               return(-1);
6280 #endif
6281           case SSL_ERROR_ZERO_RETURN:
6282             debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
6283             netclos();
6284             return(-2);
6285           default:
6286             debug(F100,"nettol SSL_ERROR_?????","",0);
6287             netclos();
6288             return(-2);
6289         }
6290     }
6291 #endif /* CK_SSL */
6292
6293   nettol_retry:
6294     try++;                              /* Increase the try counter */
6295
6296     if (ttnet == NET_TCPB) {
6297 #ifdef BSDSELECT
6298         fd_set wfds;
6299         struct timeval tv;
6300
6301         debug(F101,"nettol BSDSELECT","",0);
6302         tv.tv_usec = 0L;
6303         tv.tv_sec=30;
6304 #ifdef NT
6305         WSASafeToCancel = 1;
6306 #endif /* NT */
6307 #ifdef STREAMING
6308       do_select:
6309 #endif /* STREAMING */
6310         FD_ZERO(&wfds);
6311         FD_SET(ttyfd, &wfds);
6312         if (select(FD_SETSIZE, NULL,
6313 #ifdef __DECC
6314 #ifndef __DECC_VER
6315                     (int *)
6316 #endif /* __DECC_VER */
6317 #endif /* __DECC */
6318                    &wfds, NULL, &tv) < 0) {
6319             int s_errno = socket_errno;
6320             debug(F101,"nettol select failed","",s_errno);
6321 #ifdef BETADEBUG
6322             printf("nettol select failed: %d\n", s_errno);
6323 #endif /* BETADEBUG */
6324 #ifdef NT
6325             WSASafeToCancel = 0;
6326             if (!win95selectbug)
6327 #endif /* NT */
6328               return(-1);
6329         }
6330         if (!FD_ISSET(ttyfd, &wfds)) {
6331 #ifdef STREAMING
6332             if (streaming)
6333               goto do_select;
6334 #endif /* STREAMING */
6335             debug(F111,"nettol","!FD_ISSET",ttyfd);
6336 #ifdef NT
6337             WSASafeToCancel = 0;
6338             if (!win95selectbug)
6339 #endif /* NT */
6340               return(-1);
6341         }
6342 #ifdef NT
6343         WSASafeToCancel = 0;
6344 #endif /* NT */
6345 #else /* BSDSELECT */
6346 #ifdef IBMSELECT
6347         {
6348             int tries = 0;
6349             debug(F101,"nettol IBMSELECT","",0);
6350             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6351                 int count;
6352                 if (tries++ >= 60) {
6353                     /* if after 60 seconds we can't get permission to write */
6354                     debug(F101,"nettol select failed","",socket_errno);
6355                     return(-1);
6356                 }
6357                 if ((count = nettchk()) < 0) {
6358                     debug(F111,"nettol","nettchk()",count);
6359                     return(count);
6360                 }
6361             }
6362         }
6363 #endif /* IBMSELECT */
6364 #endif /* BSDSELECT */
6365         if ((count = socket_write(ttyfd,s,n)) < 0) {
6366             int s_errno = socket_errno; /* maybe a function */
6367             debug(F101,"nettol socket_write error","",s_errno);
6368 #ifdef OS2
6369             if (os2socketerror(s_errno) < 0)
6370               return(-2);
6371 #endif /* OS2 */
6372             return(-1);                 /* Call it an i/o error */
6373         }
6374         if (count < n) {
6375             debug(F111,"nettol socket_write",s,count);
6376             if (try > 25) {
6377                 /* don't try more than 25 times */
6378                 debug(F100,"nettol tried more than 25 times","",0);
6379                 return(-1);
6380             }
6381             if (count > 0) {
6382                 s += count;
6383                 n -= count;
6384             }
6385             debug(F111,"nettol retry",s,n);
6386             goto nettol_retry;
6387         } else {
6388             debug(F111,"nettol socket_write",s,count);
6389             return(len); /* success - return total length */
6390         }
6391     } else
6392       return(-2);
6393 #else
6394     debug(F100,"nettol TCPIPLIB not defined","",0);
6395     return(-2);
6396 #endif /* TCPIPLIB */
6397 }
6398
6399 /*  N E T T O C  --   Output character to network */
6400 /*
6401   Call with character to be transmitted.
6402   Returns 0 if transmission was successful, or
6403   -1 upon i/o error, or -2 if called improperly.
6404 */
6405 int
6406 #ifdef CK_ANSIC
6407 nettoc(CHAR c)
6408 #else
6409 nettoc(c) CHAR c;
6410 #endif /* CK_ANSIC */
6411 /* nettoc */ {
6412 #ifdef UNIX
6413     return(ttoc(c));
6414 #else
6415 #ifdef TCPIPLIB
6416     unsigned char cc;
6417     if (ttyfd == -1) {
6418         debug(F100,"nettoc socket is closed","",0);
6419         return -1;
6420     }
6421     cc = c;
6422     debug(F101,"nettoc cc","",cc);
6423
6424 #ifdef CK_KERBEROS
6425 #ifdef KRB4
6426 #ifdef RLOGCODE
6427     if (ttnproto == NP_EK4LOGIN) {
6428         return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
6429     }
6430 #endif /* RLOGCODE */
6431 #endif /* KRB4 */
6432 #ifdef KRB5
6433 #ifdef RLOGCODE
6434     if (ttnproto == NP_EK5LOGIN) {
6435         return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1);
6436     }
6437 #endif /* RLOGCODE */
6438 #ifdef KRB5_U2U
6439     if (ttnproto == NP_K5U2U) {
6440         return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1);
6441     }
6442 #endif /* KRB5_U2U */
6443 #endif /* KRB5 */
6444 #endif /* CK_KERBEROS */
6445
6446 #ifdef CK_ENCRYPTION
6447         if ( TELOPT_ME(TELOPT_ENCRYPTION) )
6448             ck_tn_encrypt(&cc,1);
6449 #endif /* CK_ENCRYPTION */
6450 #ifdef CK_SSL
6451     if (ssl_active_flag || tls_active_flag) {
6452         int len, error;
6453         /* Write using SSL */
6454       ssl_retry:
6455         if (ssl_active_flag)
6456           len = SSL_write(ssl_con, &cc, 1);
6457         else
6458           len = SSL_write(tls_con, &cc, 1);
6459         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
6460           case SSL_ERROR_NONE:
6461             debug(F111,"nettoc","SSL_write",len);
6462             return(len == 1 ? 0 : -1);
6463           case SSL_ERROR_WANT_WRITE:
6464           case SSL_ERROR_WANT_READ:
6465             return(-1);
6466           case SSL_ERROR_SYSCALL:
6467               if ( len == 0 ) { /* EOF */
6468                   netclos();
6469                   return(-2);
6470               } else {
6471                   int rc = -1;
6472 #ifdef NT
6473                   int gle = GetLastError();
6474                   debug(F111,"nettoc SSL_ERROR_SYSCALL",
6475                          "GetLastError()",gle);
6476                   rc = os2socketerror(gle);
6477                   if (rc == -1)
6478                       rc = -2;
6479                   else if ( rc == -2 )
6480                       rc = -1;
6481 #endif /* NT */
6482                   return(rc);
6483               }
6484         case SSL_ERROR_SSL:
6485               if (bio_err!=NULL) {
6486                   int len;
6487                   extern char ssl_err[];
6488                   BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n");
6489                   ERR_print_errors(bio_err);
6490                   len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6491                   ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6492                   debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0);
6493                   if (ssl_debug_flag)
6494                       printf(ssl_err);
6495               } else if (ssl_debug_flag) {
6496                   debug(F100,"nettoc SSL_ERROR_SSL","",0);
6497                   fflush(stderr);
6498                   fprintf(stderr,"nettoc() SSL_ERROR_SSL\n");
6499                   ERR_print_errors_fp(stderr);
6500               }
6501               return(-1);
6502               break;
6503           case SSL_ERROR_WANT_X509_LOOKUP:
6504           case SSL_ERROR_ZERO_RETURN:
6505           default:
6506             netclos();
6507             return(-2);
6508         }
6509     }
6510 #endif /* CK_SSL */
6511     if (ttnet == NET_TCPB) {
6512 #ifdef BSDSELECT
6513         fd_set wfds;
6514         struct timeval tv;
6515
6516         debug(F101,"nettoc BSDSELECT","",0);
6517         tv.tv_usec = 0L;
6518         tv.tv_sec = 30;
6519
6520 #ifdef STREAMING
6521       do_select:
6522 #endif /* STREAMING */
6523
6524         FD_ZERO(&wfds);
6525         FD_SET(ttyfd, &wfds);
6526         if (select(FD_SETSIZE, NULL,
6527 #ifdef __DECC
6528 #ifndef __DECC_VER
6529                    (int *)
6530 #endif /* __DECC_VER */
6531 #endif /* __DECC */
6532                    &wfds, NULL, &tv) < 0) {
6533             int s_errno = socket_errno;
6534             debug(F101,"nettoc select failed","",s_errno);
6535 #ifdef BETADEBUG
6536             printf("nettoc select failed: %d\n", s_errno);
6537 #endif /* BETADEBUG */
6538 #ifdef NT
6539             WSASafeToCancel = 0;
6540             if (!win95selectbug)
6541 #endif /* NT */
6542               return(-1);
6543         }
6544         if (!FD_ISSET(ttyfd, &wfds)) {
6545 #ifdef STREAMING
6546             if (streaming)
6547               goto do_select;
6548 #endif /* STREAMING */
6549             debug(F111,"nettoc","!FD_ISSET",ttyfd);
6550 #ifdef NT
6551             WSASafeToCancel = 0;
6552             if (!win95selectbug)
6553 #endif /* NT */
6554               return(-1);
6555         }
6556 #ifdef NT
6557         WSASafeToCancel = 0;
6558 #endif /* NT */
6559 #else /* BSDSELECT */
6560 #ifdef IBMSELECT
6561         {
6562             int tries = 0;
6563             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6564                 int count;
6565                 if (tries++ >= 60) {
6566                     /* if after 60 seconds we can't get permission to write */
6567                     debug(F101,"nettoc select failed","",socket_errno);
6568                     return(-1);
6569                 }
6570                 if ((count = nettchk()) < 0) {
6571                     debug(F111,"nettoc","nettchk()",count);
6572                     return(count);
6573                 }
6574             }
6575         }
6576 #endif /* IBMSELECT */
6577 #endif /* BSDSELECT */
6578         if (socket_write(ttyfd,&cc,1) < 1) {
6579             int s_errno = socket_errno;         /* maybe a function */
6580             debug(F101,"nettoc socket_write error","",s_errno);
6581 #ifdef OS2
6582             if (os2socketerror(s_errno) < 0)
6583               return(-2);
6584 #endif /* OS2 */
6585             return(-1);
6586         }
6587         debug(F101,"nettoc socket_write","", cc);
6588         return(0);
6589     } else return(-2);
6590 #else
6591     return(-2);
6592 #endif /* TCPIPLIB */
6593 #endif /* UNIX */
6594 }
6595
6596 /*  N E T F L U I  --  Flush network input buffer  */
6597
6598 #ifdef TNCODE
6599 static int
6600 #ifdef CK_ANSIC
6601 netgetc(int timo)                       /* Input function to point to... */
6602 #else  /* CK_ANSIC */
6603 netgetc(timo) int timo;
6604 #endif /* CK_ANSIC */
6605 {                                       /* ...in the tn_doop() call */
6606 #ifdef TCPIPLIB
6607     return netinc(timo);
6608 #else /* TCPIPLIB */
6609     return ttinc(timo);
6610 #endif /* TCPIPLIB */
6611 }
6612 #endif /* TNCODE */
6613
6614 int
6615 netflui() {
6616     int n;
6617     int ch;
6618 #ifdef NETLEBUF
6619     ttpush = -1;                        /* Clear the peek-ahead char */
6620     while (le_data && (le_inbuf() > 0)) {
6621         CHAR ch = '\0';
6622         if (le_getchar(&ch) > 0) {
6623             debug(F101,"ttflui le_inbuf ch","",ch);
6624         }
6625     }
6626 #endif /* NETLEBUF */
6627
6628 #ifdef TCPIPLIB
6629 #ifdef OS2
6630     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6631 #endif /* OS2 */
6632 #ifdef TNCODE
6633     if (ttnproto == NP_TELNET) {
6634         /* Netflui must process Telnet negotiations or get out of sync */
6635         if ((n = nettchk()) <= 0)
6636           goto exit_flui;
6637         while (n-- > 0) {
6638             ch = netinc(1);
6639             if (ch == IAC) {
6640                 extern int duplex;  /* this really shouldn't be here but ... */
6641                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6642                 if (tx == 1) duplex = 1;
6643                 else if (tx == 2) duplex = 0;
6644                 n = nettchk();
6645             }
6646         }
6647     } else
6648 #endif /* TNCODE */
6649     {
6650         ttibuf[ttibp+ttibn] = '\0';
6651         debug(F111,"netflui 1",ttibuf,ttibn);
6652 #ifdef CK_ENCRYPTION
6653         if (TELOPT_U(TELOPT_ENCRYPTION)) {
6654             ck_tn_decrypt(&ttibuf[ttibp],ttibn);
6655         }
6656 #endif /* CK_ENCRYPTION */
6657         ttibn = ttibp = 0;              /* Flush internal buffer *FIRST* */
6658         if (ttyfd < 1)
6659           goto exit_flui;
6660         if ((n = nettchk()) > 0) {      /* Now see what's waiting on the net */
6661             if (n > TTIBUFL) n = TTIBUFL;       /* and sponge it up */
6662             debug(F101,"netflui 2","",n);       /* ... */
6663             n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
6664             if (n >= 0) ttibuf[n] = '\0';
6665             debug(F111,"netflui 3",ttibuf,n);
6666 #ifdef CK_ENCRYPTION
6667             if (TELOPT_U(TELOPT_ENCRYPTION)) {
6668                 ck_tn_decrypt(&ttibuf[ttibp],n);
6669             }
6670 #endif /* CK_ENCRYPTION */
6671             ttibuf[0] = '\0';
6672         }
6673     }
6674 #else  /* !TCPIPLIB */
6675     if (ttyfd < 1)
6676       goto exit_flui;
6677 #ifdef TNCODE
6678     if (ttnproto == NP_TELNET) {
6679         if ((n = ttchk()) <= 0)
6680           goto exit_flui;
6681         while (n-- >= 0) {
6682             /* Netflui must process Telnet negotiations or get out of sync */
6683             ch = ttinc(1);
6684             if (ch == IAC) {
6685                 extern int duplex;  /* this really shouldn't be here but ... */
6686                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6687                 if (tx == 1) duplex = 1;
6688                 else if (tx == 2) duplex = 0;
6689                 n = ttchk();
6690             }
6691         };
6692     } else
6693 #endif /* TNCODE */
6694     if ((n = ttchk()) > 0) {
6695         debug(F101,"netflui non-TCPIPLIB","",n);
6696         while ((n--) && ttinc(1) > -1)  /* Don't worry, ttinc() is buffered */
6697           ;                             /* and it handles the decryption... */
6698     }
6699 #endif /* TCPIPLIB */
6700   exit_flui:
6701 #ifdef OS2
6702     ReleaseTCPIPMutex();
6703 #endif /* OS2 */
6704     return(0);
6705 }
6706
6707 #ifdef CK_KERBEROS
6708 /* The following two functions are required for encrypted rlogin */
6709 /* They are called with nettoc() or nettol() are transmitting    */
6710 /* encrypted data.  They call a function to encrypt the data     */
6711 /* and that function needs to be able to write to/read from the  */
6712 /* network in an unimpeded manner.  Hence, these two simple fns. */
6713 int
6714 net_write(fd, buf, len)
6715     int fd;
6716     register const char *buf;
6717     int len;
6718 {
6719     int cc;
6720     register int wrlen = len;
6721     do {
6722 #ifdef TCPIPLIB
6723         cc = socket_write(fd, buf, wrlen);
6724 #else
6725         cc = write(fd,buf,wrlen);
6726 #endif /* TCPIPLIB */
6727         if (cc < 0) {
6728             int s_errno = socket_errno;
6729             debug(F101,"net_write error","",s_errno);
6730 #ifdef OS2
6731             if (os2socketerror(s_errno) < 0)
6732                 return(-1);
6733             else
6734                 continue;
6735 #else /* OS2 */
6736             if (errno == EINTR)
6737                 continue;
6738             return(-1);
6739 #endif /* OS2 */
6740         }
6741         else {
6742             buf += cc;
6743             wrlen -= cc;
6744         }
6745     } while (wrlen > 0);
6746     return(len);
6747 }
6748 int
6749 net_read(fd, buf, len)
6750     int fd;
6751     register char *buf;
6752     register int len;
6753 {
6754     int cc, len2 = 0;
6755
6756     do {
6757 #ifdef TCPIPLIB
6758         cc = socket_read(fd, buf, len);
6759 #else
6760         cc = read(fd,buf,len);
6761 #endif
6762         if (cc < 0) {
6763             int s_errno = socket_errno;
6764             debug(F101,"net_read error","",s_errno);
6765 #ifdef OS2
6766             if (os2socketerror(s_errno) < 0)
6767                 return(-1);
6768 #endif /* OS2 */
6769             return(cc);          /* errno is already set */
6770         }
6771         else if (cc == 0) {
6772             netclos();
6773             return(len2);
6774         } else {
6775             buf += cc;
6776             len2 += cc;
6777             len -= cc;
6778         }
6779     } while (len > 0);
6780     return(len2);
6781 }
6782 #endif /* CK_KERBEROS */
6783 #endif /* NONET */
6784
6785 /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
6786  *   If the host is multi-homed it returns only one address.
6787  *
6788  * Two techniques are used.
6789  * (1) get the local host name and perform a DNS lookup, then take
6790  *     the first entry;
6791  * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
6792  *    no data is sent), then retrieve the local address from the socket.
6793  * Note: the second technique won't work on Microsoft systems.  See
6794  * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
6795  */
6796
6797 /* Technique number one cannot work reliably if the machine is a laptop
6798  * and the hostname is associated with a physical adapter which is not
6799  * installed and a PPP connection is being used instead.  This is because
6800  * the hostname DNS lookup will succeed for the physical adapter even though
6801  * it would be impossible to use it.  In NT4 SP4, the gethostbyname()
6802  * when given the result of gethostname() returns not the real DNS entries
6803  * for that name+domain.  Instead it returns all of the static and dynamic
6804  * IP addresses assigned to any physical or virtual adapter defined in the
6805  * system regardless of whether or not it is installed.  The order of the
6806  * addresses is fixed according to the binding order in the NT registry.
6807  */
6808
6809 /*
6810  * It appears that calling gethostbyname(NULL) is more reliable than
6811  * calling gethostbyname(gethostname()) on Windows.  So on Windows we will
6812  * only call gethostbyname(NULL).
6813  */
6814
6815 int
6816 getlocalipaddr() {
6817 #ifndef datageneral
6818     struct sockaddr_in l_sa;
6819     struct sockaddr_in r_sa;
6820     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6821     int sock;
6822     int rc;
6823     struct in_addr laddr;
6824
6825     /* if still not resolved, then try second strategy */
6826     /* This second strategy does not work on Windows */
6827
6828     memset(&l_sa,0,slen);
6829     memset(&r_sa,0,slen);
6830
6831     /* get a UDP socket */
6832     sock = socket(AF_INET, SOCK_DGRAM, 0);
6833     if (sock != -1) {
6834         /* connect to arbirary port and address (NOT loopback) */
6835         r_sa.sin_family = AF_INET;
6836         r_sa.sin_port = htons(IPPORT_ECHO);
6837
6838         /* The following is an "illegal conversion" in AOS/VS */
6839         /* (and who knows where else) */
6840
6841 #ifdef INADDRX
6842         inaddrx = inet_addr("128.127.50.1");
6843         r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
6844 #else
6845         r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
6846 #endif /* INADDRX */
6847         rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
6848         if (!rc) {                      /* get local address */
6849             getsockname(sock,(struct sockaddr *)&l_sa,&slen);
6850 #ifdef TCPIPLIB
6851             socket_close(sock);         /* We're done with the socket */
6852 #else
6853             close(sock);
6854 #endif /* TCPIPLIB */
6855             if (l_sa.sin_addr.s_addr != INADDR_ANY) {
6856                 myxipaddr = ntohl(l_sa.sin_addr.s_addr);
6857                 ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
6858                 debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
6859                 return(0);
6860             }
6861         }
6862     }
6863     return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
6864 #else /* datageneral */
6865     return(-1);
6866 #endif /* datageneral */
6867 }
6868
6869 int
6870 getlocalipaddrs(buf,bufsz,index)
6871     char * buf;
6872     int    bufsz;
6873     int    index;
6874 /* getlocalipaddrs */ {
6875 #ifndef datageneral
6876     char localhost[256];
6877     struct hostent * host=NULL;
6878     struct sockaddr_in l_sa;
6879     struct sockaddr_in r_sa;
6880     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6881     int rc;
6882 #ifdef COMMENT
6883     int sock;
6884     char messageBuf[60];
6885     struct in_addr laddr;
6886 #endif /* COMMENT */
6887
6888     memset(&l_sa,0,slen);
6889     memset(&r_sa,0,slen);
6890
6891     /* init local address (to zero) */
6892     l_sa.sin_addr.s_addr = INADDR_ANY;
6893
6894 #ifdef CKGHNLHOST
6895     rc = gethostname(localhost, 256);
6896     debug(F110,"getlocalipaddrs localhost",localhost,0);
6897 #else
6898     /* This doesn't work on some platforms, e.g. Solaris */
6899     rc = 0;
6900     localhost[0] = '\0';
6901 #ifdef NT
6902     if ( winsock_version < 20 ) {
6903         rc = gethostname(localhost, 256);
6904         debug(F110,"getlocalipaddrs localhost",localhost,0);
6905     }
6906 #endif /* NT */
6907 #endif /* CKGHNLHOST */
6908     if (!rc) {
6909         /* resolve host name for local address */
6910         debug(F110,"getlocalipaddrs","calling gethostbyname()",0);
6911         host = gethostbyname(localhost);
6912         debug(F111,"getlocalipaddrs","gethostbyname() returned",host);
6913         if (host) {
6914 #ifdef HADDRLIST
6915             host = ck_copyhostent(host);
6916             if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
6917                 buf[0] = '\0';
6918                 return(-1);
6919             }
6920             l_sa.sin_addr.s_addr =
6921               *((unsigned long *) (host->h_addr_list[index]));
6922             ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
6923             debug(F110,"getlocalipaddrs setting buf to",buf,0);
6924
6925 #ifdef COMMENT
6926             /* This is for reporting multiple IP Address */
6927             while (host->h_addr_list && host->h_addr_list[0]) {
6928                 l_sa.sin_addr.s_addr =
6929                   *((unsigned long *) (host->h_addr_list[0]));
6930                 ckstrncpy(messageBuf,
6931                         (char *)inet_ntoa(l_sa.sin_addr),60);
6932                 if (tcp_address) {
6933                     if (!strcmp(messageBuf,tcp_address))
6934                       ckstrncpy(myipaddr,tcp_address,20);
6935                 }
6936                 debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
6937                 host->h_addr_list++;
6938             }
6939 #endif /* COMMENT */
6940 #else   /* HADDRLIST */
6941             if (index != 0) {
6942                 buf[0] = '\0';
6943                 return(-1);
6944             }
6945             l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
6946             ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
6947             debug(F110,"getlocalipaddrs setting buf to",buf,0);
6948 #endif  /* HADDRLIST */
6949             return(0);
6950         } else debug(F110,
6951                      "getlocalipaddrs: gethostbyname() failed",
6952                      localhost,
6953                      0
6954                      );
6955     }
6956 #endif /* datageneral */
6957     return(-1);
6958 }
6959
6960 #ifdef RLOGCODE                 /* TCP/IP RLOGIN protocol support code */
6961 int
6962 rlog_naws() {
6963     struct rlog_naws {
6964         unsigned char id[4];
6965         unsigned short rows, cols, ypix, xpix;
6966     } nawsbuf;
6967
6968     if (ttnet != NET_TCPB)
6969       return 0;
6970     if (ttnproto != NP_RLOGIN
6971 #ifdef CK_KERBEROS
6972         && ttnproto != NP_K4LOGIN
6973         && ttnproto != NP_EK4LOGIN
6974         && ttnproto != NP_K5LOGIN
6975         && ttnproto != NP_EK5LOGIN
6976 #endif /* CK_KERBEROS */
6977          )
6978       return 0;
6979     if (!TELOPT_ME(TELOPT_NAWS))
6980       return 0;
6981
6982     debug(F100,"rlogin Window Size sent","",0);
6983
6984     nawsbuf.id[0] = nawsbuf.id[1] = 0377;
6985     nawsbuf.id[2] = nawsbuf.id[3] = 's';
6986 #ifdef OS2
6987     nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
6988                           -(tt_status[VTERM]?1:0)));
6989     nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
6990 #else /* OS2 */
6991     nawsbuf.rows = htons((unsigned short) tt_rows);
6992     nawsbuf.cols = htons((unsigned short) tt_cols);
6993 #endif /* OS2 */
6994     nawsbuf.ypix = htons(0);            /* y pixels */
6995
6996     nawsbuf.xpix = htons(0);            /* x pixels */
6997     if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0)
6998       return(-1);
6999     return(0);
7000 }
7001
7002 #ifdef OS2ORUNIX
7003 #define RLOGOUTBUF
7004 #endif /* OS2 */
7005 static int
7006 #ifdef CK_ANSIC
7007 rlog_ini(CHAR * hostname, int port,
7008          struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
7009 #else /* CK_ANSIC */
7010 rlog_ini(hostname, port, l_addr, r_addr)
7011     CHAR * hostname;
7012     int port;
7013     struct sockaddr_in * l_addr;
7014     struct sockaddr_in * r_addr;
7015 #endif /* CK_ANSIC */
7016 /* rlog_ini */ {
7017
7018 #ifdef RLOGOUTBUF
7019     char outbuf[512];
7020     int  outbytes=0;
7021 #endif /* RLOGOUTBUF */
7022     int flag = 0;
7023 #define TERMLEN 16
7024 #define CONSPDLEN 16
7025     CHAR localuser[UIDBUFLEN+1];
7026     CHAR remoteuser[UIDBUFLEN+1];
7027     int userlen = 0;
7028     CHAR term_speed[TERMLEN+CONSPDLEN+1];
7029 #ifdef CONGSPD
7030     long conspd = -1L;
7031 #endif /* CONGSPD */
7032 #ifdef OS2
7033     extern int tt_type, max_tt;
7034     extern struct tt_info_rec tt_info[];
7035 #endif /* OS2 */
7036     int i, n;
7037
7038     int rc = 0;
7039     tn_reset();                 /* This call will reset all of the Telnet */
7040                                 /* options and then quit.  We need to do  */
7041                                 /* this since we use the Telnet options   */
7042                                 /* to hold various state information      */
7043     duplex = 0;                 /* Rlogin is always remote echo */
7044     rlog_inband = 0;
7045
7046 #ifdef CK_TTGWSIZ
7047 /*
7048   But compute the values anyway before the first read since the out-
7049   of-band NAWS request would arrive before the first data byte (NULL).
7050 */
7051 #ifdef OS2
7052     /* Console terminal screen rows and columns */
7053     debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
7054            -(tt_status[VTERM]?1:0));
7055     debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
7056     /* Not known yet */
7057     if (VscrnGetWidth(VTERM) < 0 ||
7058         VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
7059         ttgwsiz();                      /* Try to get screen dimensions */
7060     }
7061     debug(F101,
7062           "rlog_ini tt_rows 2",
7063           "",
7064           VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
7065           );
7066     debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
7067 #else /* OS2 */
7068     debug(F101,"rlog_ini tt_rows 1","",tt_rows);
7069     debug(F101,"rlog_ini tt_cols 1","",tt_cols);
7070     if (tt_rows < 0 || tt_cols < 0) {   /* Not known yet */
7071         ttgwsiz();                      /* Try to find out */
7072     }
7073     debug(F101,"rlog_ini tt_rows 2","",tt_rows);
7074     debug(F101,"rlog_ini tt_cols 2","",tt_cols);
7075 #endif /* OS2 */
7076 #endif /* CK_TTGWSIZ */
7077
7078     ttflui();                           /* Start by flushing the buffers */
7079
7080     rlog_mode = RL_COOKED;
7081
7082     /* Determine the user's local username ... */
7083
7084     localuser[0] = '\0';
7085 #ifdef NT
7086     {
7087         char localuid[UIDBUFLEN+1];
7088         ckstrncpy((char *)localuser,(char *)GetLocalUser(),UIDBUFLEN);
7089     }
7090
7091     if ( !localuser[0] )
7092 #endif /* NT */
7093     {
7094         char * user = getenv("USER");
7095         if (!user)
7096           user = "";
7097         userlen = strlen(user);
7098         debug(F111,"rlogin getenv(USER)",user,userlen);
7099         ckstrncpy((char *)localuser,user,UIDBUFLEN);
7100         debug(F110,"rlog_ini localuser 1",localuser,0);
7101     }
7102     if ( !localuser[0] )
7103         strcpy((char *)localuser,"unknown");
7104     else if (ck_lcname) {
7105         cklower((char *)localuser);
7106         debug(F110,"rlog_ini localuser 2",localuser,0);
7107     }
7108
7109     /* And the username to login with */
7110     if (uidbuf[0]) {
7111         ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
7112         debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
7113     } else if (localuser[0]) {
7114         ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
7115         debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
7116     } else {
7117         remoteuser[0] = '\0';
7118         debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
7119     }
7120     if (ck_lcname)
7121       cklower((char *)remoteuser);
7122     debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
7123
7124     /* The command to issue is the terminal type and speed */
7125     term_speed[0] = '\0';
7126     if (tn_term) {                      /* SET TELNET TERMINAL-TYPE value */
7127         if (*tn_term) {                 /* (if any) takes precedence. */
7128             ckstrncpy((char *)term_speed, tn_term, TERMLEN);
7129             flag = 1;
7130         }
7131     } else {                            /* Otherwise the local terminal type */
7132 #ifdef OS2
7133         /* In terminal-emulating versions, it's the SET TERM TYPE value */
7134         ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
7135                 tt_info[tt_type].x_name : "network", TERMLEN);
7136 #else
7137         /* In the others, we just look at the TERM environment variable */
7138         {
7139             char *p = getenv("TERM");
7140             if (p)
7141               ckstrncpy((char *)term_speed,p,TERMLEN);
7142             else
7143               term_speed[0] = '\0';
7144 #ifdef VMS
7145             for (p = (char *) term_speed; *p; p++) {
7146                 if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
7147                   break;
7148                 else if (isupper(*p))
7149                   *p = tolower(*p);
7150             }
7151             *p = '\0';
7152 #endif /* VMS */
7153         }
7154 #endif /* OS2 */
7155     }
7156     n = strlen((char *)term_speed);
7157     if (n > 0) {                        /* We have a terminal type */
7158         if (!flag) {                    /* If not user-specified */
7159             for (i = 0; i < n; i++)     /* then lowercase it.    */
7160               if (isupper(term_speed[i]))
7161                 term_speed[i] = tolower(term_speed[i]);
7162         }
7163         debug(F110,"rlog_ini term_speed 1",term_speed,0);
7164
7165 #ifdef CONGSPD
7166         /* conspd() is not yet defined in all ck*tio.c modules */
7167         conspd = congspd();
7168         if (conspd > 0L) {
7169             ckstrncat((char *)term_speed,"/",sizeof(term_speed));
7170             ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed));
7171         } else
7172 #endif /* CONGSPD */
7173           ckstrncat((char *)term_speed,"/19200",sizeof(term_speed));
7174         debug(F110,"rlog_ini term_speed 2",term_speed,0);
7175     } else {
7176         term_speed[0] = '\0';
7177         debug(F110,"rlog_ini term_speed 3",term_speed,0);
7178     }
7179
7180 #ifdef CK_KERBEROS
7181     if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
7182         ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
7183         int kver, encrypt, rc;
7184         switch (ttnproto) {
7185           case NP_K4LOGIN:
7186             kver = 4;
7187             encrypt = 0;
7188             break;
7189           case NP_EK4LOGIN:
7190             kver = 4;
7191             encrypt = 1;
7192             break;
7193           case NP_K5LOGIN:
7194             kver = 5;
7195             encrypt = 0;
7196             break;
7197           case NP_EK5LOGIN:
7198             kver = 5;
7199             encrypt = 1;
7200             break;
7201         default:
7202             kver = 0;
7203             encrypt = 0;
7204         }
7205         rc = ck_krb_rlogin(hostname, port,
7206                            localuser, remoteuser, term_speed,
7207                            l_addr, r_addr, kver, encrypt);
7208         if (!rc) {                      /* success */
7209             TELOPT_ME(TELOPT_NAWS) = 1;
7210             rc = rlog_naws();
7211         }
7212         return(rc);
7213     } else
7214 #endif /* CK_KERBEROS */
7215     if (ttnproto == NP_RLOGIN) {
7216 #ifdef RLOGOUTBUF
7217         /*
7218          *  The rcmds start the connection with a series of init data:
7219          *
7220          *    a port number upon which client is listening for stderr data
7221          *    the user's name on the client machine
7222          *    the user's name on the server machine
7223          *    the terminal_type/speed or command to execute
7224          */
7225         outbuf[outbytes++] = 0;
7226         strcpy((char *)outbuf+outbytes,(char *)localuser);
7227         outbytes += strlen((char *)localuser) + 1;
7228         strcpy((char *)outbuf+outbytes,(char *)remoteuser);
7229         outbytes += strlen((char *)remoteuser) + 1;
7230         strcpy((char *)outbuf+outbytes,(char *)term_speed);
7231         outbytes += strlen((char *)term_speed) + 1;
7232         rc = ttol((CHAR *)outbuf,outbytes);
7233 #else /* RLOGOUTBUF */
7234         ttoc(0);                        /* Send an initial NUL as wake-up */
7235         /* Send each variable with the trailing NUL */
7236         rc = ttol(localuser,strlen((char *)localuser)+1);
7237         if (rc > 0)
7238           rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
7239         if (rc > 0)
7240           rc = ttol(term_speed,strlen((char *)term_speed)+1);
7241 #endif /* RLOGOUTBUF */
7242
7243         /* Now we are supposed to get back a single NUL as confirmation */
7244         errno = 0;
7245         rc = ttinc(60);
7246         debug(F101,"rlogin first ttinc","",rc);
7247         if (rc > 0) {
7248             debug(F101,"rlogin ttinc 1","",rc);
7249             printf(
7250                "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
7251             return(-1);
7252         } else if (rc < 0) {
7253             debug(F101,"rlogin ttinc errno","",errno);
7254             /* printf("Network error: %d\n", errno); */
7255             return(-1);
7256         }
7257     }
7258     return(0);
7259 }
7260
7261 /* two control messages are defined:
7262
7263    a double flag byte of 'o' indicates a one-byte message which is
7264    identical to what was once carried out of band.
7265
7266    a double flag byte of 'q' indicates a zero-byte message.  This
7267    message is interpreted as two \377 data bytes.  This is just a
7268    quote rule so that binary data from the server does not confuse the
7269    client.  */
7270
7271 int 
7272 rlog_ctrl(cp, n)
7273      unsigned char *cp;
7274      int n;
7275 {
7276     if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
7277         if (rlog_oob(&cp[4],1))
7278             return(-5);
7279         return(5);
7280     } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
7281         /* this is somewhat of a hack */
7282         cp[2] = '\377';
7283         cp[3] = '\377';
7284         return(2);
7285     }
7286     return(0);
7287 }
7288
7289 static int
7290 rlog_oob(oobdata, count) CHAR * oobdata; int count; {
7291     int i;
7292     int flush = 0;
7293
7294     debug(F111,"rlogin out_of_band","count",count);
7295
7296     for (i = 0; i<count; i++)   {
7297         debug(F101,"rlogin out_of_band","",oobdata[i]);
7298                 if (oobdata[i] & 0x01)
7299                         continue;
7300
7301         if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
7302             debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
7303
7304             /* Only flush the data if in fact we are in a mode that won't */
7305             /* get out of sync.  Ie, not when we are in protocol mode.    */
7306             switch ( what ) {
7307             case W_NOTHING:
7308             case W_CONNECT:
7309             case W_COMMAND:
7310                 if ( rlog_inband )
7311                     flush = 1;
7312                 else
7313                     ttflui();
7314                 break;
7315             }
7316         }
7317         if (oobdata[i] & 0x10) {        /* Switch to RAW mode */
7318             debug(F101,"rlogin Raw Mode command","",oobdata[i]);
7319             rlog_mode = RL_RAW;
7320         }
7321
7322         if (oobdata[i] & 0x20) {        /* Switch to COOKED mode */
7323             debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
7324             rlog_mode = RL_COOKED;
7325         }
7326         if (oobdata[i] & 0x80)
7327         {        /* Send Window Size Info */
7328             debug(F101,"rlogin Window Size command","",oobdata[i]);
7329             /* Remember to send WS Info when Window Size changes */
7330             if ( !TELOPT_ME(TELOPT_NAWS) ) {
7331                 TELOPT_ME(TELOPT_NAWS) = 1;
7332                 rlog_naws();
7333             }
7334         }
7335     }
7336     return(flush);
7337 }
7338 #ifndef TCPIPLIB
7339 static SIGTYP
7340 rlogoobh(sig) int sig; {
7341 #ifdef SOLARIS
7342     char                                /* Or should it be char for all? */
7343 #else
7344     CHAR
7345 #endif /* SOLARIS */
7346       oobdata;
7347
7348     /* int  count = 0; */ /* (not used) */
7349
7350     while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
7351       /*
7352        * We need to do some special processing here.
7353        * Just in case the socket is blocked for input
7354        *
7355        */
7356         switch (errno) {
7357           case EWOULDBLOCK:
7358             break;
7359           default:
7360             return;
7361         }
7362     }
7363     debug(F101,"rlogin out_of_band","",oobdata);
7364     if (oobdata == 0x02) {      /* Flush Buffered Data not yet displayed */
7365         debug(F101,"rlogin Flush Buffered Data command","",oobdata);
7366         netflui();
7367     }
7368     if (oobdata & 0x10) {               /* Switch to raw mode */
7369         debug(F101,"rlogin Raw Mode command","",oobdata);
7370         rlog_mode = RL_RAW;
7371     }
7372     if (oobdata & 0x20) {               /* Switch to cooked mode */
7373         debug(F101,"rlogin Cooked Mode command","",oobdata);
7374         rlog_mode = RL_COOKED;
7375     }
7376     if (oobdata & 0x80) {                 /* Send Window Size Info */
7377         debug(F101,"rlogin Window Size command","",oobdata);
7378         /* Remember to send WS Info when Window Size changes */
7379         if ( !TELOPT_ME(TELOPT_NAWS) ) {
7380             TELOPT_ME(TELOPT_NAWS) = 1;
7381             rlog_naws();
7382         }
7383     }
7384 }
7385 #endif /* TCPIPLIB */
7386 #endif /* RLOGCODE */
7387
7388 /* Send network BREAK */
7389 /*
7390   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
7391 */
7392 int
7393 netbreak() {
7394     CHAR buf[3];
7395     if (ttnet == NET_TCPB) {
7396         if (ttnproto == NP_TELNET) {
7397 #ifdef TNCODE
7398             buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
7399             if (
7400 #ifdef OS2
7401                 nettol((char *) buf, 2)
7402 #else
7403                 ttol(buf, 2)
7404 #endif /* OS2 */
7405                 < 2)
7406               return(-1);
7407             if (tn_deb || debses || deblog) {
7408                 extern char tn_msg[];
7409                 ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
7410                           NULL,NULL);
7411                 debug(F101,tn_msg,"",BREAK);
7412                 if (debses || tn_deb) tn_debug(tn_msg);
7413             }
7414             return(1);
7415 #else
7416             debug(F100,"netbreak no TNCODE","",0);
7417             return(0);
7418 #endif /* TNCODE */
7419         }
7420         /* Insert other TCP/IP protocols here */
7421     }
7422     /* Insert other networks here */
7423     return(0);
7424 }
7425 #endif /* NETCONN */
7426
7427
7428 #ifdef NETCONN
7429 #ifdef SUNX25
7430 /*
7431   SunLink X.25 support by Marcello Frutig, Catholic University,
7432   Rio de Janeiro, Brazil, 1990.
7433 */
7434
7435 /* PAD X.3, X.28 and X.29 support */
7436
7437 static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
7438
7439 /* Initialize PAD */
7440
7441 extern CHAR padparms[];
7442
7443 VOID
7444 initpad() {
7445   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
7446   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
7447   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
7448   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
7449   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
7450   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
7451   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
7452   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
7453   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
7454   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
7455   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
7456   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
7457   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
7458   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
7459   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
7460   padparms[PAD_EDITING]                = 1;  /* can edit */
7461   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
7462   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
7463   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
7464 }
7465
7466 /* Set PAD parameters */
7467
7468 VOID
7469 setpad(s,n) CHAR *s; int n; {
7470     int i;
7471     CHAR *ps = s;
7472
7473     if (n < 1) {
7474         initpad();
7475     } else {
7476         for (i = 0; i < n; i++) {
7477             if (*ps > MAXPADPARMS)
7478               x29err[i+2] = *ps;
7479             else
7480               padparms[*ps] = *(ps+1);
7481             ps += 2;
7482         }
7483     }
7484 }
7485
7486 /* Read PAD parameters */
7487
7488 VOID
7489 readpad(s,n,r) CHAR *s; int n; CHAR *r; {
7490     int i;
7491     CHAR *ps = s;
7492     CHAR *pr = r;
7493
7494     *pr++ = X29_PARAMETER_INDICATION;
7495     if (n > 0) {
7496         for (i = 0; i < n; i++, ps++) {
7497             if (*ps > MAXPADPARMS) {
7498                 x29err[i+2] = *ps++;
7499             } else {
7500                 *pr++ = *ps;
7501                 *pr++ = padparms[*ps++];
7502             }
7503         }
7504     } else {
7505         for (i = 1; i < MAXPADPARMS; i++) {
7506             *pr++ = i;
7507             *pr++ = padparms[i];
7508         }
7509     }
7510 }
7511
7512 int
7513 qbitpkt(s,n) CHAR *s; int n; {
7514     CHAR *ps = s;
7515     int x29cmd = *ps;
7516     CHAR *psa = s+1;
7517     CHAR x29resp[(MAXPADPARMS*2)+1];
7518
7519     switch (x29cmd) {
7520
7521         case X29_SET_PARMS:
7522             setpad (ps+1,n/2);
7523             if ((int)strlen((char *)x29err) > 2) {
7524                 ttol(x29err,(int)strlen((char *)x29err));
7525                 x29err[2] = '\0';
7526             }
7527             return (-2);
7528         case X29_READ_PARMS:
7529             readpad (ps+1,n/2,x29resp);
7530             setqbit ();
7531             ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7532             if ((int)strlen((char *)x29err) > 2) {
7533                 ttol(x29err,(int)strlen((char *)x29err));
7534                 x29err[2] = '\0';
7535             }
7536             resetqbit();
7537             break;
7538         case X29_SET_AND_READ_PARMS:
7539             setpad (ps+1,n/2);
7540             readpad (ps+1,n/2,x29resp);
7541             setqbit();
7542             ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7543             if ((int)strlen((char *)x29err) > 2) {
7544                 ttol (x29err,(int)strlen((char *)x29err));
7545                 x29err [2] = '\0';
7546             }
7547             resetqbit();
7548             return (-2);
7549         case X29_INVITATION_TO_CLEAR:
7550             (VOID) x25clear();
7551             return (-1);
7552         case X29_INDICATION_OF_BREAK:
7553             break;
7554     }
7555     return (0);
7556 }
7557
7558 /* PAD break action processor */
7559
7560 VOID
7561 breakact() {
7562     extern char x25obuf[MAXOX25];
7563     extern int obufl;
7564     extern int active;
7565     extern unsigned char tosend;
7566     static CHAR indbrk[3] = {
7567         X29_INDICATION_OF_BREAK,
7568         PAD_SUPPRESSION_OF_DATA,
7569         1
7570     };
7571     CHAR intudat, cause, diag;
7572
7573     if (x25stat() < 0) return;  /* Ignore if no virtual call established */
7574
7575     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
7576         if (ttol((CHAR *)x25obuf,obufl) < 0) {
7577             perror ("\r\nCan't send characters");
7578             active = 0;
7579         } else {
7580             bzero (x25obuf,sizeof(x25obuf));
7581             obufl = 0;
7582             tosend = 0;
7583         };
7584
7585     switch (padparms[PAD_BREAK_ACTION]) {
7586
7587        case 0 : break;                  /* do nothing */
7588        case 1 : /* send interrupt packet with interrupt user data field = 1 */
7589                 intudat = 1;
7590                 x25intr (intudat);
7591                 break;
7592        case 2 : /* send reset packet with cause and diag = 0 */
7593                 cause = diag = 0;
7594                 x25reset (cause,diag);
7595                 break;
7596        case 5 : /* send interrupt packet with interrupt user data field = 0 */
7597                 intudat = 0;
7598                 x25intr (intudat);
7599                 setqbit ();
7600                 /* send indication of break without a parameter field */
7601                 ttoc(X29_INDICATION_OF_BREAK);
7602                 resetqbit ();
7603                 break;
7604        case 8 : active = 0;             /* leave data transfer */
7605                 conol ("\r\n");
7606                 break;
7607        case 21: /* send interrupt packet with interrupt user data field = 0 */
7608                 intudat = 0;
7609                 x25intr (intudat);
7610                 setpad (indbrk+1,2);    /* set pad to discard input */
7611                 setqbit ();
7612                 /* send indication of break with parameter field */
7613                 ttol (indbrk,sizeof(indbrk));
7614                 resetqbit ();
7615                 break;
7616      }
7617 }
7618
7619 /* X.25 support functions */
7620
7621 X25_CAUSE_DIAG diag;
7622
7623 /*
7624   Convert a null-terminated string representing an X.121 address
7625   to a packed BCD form.
7626 */
7627 int
7628 pkx121(str,bcd) char *str; CHAR *bcd; {
7629     int i, j;
7630     u_char c;
7631
7632     i = j = 0;
7633     while (str[i]) {
7634         if (i >= 15 || str [i] < '0' || str [i] > '9')
7635           return (-1);
7636         c = str [i] - '0';
7637         if (i & 1)
7638           bcd [j++] |= c;
7639         else
7640           bcd [j] = c << 4;
7641         i++;
7642     }
7643     return (i);
7644 }
7645
7646 /* Reads and prints X.25 diagnostic */
7647
7648 int
7649 x25diag () {
7650     int i;
7651
7652     bzero ((char *)&diag,sizeof(diag));
7653     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
7654         perror ("Reading X.25 diagnostic");
7655         return(-1);
7656     }
7657     if (diag.datalen > 0) {
7658         printf ("X.25 Diagnostic :");
7659         for (i = 0; i < (int)diag.datalen; i++)
7660           printf(" %02h",diag.data[i])+
7661         printf ("\r\n");
7662     }
7663     return(0);
7664 }
7665
7666 /* X.25 Out-of-Band Signal Handler */
7667
7668 SIGTYP
7669 x25oobh(foo) int foo; {
7670     int oobtype;
7671     u_char oobdata;
7672     int t;
7673
7674     (VOID) signal(SIGURG,x25oobh);
7675     do {
7676         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
7677             perror ("Getting signal type");
7678             return;
7679         }
7680         switch (oobtype) {
7681           case INT_DATA:
7682             if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
7683                 perror ("Receiving X.25 interrupt data");
7684                 return;
7685             }
7686             t = oobdata;
7687             printf ("\r\nInterrupt received, data = %d\r\n", t);
7688             break;
7689           case VC_RESET:
7690             printf ("\r\nVirtual circuit reset\r\n");
7691             x25diag ();
7692             break;
7693           case N_RESETS:
7694             printf ("\r\nReset timeout\r\n");
7695             break;
7696           case N_CLEARS:
7697             printf ("\r\nClear timeout\r\n");
7698             break;
7699           case MSG_TOO_LONG:
7700             printf ("\r\nMessage discarded, too long\r\n");
7701             break;
7702           default:
7703             if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
7704             break;
7705         }
7706     } while (oobtype);
7707 }
7708
7709 /* Send a X.25 interrupt packet */
7710
7711 int
7712 #ifdef CK_ANSIC
7713 x25intr(char intr)
7714 #else
7715 x25intr(intr) char intr;
7716 #endif /* CK_ANSIC */
7717 /* x25intr */ {
7718     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
7719     debug(F100,"X.25 intr","",0);
7720     return(0);
7721 }
7722
7723 /* Reset X.25 virtual circuit */
7724 int
7725 #ifdef CK_ANSIC
7726 x25reset(char cause, char diagn)
7727 #else
7728 x25reset(cause, diagn) char cause; char diagn;
7729 #endif /* CK_ANSIC */
7730 /* x25reset */ {
7731     bzero ((char *)&diag,sizeof(diag));
7732     diag.flags   = 0;
7733     diag.datalen = 2;
7734     diag.data[0] = cause;
7735     diag.data[1] = diagn;
7736     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
7737       return(-1);
7738     debug(F100,"X.25 reset","",0);
7739     return(0);
7740 }
7741
7742 /* Clear X.25 virtual circuit */
7743 int
7744 x25clear() {
7745     int i;
7746     debug(F100,"X.25 clear","",0);
7747     bzero ((char *)&diag,sizeof(diag));
7748     diag.flags = (1 << DIAG_TYPE);
7749     diag.datalen = 2;
7750     diag.data[0] = 0;
7751     diag.data[1] = 0;
7752     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
7753     return(ttclos(0));                  /* Close socket */
7754 }
7755
7756 /* X.25 status */
7757 int
7758 x25stat() {
7759     if (ttyfd == -1) return (-1);
7760     return(0);
7761 }
7762
7763 /* Set Q_BIT on */
7764 VOID
7765 setqbit() {
7766     static int qbiton = 1 << Q_BIT;
7767     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
7768 }
7769
7770 /* Set Q_BIT off */
7771 VOID
7772 resetqbit() {
7773     static int qbitoff = 0;
7774     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
7775 }
7776
7777 /* Read n characters from X.25 circuit into buf */
7778
7779 int
7780 x25xin(n,buf) int n; CHAR *buf; {
7781     register int x, c;
7782     int qpkt;
7783
7784     do {
7785         x = read(ttyfd,buf,n);
7786         if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
7787             /* If return -1 : invitation to clear; -2 : PAD changes */
7788             if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
7789             qpkt = 1;
7790         } else qpkt = 0;
7791     } while (qpkt);
7792
7793 #ifdef COMMENT                  /* Disabled by Stephen Riehm 19.12.97 */
7794     /* BUG!
7795      * if buf[] is full, then this null lands in nirvana!
7796      * I was unable to find any code which needs a trailing null in buf[]
7797      */
7798     if (x > 0) buf[x] = '\0';
7799 #endif /* COMMENT */
7800     if (x < 1) x = -1;
7801     debug(F101,"x25xin x","",x);
7802
7803     return(x);
7804 }
7805
7806 #ifdef COMMENT /* NO LONGER NEEDED! */
7807 /* X.25 read a line */
7808
7809 int
7810 #ifdef PARSENSE
7811 #ifdef CK_ANSIC
7812 x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
7813 #else
7814 x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
7815 #endif /* CK_ANSIC */
7816 #else /* not PARSENSE */
7817 #ifdef CK_ANSIC
7818 x25inl(CHAR *dest, int max,int timo, CHAR eol)
7819 #else
7820 x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
7821 #endif /* __SDTC__ */
7822 #endif /*PARSENSE */
7823  /* x25inl */ {
7824     CHAR *pdest;
7825     int pktype, goteol, rest, n;
7826     int i, flag = 0;
7827     extern int ttprty, ttpflg;
7828     int ttpmsk;
7829
7830     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
7831
7832     debug(F101,"x25inl max","",max);
7833     debug(F101,"x25inl eol","",eol);
7834     pdest  = dest;
7835     rest   = max;
7836     goteol = 0;
7837     do {
7838         n = read(ttyfd,pdest,rest);
7839         n--;
7840         pktype = *pdest & 0x7f;
7841         switch (pktype) {
7842           case 1 << Q_BIT:
7843             if (qbitpkt(pdest+1,--n) < 0) return(-2);
7844             break;
7845           default:
7846             if (flag == 0) { /* if not in packet, search start */
7847                 for (i = 1; (i < n) &&
7848                      !(flag = ((dest[i] & 0x7f) == start));
7849                      i++);
7850                 if (flag == 0) { /* not found, discard junk */
7851                     debug(F101,"x25inl skipping","",n);
7852                     continue;
7853                 } else {                /* found, discard junk before start */
7854                     int k;
7855                     n = n - i + 1;
7856                     for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
7857                 }
7858             }
7859             for (i = 0; (i < n) && /* search for eol */
7860                  !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
7861                  i++,pdest++);
7862             *pdest = '\0';
7863             rest -= n;
7864         }
7865     } while ((rest > 0) && (!goteol));
7866
7867     if (goteol) {
7868         n = max - rest;
7869         debug (F111,"x25inl X.25 got",(char *) dest,n);
7870         if (timo) ttimoff();
7871         if (ttpflg++ == 0 && ttprty == 0) {
7872             if ((ttprty = parchk(dest,start,n)) > 0) {
7873                 int j;
7874                 debug(F101,"x25inl senses parity","",ttprty);
7875                 debug(F110,"x25inl packet before",(char *)dest,0);
7876                 ttpmsk = 0x7f;
7877                 for (j = 0; j < n; j++)
7878                   dest[j] &= 0x7f; /* Strip parity from packet */
7879                 debug(F110,"x25inl packet after ",dest,0);
7880             } else {
7881                 debug(F101,"parchk","",ttprty);
7882                 if (ttprty < 0) { ttprty = 0; n = -1; }
7883             }
7884         }
7885         ttimoff();
7886         return(n);
7887     }
7888     ttimoff();
7889     return(-1);
7890 }
7891 #endif /* COMMENT */
7892 #endif /* SUNX25 */
7893
7894 #ifdef IBMX25
7895 /*
7896  * IBM X25 support - using the NPI streams interface
7897  * written by Stephen Riehm, pc-plus, Munich Germany
7898  */
7899
7900 /* riehm: missing functions / TODO list */
7901
7902 /*
7903   x25intr() - Send an interrupt packet
7904 */
7905
7906 /* return an error message depending on packet type */
7907 char *
7908 x25err(n) int n; {
7909     static char buf[30];
7910     switch (n) {
7911       case NBADADDR:     return "invalid address";
7912       case NBADOPT:      return "invalid options";
7913       case NACCESS:      return "no permission";
7914       case NNOADDR:      return "unable to allocate address";
7915       case NOUTSTATE:    return "invalid state";
7916       case NBADSEQ:      return "invalid sequence number";
7917       case NSYSERR:      return "system error";
7918       case NBADDATA:     return "invalid data size";
7919       case NBADFLAG:     return "invalid flag";
7920       case NNOTSUPPORT:  return "unsupported primitive";
7921       case NBOUND:       return "address in use";
7922       case NBADQOSPARAM: return "bad QOS parameters";
7923       case NBADQOSTYPE:  return "bad QOS type";
7924       case NBADTOKEN:    return "bad token value";
7925       case NNOPROTOID:   return "protocol id could not be allocated";
7926       case NODDCUD:      return "odd length call user data";
7927       default:
7928         ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL);
7929         return buf;
7930     }
7931 }
7932
7933 /* turn a meaningless primitive number into a meaningful primitive name */
7934 char *
7935 x25prim(n) int n; {
7936     static char buf[30];
7937     switch(n) {
7938       case N_BIND_ACK:     return "N_BIND_ACK";
7939       case N_BIND_REQ:     return "N_BIND_REQ";
7940       case N_CONN_CON:     return "N_CONN_CON";
7941       case N_CONN_IND:     return "N_CONN_IND";
7942       case N_CONN_REQ:     return "N_CONN_REQ";
7943       case N_CONN_RES:     return "N_CONN_RES";
7944       case N_DATACK_IND:   return "N_DATAACK_IND";
7945       case N_DATACK_REQ:   return "N_DATAACK_REQ";
7946       case N_DATA_IND:     return "N_DATA_IND";
7947       case N_DATA_REQ:     return "N_DATA_REQ";
7948       case N_DISCON_IND:   return "N_DISCON_IND";
7949       case N_DISCON_REQ:   return "N_DISCON_REQ";
7950       case N_ERROR_ACK:    return "N_ERROR_ACK";
7951       case N_EXDATA_IND:   return "N_EXDATA_IND";
7952       case N_EXDATA_REQ:   return "N_EXDATA_REQ";
7953       case N_INFO_ACK:     return "N_INFO_ACK";
7954       case N_INFO_REQ:     return "N_INFO_REQ";
7955       case N_OK_ACK:       return "N_OK_ACK";
7956       case N_OPTMGMT_REQ:  return "N_OPTMGMT_REQ";
7957       case N_RESET_CON:    return "N_RESET_CON";
7958       case N_RESET_IND:    return "N_RESET_IND";
7959       case N_RESET_REQ:    return "N_RESET_REQ";
7960       case N_RESET_RES:    return "N_RESET_RES";
7961       case N_UDERROR_IND:  return "N_UDERROR_IND";
7962       case N_UNBIND_REQ:   return "N_UNBIND_REQ";
7963       case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
7964       case N_UNITDATA_IND: return "N_UNITDATA_IND";
7965       default:
7966         ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL);
7967         return buf;
7968     }
7969 }
7970
7971 /*****************************************************************************
7972  * Function: x25getmsg()
7973  * Description: get a STREAMS message, and check it for errors
7974  *
7975  * Parameters:
7976  * fd           - file descriptor to x25 device (opened)
7977  * control      - control buffer (pre-allocated)
7978  * ctl_size     - size of control buffer
7979  * data         - data buffer (pre-allocated)
7980  * data_size    - size of data buffer
7981  * flags        - flags for getmsg()
7982  * expected     - expected Primitive type
7983  *
7984  * Return Value:
7985  *      >= 0    OK (size of data returned)
7986  *      -1      error
7987  *
7988  */
7989 int
7990 x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
7991     int                 fd;             /* X25 device (opened) */
7992     N_npi_ctl_t         *control;       /* control buffer (pre-allocated) */
7993     int                 ctl_size;       /* size of control buffer */
7994     N_npi_data_t        *data;          /* data buffer (pre-allocated) */
7995     int                 data_size;      /* size of data buffer */
7996     int                 *get_flags;     /* getmsg() flags */
7997     int                 expected;       /* expected primitive type */
7998 /* x25getmsg */ {
7999     int                 rc = 0;         /* return code */
8000     struct strbuf       *get_ctl=NULL;  /* getmsg control */
8001     struct strbuf       *get_data=NULL; /* getmsg data */
8002     int                 more = 0;       /* flag for more data etc */
8003     int                 file_status = -1; /* file async status */
8004     N_npi_ctl_t         * result;       /* pointer to simplify switch() */
8005     int                 packet_type = -1; /* unknown packet thus far */
8006
8007 #ifdef TRACE
8008     printf( "TRACE: entering x25getmsg\n" );
8009 #endif /* TRACE */
8010
8011     debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
8012     /* prepare the control structures for getmsg */
8013     if (control) {
8014         if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8015           {
8016               perror("kermit x25getmsg(): get_ctl malloc failed\n");
8017               debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
8018               return(-1);
8019           }
8020         /* allow getmsg to return an unexpected packet type (which may be
8021          * larger than the expected one)
8022          */
8023         get_ctl->maxlen = NPI_MAX_CTL;
8024         get_ctl->len = 0;
8025         get_ctl->buf = (char *)control;
8026     } else {
8027         printf(
8028  "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
8029                );
8030         debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
8031         return( -1 );
8032     }
8033     if (data) {
8034         if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8035           {
8036             perror("kermit x25getmsg(): get_data malloc failed\n");
8037             debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
8038             return(-1);
8039         }
8040         get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
8041           NPI_MAX_DATA :
8042             data_size;
8043         get_data->len = 0;
8044         get_data->buf = (char *)data;
8045     }
8046
8047     /* get an X.25 packet -
8048      * it may be any kind of packet, so check for special cases
8049      * it may be split into multiple parts - so loop if necessary
8050      */
8051     do {
8052 #ifdef DEBUG
8053         printf( "kermit: x25getmsg(): getting a message\n" );
8054 #endif /* DEBUG */
8055         errno = 0;
8056         if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
8057 #ifdef DEBUG
8058             printf( "kermit: x25getmsg(): getmsg returned an error\n" );
8059             perror( "getmsg error was" );
8060 #endif /* DEBUG */
8061             debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
8062             if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
8063                 /* was in non-blocking mode, nothing to get, but we're
8064                  * already waiting for the rest of the packet -
8065                  * switch to blocking mode for the next read.
8066                  * file_status used to reset file status before returning
8067                  */
8068                 if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
8069                     || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
8070                   {
8071                       perror("x25getmsg(): couldn't change x25 blocking mode");
8072                       debug(F101,
8073                             "x25getmsg fcntl returned an error\n", "", errno);
8074                       /* netclos(); */
8075                       rc = -1;
8076                       break;
8077                   } else {
8078                       /* loop again into a blocking getmsg() */
8079                       continue;
8080                   }
8081             } else {
8082                 /* no data to get in non-blocking mode - return empty handed */
8083                 perror( "x25getmsg(): getmsg failed" );
8084                 debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
8085                 rc = -1;
8086                 break;
8087             }
8088         } else if (more & MORECTL) {
8089             /* panic - the control information was larger than the
8090              * maximum control buffer size!
8091              */
8092             /* riehm: close connection? */
8093 #ifdef DEBUG
8094             printf("x25getmsg(): received partial control packet - panic\n");
8095 #endif /* DEBUG */
8096             debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
8097             rc = -1;
8098             break;
8099         }
8100
8101         if (result = (N_npi_ctl_t *)control) {
8102             packet_type = result->bind_ack.PRIM_type;
8103             if (packet_type != N_OK_ACK) {
8104                 x25lastmsg = packet_type;
8105             }
8106         }
8107 #ifdef DEBUG
8108         /* printf( "kermit: x25getmsg(): getting " ); */
8109         if (get_ctl->len > 0) {
8110             x25dump_prim(result);
8111         }
8112         debug(F110,
8113               "x25getmsg got packet ",
8114               x25prim( result->bind_ack.PRIM_type ),
8115               0
8116               );
8117 #endif /* DEBUG */
8118
8119         if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
8120             /* not as pretty as a switch(), but switch can't handle
8121              * runtime variable values :-(
8122              */
8123             if (packet_type == expected ) {
8124                 /* got what we wanted, special case for DATA_IND
8125                  * packets though */
8126                 /* riehm: check Q-bit ? */
8127 #ifdef DEBUG
8128                 printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
8129 #endif /* DEBUG */
8130                 if (packet_type == N_DATA_IND ) {
8131                     /* data received. May be incomplete, even though
8132                      * getmsg returned OK
8133                      */
8134                     if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
8135                         more |= MOREDATA;
8136                     if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
8137                         printf( "x25getmsg(): data packet wants ack\n" );
8138                 }
8139             } else if( packet_type == N_DISCON_IND) {
8140                 printf( "X25 diconnected\n" );
8141                 /* riehm: need to acknowledge a disconnection? */
8142                 x25clear();
8143                 /* x25unbind( ttyfd ); */
8144                 rc = -1;
8145             } else if( packet_type == N_ERROR_ACK) {
8146                 errno = result->error_ack.UNIX_error;
8147                 perror( "X25 error received" );
8148                 rc = -1;
8149             } else {
8150                 printf("x25getmsg(): failed %s\n", x25err(packet_type));
8151                 rc = -1;
8152             }
8153         }
8154 #ifdef COMMENT
8155         else {
8156             /* Panic - no control data */
8157             printf( "kermit: x25getmsg(): no control data with packet\n" );
8158             rc = -1;
8159         }
8160 #endif /* COMMENT */
8161
8162         if (get_data && (get_data->len >= 0)) {
8163             get_data->buf += get_data->len;
8164             get_data->maxlen -= get_data->len;
8165         }
8166     } while ((rc == 0)
8167              && (get_data && (get_data->maxlen > 0))
8168              && (more & MOREDATA)
8169              );
8170
8171     /* return the file status to its original value, unless its still
8172      * set to -1, or one of the fcntl's failed */
8173     if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
8174         rc = -1;
8175
8176     /*
8177      * Verify that we received an expected primitive
8178      * there is apparantly an error case where the primitive is set
8179      * correctly, but there is not enough data in the control structure
8180      */
8181     if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
8182         fprintf(stderr,
8183                 "x25getmsg(): %s NOT received. Primitive received was %s\n",
8184                 x25prim( expected ), x25prim( packet_type ));
8185         debug(F110, "x25getmsg got an unexpected packet ",
8186               x25prim(packet_type),
8187               0
8188               );
8189         rc = -1;
8190     }
8191
8192     if (rc == 0) {
8193         if (get_data && ( get_data->len >= 0)) {
8194             rc = get_data->len;
8195         }
8196     }
8197
8198     if (get_ctl)  { free(get_ctl); get_ctl = NULL; }
8199     if (get_data) { free(get_data); get_data = NULL; }
8200
8201 #ifdef COMMENT
8202 #ifdef DEBUG
8203     printf( "kermit x25getmsg(): returning %d\n", rc );
8204 #endif /* DEBUG */
8205 #endif /* COMMENT */
8206     debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
8207
8208 #ifdef TRACE
8209     printf( "TRACE: leaving x25getmsg\n" );
8210 #endif /* TRACE */
8211     return(rc);
8212 }
8213
8214 /*****************************************************************************
8215  * Function: x25putmsg()
8216  *
8217  * Description:
8218  *      send a message to a X25 STREAM
8219  *
8220  * Parameters:
8221  *      fd              - file descriptor to x25 device (opened)
8222  *      control         - control buffer (pre-allocated)
8223  *      data            - data buffer (pre-allocated)
8224  *      data_len        - length of data to be transmitted
8225  *      put_flags       - flags for putmsg()
8226  *
8227  * Return Value:
8228  *      >= 0    number of bytes transmitted
8229  *      -1      error
8230  */
8231 int
8232 x25putmsg(fd, control, data, data_len, put_flags)
8233     int                 fd;             /* X25 device (opened) */
8234     N_npi_ctl_t         *control;       /* control buffer (pre-allocated) */
8235     N_npi_data_t        *data;          /* data buffer (pre-allocated) */
8236     int                 data_len;       /* length of data (not the size of
8237                                            the buffer) */
8238     int                 *put_flags;     /* putmsg() flags */
8239 /* x25putmsg */ {
8240     int                 rc = 0;         /* return code */
8241     ulong               type;           /* primitive type */
8242     struct strbuf       *put_ctl = NULL; /* putmsg control */
8243     struct strbuf       *put_data = NULL; /* putmsg data */
8244
8245 #ifdef TRACE
8246     printf( "TRACE: entering x25putmsg\n" );
8247 #endif /* TRACE */
8248
8249 #ifdef DEBUG
8250     printf( "kermit: x25putmsg(): putting " );
8251     x25dump_prim( control );
8252     printf( "\tdata:\t\t" );
8253     x25dump_data( data, 0, data_len );
8254     debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
8255 #endif /* DEBUG */
8256
8257     if (control) {
8258         put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8259         if (put_ctl == NULL) {
8260             perror("kermit x25putmsg(): put_ctl malloc failed\n");
8261             return(-1);
8262         }
8263         put_ctl->maxlen = 0;                    /* unused by putmsg */
8264         put_ctl->len = NPI_MAX_CTL;
8265         put_ctl->buf = (char *)control;
8266     }
8267     if (data && ( data_len > 0)) {
8268         put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8269         if( put_data == NULL) {
8270             perror("kermit x25putmsg(): put_data malloc failed\n");
8271             return(-1);
8272         }
8273         put_data->maxlen = 0;                   /* unused by putmsg */
8274         put_data->len = data_len;
8275         put_data->buf = (char *)data;
8276     }
8277
8278     errno = 0;
8279     rc = putmsg (fd, put_ctl, put_data, 0);
8280     if (rc < 0) {
8281         printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
8282         perror("kermit: x25putmsg(): putmsg failed");
8283         return(-1);
8284     }
8285
8286     /* riehm: this should perhaps be discounted! */
8287     x25lastmsg = control->PRIM_type;
8288
8289 #ifdef COMMENT
8290 #ifdef DEBUG
8291     printf( "kermit debug: x25putmsg() returning %d\n", data_len );
8292 #endif /* DEBUG */
8293 #endif /* COMMENT */
8294     debug( F101, "x25putmsg block size put ", "", data_len);
8295
8296 #ifdef TRACE
8297     printf( "TRACE: leaving x25putmsg\n" );
8298 #endif /* TRACE */
8299
8300     return( data_len );
8301 }
8302
8303 /*****************************************************************************
8304 * Function: x25bind
8305 * Description:  The bind submitted to NPI provides the information required
8306 *               by the packet layer for it to listen for suitable incoming
8307 *               calls.
8308 *
8309 * WARNING:
8310 *
8311 * This routine needs to be called in a completely different manner for
8312 * the client and server side. When starting a client, the
8313 * num_waiting_calls and CUD information should all be set to 0! The
8314 * client's CUD must be inserted in the CONN_REQ data block.
8315 * When starting a server, the CUD must be set to a CUD pattern, and
8316 * the number of waiting calls should be set to a number other than 0.
8317 * (num waiting calls is the number of incomming calls which are to be
8318 * put on hold while the server is servicing another client.)
8319 *
8320 * Who invented this crap?
8321 *
8322 * Parameters:
8323 *       fd              - X25 device (opened)
8324 *       addr            - local address
8325 *       cud             - User Data (null terminated)
8326 *       cud_len         - User Data length
8327 *       num_waiting_calls - number of outstanding calls allowed on this stream
8328 *       line            - logical port number (1)
8329 *       flags           - 0, DEFAULT_LISTENER or TOKEN_REQUEST
8330 *
8331 * Return Value:
8332 *       if binding is successful, 0 is returned for a client, and a token is
8333 *       returned for a server
8334 *
8335 * Return code: 0 if successful
8336 *              -1 if unsuccessful
8337 *****************************************************************************/
8338
8339 ulong
8340 x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
8341     int fd;                             /* X25 device (opened) */
8342     char * addr;                        /* local address */
8343     char * cud;                         /* Call User Data (null terminated) */
8344     int cud_len;                        /* User Data length */
8345     int num_waiting_calls;              /* Outstanding calls allowed */
8346     int line;                           /* logical port number */
8347     ulong bind_flags;           /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
8348 /* x25bind */ {
8349     ulong rc;                           /* return code */
8350     int get_flags;                      /* priority flag passed to getmsg */
8351     int put_flags = 0;                  /* output flags for putmsg, always 0 */
8352     ulong type;                         /* primitive type */
8353     N_bind_req_t *bind_req;             /* pointer to N_BIND_REQ primitive */
8354     N_bind_ack_t *bind_ack;             /* pointer to N_BIND_ACK primitive */
8355     char *addtl_info;                   /* pointer to info in addition to
8356                                          * the N_BIND_REQ primitive that is
8357                                          * passed in the control structure
8358                                          * to putmsg */
8359     int addr_len = 0;                   /* length of address string */
8360     ulong bind_req_t_size;              /* for debugging only */
8361
8362 #ifdef TRACE
8363     printf("TRACE: entering x25bind\n" );
8364 #endif /* TRACE */
8365
8366 #ifdef DEBUG
8367     printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
8368            fd, addr, cud, line, bind_flags
8369            );
8370 #endif /* DEBUG */
8371
8372     /*
8373      * Allocate  and zero out space to hold the control portion of the
8374      * message passed to putmsg. This will contain the N_BIND_REQ
8375      * primitive and any additional info required for that.
8376      *
8377      * Note: allocated space is the size of the union typedef
8378      * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
8379      */
8380     bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
8381     if (bind_req == NULL) {
8382         perror("kermit: x25bind(): bind_req malloc failed");
8383         debug(F100, "x25bind bind_req malloc failed", "", 0);
8384         return(-1);
8385     }
8386     bzero((char *)bind_req, sizeof(N_npi_ctl_t));
8387
8388     /* Build the Bind Request Primitive */
8389     bind_req->PRIM_type = (ulong) N_BIND_REQ;
8390
8391     /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
8392      * the actual address in an N_BIND_REQ. The first byte contains the
8393      * line number being used with this address, and the second byte is the
8394      * X.121 address prefix, which must be zero.
8395      */
8396     addr_len = strlen(addr);
8397     bind_req->ADDR_length = (ulong) (addr_len + 2);
8398     bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
8399     bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
8400     bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
8401     bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
8402     if (cud_len == 0) {
8403         bind_req->PROTOID_offset = (ulong) 0;
8404     } else {
8405         /* need to remember the trailing NULL in the address - not
8406          * counted in the address length
8407          */
8408         bind_req->PROTOID_offset
8409           = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
8410     }
8411
8412     /*
8413      * Now fill in the additional information required with this primitive
8414      * (address and protocol information (Call User Data))
8415      */
8416     addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
8417     /*
8418      * The bitwise "&" ensures that the line number is only one byte long
8419      */
8420     *addtl_info++ = (char) line & 0xff;
8421     *addtl_info++ = (char) 0; /* X.121 format */
8422     bcopy( addr, addtl_info, addr_len ); /* include trailing null */
8423     addtl_info += addr_len;
8424     if (cud_len > 0)
8425       bcopy( cud, addtl_info, cud_len );
8426     /*
8427      * Call putmsg() to put the bind request message on the stream
8428      */
8429     if (x25putmsg(fd,
8430                   (N_npi_ctl_t*)bind_req,
8431                   (N_npi_data_t *)NULL,
8432                   0,
8433                   &put_flags
8434                   ) < 0) {
8435         printf( "kermit: x25bind(): x25putmsg failed\n" );
8436         return(-1);
8437     }
8438
8439     /*
8440      * Allocate and zero out space for the N_BIND_ACK primitive
8441      */
8442     bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
8443     if (bind_ack == NULL){
8444         perror("kermit: x25bind(): bind_ack malloc failed");
8445         return(-1);
8446     }
8447     bzero(bind_ack, sizeof(N_npi_ctl_t));
8448     /*
8449      * Initialize the control structure and flag variable sent to getmsg
8450      */
8451     get_flags=0;
8452
8453     /* get the ACK for the bind */
8454 #ifdef DEBUG
8455     printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
8456 #endif /* DEBUG */
8457     rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
8458             (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
8459             N_BIND_ACK );
8460
8461     /* turn quantitive return code into a qualitative one */
8462     if (rc > 0) rc = 0;
8463
8464     /* if all went well, get the token from the acknowledgement packet */
8465     if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
8466         rc = bind_ack->TOKEN_value;
8467     }
8468
8469     /* free up the memory we allocated earlier */
8470     free(bind_req);
8471     free(bind_ack);
8472
8473 #ifdef TRACE
8474     printf( "TRACE: leaving x25bind\n" );
8475 #endif /* TRACE */
8476
8477     return( rc );
8478 }
8479
8480 /*****************************************************************************
8481 * Function: x25call
8482 * Description:  This routine builds and sends an N_CONN_REQ primitive, then
8483 *               checks for an N_CONN_CON primitive in return.
8484 *
8485 * Parameters:
8486 * fd    - file descriptor of stream
8487 * caddr - called address (remote address)
8488 *
8489 * Functions Referenced:
8490 * malloc()
8491 * bzero()
8492 * getmsg()
8493 * putmsg()
8494 *
8495 * Return code:
8496 * 0 - if successful
8497 * -1 if not successful
8498 *****************************************************************************/
8499 int
8500 x25call(fd, remote_nua, cud)
8501     int fd;                             /* X25 device (opened) */
8502     char * remote_nua;                  /* remote address to call */
8503     char * cud;                         /* call user data */
8504 /* x25call */ {
8505     int rc;                             /* return code */
8506     int flags;                          /* Connection flags */
8507     int get_flags;                      /* priority flags for getmsg */
8508     ulong type;                         /* primitive type */
8509     N_conn_req_t *connreq_ctl;          /* pointer to N_CONN_REQ primitive */
8510     N_npi_data_t *connreq_data;         /* pointer to N_CONN_REQ data (CUD) */
8511     int connreq_data_len;               /* length of filled data buffer */
8512     N_conn_con_t *conncon_ctl;          /* pointer to N_CONN_CON primitive */
8513     N_npi_data_t *conncon_data;         /* pointer to any data associated with
8514                                          * the N_CONN_CON primitive */
8515     char *addtl_info;                   /* pointer to additional info needed
8516                                          * for N_CONN_REQ primitive */
8517     int addr_len;                       /* length of address */
8518
8519 #ifdef TRACE
8520     printf( "TRACE: entering x25call\n" );
8521 #endif /* TRACE */
8522
8523 #ifdef DEBUG
8524     printf( "x25call( %d, %s )\n", fd, remote_nua );
8525     printf( "connecting to %s on fd %d\n", remote_nua, fd );
8526 #endif /* DEBUG */
8527
8528     /*
8529      * Allocate and zero out space for the N_CONN_REQ primitive
8530      * use the size of the generic NPI primitive control buffer
8531      */
8532     connreq_ctl  = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
8533     if (connreq_ctl == NULL){
8534         perror("kermit: x25call(): connreq_ctl malloc failed");
8535         return(-1);
8536     }
8537     bzero(connreq_ctl,sizeof(N_npi_ctl_t));
8538     /*
8539      * Build the Connection Request Primitive
8540      */
8541     flags = 0;
8542     connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
8543
8544     /* Note that the address length is nchai+1 and not n+2. The line number
8545      * is only passed with the address for the bind. The first byte of
8546      * the address for the N_CONN primitives contains the X.121
8547      * address prefix, which must be zero. The remaining bytes are the
8548      * address itself.
8549      */
8550     addr_len = strlen( remote_nua );
8551     connreq_ctl->DEST_length = (ulong) (addr_len + 1);
8552     connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
8553     /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
8554     connreq_ctl->CONN_flags = (ulong) 0;
8555     connreq_ctl->QOS_length = (ulong) 0;        /* unsupported in AIX 4.1 */
8556     connreq_ctl->QOS_offset = (ulong) 0;        /* unsupported in AIX 4.1 */
8557
8558     addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
8559     *addtl_info++ = (char) 0; /* X.121 format */
8560     bcopy( remote_nua, addtl_info, addr_len );
8561
8562     /*
8563      * setup the data buffer for the connection request
8564      */
8565     connreq_data  = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
8566     if (connreq_data == NULL){
8567         perror("kermit: x25call(): connreq_data malloc failed");
8568         return(-1);
8569     }
8570     bzero(connreq_data,sizeof(N_npi_data_t));
8571
8572     /* facility selection needs to be put in the front of connreq_data */
8573     connreq_data_len = 0;
8574     connreq_data_len += x25facilities( (char *)connreq_data );
8575     if (cud && *cud) {
8576         bcopy(cud,
8577               (char *)((char *)connreq_data + connreq_data_len),
8578               strlen(cud)
8579               );
8580         connreq_data_len += strlen( cud );
8581         }
8582
8583     /*
8584      * Call putmsg() to put the connection request message on the stream
8585      */
8586     rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
8587             connreq_data_len, &flags );
8588     if (rc < 0) {
8589         return(-1);
8590     }
8591
8592     /*
8593      * Allocate and zero out space for the N_CONN_CON primitive
8594      */
8595     if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8596         perror("kermit: x25call(): conncon_ctl malloc failed");
8597         return(-1);
8598     }
8599     bzero(conncon_ctl, sizeof(N_npi_ctl_t));
8600
8601     /*
8602      * Allocate and zero out space for any data associated with N_CONN_CON
8603      */
8604     if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
8605         perror("kermit: x25call(): conncon_data malloc failed");
8606         return(-1);
8607     }
8608     bzero(conncon_data, NPI_MAX_DATA);
8609
8610     /* Initialize and build the structures for getmsg */
8611     get_flags=0;
8612
8613     rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
8614             conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
8615
8616     /* turn quantitive return code into a qualitative one */
8617     if (rc > 0) rc = 0;
8618
8619     /* Free the space that we no longer need */
8620     if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
8621     if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
8622     if (conncon_data) { free(conncon_data); conncon_data = NULL; }
8623
8624 #ifdef TRACE
8625     printf( "TRACE: leaving x25call\n" );
8626 #endif /* TRACE */
8627
8628     return(rc);
8629 }
8630
8631 /*****************************************************************************
8632  * Function: x25getcall
8633  *
8634  * Description: This routine checks for an incomming call, verified
8635  * that it is a CONNIND (connection indication) message, and then
8636  * accepts the call and returns the file descriptor of the new stream
8637  *
8638  * Parameters:
8639  * fd   - file descriptor of listening stream
8640  *
8641  * Return Codes:
8642  * callfd       - file descriptor of connected incomming call.
8643  *              - set to -1 if an error occured
8644  *
8645  *****************************************************************************/
8646 int
8647 x25getcall(fd) int fd; {
8648     int x25callfd;                      /* fd of incomming call */
8649     N_conn_ind_t *connind_ctl;          /* connind controll buffer */
8650     N_npi_data_t *connind_data;         /* connind data buffer */
8651     int get_flags;                      /* flags for getmsg */
8652     ulong flags;                        /* connection flags */
8653     int rc;                             /* return code */
8654
8655     extern x25addr_t remote_nua;        /* remote X.25 addr global var */
8656
8657 #ifdef TRACE
8658     printf( "TRACE: entering x25getcall\n" );
8659 #endif /* TRACE */
8660
8661     /* allocate space for connection indication buffers */
8662     if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
8663         perror("kermit: x25getcall(): connind_ctl malloc failed");
8664         return (-1);
8665     }
8666     bzero(connind_ctl, sizeof(N_npi_ctl_t));
8667
8668     if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
8669         perror("kermit: x25getcall(): connind_data malloc failed");
8670         return (-1);
8671     }
8672     bzero(connind_data, NPI_MAX_DATA);
8673
8674     /* initialise control structures */
8675     get_flags = 0;
8676
8677     /* call getmsg to check for a connection indication */
8678     if (x25getmsg(fd,
8679                   (N_npi_ctl_t*)connind_ctl,
8680                   (int)sizeof(N_conn_ind_t),
8681                   connind_data,
8682                   NPI_MAX_DATA,
8683                   &get_flags,
8684                   N_CONN_IND
8685                   ) < 0) {
8686 #ifdef DEBUG
8687         printf( "x25getcall(): errno is: %d\n", errno );
8688 #endif /* DEBUG */
8689         perror ("x25getcall(): getmsg failed");
8690         return(-1);
8691     }
8692
8693     /* a connection indication was received
8694      * - pull it to bits and answer the call
8695      */
8696     x25seqno = connind_ctl->SEQ_number;
8697     flags = connind_ctl->CONN_flags;
8698 #ifdef DEBUG
8699     printf( "setting remote_nua to a new value due to incomming call\n" );
8700 #endif /* DEBUG */
8701     /*
8702      * no guarantee that the address is null terminated, ensure that
8703      * after copying that it is (assumption: remote_nua is longer than
8704      * the address + 1)
8705      */
8706     bzero(remote_nua, sizeof(remote_nua));
8707     /* note: connind_ctl contains a x121 address, which has a null as
8708      * the FIRST character - strip it off!
8709      */
8710     ckstrncpy(remote_nua,
8711             (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
8712             connind_ctl->SRC_length - 1
8713             );
8714 #ifdef DEBUG
8715     printf( "remote_nua set to new value of %s\n", remote_nua );
8716 #endif /* DEBUG */
8717
8718     /* errors handled by callee */
8719     x25callfd = x25accept(x25seqno, flags);
8720
8721     /* free the malloc'd buffers */
8722     if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
8723     if (connind_data) { free(connind_data); connind_data = NULL; }
8724
8725 #ifdef TRACE
8726     printf( "TRACE: leaving x25getcall\n" );
8727 #endif /* TRACE */
8728
8729     /* return the file descriptor (or error if < 0) */
8730     return( x25callfd );
8731 }
8732
8733 /*****************************************************************************
8734  * Function: x25accept
8735  *
8736  * Description: accept an incomming call
8737  *              This essentially means opening a new STREAM and sending
8738  *              an acknowledge back to the caller.
8739  *
8740  * Parameters:
8741  *      seqno   - sequence number for acknowledgement
8742  *      flags   - flags passed to us by the caller
8743  *
8744  * Return Codes:
8745  *      fd      - file descriptor of new STREAM
8746  *                set to -1 if an error occured
8747  *
8748  *****************************************************************************/
8749 int
8750 x25accept(seqno,flags)
8751     ulong seqno;                        /* connection sequence number */
8752     ulong flags;                        /* connection flags */
8753 /* x25accept */ {
8754     int x25callfd;                      /* fd for incomming call */
8755     int get_flags;                      /* priority flags for getmsg */
8756     int put_flags = 0;                  /* flags for putmsg, always 0 */
8757     int addr_len;                       /* length of local address */
8758     ulong token;                        /* connection token */
8759     N_conn_res_t *conn_res;             /* N_CONN_RES primitive */
8760     N_ok_ack_t *ok_ack;                 /* N_OK_ACK primitive */
8761     char *addtl_info;                   /* temp pointer */
8762     int rc;                             /* temporary return code */
8763
8764 /* global variables from ckcmai.c */
8765     extern int revcall, closgr, cudata;
8766     extern char udata[];
8767     extern x25addr_t local_nua;         /* local X.25 address */
8768     extern char x25name[];              /* x25 device name (sx25a0) */
8769     extern char x25dev[];               /* x25 device file /dev/x25pkt */
8770     extern int x25port;                 /* logical port to use */
8771     ulong bind_flags = 0;               /* flags for binding the X25 stream */
8772
8773 #ifdef TRACE
8774     printf( "TRACE: entering x25accept\n" );
8775 #endif /* TRACE */
8776
8777     /* open a new packet level stream */
8778     if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
8779         perror ("kermit: x25accept(): X.25 device open error");
8780         debug(F101,"x25accept() device open error","",errno);
8781         return(-1);
8782     }
8783
8784     /* push the NPI onto the STREAM */
8785     if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
8786         perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
8787         debug(F101,"x25accept can't push npi on the X25 stream","",errno);
8788         return (-1);
8789     }
8790
8791     /* bind kermit server to the local X25 address */
8792     /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
8793     bind_flags |= TOKEN_REQUEST;
8794     token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
8795     if (token < 0) {
8796         printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
8797         netclos();
8798         return(-1);
8799     }
8800
8801     /* allocate connection response primitive */
8802     if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
8803         perror("kermit: x25accept(): conn_res malloc failed");
8804         return (-1);
8805     }
8806     bzero((char *)conn_res, NPI_MAX_CTL);
8807
8808     /* setup connection response primitive */
8809     addr_len = strlen( local_nua );
8810     conn_res->PRIM_type = (ulong)N_CONN_RES;
8811     conn_res->TOKEN_value = token;
8812     /* note address length is n+1 to accomodate the X.121 address prefix */
8813     conn_res->RES_length = (ulong)(addr_len + 1);
8814     conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
8815     conn_res->SEQ_number = seqno;
8816     conn_res->CONN_flags = 0;
8817     conn_res->QOS_length = 0;           /* unsupported - must be 0 (!?) */
8818     conn_res->QOS_offset = 0;
8819
8820     addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
8821     *addtl_info++ = (char)0;    /* X.121 address prefix */
8822     bcopy( local_nua, addtl_info, addr_len );
8823
8824     /*
8825      * send off the connect response
8826      */
8827     if (x25putmsg(x25callfd,
8828                   (N_npi_ctl_t*)conn_res,
8829                   (N_npi_data_t *)NULL,
8830                   0,
8831                   &put_flags
8832                   ) < 0 ) {
8833         perror("kermit: x25accept(): putmsg connect response failed");
8834         return(-1);
8835     }
8836
8837     /*
8838      * Allocate and zero out space for the OK_ACK primitive
8839      */
8840     if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8841         perror("kermit: x25call(): ok_ack malloc failed");
8842         return(-1);
8843     }
8844     bzero(ok_ack, sizeof(N_npi_ctl_t));
8845
8846     /* Initialize and build the structures for getmsg */
8847     get_flags=0;
8848
8849     rc = (int)x25getmsg(x25callfd,
8850                         (N_npi_ctl_t*)ok_ack,
8851                         (int)sizeof(N_ok_ack_t),
8852                         (N_npi_data_t*)NULL,
8853                         0,
8854                         &get_flags,
8855                         N_OK_ACK
8856                         );
8857     if (rc == 0) {
8858         /* sequence number is only for disconnecting when not connected !? */
8859         x25seqno = 0;
8860     }
8861
8862     /* free up malloc'ed buffer space */
8863     if (conn_res) { free(conn_res); conn_res = NULL; }
8864     if (ok_ack) { free(ok_ack); ok_ack = NULL; }
8865
8866 #ifdef TRACE
8867     printf( "TRACE: leaving x25accept\n" );
8868 #endif /* TRACE */
8869
8870     return( ( rc >= 0 ) ? x25callfd : -1 );
8871 }
8872
8873 /*****************************************************************************
8874  * Function: x25unbind
8875  *
8876  * Description:  This subroutine builds and sends an unbind request and gets
8877  * the acknowledgement for it.
8878  *
8879  * Parameters:
8880  * fd - File descriptor of the stream
8881  *
8882  * Functions Referenced:
8883  * getmsg()
8884  * putmsg()
8885  * malloc()
8886  * bzero()
8887  *
8888  * Return code:
8889  * 0 - if successful
8890  * -1 - if not successful
8891  *****************************************************************************/
8892 int
8893 x25unbind(fd) int fd; {                 /* X25 device (opened) */
8894     int rc;                             /* return code */
8895     int flags;                          /* bind flags */
8896     int get_flags;                      /* priority flag for getmsg */
8897     ulong type;                         /* primitive type */
8898     N_unbind_req_t *unbind_req;         /* pointer to N_UNBIND_REQ */
8899     N_ok_ack_t *ok_ack;                 /* pointer to N_OK_ACK */
8900
8901 #ifdef TRACE
8902     printf( "TRACE: entering x25unbind\n" );
8903 #endif /* TRACE */
8904
8905 #ifdef DEBUG
8906     /* printf( "x25unbind( %d )\n", fd ); */
8907 #endif /* DEBUG */
8908     debug(F101,"x25unbind closing x25 connection #","",fd);
8909
8910     /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
8911     unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
8912     if (unbind_req == NULL) {
8913         perror("kermit: x25unbind(): unbind_req malloc failed");
8914         return(-1);
8915     }
8916     bzero(unbind_req, sizeof(N_npi_ctl_t));
8917
8918     /*
8919      * Build the Unbind Request Primitive
8920      */
8921     flags = 0;
8922     unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
8923
8924     /*
8925      * Call putmsg() to put the bind request message on the stream
8926      */
8927     if (x25putmsg(fd,
8928                   (N_npi_ctl_t*)unbind_req,
8929                   (N_npi_data_t *)NULL,
8930                   0,
8931                   &flags
8932                   ) < 0) {
8933         perror ("kermit: x25unbind(): putmsg failed");
8934         return(-1);
8935     }
8936
8937     /* Allocate and Zero out space for the N_OK_ACK primitive */
8938     ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
8939     if (ok_ack == NULL) {
8940         perror("kermit x25unbind(): ok_ack malloc failed\n");
8941         return(-1);
8942     }
8943     bzero(ok_ack, sizeof(N_npi_ctl_t));
8944
8945     /* Initialize and build the control structure for getmsg */
8946     get_flags=0;
8947
8948     /* Call getmsg() to check for an acknowledgement */
8949     rc = x25getmsg(fd,
8950                    (N_npi_ctl_t*)ok_ack,
8951                    (int)sizeof(N_ok_ack_t),
8952                    (N_npi_data_t*)NULL,
8953                    0,
8954                    &get_flags,
8955                    N_OK_ACK
8956                    );
8957     if (rc < 0) {
8958         perror ("kermit: x25unbind: getmsg failed");
8959         return(-1);
8960     }
8961
8962     /* Free up the space that we no longer need */
8963     if (unbind_req) { free(unbind_req); unbind_req = NULL; }
8964     if (ok_ack) { free(ok_ack); ok_ack = NULL; }
8965
8966 #ifdef TRACE
8967     printf( "TRACE: leaving x25unbind\n" );
8968 #endif /* TRACE */
8969
8970     return(0);
8971 }
8972
8973 /*****************************************************************************
8974  * Function: x25xin
8975  *
8976  * Description:
8977  *      Read n characters from X.25 circuit into buf (AIX only)
8978  *
8979  * Parameters:
8980  *      data_buf_len    maximum size of data buffer
8981  *      data_buf        pointer to pre-allocated buffer space
8982  *
8983  * Return Value:
8984  *      the number of characters actually read
8985  */
8986 int
8987 x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
8988     struct strbuf getmsg_ctl;           /* streams control structure */
8989     struct strbuf getmsg_data;          /* streams data structure */
8990     int rc = 0;                         /* return code */
8991     int getmsg_flags;                   /* packet priority flags */
8992     char * ctl_buf;                     /* npi control buffer */
8993     N_npi_ctl_t * result;               /* pointer to simplify switch() */
8994
8995 #ifdef TRACE
8996     printf( "TRACE: entering x25xin\n" );
8997 #endif /* TRACE */
8998
8999     /* ensure that no maximum's are overridden */
9000     data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
9001
9002     /* allocate space for packet control info */
9003     if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
9004         perror( "kermit: x25xin(): ctl_buf malloc" );
9005         return(-1);
9006     }
9007 #ifdef COMMENT
9008     /* riehm: need zeroed buffer for getmsg? */
9009     bzero( ctl_buf, NPI_MAX_CTL );
9010     /* clear data buffer */
9011     bzero( data_buf, data_buf_len );
9012 #endif /* COMMENT */
9013
9014     getmsg_flags = 0;                   /* get the first packet available */
9015
9016     rc = x25getmsg(ttyfd,
9017                    ctl_buf,
9018                    NPI_MAX_CTL,
9019                    data_buf,
9020                    data_buf_len,
9021                    &getmsg_flags,
9022                    N_DATA_IND
9023                    );
9024 #ifdef COMMENT
9025 #ifdef DEBUG
9026     if (rc >= 0) {
9027         printf( "kermit: x25xin(): got " );
9028         x25dump_data( data_buf, 0, rc );
9029     } else {
9030         printf( "x25xin(): attempt to get data resulted in an error\n" );
9031     }
9032 #endif /* DEBUG */
9033 #endif /* COMMENT */
9034
9035     /* free buffers */
9036     if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
9037
9038 #ifdef TRACE
9039     printf( "TRACE: leaving x25xi\n" );
9040 #endif /* TRACE */
9041
9042     return(rc);
9043 }
9044
9045 /*****************************************************************************
9046  * Function: x25write
9047  *
9048  * Description:
9049  *      write a block of characters to the X25 STREAM (AIX)
9050  *
9051  * Parameters:
9052  *      fd              file descriptor to write to
9053  *      databuf         buffer containing data to write
9054  *      databufsize             size of the buffer to write
9055  *
9056  * Return Value:
9057  *      size            the number of bytes actually transmitted
9058  */
9059 int
9060 x25write(fd, databuf, databufsize)
9061     int         fd;                  /* X25 STREAMS file descriptor (ttyfd) */
9062     char        *databuf;               /* buffer to write */
9063     int         databufsize;            /* buffer size */
9064 /* x25write */ {
9065     N_data_req_t *data_req_ctl;
9066     int rc;                             /* return code (size transmitted) */
9067     int write_flags = 0;                /* always 0 !? */
9068
9069 #ifdef TRACE
9070     printf( "TRACE: entering x25write\n" );
9071 #endif /* TRACE */
9072
9073     if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
9074         perror( "kermit: x25write(): data_req_ctl malloc" );
9075         return(-1);
9076     }
9077     data_req_ctl->PRIM_type = N_DATA_REQ;
9078     data_req_ctl->DATA_xfer_flags = 0;
9079
9080     /* riehm: possible extension
9081      * possibly need to think about splitting up the data buffer
9082      * into multiple parts if databufsize > NPI_MAX_DATA
9083      */
9084
9085 #ifdef COMMENT
9086 #ifdef DEBUG
9087     printf( "kermit: x25write(): writing data to x25 stream\n" );
9088     printf( "\tdata:\t" );
9089     x25dump_data(databuf, 0, databufsize);
9090 #endif /* DEBUG */
9091 #endif /* COMMENT */
9092     rc = x25putmsg(fd,
9093                    (N_npi_ctl_t*)data_req_ctl,
9094                    (N_npi_data_t*)databuf,
9095                    databufsize,
9096                    &write_flags
9097                    );
9098     if (data_req) { free(data_req_ctl);  data_req = NULL; }
9099
9100 #ifdef TRACE
9101     printf( "TRACE: leaving x25write\n" );
9102 #endif /* TRACE */
9103
9104     return(rc);
9105 }
9106
9107 /*****************************************************************************
9108  * Function: x25local_nua
9109  *
9110  * Description:
9111  *      This routine is only interesting for IBM computers. In order
9112  *      to set up a connection (see x25bind()) you need to know the
9113  *      local NUA (x25 address). Unfortunately, you need all this code
9114  *      to find that out, I just hope this works for everyone else!
9115  *
9116  * Parameters:
9117  *      a pre-allocated character buffer, long enough to hold an X.25 address
9118  *      and the tailing null.
9119  *
9120  * Return Value:
9121  *      the length of the address string.
9122  *      0 = error
9123  */
9124 int
9125 x25local_nua(char *buf) {
9126     struct CuAt *response;      /* structure to fill with info from ODM */
9127     CLASS_SYMBOL retClass;      /* ODM class */
9128     char query[64];             /* odm database query */
9129     int rc = 0;                 /* return value (length of local NUA) */
9130     extern char x25name[];      /* x25 device name (sx25a0) */
9131
9132 #ifdef TRACE
9133     printf( "TRACE: entering x25local_nua\n" );
9134 #endif /* TRACE */
9135
9136     /* set up query string */
9137     if (x25name[0] == '\0') {
9138 #ifdef DEBUG
9139         printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
9140 #endif /* DEBUG */
9141         strcpy( x25name, "sx25a0" );
9142     }
9143     ckmakmsg(query, sizeof(query), "name like ",x25name,
9144              " and attribute like local_nua");
9145
9146     /* initialise ODM database */
9147     odmerrno = 0;
9148     if (odm_initialize() == -1) {
9149         printf( "x25local_nua(): can't initialize ODM database");
9150         switch (odmerrno) {
9151           case ODMI_INVALID_PATH:
9152             printf( "invalid path\n" );
9153             break;
9154           case ODMI_MALLOC_ERR:
9155             printf( "malloc failed\n" );
9156             break;
9157           default:
9158             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9159         }
9160         return(rc);
9161     }
9162
9163     /* open the CuAt class */
9164     retClass = odm_open_class(CuAt_CLASS);
9165     if (((int)retClass) == -1) {
9166         printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
9167         switch (odmerrno) {
9168           case ODMI_CLASS_DNE:
9169             printf( "CuAt class doesn't exist\n" );
9170             break;
9171           case ODMI_CLASS_PERMS:
9172             printf( "permission to CuAt class file denied\n" );
9173             break;
9174           case ODMI_MAGICNO_ERR:
9175             printf( "CuAt is an invalid ODM object class\n" );
9176             break;
9177           case ODMI_OPEN_ERR:
9178             printf( "cannot open CuAt class - and don't know why!\n" );
9179             break;
9180           case ODMI_INVALID_PATH:
9181             printf( "invalid path\n" );
9182             break;
9183           case ODMI_TOOMANYCLASSES:
9184             printf( "too many object classes have been opened\n" );
9185             break;
9186           default:
9187             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9188         }
9189         return(rc);
9190     }
9191
9192 #ifdef DEBUG
9193     printf("retClass= %d\n", retClass);
9194 #endif /* DEBUG */
9195
9196     response = (struct CuAt *)odm_get_first( retClass, query, NULL );
9197     if (((int)response) == -1) {
9198         printf( "kermit: x25local_nua(): odm query failed " );
9199         switch (odmerrno) {
9200           case ODMI_BAD_CRIT:           /* Programming error */
9201             printf( "bad search criteria\n" );
9202             break;
9203           case ODMI_CLASS_DNE:
9204             printf( "CuAt class doesn't exist\n" );
9205             break;
9206           case ODMI_CLASS_PERMS:
9207             printf( "permission to CuAt class file denied\n" );
9208             break;
9209           case ODMI_INTERNAL_ERR:
9210             printf("odm internal error\nPlease contact your administrator\n" );
9211             break;
9212           case ODMI_INVALID_CLXN:
9213             printf("CuAt is invalid or inconsistent odm class collection\n");
9214             break;
9215           case ODMI_INVALID_PATH:
9216             printf( "invalid path\n" );
9217             break;
9218           case ODMI_MAGICNO_ERR:
9219             printf( "CuAt is an invalid ODM object class\n" );
9220             break;
9221           case ODMI_MALLOC_ERR:
9222             printf( "malloc failed\n" );
9223             break;
9224           case ODMI_OPEN_ERR:
9225             printf( "cannot open CuAt class - and don't know why!\n" );
9226             break;
9227           case ODMI_TOOMANYCLASSES:
9228             printf( "too many object classes have been opened\n" );
9229             break;
9230           default:
9231             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9232         }
9233         return(rc);
9234     }
9235
9236     /* check for a meaningfull response */
9237     if (response != NULL) {
9238         if (response->value != NULL) {
9239             strcpy(buf, response->value);
9240             rc = strlen( buf );
9241 #ifdef DEBUG
9242 /*
9243             printf( "attribute name is: %s\n", (char *)response->attribute );
9244             printf( "I think my address is %s\n", (char*)response->value );
9245 */
9246 #endif /* DEBUG */
9247         } else {
9248             printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
9249         }
9250     } else {
9251         switch (odmerrno) {
9252           case ODMI_BAD_CRIT:
9253             printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
9254             break;
9255           case ODMI_CLASS_DNE:
9256             printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
9257             break;
9258           case ODMI_CLASS_PERMS:
9259             printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
9260             break;
9261           case ODMI_INTERNAL_ERR:
9262             printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
9263             break;
9264           case ODMI_INVALID_CLXN:
9265             printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
9266             break;
9267           case ODMI_INVALID_PATH:
9268             printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
9269             break;
9270           case ODMI_MAGICNO_ERR:
9271             printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
9272             break;
9273           case ODMI_MALLOC_ERR:
9274             printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
9275             break;
9276           case ODMI_OPEN_ERR:
9277             printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
9278             break;
9279           case ODMI_TOOMANYCLASSES:
9280             printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
9281             break;
9282           default:
9283             printf( "Unknown error!\n" );
9284         }
9285         return(rc);
9286     }
9287
9288     /* close the database again */
9289     odm_close_class( retClass );
9290
9291     /* forget about ODM all together */
9292     odm_terminate();
9293
9294 #ifdef TRACE
9295     printf( "TRACE: leaving x25local_nua\n" );
9296 #endif /* TRACE */
9297
9298     debug(F110, "x25local_nua local address is ", buf, 0);
9299     return(rc);
9300 }
9301
9302 /*****************************************************************************
9303  * Function: x25facilities
9304  *
9305  * Description:
9306  *      build up the facilities data packet for a connection request
9307  *
9308  * Parameters:
9309  *      a pre-allocated char buffer, normally NPI_MAX_DATA big.
9310  *
9311  * Return Value:
9312  *      the number of characters inserted into the buffer
9313  */
9314 int
9315 x25facilities(buffer) char *buffer; {
9316     extern int revcall;
9317     extern int closgr;
9318     char *p;                            /* temp pointer */
9319     char *start;                        /* temp pointer */
9320
9321 #ifdef TRACE
9322     printf( "TRACE: entering x25facilities\n" );
9323 #endif /* TRACE */
9324
9325     p = buffer + 1;
9326     start = p;
9327
9328 #ifdef DEBUG
9329     printf( "kermit: x25facilities(): getting X25 facilities\n" );
9330 #endif /* DEBUG */
9331
9332     if (revcall != 0) {
9333 #ifdef DEBUG
9334         printf("reverse charge: %d\n", revcall );
9335 #endif /* DEBUG */
9336         *++p = 0x01;
9337         *++p = revcall;
9338     }
9339     if (closgr > 0) {
9340 #ifdef DEBUG
9341         printf("closed user group: %d\n", closgr );
9342 #endif /* DEBUG */
9343         *++p = 0x03;
9344         *++p = closgr;
9345     }
9346
9347 #ifdef DEBUG
9348     if (p == start) {
9349         printf( "no facilities\n" );
9350     }
9351 #endif /* DEBUG */
9352
9353     /* set the size of the facilities buffer */
9354     *buffer = (char)( p - start ) & 0xff;
9355
9356 #ifdef DEBUG
9357     printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer)  );
9358 #endif /* DEBUG */
9359
9360 #ifdef TRACE
9361     printf( "TRACE: leaving x25facilities\n" );
9362 #endif /* TRACE */
9363
9364     /* return the size of the facilities with size byte */
9365     /* 1 == no facilities, 0 byte returned as facilities size */
9366     return( (int)(p - buffer) );
9367 }
9368
9369 /*
9370  * reset the connection
9371  */
9372 int
9373 x25reset(cause, diagn) char cause; char diagn; {
9374     /* not implemented */
9375
9376 #ifdef TRACE
9377     printf( "TRACE: entering x25reset\n" );
9378 #endif /* TRACE */
9379
9380 #ifdef TRACE
9381     printf( "TRACE: leaving x25reset\n" );
9382 #endif /* TRACE */
9383
9384     return(0);
9385 }
9386
9387 /*
9388  * clear the x25 connection - ie: hang up
9389  */
9390 int
9391 x25clear() {
9392     int get_flags = 0;                  /* priority flag for getmsg */
9393     int put_flags = 0;                  /* send flags, always 0 */
9394     ulong type;                         /* primitive type */
9395     N_discon_req_t *discon_req;         /* pointer to N_DISCON_REQ */
9396     N_discon_ind_t *discon_ind;         /* pointer to N_DISCON_IND */
9397     N_npi_data_t *discon_data;          /* pointer to N_DISCON_IND data */
9398     int rc = 0;                         /* return code */
9399
9400 #ifdef TRACE
9401     printf( "TRACE: entering x25clear\n" );
9402 #endif /* TRACE */
9403
9404 #ifdef DEBUG
9405     /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
9406 #endif /* DEBUG */
9407
9408     /*
9409     * The following checks are used to ensure that we don't disconnect
9410     * or unbind twice - this seems to throw the NPI interface right out of
9411     * kilter.
9412     */
9413     switch(x25lastmsg) {
9414       case N_BIND_ACK:
9415       case N_CONN_CON:
9416       case N_CONN_REQ:
9417       case N_DATA_REQ:
9418       case N_DATA_IND:
9419         {
9420 #ifdef DEBUG
9421             /* printf("x25clear(): actively disconnecting\n"); */
9422 #endif /* DEBUG */
9423
9424                 discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
9425                 if (discon_req == NULL) {
9426                     perror("kermit x25clear(): discon_req malloc failed\n");
9427                     /* fallthrough, try to unbind the NPI anyway */
9428                 } else {
9429                     discon_req->PRIM_type = N_DISCON_REQ;
9430                     discon_req->DISCON_reason = 0;      /* not used by AIX */
9431                     discon_req->RES_length = 0;
9432                     discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
9433                     discon_req->SEQ_number = x25seqno;  /* global */
9434
9435                     if (x25putmsg(ttyfd,
9436                                   (N_npi_ctl_t*)discon_req,
9437                                   (N_npi_data_t*)NULL,
9438                                   0,
9439                                   &put_flags
9440                                   ) < 0) {
9441                         perror("x25putmsg failed in x25clear()");
9442                     }
9443                     discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
9444                     discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
9445                     if((discon_ind == NULL) || (discon_data == NULL)) {
9446                         perror("x25clear(): discon_ind malloc failed\n");
9447                         /* fallthrough, try to unbind the NPI anyway */
9448                     } else {
9449                         if(x25getmsg(ttyfd,
9450                                      (N_npi_ctl_t*)discon_ind,
9451                                      NPI_MAX_CTL,
9452                                      (N_npi_data_t*)discon_data,
9453                                      NPI_MAX_DATA,
9454                                      &get_flags,
9455                                      N_OK_ACK
9456                                      ) < 0 ) {
9457                             perror("x25getmsg failed in x25clear()");
9458                             /* fallthrough, try to unbind the NPI anyway */
9459                         }
9460                     }
9461                 }
9462                 break;
9463             }
9464     }
9465
9466     if (x25lastmsg != N_UNBIND_REQ) {
9467         rc = x25unbind(ttyfd);
9468     }
9469
9470 #ifdef TRACE
9471     printf( "TRACE: leaving x25clear\n" );
9472 #endif /* TRACE */
9473
9474     return(rc);
9475 }
9476
9477 #ifdef DEBUG
9478 /*
9479  * only for debugging
9480  *
9481  * turn the internal representation of a datablock into something
9482  * half-way readable. Because the length is known, we can print
9483  * the string including null's etc (important, because the first(!)
9484  * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
9485  */
9486 x25dump_data(char *addr, ulong offset, ulong length) {
9487     char *ptr = addr + offset;
9488     ulong i = length;
9489     /* allocate enough memory for all unprintable chars */
9490     char *buf = (char *)malloc( length * 4 );
9491     char *bptr = buf;   /* pointer to current place in the print buffer */
9492
9493     while (i > 0) {
9494         if (isprint(*ptr)) {
9495             *bptr++ = *ptr;
9496         } else {
9497             *bptr++ = '[';
9498             strcpy(bptr,ckctox(*ptr,1)); bptr += 2;
9499             *bptr++ = ']';
9500         }
9501         ptr++;
9502         i--;
9503     }
9504     if (length > 0) {
9505         *bptr = '\0';
9506         printf( "%s", buf );
9507     }
9508     printf( " (%d+%d)\n", offset, length );
9509
9510     if (buf) { free(buf); buf = NULL; }
9511     return;
9512 }
9513
9514 /*
9515  * only for debugging
9516  * print as much useful information about a packet as possible
9517  */
9518 x25dump_prim(primitive)    N_npi_ctl_t *primitive; {
9519     printf("Primitive");
9520     switch (primitive->PRIM_type) {
9521       case N_BIND_ACK:
9522         printf( "\tN_BIND_ACK\n\taddress:\t" );
9523         x25dump_data( (char *)primitive,
9524                      primitive->bind_ack.ADDR_offset,
9525                      primitive->bind_ack.ADDR_length );
9526         printf( "\tproto id:\t" );
9527         x25dump_data( (char *)primitive,
9528                      primitive->bind_ack.PROTOID_offset,
9529                      primitive->bind_ack.PROTOID_length );
9530         printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
9531                primitive->bind_ack.CONIND_number,
9532                primitive->bind_ack.TOKEN_value );
9533         break;
9534
9535       case N_BIND_REQ:
9536         printf( "\tN_BIND_REQ\n\taddress:\t" );
9537         x25dump_data( (char *)primitive,
9538                      primitive->bind_req.ADDR_offset,
9539                      primitive->bind_req.ADDR_length );
9540         printf( "\tproto id:\t" );
9541         x25dump_data( (char *)primitive,
9542                      primitive->bind_req.PROTOID_offset,
9543                      primitive->bind_req.PROTOID_length );
9544         printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
9545                primitive->bind_req.CONIND_number,
9546                primitive->bind_req.BIND_flags );
9547         break;
9548
9549       case N_CONN_CON:
9550         printf( "\tN_CONN_CON\n" );
9551         printf( "\tRES\t\t" );
9552         x25dump_data( (char *)primitive,
9553                      primitive->conn_con.RES_offset,
9554                      primitive->conn_con.RES_length );
9555         printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
9556         break;
9557
9558       case N_CONN_IND:
9559         printf( "\tN_CONN_IND\n" );
9560         printf( "\tsource:\t\t" );
9561         x25dump_data( (char *)primitive,
9562                      primitive->conn_ind.SRC_offset,
9563                      primitive->conn_ind.SRC_length );
9564         printf( "\tdestination:\t" );
9565         x25dump_data( (char *)primitive,
9566                      primitive->conn_ind.DEST_offset,
9567                      primitive->conn_ind.DEST_length );
9568         printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
9569         printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
9570         break;
9571
9572       case N_CONN_REQ:
9573         printf( "\tN_CONN_REQ\n\tdestination:\t" );
9574         x25dump_data( (char *)primitive,
9575                      primitive->conn_req.DEST_offset,
9576                      primitive->conn_req.DEST_length );
9577         printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
9578         break;
9579
9580       case N_CONN_RES:
9581         printf( "\tN_CONN_RES\n" );
9582         printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
9583         printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
9584         printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
9585         printf( "\tRES\t\t" );
9586         x25dump_data( (char *)primitive,
9587                      primitive->conn_res.RES_offset,
9588                      primitive->conn_res.RES_length );
9589         break;
9590
9591       case N_DATACK_IND:
9592         printf( "\tN_DATACK_IND\n" );
9593         break;
9594
9595       case N_DATACK_REQ:
9596         printf( "\tN_DATACK_REQ\n" );
9597         printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
9598         break;
9599
9600       case N_DATA_IND:
9601         printf( "\tN_DATA_IND\n" );
9602         printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
9603         break;
9604
9605       case N_DATA_REQ:
9606         printf( "\tN_DATA_REQ\n" );
9607         break;
9608
9609       case N_DISCON_IND:
9610         printf( "\tN_DISCON_IND\n" );
9611         printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
9612         printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
9613         printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
9614         printf( "\tRES:\t" );
9615         x25dump_data( (char *)primitive,
9616                      primitive->discon_ind.RES_offset,
9617                      primitive->discon_ind.RES_length );
9618         break;
9619
9620       case N_DISCON_REQ:
9621         printf( "\tN_DISCON_REQ\n" );
9622         printf( "\tDISCON_reason:\t%d\n",
9623                primitive->discon_req.DISCON_reason );
9624         printf( "\tRES:\t" );
9625         x25dump_data( (char *)primitive,
9626                      primitive->discon_req.RES_offset,
9627                      primitive->discon_req.RES_length );
9628         printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
9629         break;
9630
9631       case N_ERROR_ACK:
9632         printf( "\tN_ERROR_ACK\n" );
9633         printf( "\tCaused by:\t%s\n",
9634                x25prim( primitive->error_ack.ERROR_prim ) );
9635         printf( "\tNPI error:\t%s\n",
9636                x25err( primitive->error_ack.NPI_error ));
9637         errno = primitive->error_ack.UNIX_error;
9638         perror( "\t" );
9639         break;
9640
9641       case N_EXDATA_IND:
9642         printf( "\tN_EXDATA_ACK\n" );
9643         break;
9644
9645       case N_EXDATA_REQ:
9646         printf( "\tN_EXDATA_REQ\n" );
9647         break;
9648
9649       case N_INFO_ACK:
9650         printf( "\tN_INFO_ACK\n" );
9651         printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
9652         printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
9653         printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
9654         printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
9655         printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
9656         printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
9657         break;
9658
9659       case N_INFO_REQ:
9660         printf( "\tN_INFO_REQ\n" );
9661         break;
9662
9663       case N_OK_ACK:
9664         printf( "\tN_OK_ACK\n" );
9665         break;
9666
9667       case N_OPTMGMT_REQ:
9668         printf( "\tN_OPTMGMT_REQ\n" );
9669         break;
9670
9671       case N_RESET_CON:
9672         printf( "\tN_RESET_CON\n" );
9673         break;
9674
9675       case N_RESET_IND:
9676         printf( "\tN_RESET_IND\n" );
9677         printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
9678         printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
9679         break;
9680
9681       case N_RESET_REQ:
9682         printf( "\tN_RESET_REQ\n" );
9683         printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
9684         break;
9685
9686       case N_RESET_RES:
9687         printf( "\tN_RESET_RES\n" );
9688         break;
9689
9690       case N_UDERROR_IND:
9691         printf( "\tN_UDERROR_IND\n" );
9692         break;
9693
9694       case N_UNBIND_REQ:
9695         printf( "\tN_UNBIND_REQ\n" );
9696         break;
9697
9698       case N_UNITDATA_REQ:
9699         printf( "\tN_UNITDATA_REQ\n" );
9700         break;
9701
9702       case N_UNITDATA_IND:
9703         printf( "\tN_UNITDATA_IND\n" );
9704         break;
9705
9706       default:
9707         (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
9708         return 0;
9709     }
9710 }
9711 #endif /* DEBUG */
9712
9713 /* it looks like signal handling is not needed with streams! */
9714 /* x25oobh()    - handle SIGURG signals - take from isode ? */
9715
9716 #endif /* IBMX25 */
9717
9718 #ifndef NOHTTP
9719 /*
9720   Which time.h files to include... See ckcdeb.h for defaults.
9721   Note that 0, 1, 2, or all 3 of these can be included according to
9722   the symbol definitions.
9723 */
9724 #ifndef NOTIMEH
9725 #ifdef TIMEH
9726 #include <time.h>
9727 #endif /* TIMEH */
9728 #endif /* NOTIMEH */
9729
9730 #ifndef NOSYSTIMEH
9731 #ifdef SYSTIMEH
9732 #include <sys/time.h>
9733 #endif /* SYSTIMEH */
9734 #endif /* NOSYSTIMEH */
9735
9736 #ifndef NOSYSTIMEBH
9737 #ifdef SYSTIMEBH
9738 #include <sys/timeb.h>
9739 #endif /* SYSTIMEBH */
9740 #endif /* NOSYSTIMEBH */
9741
9742 #ifndef TIMEH
9743 #ifndef SYSTIMEH
9744 #ifndef SYSTIMEBH
9745 #ifdef Plan9
9746 #include <sys/time.h>
9747 #else
9748 #ifdef AIX41
9749 #include <time.h>
9750 #else
9751 #ifdef SUNOS4
9752 #include <sys/time.h>
9753 #else
9754 #ifdef SYSTIMEH
9755 #include <sys/time.h>
9756 #else
9757 #ifdef POSIX
9758 #include <posix/time.h>
9759 #else
9760 #ifdef CLIX
9761 #include <sys/time.h>
9762 #else
9763 #ifdef OS2
9764 #include <time.h>
9765 #else
9766 #include <time.h>
9767 /* #include <utime.h> */
9768 #endif /* OS2 */
9769 #endif /* CLIX */
9770 #endif /* POSIX */
9771 #endif /* SYSTIMEH */
9772 #endif /* SUNOS4 */
9773 #endif /* AIX41 */
9774 #endif /* Plan9 */
9775 #endif
9776 #endif
9777 #endif
9778
9779 #ifdef OS2
9780 #include <sys/utime.h>
9781 #ifdef NT
9782 #define utimbuf _utimbuf
9783 #endif /* NT */
9784 #define utime   _utime
9785 #else
9786 #ifdef SYSUTIMEH                        /* <sys/utime.h> if requested,  */
9787 #include <sys/utime.h>                  /* for extra fields required by */
9788 #else                                   /* 88Open spec. */
9789 #ifdef UTIMEH                           /* or <utime.h> if requested */
9790 #include <utime.h>                      /* (SVR4, POSIX) */
9791 #define SYSUTIMEH                       /* Use this for both cases. */
9792 #endif /* UTIMEH */
9793 #endif /* SYSUTIMEH */
9794 #endif /* OS2 */
9795
9796 #ifndef HTTP_VERSION
9797 #define HTTP_VERSION "HTTP/1.1"
9798 #endif /* HTTP_VERSION */
9799
9800 #ifdef CMDATE2TM
9801 time_t
9802 #ifdef CK_ANSIC
9803 http_date(char * date)
9804 #else
9805 http_date(date) char * date;
9806 #endif /* CK_ANSIC */
9807 /* http_date */ {
9808     /* HTTP dates are of the form:  "Sun, 06 Oct 1997 20:11:47 GMT" */
9809     /* There are two older formats which we are required to parse
9810      * that we currently do not:
9811      *
9812      * RFC 850:   "Sunday, 06-Oct-97 20:11:47 GMT"
9813      * asctime(): "Sun Nov  6 20:11:47 1997"
9814      *
9815      * However, it is required that all dates be sent in the form we
9816      * do accept.  The other two formats are for compatibility with
9817      * really old servers.
9818      */
9819     extern char cmdatebuf[18];
9820     struct tm t_tm;
9821     time_t t;
9822     char ldate[32];
9823     int j;
9824
9825     j = ckindex(",",date,0,0,0);
9826     ckstrncpy(ldate,&date[j+1],25);
9827
9828     {   /*
9829            cmcvtate() date changed to return a string pointer.
9830            fdc, 12 Aug 2001.
9831         */
9832         char * dp;
9833         dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */
9834         if (!dp)
9835           return(0);
9836         t_tm = *cmdate2tm(dp,1);
9837     }
9838 /*
9839   From Lucas Hart, 5 Dec 2001:
9840   "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64),
9841   setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes
9842   the specified (GMT) time if the buffer size is 21, or the contemporaneous
9843   localtime if the buffer size is 25.  Perhaps tm_isdst should be set in
9844   cmdate2tm(), rather than only in http_date."
9845 */
9846 #ifndef NOTM_ISDST                      /* For platforms where */
9847     t_tm.tm_isdst = -1;                 /* tm_isdst doesn't exist. */
9848 #endif /* NOTM_ISDST */
9849
9850     t = mktime(&t_tm);                  /* NOT PORTABLE */
9851
9852 #ifdef XX_TIMEZONE
9853     t -= _timezone;
9854 #endif /* XX_TIMEZONE */
9855
9856     return(t);
9857 }
9858 #endif /* CMDATE2TM */
9859
9860 char *
9861 http_now() {
9862     static char nowstr[32];
9863 #ifdef CMDATE2TM
9864     struct tm  *gmt;
9865     time_t ltime;                       /* NOT PORTABLE */
9866
9867     time(&ltime);
9868
9869     gmt = gmtime(&ltime);               /* PROBABLY NOT PORTABLE */
9870     strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
9871     /* not only is it not portable but it's locale-dependent */
9872 #else
9873 /*
9874   This is hopeless.  First of all, it seems that HTTP wants Day and Month
9875   NAMES?  In English?  Whose idea was that?  Even worse, the date/time must be
9876   expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
9877   nightmare.  Every platform does it differently, if at all -- even if we
9878   restrict ourselves to UNIX.  For example (quoting from recent C-Kermit edit
9879   history), "Fixed a longstanding bug in the BSDI version, in which incoming
9880   file dates were set in GMT rather than local time.  It seems in 4.4BSD,
9881   localtime() does not return the local time, but rather Zero Meridian (Zulu)
9882   time (GMT), and must be adjusted by the tm_gmtoff value."  Swell.  For
9883   greater appreciation of the scope of the problem, just take a look at the
9884   time-related #ifdefs in ckutio.c.  The only right way to do this is to add
9885   our own portable API for converting between local time and GMT/UTC/Zulu
9886   that shields us not only from UNIXisms like time_t and struct tm, but also
9887   the unbelievable amount of differences in time-related APIs -- e.g. is
9888   "timezone" an external variable or a function; which header file(s) do we
9889   include, etc etc etc.  It's a major project.
9890 */
9891     int x;
9892     x = cmcvtdate("",1);
9893
9894 Evidently this code is not used -- if it is, it must be fixed to use
9895 new (aug 2001) cmcvtdate() calling conventions.
9896
9897     if (x < 0)
9898       return("");
9899 /*  yyyymmdd hh:mm:ss */
9900 /*  01234567890123456 */
9901     nowstr[0]  = 'X';                   /* 1st letter of day */
9902     nowstr[1]  = 'x';                   /* 2nd letter of day */
9903     nowstr[2]  = 'x';                   /* 3rd letter of day */
9904     nowstr[3]  = ',';
9905     nowstr[4]  = ' ';
9906     nowstr[5]  = cmdate[6];
9907     nowstr[6]  = cmdate[7];
9908     nowstr[7]  = ' ';
9909     nowstr[8]  = ' ';                   /* first letter of month */
9910     nowstr[9]  = ' ';                   /* second letter of month */
9911     nowstr[10] = ' ';                   /* third letter of month */
9912     nowstr[11] = ' ';
9913     nowstr[12] = cmdate[0];
9914     nowstr[13] = cmdate[1];
9915     nowstr[14] = cmdate[2];
9916     nowstr[15] = cmdate[3];
9917     nowstr[16] = ' ';
9918     nowstr[17] = cmdate[9];
9919     nowstr[18] = cmdate[10];
9920     nowstr[19] = cmdate[11];
9921     nowstr[20] = cmdate[12];
9922     nowstr[21] = cmdate[13];
9923     nowstr[22] = cmdate[14];
9924     nowstr[23] = cmdate[15];
9925     nowstr[24] = cmdate[16];
9926     nowstr[25] = ' ';
9927     nowstr[26] = 'G';
9928     nowstr[27] = 'M';
9929     nowstr[28] = 'T';
9930     nowstr[29] = '\0';
9931 #endif /* CMDATE2TM */
9932     return(nowstr);
9933 }
9934
9935 #ifndef OS2
9936 #ifndef CK_AUTHENTICATION
9937 /* from ckuusr.h, which this module normally doesn't include */
9938 _PROTOTYP( int dclarray, (char, int) );
9939 #endif /* CK_AUTHENTICATION */
9940 #endif /* OS2 */
9941 /*
9942   Assign http response pairs to given array.
9943   For best results, response pairs should contain no spaces.
9944
9945   Call with:
9946     resp  =  pointer to response list.
9947     n     =  size of response list.
9948     array =  array letter.
9949   Returns:
9950     0 on failure.
9951     >= 1, size of array, on success.
9952 */
9953 static int
9954 #ifdef CK_ANSIC
9955 http_mkarray(char ** resp, int n, char array)
9956 #else
9957 http_mkarray(resp, n, array) char ** resp; int n; char array;
9958 #endif /* CK_ANSIC */
9959 {
9960 #ifndef NOSPL
9961     int i, x;
9962     char ** ap;
9963     extern char ** a_ptr[];
9964     extern int a_dim[];
9965
9966     if (!array || n <= 0)
9967       return(0);
9968     if ((x = dclarray(array,n)) < 0) {
9969         printf("?Array declaration failure\n");
9970         return(-9);
9971     }
9972     /* Note: argument array is 0-based but Kermit array is 1-based */
9973     ap = a_ptr[x];
9974     ap[0] = NULL;                       /* 0th element is empty */
9975     for (i = 1; i <= n; i++) {
9976         ap[i] = resp[i-1];              /* If resp elements were malloc'd */
9977         resp[i-1] = NULL;
9978     }
9979     a_dim[x] = n;
9980     return(n);
9981 #else
9982     return(0);
9983 #endif /* NOSPL */
9984 }
9985
9986 #define HTTPHEADCNT 64
9987 int
9988 http_get_chunk_len()
9989 {
9990     int len = 0;
9991     int i = 0, j = -1;
9992     char buf[24];
9993     int ch;
9994
9995     while ((ch = http_inc(0)) >= 0 && i < 24) {
9996         buf[i] = ch;
9997         if ( buf[i] == ';' )            /* Find chunk-extension (if any) */
9998             j = i;
9999         if ( buf[i] == 10 ) {           /* found end of line */
10000             if (i > 0 && buf[i-1] == 13)
10001                 i--;
10002             buf[i] = '\0';
10003             break;
10004         }
10005         i++;
10006     }
10007     if ( i < 24 ) {                     /* buf now contains len in Hex */
10008         len = hextoulong(buf, j == -1 ? i : j-1);
10009     }
10010
10011     return(len);
10012 }
10013
10014 int
10015 http_isconnected()
10016 {
10017     return(httpfd != -1);
10018 }
10019
10020 char *
10021 http_host()
10022 {
10023     return(httpfd != -1 ? http_host_port : "");
10024 }
10025
10026 char *
10027 http_security()
10028 {
10029     if ( httpfd == -1 )
10030         return("NULL");
10031 #ifdef CK_SSL
10032     if (tls_http_active_flag) {
10033         SSL_CIPHER * cipher;
10034         const char *cipher_list;
10035         static char buf[128];
10036         buf[0] = NUL;
10037         cipher = SSL_get_current_cipher(tls_http_con);
10038         cipher_list = SSL_CIPHER_get_name(cipher);
10039         SSL_CIPHER_description(cipher,buf,sizeof(buf));
10040         return(buf);
10041     }
10042 #endif /* CK_SSL */
10043     return("NULL");
10044 }
10045
10046 int
10047 http_reopen()
10048 {
10049     int rc = 0;
10050     char * s = NULL;                    /* strdup is not portable */
10051     if ( tcp_http_proxy ) {
10052         char * p;
10053         makestr(&s,(char *)http_host_port);
10054         p = s;
10055         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10056         if (*p == ':') {                     /* Have a colon */
10057             *p++ = '\0';                     /* Get service name or number */
10058         } else {
10059             p="http";
10060         }
10061         rc = http_open(s,p,http_ssl,NULL,0,http_agent);
10062     } else {
10063         makestr(&s,(char *)http_ip);
10064         rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent);
10065     }
10066     free(s);
10067     return(rc);
10068 }
10069
10070
10071 int
10072 #ifdef CK_ANSIC
10073 http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name,
10074           int rdns_len, char * agent)
10075 #else /* CK_ANSIC */
10076 http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent)
10077     char * hostname;
10078     char * svcname;
10079     int    use_ssl;
10080     char * rdns_name;
10081     int    rdns_len;
10082     char * agent;
10083 #endif /* CK_ANSIC */
10084 {
10085     char namecopy[NAMECPYL];
10086     char *p;
10087     int i, x, dns = 0;
10088 #ifdef TCPSOCKET
10089     int isconnect = 0;
10090 #ifdef SO_OOBINLINE
10091     int on = 1;
10092 #endif /* SO_OOBINLINE */
10093     struct servent *service=NULL;
10094     struct hostent *host=NULL;
10095     struct sockaddr_in r_addr;
10096     struct sockaddr_in sin;
10097     struct sockaddr_in l_addr;
10098     GSOCKNAME_T l_slen;
10099 #ifdef EXCELAN
10100     struct sockaddr_in send_socket;
10101 #endif /* EXCELAN */
10102
10103 #ifdef INADDRX
10104 /* inet_addr() is of type struct in_addr */
10105 #ifdef datageneral
10106     extern struct in_addr inet_addr();
10107 #else
10108 #ifdef HPUX5WINTCP
10109     extern struct in_addr inet_addr();
10110 #endif /* HPUX5WINTCP */
10111 #endif /* datageneral */
10112     struct in_addr iax;
10113 #else
10114 #ifdef INADDR_NONE
10115     struct in_addr iax;
10116 #else /* INADDR_NONE */
10117     long iax;
10118 #endif /* INADDR_NONE */
10119 #endif /* INADDRX */
10120
10121     if ( rdns_name == NULL || rdns_len < 0 )
10122         rdns_len = 0;
10123
10124     *http_ip = '\0';                     /* Initialize IP address string */
10125     namecopy[0] = '\0';
10126
10127 #ifdef DEBUG
10128     if (deblog) {
10129         debug(F110,"http_open hostname",hostname,0);
10130         debug(F110,"http_open svcname",svcname,0);
10131     }
10132 #endif /* DEBUG */
10133     if (!hostname) hostname = "";
10134     if (!svcname) svcname = "";
10135     if (!*hostname || !*svcname) return(-1);
10136
10137     
10138     service = ckgetservice(hostname,svcname,http_ip,20);
10139
10140     if (service == NULL) {
10141         if ( !quiet )
10142             printf("?Invalid service: %s\r\n",svcname);
10143         return(-1);
10144     }
10145
10146     /* For HTTP connections we must preserve the original hostname and */
10147     /* service requested so we can include them in the Host header.    */
10148     ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":",
10149               ckuitoa(ntohs(service->s_port)),NULL);
10150     http_port = ntohs(service->s_port);
10151     http_ssl = use_ssl;
10152     debug(F111,"http_open",http_host_port,http_port);
10153
10154     /* 'http_ip' contains the IP address to which we want to connect        */
10155     /* 'svcnam'   contains the service name                                 */
10156     /* 'service->s_port' contains the port number in network byte order     */
10157
10158     /* If we are using an http proxy, we need to create a buffer containing */
10159     /*   hostname:port-number                                               */
10160     /* to pass to the http_connect() function.  Then we need to replace     */
10161     /* 'namecopy' with the name of the proxy server and the service->s_port */
10162     /* with the port number of the proxy (default port 80).                 */
10163
10164     if ( tcp_http_proxy ) {
10165
10166         ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":",
10167                  ckuitoa(ntohs(service->s_port)),NULL);
10168         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10169
10170         p = namecopy;                       /* Was a service requested? */
10171         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10172         if (*p == ':') {                    /* Have a colon */
10173             debug(F110,"http_open name has colon",namecopy,0);
10174             *p++ = '\0';                    /* Get service name or number */
10175         } else {
10176             strcpy(++p,"http");
10177         }
10178
10179         service = ckgetservice(namecopy,p,http_ip,20);
10180         if (!service) {
10181             fprintf(stderr, "Can't find port for service %s\n", p);
10182 #ifdef TGVORWIN
10183             debug(F101,"http_open can't get service for proxy","",socket_errno);
10184 #else
10185             debug(F101,"http_open can't get service for proxy","",errno);
10186 #endif /* TGVORWIN */
10187             errno = 0;                  /* (rather than mislead) */
10188             return(-1);
10189         }
10190
10191         /* copy the proxyname and remove the service if any so we can use 
10192          * it as the hostname 
10193          */
10194         ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10195         p = namecopy;                       /* Was a service requested? */
10196         while (*p != '\0' && *p != ':') p++; /* Look for colon */
10197         if (*p == ':') {                    /* Have a colon */
10198             *p = '\0';                      /* terminate string */
10199         }        
10200         hostname = namecopy;                /* use proxy as hostname */
10201     }
10202
10203     /* Set up socket structure and get host address */
10204     bzero((char *)&r_addr, sizeof(r_addr));
10205     debug(F100,"http_open bzero ok","",0);
10206
10207 #ifdef INADDR_NONE
10208     debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE);
10209 #else /* INADDR_NONE */
10210     debug(F100,"http_open INADDR_NONE not defined","",0);
10211 #endif /* INADDR_NONE */
10212 #ifdef INADDRX
10213     debug(F100,"http_open INADDRX defined","",0);
10214 #else /* INADDRX */
10215     debug(F100,"http_open INADDRX not defined","",0);
10216 #endif /* INADDRX */
10217
10218 #ifndef NOMHHOST
10219 #ifdef INADDRX
10220     iax = inet_addr(http_ip[0]?http_ip:hostname);
10221     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10222 #else /* INADDRX */
10223 #ifdef INADDR_NONE
10224     iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname);
10225     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10226 #else /* INADDR_NONE */
10227 #ifndef datageneral
10228     iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname);
10229 #else
10230     iax = -1L;
10231 #endif /* datageneral */
10232     debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax);
10233 #endif /* INADDR_NONE */
10234 #endif /* INADDRX */
10235
10236     dns = 0;
10237     if (
10238 #ifdef INADDR_NONE
10239 /* This might give warnings on 64-bit platforms but they should be harmless */
10240 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
10241 /* probably superfluous -- not sure why it's even there, maybe it should be */
10242 /* removed. */
10243         iax.s_addr == INADDR_NONE || iax.s_addr == (unsigned long) -1L
10244 #else /* INADDR_NONE */
10245         iax < 0
10246 #endif /* INADDR_NONE */
10247         ) {
10248         if (!quiet) {
10249             printf(" DNS Lookup... ");
10250             fflush(stdout);
10251         }
10252         if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) {
10253             debug(F100,"http_open gethostbyname != NULL","",0);
10254             host = ck_copyhostent(host);
10255             dns = 1;                    /* Remember we performed dns lookup */
10256             r_addr.sin_family = host->h_addrtype;
10257             if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0)
10258                  && (tcp_http_proxy == NULL)
10259                  )
10260                 ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL);
10261
10262 #ifdef HADDRLIST
10263 #ifdef h_addr
10264             /* This is for trying multiple IP addresses - see <netdb.h> */
10265             if (!(host->h_addr_list))
10266               return(-1);
10267             bcopy(host->h_addr_list[0],
10268                   (caddr_t)&r_addr.sin_addr,
10269                   host->h_length
10270                   );
10271 #else
10272             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10273 #endif /* h_addr */
10274 #else  /* HADDRLIST */
10275             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10276 #endif /* HADDRLIST */
10277 #ifndef EXCELAN
10278             debug(F111,"BCOPY","host->h_addr",host->h_addr);
10279 #endif /* EXCELAN */
10280             debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
10281                   (caddr_t)&r_addr.sin_addr);
10282             debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
10283                   r_addr.sin_addr.s_addr);
10284             debug(F111,"BCOPY","host->h_length",host->h_length);
10285         }
10286     }
10287 #endif /* NOMHHOST */
10288
10289     if (!dns) {
10290 #ifdef INADDRX
10291 /* inet_addr() is of type struct in_addr */
10292         struct in_addr ina;
10293         unsigned long uu;
10294         debug(F100,"http_open gethostbyname == NULL: INADDRX","",0);
10295         ina = inet_addr(http_ip[0]?http_ip:hostname);
10296         uu = *(unsigned int *)&ina;
10297 #else /* Not INADDRX */
10298 /* inet_addr() is unsigned long */
10299         unsigned long uu;
10300         debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0);
10301         uu = inet_addr(http_ip[0]?http_ip:hostname);
10302 #endif /* INADDRX */
10303         debug(F101,"http_open uu","",uu);
10304         if (
10305 #ifdef INADDR_NONE
10306             !(uu == INADDR_NONE || uu == (unsigned int) -1L)
10307 #else   /* INADDR_NONE */
10308             uu != ((unsigned long)-1)
10309 #endif /* INADDR_NONE */
10310             ) {
10311             r_addr.sin_addr.s_addr = uu;
10312             r_addr.sin_family = AF_INET;
10313         } else {
10314 #ifdef VMS
10315             fprintf(stdout, "\r\n");    /* complete any previous message */
10316 #endif /* VMS */
10317             fprintf(stderr, "Can't get address for %s\n",
10318                      http_ip[0]?http_ip:hostname);
10319 #ifdef TGVORWIN
10320             debug(F101,"http_open can't get address","",socket_errno);
10321 #else
10322             debug(F101,"http_open can't get address","",errno);
10323 #endif /* TGVORWIN */
10324             errno = 0;                  /* Rather than mislead */
10325             return(-1);
10326         }
10327     }
10328
10329     /* Get a file descriptor for the connection. */
10330
10331     r_addr.sin_port = service->s_port;
10332     ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10333     debug(F110,"http_open trying",http_ip,0);
10334     if (!quiet && *http_ip) {
10335         printf(" Trying %s... ", http_ip);
10336         fflush(stdout);
10337     }
10338
10339     /* Loop to try additional IP addresses, if any. */
10340
10341     do {
10342 #ifdef EXCELAN
10343         send_socket.sin_family = AF_INET;
10344         send_socket.sin_addr.s_addr = 0;
10345         send_socket.sin_port = 0;
10346         if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0,
10347                             &send_socket, SO_REUSEADDR)) < 0)
10348 #else  /* EXCELAN */
10349         if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
10350 #endif /* EXCELAN */
10351             {
10352 #ifdef EXCELAN
10353                 experror("TCP socket error");
10354 #else
10355 #ifdef TGVORWIN
10356 #ifdef OLD_TWG
10357                 errno = socket_errno;
10358 #endif /* OLD_TWG */
10359                 socket_perror("TCP socket error");
10360                 debug(F101,"http_open socket error","",socket_errno);
10361 #else
10362                 perror("TCP socket error");
10363                 debug(F101,"http_open socket error","",errno);
10364 #endif /* TGVORWIN */
10365 #endif /* EXCELAN */
10366                 return (-1);
10367             }
10368         errno = 0;
10369
10370        /* If a specific TCP address on the local host is desired we */
10371        /* must bind it to the socket.                               */
10372 #ifndef datageneral
10373          if (tcp_address) {
10374              int s_errno;
10375
10376              debug(F110,"http_open binding socket to",tcp_address,0);
10377              bzero((char *)&sin,sizeof(sin));
10378              sin.sin_family = AF_INET;
10379 #ifdef INADDRX
10380              inaddrx = inet_addr(tcp_address);
10381              sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
10382 #else
10383              sin.sin_addr.s_addr = inet_addr(tcp_address);
10384 #endif /* INADDRX */
10385              sin.sin_port = 0;
10386              if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
10387                  s_errno = socket_errno; /* Save error code */
10388 #ifdef TCPIPLIB
10389                  socket_close(httpfd);
10390 #else /* TCPIPLIB */
10391                  close(httpfd);
10392 #endif /* TCPIPLIB */
10393                  httpfd = -1;
10394                  errno = s_errno;       /* and report this error */
10395                  debug(F101,"http_open bind errno","",errno);
10396                  return(-1);
10397              }
10398          }
10399 #endif /* datageneral */
10400
10401 /* Now connect to the socket on the other end. */
10402
10403 #ifdef EXCELAN
10404         if (connect(httpfd, &r_addr) < 0)
10405 #else
10406 #ifdef NT
10407           WSASafeToCancel = 1;
10408 #endif /* NT */
10409         if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
10410 #endif /* EXCELAN */
10411           {
10412 #ifdef NT
10413               WSASafeToCancel = 0;
10414 #endif /* NT */
10415 #ifdef OS2
10416               i = socket_errno;
10417 #else /* OS2 */
10418 #ifdef TGVORWIN
10419               i = socket_errno;
10420 #else
10421               i = errno;                /* Save error code */
10422 #endif /* TGVORWIN */
10423 #endif /* OS2 */
10424 #ifdef HADDRLIST
10425 #ifdef h_addr
10426               if (host && host->h_addr_list && host->h_addr_list[1]) {
10427                   perror("");
10428                   host->h_addr_list++;
10429                   bcopy(host->h_addr_list[0],
10430                         (caddr_t)&r_addr.sin_addr,
10431                         host->h_length);
10432
10433                   ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10434                   debug(F110,"http_open h_addr_list",http_ip,0);
10435                   if (!quiet && *http_ip) {
10436                       printf(" Trying %s... ", http_ip);
10437                       fflush(stdout);
10438                   }
10439 #ifdef TCPIPLIB
10440                   socket_close(httpfd); /* Close it. */
10441 #else
10442                   close(httpfd);
10443 #endif /* TCPIPLIB */
10444                   continue;
10445               }
10446 #endif /* h_addr */
10447 #endif  /* HADDRLIST */
10448               http_close();
10449               httpfd = -1;
10450               errno = i;                /* And report this error */
10451 #ifdef EXCELAN
10452               if (errno) experror("http_open connect");
10453 #else
10454 #ifdef TGVORWIN
10455               debug(F101,"http_open connect error","",socket_errno);
10456               /* if (errno) socket_perror("http_open connect"); */
10457 #ifdef OLD_TWG
10458               errno = socket_errno;
10459 #endif /* OLD_TWG */
10460               if (!quiet)
10461                 socket_perror("http_open connect");
10462 #else /* TGVORWIN */
10463               debug(F101,"http_open connect errno","",errno);
10464 #ifdef VMS
10465               if (!quiet)
10466                 perror("\r\nFailed");
10467 #else
10468               if (!quiet)
10469                 perror("Failed");
10470 #endif /* VMS */
10471 #ifdef DEC_TCPIP
10472               if (!quiet)
10473                 perror("http_open connect");
10474 #endif /* DEC_TCPIP */
10475 #ifdef CMU_TCPIP
10476               if (!quiet)
10477                 perror("http_open connect");
10478 #endif /* CMU_TCPIP */
10479 #endif /* TGVORWIN */
10480 #endif /* EXCELAN */
10481               return(-1);
10482           }
10483 #ifdef NT
10484         WSASafeToCancel = 0;
10485 #endif /* NT */
10486         isconnect = 1;
10487     } while (!isconnect);
10488
10489 #ifdef NON_BLOCK_IO
10490     on = 1;
10491     x = socket_ioctl(httpfd,FIONBIO,&on);
10492     debug(F101,"http_open FIONBIO","",x);
10493 #endif /* NON_BLOCK_IO */
10494
10495     /* We have succeeded in connecting to the HTTP PROXY.  So now we   */
10496     /* need to attempt to connect through the proxy to the actual host */
10497     /* If that is successful, we have to pretend that we made a direct */
10498     /* connection to the actual host.                                  */
10499
10500     if ( tcp_http_proxy ) {
10501 #ifdef OS2
10502         if (!agent) 
10503           agent = "Kermit 95";  /* Default user agent */
10504 #else
10505         if (!agent) 
10506           agent = "C-Kermit";
10507 #endif /* OS2 */
10508
10509         if (http_connect(httpfd,
10510                          tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
10511                          NULL,
10512                          tcp_http_proxy_user,
10513                          tcp_http_proxy_pwd,
10514                          0,
10515                          proxycopy
10516                          ) < 0) {
10517             http_close();
10518             return(-1);
10519         }
10520     }
10521
10522 #ifdef SO_OOBINLINE
10523     /* See note on SO_OOBINLINE in netopen() */
10524 #ifdef datageneral
10525     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10526 #else
10527 #ifdef BSD43
10528     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10529 #else
10530 #ifdef OSF1
10531     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10532 #else
10533 #ifdef POSIX
10534     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10535 #else
10536 #ifdef MOTSV88R4
10537     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10538 #else
10539 #ifdef SOLARIS
10540 /*
10541   Maybe this applies to all SVR4 versions, but the other (else) way has been
10542   compiling and working fine on all the others, so best not to change it.
10543 */
10544     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10545 #else
10546 #ifdef OSK
10547     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10548 #else
10549 #ifdef OS2
10550     {
10551         int rc;
10552         rc = setsockopt(httpfd,
10553                         SOL_SOCKET,
10554                         SO_OOBINLINE,
10555                         (char *) &on,
10556                         sizeof on
10557                         );
10558         debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
10559     }
10560 #else
10561 #ifdef VMS /* or, at least, VMS with gcc */
10562     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10563 #else
10564 #ifdef CLIX
10565     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10566 #else
10567     setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
10568 #endif /* CLIX */
10569 #endif /* VMS */
10570 #endif /* OS2 */
10571 #endif /* OSK */
10572 #endif /* SOLARIS */
10573 #endif /* MOTSV88R4 */
10574 #endif /* POSIX */
10575 #endif /* BSD43 */
10576 #endif /* OSF1 */
10577 #endif /* datageneral */
10578 #endif /* SO_OOBINLINE */
10579
10580 #ifndef NOTCPOPTS
10581 #ifndef datageneral
10582 #ifdef SOL_SOCKET
10583 #ifdef TCP_NODELAY
10584     no_delay(ttyfd,tcp_nodelay);
10585 #endif /* TCP_NODELAY */
10586 #ifdef SO_KEEPALIVE
10587     keepalive(ttyfd,tcp_keepalive);
10588 #endif /* SO_KEEPALIVE */
10589 #ifdef SO_LINGER
10590     ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
10591 #endif /* SO_LINGER */
10592 #ifdef SO_SNDBUF
10593     sendbuf(ttyfd,tcp_sendbuf);
10594 #endif /* SO_SNDBUF */
10595 #ifdef SO_RCVBUF
10596     recvbuf(ttyfd,tcp_recvbuf);
10597 #endif /* SO_RCVBUF */
10598 #endif /* SOL_SOCKET */
10599 #endif /* datageneral */
10600 #endif /* NOTCPOPTS */
10601
10602 #ifndef datageneral
10603     /* Find out our own IP address. */
10604     /* We need the l_addr structure for [E]KLOGIN. */
10605     l_slen = sizeof(l_addr);
10606     bzero((char *)&l_addr, l_slen);
10607 #ifndef EXCELAN
10608     if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) {
10609         char * s = (char *)inet_ntoa(l_addr.sin_addr);
10610         ckstrncpy(myipaddr, s, 20);
10611         debug(F110,"getsockname",myipaddr,0);
10612     }
10613 #endif /* EXCELAN */
10614 #endif /* datageneral */
10615
10616 /* See note in netopen() on Reverse DNS lookups */
10617      if (tcp_rdns == SET_ON) {
10618 #ifdef NT
10619         if (isWin95())
10620           sleep(1);
10621 #endif /* NT */
10622         if (!quiet) {
10623             printf(" Reverse DNS Lookup... ");
10624             fflush(stdout);
10625         }
10626         if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
10627             char * s;
10628             host = ck_copyhostent(host);
10629             debug(F100,"http_open gethostbyname != NULL","",0);
10630             if (!quiet) {
10631                 printf("(OK)\n");
10632                 fflush(stdout);
10633             }
10634             s = host->h_name;
10635             if (!s) {                   /* This can happen... */
10636                 debug(F100,"http_open host->h_name is NULL","",0);
10637                 s = "";
10638             }
10639             /* Something is wrong with inet_ntoa() on HPUX 10.xx */
10640             /* The compiler says "Integral value implicitly converted to */
10641             /* pointer in assignment."  The prototype is right there */
10642             /* in <arpa/inet.h> so what's the problem? */
10643             /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
10644             if (!*s) {                  /* No name so substitute the address */
10645                 debug(F100,"http_open host->h_name is empty","",0);
10646                 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
10647                 if (!s)                 /* Trust No 1 */
10648                   s = "";
10649                 if (*s) {               /* If it worked, use this string */
10650                     ckstrncpy(http_ip,s,20);
10651                 }
10652                 s = http_ip;             /* Otherwise stick with the IP */
10653                 if (!*s)                 /* or failing that */
10654                   s = http_host_port;    /* the name we were called with. */
10655             }
10656             if (*s)                     /* return the rdns name */
10657                 ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL);
10658
10659             if (!quiet && *s
10660 #ifndef NOICP
10661                 && !doconx
10662 #endif /* NOICP */
10663                 ) {
10664                 printf(" %s connected on port %s\n",s,
10665                        ckuitoa(ntohs(service->s_port)));
10666 #ifdef BETADEBUG
10667                 /* This is simply for testing the DNS entries */
10668                 if (host->h_aliases) {
10669                     char ** a = host->h_aliases;
10670                     while (*a) {
10671                         printf(" alias => %s\n",*a);
10672                         a++;
10673                     }
10674                 }
10675 #endif /* BETADEBUG */
10676             }
10677         } else {
10678             if (!quiet) printf("Failed.\n");
10679         }
10680     } else if (!quiet) printf("(OK)\n");
10681     if (!quiet) fflush(stdout);
10682
10683
10684     if ( tcp_http_proxy ) {
10685         /* Erase the IP address since we cannot reuse it */
10686         http_ip[0] = '\0';
10687     } else {
10688         /* This should already have been done but just in case */
10689         ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10690     }
10691     makestr(&http_agent,agent);
10692
10693 #ifdef CK_SSL
10694     if (use_ssl && ck_ssleay_is_installed()) {
10695         if (!ssl_http_init(hostname)) {
10696             if (bio_err!=NULL) {
10697                 BIO_printf(bio_err,"ssl_tn_init() failed\n");
10698                 ERR_print_errors(bio_err);
10699             } else {
10700                 fflush(stderr);
10701                 fprintf(stderr,"ssl_tn_init() failed\n");
10702                 ERR_print_errors_fp(stderr);
10703             }
10704             http_close();
10705             return(-1);
10706         } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) {
10707             http_close();
10708             return(-1);
10709         }
10710     }
10711 #endif /* CK_SSL */
10712 #endif /* TCPSOCKET */
10713
10714     return(0);                          /* Done. */
10715 }
10716
10717 int
10718 #ifdef CK_ANSIC
10719 http_close(VOID)
10720 #else /* CK_ANSIC */
10721 http_close()
10722 #endif /* CK_ANSIC */
10723 {
10724     int x = 0;
10725     debug(F101,"http_close","",httpfd);
10726
10727     if (httpfd == -1)                    /* Was open? */
10728       return(0);                        /* Wasn't. */
10729
10730 #ifndef OS2
10731     if (httpfd > -1)                     /* Was. */
10732 #endif /* OS2 */
10733       {
10734 #ifdef CK_SSL
10735           if (tls_http_active_flag) {
10736               if (ssl_debug_flag)
10737                 BIO_printf(bio_err,"calling SSL_shutdown\n");
10738               SSL_shutdown(tls_http_con);
10739               tls_http_active_flag = 0;
10740           }
10741 #endif /* CK_SSL */
10742 #ifdef TCPIPLIB
10743           x = socket_close(httpfd);      /* Close it. */
10744 #else
10745 #ifndef OS2
10746           x = close(httpfd);
10747 #endif /* OS2 */
10748 #endif /* TCPIPLIB */
10749       }
10750     httpfd = -1;                          /* Mark it as closed. */
10751     /* do not erase http_host_port, http_ip, http_port so they */
10752     /* can be used by http_reopen() */
10753     return(x);
10754 }
10755
10756
10757 /* http_tol()
10758  * Call with s = pointer to string, n = length.
10759  * Returns number of bytes actually written on success, or
10760  * -1 on i/o error, -2 if called improperly.
10761  */
10762
10763 int
10764 http_tol(s,n) CHAR *s; int n; {
10765     int count = 0;
10766     int len = n;
10767     int try = 0;
10768
10769     if (httpfd == -1) {
10770         debug(F100,"http_tol socket is closed","",0);
10771         return -1;
10772     }
10773     debug(F101,"http_tol TCPIPLIB ttnet","",ttnet);
10774 #ifdef COMMENT
10775     hexdump("http_tol",s,n);
10776 #endif /* COMMENT */
10777
10778 #ifdef CK_SSL
10779     if (tls_http_active_flag) {
10780         int error, r;
10781         /* Write using SSL */
10782       ssl_retry:
10783           r = SSL_write(tls_http_con, s, len /* >1024?1024:len */);
10784         switch (SSL_get_error(tls_http_con,r)) {
10785           case SSL_ERROR_NONE:
10786             debug(F111,"http_tol","SSL_write",r);
10787             if ( r == len )
10788                 return(n);
10789              s += r;
10790              len -= r;
10791              goto ssl_retry;
10792           case SSL_ERROR_WANT_WRITE:
10793             debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0);
10794               return(-1);
10795           case SSL_ERROR_WANT_READ:
10796             debug(F100,"http_tol SSL_ERROR_WANT_READ","",0);
10797             return(-1);
10798           case SSL_ERROR_SYSCALL:
10799               if ( r == 0 ) { /* EOF */
10800                   http_close();
10801                   return(-2);
10802               } else {
10803                   int rc = -1;
10804 #ifdef NT
10805                   int gle = GetLastError();
10806                   debug(F111,"http_tol SSL_ERROR_SYSCALL",
10807                          "GetLastError()",gle);
10808                   rc = os2socketerror(gle);
10809                   if (rc == -1)
10810                       rc = -2;
10811                   else if ( rc == -2 )
10812                       return -1;
10813 #endif /* NT */
10814                   return(rc);
10815               }
10816           case SSL_ERROR_WANT_X509_LOOKUP:
10817             debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0);
10818             http_close();
10819             return(-2);
10820           case SSL_ERROR_SSL:
10821             debug(F100,"http_tol SSL_ERROR_SSL","",0);
10822             http_close();
10823             return(-2);
10824           case SSL_ERROR_ZERO_RETURN:
10825             debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0);
10826             http_close();
10827             return(-2);
10828           default:
10829             debug(F100,"http_tol SSL_ERROR_?????","",0);
10830             http_close();
10831             return(-2);
10832         }
10833     }
10834 #endif /* CK_SSL */
10835
10836   http_tol_retry:
10837     try++;                              /* Increase the try counter */
10838
10839     {
10840 #ifdef BSDSELECT
10841         fd_set wfds;
10842         struct timeval tv;
10843
10844         debug(F101,"http_tol BSDSELECT","",0);
10845         tv.tv_usec = 0L;
10846         tv.tv_sec=30;
10847 #ifdef NT
10848         WSASafeToCancel = 1;
10849 #endif /* NT */
10850 #ifdef STREAMING
10851       do_select:
10852 #endif /* STREAMING */
10853         FD_ZERO(&wfds);
10854         FD_SET(httpfd, &wfds);
10855         if (select(FD_SETSIZE, NULL,
10856 #ifdef __DECC
10857 #ifndef __DECC_VER
10858                     (int *)
10859 #endif /* __DECC_VER */
10860 #endif /* __DECC */
10861                    &wfds, NULL, &tv) < 0) {
10862             int s_errno = socket_errno;
10863             debug(F101,"http_tol select failed","",s_errno);
10864 #ifdef BETADEBUG
10865             printf("http_tol select failed: %d\n", s_errno);
10866 #endif /* BETADEBUG */
10867 #ifdef NT
10868             WSASafeToCancel = 0;
10869             if (!win95selectbug)
10870 #endif /* NT */
10871               return(-1);
10872         }
10873         if (!FD_ISSET(httpfd, &wfds)) {
10874 #ifdef STREAMING
10875             if (streaming)
10876               goto do_select;
10877 #endif /* STREAMING */
10878             debug(F111,"http_tol","!FD_ISSET",ttyfd);
10879 #ifdef NT
10880             WSASafeToCancel = 0;
10881             if (!win95selectbug)
10882 #endif /* NT */
10883               return(-1);
10884         }
10885 #ifdef NT
10886         WSASafeToCancel = 0;
10887 #endif /* NT */
10888 #else /* BSDSELECT */
10889 #ifdef IBMSELECT
10890         {
10891             int tries = 0;
10892             debug(F101,"http_tol IBMSELECT","",0);
10893             while (select(&httpfd, 0, 1, 0, 1000) != 1) {
10894                 int count;
10895                 if (tries++ >= 60) {
10896                     /* if after 60 seconds we can't get permission to write */
10897                     debug(F101,"http_tol select failed","",socket_errno);
10898                     return(-1);
10899                 }
10900 #ifdef COMMENT
10901                 if ((count = http_tchk()) < 0) {
10902                     debug(F111,"http_tol","http_tchk()",count);
10903                     return(count);
10904                 }
10905 #endif /* COMMENT */
10906             }
10907         }
10908 #endif /* IBMSELECT */
10909 #endif /* BSDSELECT */
10910 #ifdef TCPIPLIB
10911         if ((count = socket_write(httpfd,s,n)) < 0) {
10912             int s_errno = socket_errno; /* maybe a function */
10913             debug(F101,"http_tol socket_write error","",s_errno);
10914 #ifdef OS2
10915             if (os2socketerror(s_errno) < 0)
10916               return(-2);
10917 #endif /* OS2 */
10918             return(-1);                 /* Call it an i/o error */
10919         }
10920 #else /* TCPIPLIB */
10921         if ((count = write(httpfd,s,n)) < 0) {
10922             debug(F101,"http_tol socket_write error","",errno);
10923             return(-1);                 /* Call it an i/o error */
10924         }
10925 #endif /* TCPIPLIB */
10926         if (count < n) {
10927             debug(F111,"http_tol socket_write",s,count);
10928             if (try > 25) {
10929                 /* don't try more than 25 times */
10930                 debug(F100,"http_tol tried more than 25 times","",0);
10931                 return(-1);
10932             }
10933             if (count > 0) {
10934                 s += count;
10935                 n -= count;
10936             }
10937             debug(F111,"http_tol retry",s,n);
10938             goto http_tol_retry;
10939         } else {
10940             debug(F111,"http_tol socket_write",s,count);
10941             return(len); /* success - return total length */
10942         }
10943     }
10944 }
10945
10946
10947 int
10948 http_inc(timo) int timo; {
10949     int x=-1; unsigned char c;             /* The locals. */
10950
10951     if (httpfd == -1) {
10952         debug(F100,"http_inc socket is closed","",0);
10953         return(-2);
10954     }
10955
10956 #ifdef CK_SSL
10957     /*
10958      * In the case of OpenSSL, it is possible that there is still
10959      * data waiting in the SSL session buffers that has not yet
10960      * been read by Kermit.  If this is the case we must process
10961      * it without calling select() because select() will not return
10962      * with an indication that there is data to be read from the
10963      * socket.  If there is no data pending in the SSL session
10964      * buffers then fall through to the select() code and wait for
10965      * some data to arrive.
10966      */
10967     if (tls_http_active_flag) {
10968         int error;
10969
10970         x = SSL_pending(tls_http_con);
10971         if (x < 0) {
10972             debug(F111,"http_inc","SSL_pending error",x);
10973             http_close();
10974             return(-1);
10975         } else if ( x > 0 ) {
10976           ssl_read:
10977             x = SSL_read(tls_http_con, &c, 1);
10978             error = SSL_get_error(tls_http_con,x);
10979             switch (error) {
10980             case SSL_ERROR_NONE:
10981                 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
10982                 if (x > 0) {
10983 #ifdef OS2
10984                     ReleaseTCPIPMutex();
10985 #endif /* OS2 */
10986                     return(c);          /* Return character. */
10987                 } else if (x < 0) {
10988 #ifdef OS2
10989                     ReleaseTCPIPMutex();
10990 #endif /* OS2 */
10991                     return(-1);
10992                 } else {
10993                     http_close();
10994 #ifdef OS2
10995                     ReleaseTCPIPMutex();
10996 #endif /* OS2 */
10997                     return(-2);
10998                 }
10999             case SSL_ERROR_WANT_WRITE:
11000                 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11001 #ifdef OS2
11002                 ReleaseTCPIPMutex();
11003 #endif /* OS2 */
11004                 return(-1);
11005             case SSL_ERROR_WANT_READ:
11006                 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11007 #ifdef OS2
11008                 ReleaseTCPIPMutex();
11009 #endif /* OS2 */
11010                 return(-1);
11011             case SSL_ERROR_SYSCALL:
11012                 if ( x == 0 ) { /* EOF */
11013                     http_close();
11014 #ifdef OS2
11015                     ReleaseTCPIPMutex();
11016 #endif /* OS2 */
11017                     return(-2);
11018                 } else {
11019                     int rc = -1;
11020 #ifdef NT
11021                     int gle = GetLastError();
11022                     debug(F111,"http_inc SSL_ERROR_SYSCALL",
11023                            "GetLastError()",gle);
11024                     rc = os2socketerror(gle);
11025                     if (rc == -1)
11026                         rc = -2;
11027                     else if ( rc == -2 )
11028                         rc = -1;
11029 #endif /* NT */
11030 #ifdef OS2
11031                     ReleaseTCPIPMutex();
11032 #endif /* OS2 */
11033                     return(rc);
11034                 }
11035             case SSL_ERROR_WANT_X509_LOOKUP:
11036                 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11037                 http_close();
11038 #ifdef OS2
11039                 ReleaseTCPIPMutex();
11040 #endif /* OS2 */
11041                 return(-2);
11042             case SSL_ERROR_SSL:
11043                 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11044 #ifdef COMMENT
11045                 http_close();
11046 #endif /* COMMENT */
11047 #ifdef OS2
11048                 ReleaseTCPIPMutex();
11049 #endif /* OS2 */
11050                 return(-2);
11051             case SSL_ERROR_ZERO_RETURN:
11052                 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11053                 http_close();
11054 #ifdef OS2
11055                 ReleaseTCPIPMutex();
11056 #endif /* OS2 */
11057                 return(-2);
11058             default:
11059                 debug(F100,"http_inc SSL_ERROR_?????","",0);
11060                 http_close();
11061 #ifdef OS2
11062                 ReleaseTCPIPMutex();
11063 #endif /* OS2 */
11064                 return(-2);
11065             }
11066         }
11067     }
11068 #endif /* CK_SSL */
11069     {
11070 #ifdef BSDSELECT
11071         fd_set rfds;
11072         struct timeval tv;
11073         int timeout = timo < 0 ? -timo : 1000 * timo;
11074         debug(F101,"http_inc BSDSELECT","",timo);
11075
11076         for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11077             int rc;
11078             debug(F111,"http_inc","timeout",timeout);
11079             /* Don't move select() initialization out of the loop. */
11080             FD_ZERO(&rfds);
11081             FD_SET(httpfd, &rfds);
11082             tv.tv_sec  = tv.tv_usec = 0L;
11083             if (timo)
11084                 tv.tv_usec = (long) 100000L;
11085             else
11086                 tv.tv_sec = 30;
11087 #ifdef NT
11088             WSASafeToCancel = 1;
11089 #endif /* NT */
11090             rc = select(FD_SETSIZE,
11091 #ifndef __DECC
11092                          (fd_set *)
11093 #endif /* __DECC */
11094                          &rfds, NULL, NULL, &tv);
11095             if (rc < 0) {
11096                 int s_errno = socket_errno;
11097                 debug(F111,"http_inc","select",rc);
11098                 debug(F111,"http_inc","socket_errno",s_errno);
11099                 if (s_errno)
11100                     return(-1);
11101             }
11102             debug(F111,"http_inc","select",rc);
11103 #ifdef NT
11104             WSASafeToCancel = 0;
11105 #endif /* NT */
11106             if (FD_ISSET(httpfd, &rfds)) {
11107                 x = 0;
11108                 break;
11109             } else {
11110                 /* If waiting forever we have no way of knowing if the */
11111                 /* socket closed so try writing a 0-length TCP packet  */
11112                 /* which should force an error if the socket is closed */
11113                 if (!timo) {
11114 #ifdef TCPIPLIB
11115                     if ((rc = socket_write(httpfd,"",0)) < 0) {
11116                         int s_errno = socket_errno;
11117                         debug(F101,"http_inc socket_write error","",s_errno);
11118 #ifdef OS2
11119                         if (os2socketerror(s_errno) < 0)
11120                             return(-2);
11121 #endif /* OS2 */
11122                         return(-1); /* Call it an i/o error */
11123                     }
11124 #else /* TCPIPLIB */
11125                     if ((rc = write(httpfd,"",0)) < 0) {
11126                         debug(F101,"http_inc socket_write error","",errno);
11127                         return(-1); /* Call it an i/o error */
11128                     }
11129 #endif /* TCPIPLIB */
11130                 }
11131                 continue;
11132             }
11133         }
11134 #ifdef NT
11135         WSASafeToCancel = 0;
11136 #endif /* NT */
11137 #else /* !BSDSELECT */
11138 #ifdef IBMSELECT
11139  /*
11140   Was used by OS/2, currently not used, but might come in handy some day...
11141   ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
11142   and timeval stuff since this is the only place where it is used.
11143  */
11144         int socket = httpfd;
11145         int timeout = timo < 0 ? -timo : 1000 * timo;
11146
11147         debug(F101,"http_inc IBMSELECT","",timo);
11148         for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11149             if (select(&socket, 1, 0, 0, 100L) == 1) {
11150                 x = 0;
11151                 break;
11152             }
11153         }
11154 #else /* !IBMSELECT */
11155         SELECT is required for this code
11156 #endif /* IBMSELECT */
11157 #endif /* BSDSELECT */
11158     }
11159
11160     if (timo && x < 0) {        /* select() timed out */
11161         debug(F100,"http_inc select() timed out","",0);
11162         return(-1); /* Call it an i/o error */
11163     }
11164
11165 #ifdef CK_SSL
11166         if ( tls_http_active_flag ) {
11167             int error;
11168           ssl_read2:
11169             x = SSL_read(tls_http_con, &c, 1);
11170             error = SSL_get_error(tls_http_con,x);
11171             switch (error) {
11172             case SSL_ERROR_NONE:
11173                 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11174                 if (x > 0) {
11175 #ifdef OS2
11176                     ReleaseTCPIPMutex();
11177 #endif /* OS2 */
11178                     return(c);          /* Return character. */
11179                 } else if (x < 0) {
11180 #ifdef OS2
11181                     ReleaseTCPIPMutex();
11182 #endif /* OS2 */
11183                     return(-1);
11184                 } else {
11185                     http_close();
11186 #ifdef OS2
11187                     ReleaseTCPIPMutex();
11188 #endif /* OS2 */
11189                     return(-2);
11190                 }
11191             case SSL_ERROR_WANT_WRITE:
11192                 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11193 #ifdef OS2
11194                 ReleaseTCPIPMutex();
11195 #endif /* OS2 */
11196                 return(-1);
11197             case SSL_ERROR_WANT_READ:
11198                 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11199 #ifdef OS2
11200                 ReleaseTCPIPMutex();
11201 #endif /* OS2 */
11202                 return(-1);
11203             case SSL_ERROR_SYSCALL:
11204                 if ( x == 0 ) { /* EOF */
11205                     http_close();
11206 #ifdef OS2
11207                     ReleaseTCPIPMutex();
11208 #endif /* OS2 */
11209                     return(-2);
11210                 } else {
11211                     int rc = -1;
11212 #ifdef NT
11213                     int gle = GetLastError();
11214                     debug(F111,"http_inc SSL_ERROR_SYSCALL",
11215                            "GetLastError()",gle);
11216                     rc = os2socketerror(gle);
11217                     if (rc == -1)
11218                         rc = -2;
11219                     else if ( rc == -2 )
11220                         rc = -1;
11221 #endif /* NT */
11222 #ifdef OS2
11223                     ReleaseTCPIPMutex();
11224 #endif /* OS2 */
11225                     return(rc);
11226                 }
11227             case SSL_ERROR_WANT_X509_LOOKUP:
11228                 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11229                 http_close();
11230 #ifdef OS2
11231                 ReleaseTCPIPMutex();
11232 #endif /* OS2 */
11233                 return(-2);
11234             case SSL_ERROR_SSL:
11235                 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11236 #ifdef COMMENT
11237                 http_close();
11238 #endif /* COMMENT */
11239 #ifdef OS2
11240                 ReleaseTCPIPMutex();
11241 #endif /* OS2 */
11242                 return(-2);
11243             case SSL_ERROR_ZERO_RETURN:
11244                 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11245                 http_close();
11246 #ifdef OS2
11247                 ReleaseTCPIPMutex();
11248 #endif /* OS2 */
11249                 return(-2);
11250             default:
11251                 debug(F100,"http_inc SSL_ERROR_?????","",0);
11252                 http_close();
11253 #ifdef OS2
11254                 ReleaseTCPIPMutex();
11255 #endif /* OS2 */
11256                 return(-2);
11257             }
11258         }
11259 #endif /* CK_SSL */
11260 #ifdef TCPIPLIB
11261         x = socket_read(httpfd,&c,1);
11262 #else
11263         x = read(httpfd,&c,1);
11264 #endif
11265
11266         if (x <= 0) {
11267             int s_errno = socket_errno;
11268             debug(F101,"ttbufr socket_read","",x);
11269             debug(F101,"ttbufr socket_errno","",s_errno);
11270 #ifdef OS2
11271             if (x == 0 || os2socketerror(s_errno) < 0) {
11272                 http_close();
11273                 ReleaseTCPIPMutex();
11274                 return(-2);
11275             }
11276             ReleaseTCPIPMutex();
11277             return(-1);
11278 #else /* OS2 */
11279             http_close();                      /* *** *** */
11280             return(-2);
11281 #endif /* OS2 */
11282         }
11283         return(c);
11284 }
11285
11286 void
11287 #ifdef CK_ANSIC
11288 http_set_code_reply(char * msg)
11289 #else
11290 http_set_code_reply(msg)
11291     char * msg;
11292 #endif /* CK_ANSIC */
11293 {
11294     char * p = msg;
11295     char buf[16];
11296     int i=0;
11297
11298     while ( *p != SP && *p != NUL ) {
11299         buf[i] = *p;
11300         p++;
11301         i++;
11302     }
11303
11304     http_code = atoi(buf);
11305
11306     while ( *p == SP )
11307         p++;
11308
11309     ckstrncpy(http_reply_str,p,HTTPBUFLEN);
11310 }
11311
11312 int
11313 #ifdef CK_ANSIC
11314 http_get(char * agent, char ** hdrlist, char * user,
11315          char * pwd, char array, char * local, char * remote,
11316          int stdio)
11317 #else
11318 http_get(agent, hdrlist, user, pwd, array, local, remote, stdio)
11319     char * agent; char ** hdrlist; char * user;
11320     char * pwd; char array; char * local; char * remote;
11321     int stdio;
11322 #endif /* CK_ANSIC */
11323 {
11324     char * request = NULL;
11325     int    i, j, len = 0, hdcnt = 0, rc = 0;
11326     int    ch;
11327     int    http_fnd = 0;
11328     char   buf[HTTPBUFLEN], *p;
11329     int    nullline;
11330 #ifdef OS2
11331     struct utimbuf u_t;
11332 #else /* OS2 */
11333 #ifdef SYSUTIMEH
11334     struct utimbuf u_t;
11335 #else
11336     struct utimbuf {
11337         time_t atime;
11338         time_t mtime;
11339     } u_t;
11340 #endif /* SYSUTIMH */
11341 #endif /* OS2 */
11342     time_t mod_t = 0;
11343     time_t srv_t = 0;
11344     time_t local_t = 0;
11345     char passwd[64];
11346     char b64in[128];
11347     char b64out[256];
11348     char * headers[HTTPHEADCNT];
11349     int closecon = 0;
11350     int chunked = 0;
11351     int zfile = 0;
11352     int first = 1;
11353
11354 #ifdef DEBUG
11355     if (deblog) {
11356         debug(F101,"http_get httpfd","",httpfd);
11357         debug(F110,"http_agent",agent,0);
11358         debug(F110,"http_user",user,0);
11359         debug(F110,"http_local",local,0);
11360         debug(F110,"http_remote",remote,0);
11361     }
11362 #endif /* DEBUG */
11363     if (!remote) remote = "";
11364
11365     if (httpfd == -1)
11366       return(-1);
11367
11368     if (array) {
11369         for (i = 0; i < HTTPHEADCNT; i++)
11370           headers[i] = NULL;
11371     }
11372     len = 8;                            /* GET */
11373     len += strlen(HTTP_VERSION);
11374     len += strlen(remote);
11375     len += 16;
11376
11377     if (hdrlist) {
11378         for (i = 0; hdrlist[i]; i++)
11379             len += strlen(hdrlist[i]) + 2;
11380     }
11381     len += (int) strlen(http_host_port) + 8;
11382
11383     if (agent)
11384       len += 13 + strlen(agent);
11385     if (user) {
11386         if (!pwd) {
11387             readpass("Password: ",passwd,64);
11388             pwd = passwd;
11389         }
11390         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11391         j = b8tob64(b64in,strlen(b64in),b64out,256);
11392         memset(pwd,0,strlen(pwd));      /* NOT PORTABLE */
11393         if (j < 0)
11394           return(-1);
11395         b64out[j] = '\0';
11396         len += j + 24;
11397     }
11398 #ifdef HTTP_CLOSE
11399     len += 19;                          /* Connection: close */
11400 #endif
11401     len += 3;                           /* blank line + null */
11402
11403     request = malloc(len);
11404     if (!request)
11405       return(-1);
11406
11407     sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION);       /* safe */
11408     ckstrncat(request,"Host: ", len);
11409     ckstrncat(request,http_host_port, len);
11410     ckstrncat(request,"\r\n",len);
11411     if (agent) {
11412         ckstrncat(request,"User-agent: ",len);
11413         ckstrncat(request,agent,len);
11414         ckstrncat(request,"\r\n",len);
11415     }
11416     if (user) {
11417         ckstrncat(request,"Authorization: Basic ",len);
11418         ckstrncat(request,b64out,len);
11419         ckstrncat(request,"\r\n",len);
11420     }
11421     if ( hdrlist ) {
11422         for (i = 0; hdrlist[i]; i++) {
11423             ckstrncat(request,hdrlist[i],len);
11424             ckstrncat(request,"\r\n",len);
11425         }
11426     }
11427 #ifdef HTTP_CLOSE
11428     ckstrncat(request,"Connection: close\r\n",len);
11429 #endif
11430     ckstrncat(request,"\r\n",len);
11431
11432   getreq:
11433     if (http_tol((CHAR *)request,strlen(request)) < 0)
11434     {
11435         http_close();
11436         if ( first ) {
11437             first--;
11438             http_reopen();
11439             goto getreq;
11440         }
11441         rc = -1;
11442         goto getexit;
11443     }
11444
11445     /* Process the headers */
11446     local_t = time(NULL);
11447     nullline = 0;
11448     i = 0;
11449     len = -1;
11450     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11451         buf[i] = ch;
11452         if ( buf[i] == 10 ) { /* found end of line */
11453             if (i > 0 && buf[i-1] == 13)
11454               i--;
11455             if (i < 1)
11456               nullline = 1;
11457             buf[i] = '\0';
11458             if (array && !nullline && hdcnt < HTTPHEADCNT)
11459               makestr(&headers[hdcnt++],buf);
11460             if (!ckstrcmp(buf,"HTTP",4,0)) {
11461                 http_fnd = 1;
11462                 j = ckindex(" ",buf,0,0,0);
11463                 p = &buf[j];
11464                 while ( isspace(*p) )
11465                   p++;
11466                 switch ( p[0] ) {
11467                   case '1':             /* Informational message */
11468                     break;
11469                   case '2':             /* Success */
11470                     break;
11471                   case '3':             /* Redirection */
11472                   case '4':             /* Client failure */
11473                   case '5':             /* Server failure */
11474                   default:              /* Unknown */
11475                     if (!quiet)
11476                       printf("Failure: Server reports %s\n",p);
11477                     rc = -1;
11478                     local = NULL;
11479                 }
11480                 http_set_code_reply(p);
11481 #ifdef CMDATE2TM
11482             } else if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11483                 mod_t = http_date(&buf[15]);
11484             } else if (!ckstrcmp(buf,"Date",4,0)) {
11485                 srv_t = http_date(&buf[4]);
11486 #endif /* CMDATE2TM */
11487             } else if (!ckstrcmp(buf,"Connection:",11,0)) {
11488                 if ( ckindex("close",buf,11,0,0) != 0 )
11489                     closecon = 1;
11490             } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11491                 len = atoi(&buf[16]);
11492             } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11493                 if ( ckindex("chunked",buf,18,0,0) != 0 )
11494                     chunked = 1;
11495             }
11496             i = 0;
11497         } else {
11498             i++;
11499         }
11500     }
11501     if (ch < 0 && first) {
11502         first--;
11503         http_close();
11504         http_reopen();
11505         goto getreq;
11506     }
11507     if (http_fnd == 0) {
11508         rc = -1;
11509         closecon = 1;
11510         goto getexit;
11511     }
11512
11513     /* Now we have the contents of the file */
11514     if ( local && local[0] ) {
11515         if (zopeno(ZOFILE,local,NULL,NULL))
11516             zfile = 1;
11517         else
11518             rc = -1;
11519     }
11520
11521     if ( chunked ) {
11522         while ((len = http_get_chunk_len()) > 0) {
11523             while (len && (ch = http_inc(0)) >= 0) {
11524                 len--;
11525                 if ( zfile )
11526                     zchout(ZOFILE,(CHAR)ch);
11527                 if ( stdio )
11528                     conoc((CHAR)ch);
11529             }
11530             if ((ch = http_inc(0)) != CR)
11531                 break;
11532             if ((ch = http_inc(0)) != LF)
11533                 break;
11534         }
11535     } else {
11536         while (len && (ch = http_inc(0)) >= 0) {
11537             len--;
11538             if ( zfile )
11539                 zchout(ZOFILE,(CHAR)ch);
11540             if ( stdio )
11541                 conoc((CHAR)ch);
11542         }
11543     }
11544
11545     if ( zfile )
11546         zclose(ZOFILE);
11547
11548     if ( chunked ) {            /* Parse Trailing Headers */
11549         nullline = 0;
11550         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11551             buf[i] = ch;
11552             if ( buf[i] == 10 ) { /* found end of line */
11553                 if (i > 0 && buf[i-1] == 13)
11554                   i--;
11555                 if (i < 1)
11556                   nullline = 1;
11557                 buf[i] = '\0';
11558                 if (array && !nullline && hdcnt < HTTPHEADCNT)
11559                     makestr(&headers[hdcnt++],buf);
11560 #ifdef CMDATE2TM
11561                 if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11562                     mod_t = http_date(&buf[15]);
11563                 } else if (!ckstrcmp(buf,"Date",4,0)) {
11564                     srv_t = http_date(&buf[4]);
11565                 }
11566 #endif /* CMDATE2TM */
11567                 else if (!ckstrcmp(buf,"Connection:",11,0)) {
11568                     if ( ckindex("close",buf,11,0,0) != 0 )
11569                         closecon = 1;
11570                 }
11571                 i = 0;
11572             } else {
11573                 i++;
11574             }
11575         }
11576     }
11577
11578     if ( zfile ) {              /* Set timestamp */
11579 #ifndef NOSETTIME
11580 #ifdef OS2
11581         u_t.actime = srv_t ? srv_t : local_t;
11582         u_t.modtime = mod_t ? mod_t : local_t;
11583 #else /* OS2 */
11584 #ifdef SYSUTIMEH
11585         u_t.actime = srv_t ? srv_t : local_t;
11586         u_t.modtime = mod_t ? mod_t : local_t;
11587 #else
11588 #ifdef BSD44
11589         u_t[0].tv_sec = srv_t ? srv_t : local_t;
11590         u_t[1].tv_sec = mod_t ? mod_t : local_t;
11591 #else
11592         u_t.mtime = srv_t ? srv_t : local_t;
11593         u_t.atime = mod_t ? mod_t : local_t;
11594 #endif /* BSD44 */
11595 #endif /* SYSUTIMEH */
11596 #endif /* OS2 */
11597             utime(local,&u_t);
11598 #endif /* NOSETTIME */
11599     }
11600
11601   getexit:
11602     if (array)
11603       http_mkarray(headers,hdcnt,array);
11604
11605     if ( closecon )
11606         http_close();
11607     free(request);
11608     for (i = 0; i < hdcnt; i++) {
11609         if (headers[i])
11610           free(headers[i]);
11611     }
11612     return(rc);
11613 }
11614
11615 int
11616 #ifdef CK_ANSIC
11617 http_head(char * agent, char ** hdrlist, char * user,
11618           char * pwd, char array, char * local, char * remote,
11619           int stdio)
11620 #else
11621 http_head(agent, hdrlist, user, pwd, array, local, remote, stdio)
11622     char * agent; char ** hdrlist; char * user;
11623     char * pwd; char array; char * local; char * remote;
11624     int stdio;
11625 #endif /* CK_ANSIC */
11626 {
11627     char * request = NULL;
11628     int    i, j, len = 0, hdcnt = 0, rc = 0;
11629     int    ch;
11630     int    http_fnd = 0;
11631     char   buf[HTTPBUFLEN], *p;
11632     int    nullline;
11633     time_t mod_t;
11634     time_t srv_t;
11635     time_t local_t;
11636     char passwd[64];
11637     char b64in[128];
11638     char b64out[256];
11639     char * headers[HTTPHEADCNT];
11640     int  closecon = 0;
11641     int  first = 1;
11642
11643     if (httpfd == -1)
11644       return(-1);
11645
11646     if (array) {
11647         for (i = 0; i < HTTPHEADCNT; i++)
11648           headers[i] = NULL;
11649     }
11650     len = 9;                            /* HEAD */
11651     len += strlen(HTTP_VERSION);
11652     len += strlen(remote);
11653     len += 16;
11654
11655     if ( hdrlist ) {
11656         for (i = 0; hdrlist[i]; i++)
11657             len += strlen(hdrlist[i]) + 2;
11658     }
11659     len += strlen(http_host_port) + 8;
11660
11661     if (agent)
11662       len += 13 + strlen(agent);
11663     if (user) {
11664         if (!pwd) {
11665             readpass("Password: ",passwd,64);
11666             pwd = passwd;
11667         }
11668         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11669         j = b8tob64(b64in,strlen(b64in),b64out,256);
11670         memset(pwd,0,strlen(pwd));      /* NOT PORTABLE */
11671         if (j < 0)
11672           return(-1);
11673         b64out[j] = '\0';
11674         len += j + 24;
11675     }
11676 #ifdef HTTP_CLOSE
11677     len += 19;                          /* Connection: close */
11678 #endif
11679     len += 3;                           /* blank line + null */
11680
11681     request = (char *)malloc(len);
11682     if (!request)
11683       return(-1);
11684
11685     sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
11686     ckstrncat(request,"Host: ", len);
11687     ckstrncat(request,http_host_port, len);
11688     ckstrncat(request,"\r\n",len);
11689     if (agent) {
11690         ckstrncat(request,"User-agent: ",len);
11691         ckstrncat(request,agent,len);
11692         ckstrncat(request,"\r\n",len);
11693     }
11694     if (user) {
11695         ckstrncat(request,"Authorization: Basic ",len);
11696         ckstrncat(request,b64out,len);
11697         ckstrncat(request,"\r\n",len);
11698     }
11699     if ( hdrlist ) {
11700         for (i = 0; hdrlist[i]; i++) {
11701             ckstrncat(request,hdrlist[i],len);
11702             ckstrncat(request,"\r\n",len);
11703         }
11704     }
11705 #ifdef HTTP_CLOSE
11706     ckstrncat(request,"Connection: close\r\n",len);
11707 #endif
11708     ckstrncat(request,"\r\n",len);
11709
11710     if ( local && local[0] ) {
11711         if (!zopeno(ZOFILE,local,NULL,NULL)) {
11712             free(request);
11713             return(-1);
11714         }
11715     }
11716
11717   headreq:
11718     if (http_tol((CHAR *)request,strlen(request)) < 0)
11719     {
11720         http_close();
11721         if ( first ) {
11722             first--;
11723             http_reopen();
11724             goto headreq;
11725         }
11726         rc = -1;
11727         goto headexit;
11728     }
11729
11730     /* Process the headers */
11731
11732     local_t = time(NULL);
11733     nullline = 0;
11734     i = 0;
11735     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11736         buf[i] = ch;
11737         if (buf[i] == 10) {             /* found end of line */
11738             if (i > 0 && buf[i-1] == 13)
11739               i--;
11740             if (i < 1)
11741               nullline = 1;
11742             buf[i] = '\0';
11743             if (array && !nullline && hdcnt < HTTPHEADCNT)
11744               makestr(&headers[hdcnt++],buf);
11745             if (!ckstrcmp(buf,"HTTP",4,0)) {
11746                 http_fnd = 1;
11747                 j = ckindex(" ",buf,0,0,0);
11748                 p = &buf[j];
11749                 while (isspace(*p))
11750                   p++;
11751                 switch (p[0]) {
11752                   case '1':             /* Informational message */
11753                     break;
11754                   case '2':             /* Success */
11755                     break;
11756                   case '3':             /* Redirection */
11757                   case '4':             /* Client failure */
11758                   case '5':             /* Server failure */
11759                   default:              /* Unknown */
11760                     if (!quiet)
11761                       printf("Failure: Server reports %s\n",p);
11762                     rc = -1;
11763                 }
11764                 http_set_code_reply(p);
11765             } else {
11766                 if (!ckstrcmp(buf,"Connection:",11,0)) {
11767                     if ( ckindex("close",buf,11,0,0) != 0 )
11768                         closecon = 1;
11769                 }
11770                 if ( local && local[0] ) {
11771                     zsout(ZOFILE,buf);
11772                     zsout(ZOFILE,"\r\n");
11773                 }
11774                 if (stdio)
11775                     printf("%s\r\n",buf);
11776             }
11777             i = 0;
11778         } else {
11779             i++;
11780         }
11781     }
11782     if (ch < 0 && first) {
11783         first--;
11784         http_close();
11785         http_reopen();
11786         goto headreq;
11787     }
11788     if ( http_fnd == 0 )
11789         rc = -1;
11790
11791     if (array)
11792       http_mkarray(headers,hdcnt,array);
11793
11794   headexit:
11795     if ( local && local[0] )
11796         zclose(ZOFILE);
11797     if (closecon)
11798         http_close();
11799     free(request);
11800     for (i = 0; i < hdcnt; i++) {
11801         if (headers[i])
11802           free(headers[i]);
11803     }
11804     return(rc);
11805 }
11806
11807 int
11808 #ifdef CK_ANSIC
11809 http_index(char * agent, char ** hdrlist, char * user, char * pwd,
11810              char array, char * local, char * remote, int stdio)
11811 #else
11812 http_index(agent, hdrlist, user, pwd, array, local, remote, stdio)
11813     char * agent; char ** hdrlist; char * user; char * pwd;
11814     char array; char * local; char * remote; int stdio;
11815 #endif /* CK_ANSIC */
11816 {
11817     char * request = NULL;
11818     int    i, j, len = 0, hdcnt = 0, rc = 0;
11819     int    ch;
11820     int    http_fnd = 0;
11821     char   buf[HTTPBUFLEN], *p;
11822     int    nullline;
11823     time_t mod_t;
11824     time_t srv_t;
11825     time_t local_t;
11826     char passwd[64];
11827     char b64in[128];
11828     char b64out[256];
11829     char * headers[HTTPHEADCNT];
11830     int  closecon = 0;
11831     int  chunked = 0;
11832     int  zfile = 0;
11833     int  first = 1;
11834
11835     if (httpfd == -1)
11836       return(-1);
11837
11838     if (array) {
11839         for (i = 0; i < HTTPHEADCNT; i++)
11840           headers[i] = NULL;
11841     }
11842     len = 10;                            /* INDEX */
11843     len += strlen(HTTP_VERSION);
11844     len += strlen(remote);
11845     len += 16;
11846
11847     if ( hdrlist ) {
11848         for (i = 0; hdrlist[i]; i++)
11849             len += strlen(hdrlist[i]) + 2;
11850     }
11851     len += strlen(http_host_port) + 8;
11852
11853     if (agent)
11854         len += 13 + strlen(agent);
11855     if (user) {
11856         if (!pwd) {
11857             readpass("Password: ",passwd,64);
11858             pwd = passwd;
11859         }
11860         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11861         j = b8tob64(b64in,strlen(b64in),b64out,256);
11862         memset(pwd,0,strlen(pwd));
11863         if (j < 0)
11864           return(-1);
11865         b64out[j] = '\0';
11866         len += j + 24;
11867     }
11868 #ifdef HTTP_CLOSE
11869     len += 19;                          /* Connection: close */
11870 #endif
11871     len += 3;                           /* blank line + null */
11872
11873     request = malloc(len);
11874     if (!request)
11875       return(-1);
11876
11877     sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
11878     ckstrncat(request,"Host: ", len);
11879     ckstrncat(request,http_host_port, len);
11880     ckstrncat(request,"\r\n",len);
11881     if (agent) {
11882         ckstrncat(request,"User-agent: ",len);
11883         ckstrncat(request,agent,len);
11884         ckstrncat(request,"\r\n",len);
11885     }
11886     if (user) {
11887         ckstrncat(request,"Authorization: Basic ",len);
11888         ckstrncat(request,b64out,len);
11889         ckstrncat(request,"\r\n",len);
11890     }
11891     if ( hdrlist ) {
11892         for (i = 0; hdrlist[i]; i++) {
11893             ckstrncat(request,hdrlist[i],len);
11894             ckstrncat(request,"\r\n",len);
11895         }
11896     }
11897 #ifdef HTTP_CLOSE
11898     ckstrncat(request,"Connection: close\r\n",len);
11899 #endif
11900     ckstrncat(request,"\r\n",len);
11901   indexreq:
11902     if (http_tol((CHAR *)request,strlen(request)) < 0)
11903     {
11904         http_close();
11905         if ( first ) {
11906             first--;
11907             http_reopen();
11908             goto indexreq;
11909         }
11910         rc = -1;
11911         goto indexexit;
11912     }
11913
11914     /* Process the headers */
11915     local_t = time(NULL);
11916     nullline = 0;
11917     i = 0;
11918     len = -1;
11919     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11920         buf[i] = ch;
11921         if (buf[i] == 10) {             /* found end of line */
11922             if (i > 0 && buf[i-1] == 13)
11923               i--;
11924             if (i < 1)
11925               nullline = 1;
11926             buf[i] = '\0';
11927             if (array && !nullline && hdcnt < HTTPHEADCNT)
11928               makestr(&headers[hdcnt++],buf);
11929             if (!ckstrcmp(buf,"HTTP",4,0)) {
11930                 http_fnd = 1;
11931                 j = ckindex(" ",buf,0,0,0);
11932                 p = &buf[j];
11933                 while (isspace(*p))
11934                   p++;
11935                 switch ( p[0] ) {
11936                   case '1':             /* Informational message */
11937                     break;
11938                   case '2':             /* Success */
11939                     break;
11940                   case '3':             /* Redirection */
11941                   case '4':             /* Client failure */
11942                   case '5':             /* Server failure */
11943                   default:              /* Unknown */
11944                     if (!quiet)
11945                       printf("Failure: Server reports %s\n",p);
11946                     rc = -1;
11947                 }
11948                 http_set_code_reply(p);
11949             } else if ( !nullline ) {
11950                 if (!ckstrcmp(buf,"Connection:",11,0)) {
11951                     if ( ckindex("close",buf,11,0,0) != 0 )
11952                         closecon = 1;
11953                 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11954                     len = atoi(&buf[16]);
11955                 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11956                     if ( ckindex("chunked",buf,18,0,0) != 0 )
11957                         chunked = 1;
11958                 }
11959                 printf("%s\n",buf);
11960             }
11961             i = 0;
11962         } else {
11963             i++;
11964         }
11965     }
11966
11967     if (ch < 0 && first) {
11968         first--;
11969         http_close();
11970         http_reopen();
11971         goto indexreq;
11972     }
11973     if ( http_fnd == 0 ) {
11974         rc = -1;
11975         closecon = 1;
11976         goto indexexit;
11977     }
11978
11979     /* Now we have the contents of the file */
11980     if ( local && local[0] ) {
11981         if (zopeno(ZOFILE,local,NULL,NULL))
11982             zfile = 1;
11983         else
11984             rc = -1;
11985     }
11986
11987     if ( chunked ) {
11988         while ((len = http_get_chunk_len()) > 0) {
11989             while (len && (ch = http_inc(0)) >= 0) {
11990                 len--;
11991                 if ( zfile )
11992                     zchout(ZOFILE,(CHAR)ch);
11993                 if ( stdio )
11994                     conoc((CHAR)ch);
11995             }
11996             if ((ch = http_inc(0)) != CR)
11997                 break;
11998             if ((ch = http_inc(0)) != LF)
11999                 break;
12000         }
12001     } else {
12002         while (len && (ch = http_inc(0)) >= 0) {
12003             len--;
12004             if ( zfile )
12005                 zchout(ZOFILE,(CHAR)ch);
12006             if ( stdio )
12007                 conoc((CHAR)ch);
12008         }
12009     }
12010
12011     if ( zfile )
12012         zclose(ZOFILE);
12013
12014     if ( chunked ) {            /* Parse Trailing Headers */
12015         nullline = 0;
12016         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12017             buf[i] = ch;
12018             if ( buf[i] == 10 ) { /* found end of line */
12019                 if (i > 0 && buf[i-1] == 13)
12020                   i--;
12021                 if (i < 1)
12022                   nullline = 1;
12023                 buf[i] = '\0';
12024                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12025                     makestr(&headers[hdcnt++],buf);
12026                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12027                     if ( ckindex("close",buf,11,0,0) != 0 )
12028                         closecon = 1;
12029                 }
12030                 i = 0;
12031             } else {
12032                 i++;
12033             }
12034         }
12035     }
12036     rc = 0;
12037
12038   indexexit:
12039     if (array)
12040       http_mkarray(headers,hdcnt,array);
12041
12042     if (closecon)
12043         http_close();
12044     free(request);
12045     for (i = 0; i < hdcnt; i++) {
12046         if (headers[i])
12047           free(headers[i]);
12048     }
12049     return(rc);
12050 }
12051
12052 int
12053 #ifdef CK_ANSIC
12054 http_put(char * agent, char ** hdrlist, char * mime, char * user,
12055          char * pwd, char array, char * local, char * remote,
12056          char * dest, int stdio)
12057 #else
12058 http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio)
12059     char * agent; char ** hdrlist; char * mime; char * user;
12060     char * pwd; char array; char * local; char * remote; char * dest;
12061     int stdio;
12062 #endif /* CK_ANSIC */
12063 {
12064     char * request=NULL;
12065     int    i, j, len = 0, hdcnt = 0, rc = 0;
12066     int    ch;
12067     int    http_fnd = 0;
12068     char   buf[HTTPBUFLEN], *p;
12069     int    nullline;
12070     time_t mod_t;
12071     time_t srv_t;
12072     time_t local_t;
12073     char passwd[64];
12074     char b64in[128];
12075     char b64out[256];
12076     int  filelen;
12077     char * headers[HTTPHEADCNT];
12078     int  closecon = 0;
12079     int  chunked = 0;
12080     int  first = 1;
12081     int  zfile = 0;
12082
12083     if (httpfd == -1)
12084       return(-1);
12085     if (!mime) mime = "";
12086     if (!remote) remote = "";
12087     if (!local) local = "";
12088     if (!*local) return(-1);
12089
12090     if (array) {
12091         for (i = 0; i < HTTPHEADCNT; i++)
12092           headers[i] = NULL;
12093     }
12094     filelen = zchki(local);
12095     if (filelen < 0)
12096       return(-1);
12097
12098     /* Compute length of request header */
12099     len = 8;                            /* PUT */
12100     len += strlen(HTTP_VERSION);
12101     len += strlen(remote);
12102     len += 16;
12103
12104     if ( hdrlist ) {
12105         for (i = 0; hdrlist[i]; i++)
12106             len += strlen(hdrlist[i]) + 2;
12107     }
12108     len += strlen(http_host_port) + 8;
12109
12110     if (agent)
12111       len += 13 + strlen(agent);
12112     if (user) {
12113         if (!pwd) {
12114             readpass("Password: ",passwd,64);
12115             pwd = passwd;
12116         }
12117         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12118         j = b8tob64(b64in,strlen(b64in),b64out,256);
12119         memset(pwd,0,strlen(pwd));
12120         if (j < 0)
12121           return(-1);
12122         b64out[j] = '\0';
12123         len += j + 24;
12124     }
12125     len += 16 + strlen(mime);           /* Content-type: */
12126     len += 32;                          /* Content-length: */
12127     len += 32;                          /* Date: */
12128 #ifdef HTTP_CLOSE
12129     len += 19;                          /* Connection: close */
12130 #endif
12131     len += 3;                           /* blank line + null */
12132
12133     request = malloc(len);
12134     if (!request)
12135       return(-1);
12136
12137     sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
12138     ckstrncat(request,"Date: ",len);
12139 #ifdef CMDATE2TM
12140     ckstrncat(request,http_now(),len);
12141 #else
12142     strcat(request,...);
12143 #endif /* CMDATE2TM */
12144     ckstrncat(request,"\r\n",len);
12145     ckstrncat(request,"Host: ", len);
12146     ckstrncat(request,http_host_port, len);
12147     ckstrncat(request,"\r\n",len);
12148     if (agent) {
12149         ckstrncat(request,"User-agent: ",len);
12150         ckstrncat(request,agent,len);
12151         ckstrncat(request,"\r\n",len);
12152     }
12153     if (user) {
12154         ckstrncat(request,"Authorization: Basic ",len);
12155         ckstrncat(request,b64out,len);
12156         ckstrncat(request,"\r\n",len);
12157     }
12158     if ( hdrlist ) {
12159         for (i = 0; hdrlist[i]; i++) {
12160             ckstrncat(request,hdrlist[i],len);
12161             ckstrncat(request,"\r\n",len);
12162         }
12163     }
12164     ckstrncat(request,"Content-type: ",len);
12165     ckstrncat(request,mime,len);
12166     ckstrncat(request,"\r\n",len);
12167     sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12168     ckstrncat(request,buf,len);
12169 #ifdef HTTP_CLOSE
12170     ckstrncat(request,"Connection: close\r\n",len);
12171 #endif
12172     ckstrncat(request,"\r\n",len);
12173
12174     /* Now we have the contents of the file */
12175     if (zopeni(ZIFILE,local)) {
12176
12177       putreq:                           /* Send request */
12178         if (http_tol((CHAR *)request,strlen(request)) <= 0) {
12179             http_close();
12180             if ( first ) {
12181                 first--;
12182                 http_reopen();
12183                 goto putreq;
12184             }
12185             zclose(ZIFILE);
12186             rc = -1;
12187             goto putexit;
12188         }
12189         /* Request headers have been sent */
12190
12191         i = 0;
12192         while (zchin(ZIFILE,&ch) == 0) {
12193             buf[i++] = ch;
12194             if (i == HTTPBUFLEN) {
12195                 if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) {
12196                     http_close();
12197                     if ( first ) {
12198                         first--;
12199                         http_reopen();
12200                         goto putreq;
12201                     }
12202                 }
12203                 i = 0;
12204             }
12205         }
12206         if (i > 0) {
12207             if (http_tol((CHAR *)buf,i) < 0) {
12208                 http_close();
12209                 if ( first ) {
12210                     first--;
12211                     http_reopen();
12212                     goto putreq;
12213                 }
12214             }
12215         }
12216         zclose(ZIFILE);
12217
12218         /* Process the response headers */
12219         local_t = time(NULL);
12220         nullline = 0;
12221         i = 0;
12222         len = -1;
12223         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12224             buf[i] = ch;
12225             if (buf[i] == 10) {         /* found end of line */
12226                 if (i > 0 && buf[i-1] == 13)
12227                   i--;
12228                 if (i < 1)
12229                   nullline = 1;
12230                 buf[i] = '\0';
12231                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12232                   makestr(&headers[hdcnt++],buf);
12233                 if (!ckstrcmp(buf,"HTTP",4,0)) {
12234                     http_fnd = 1;
12235                     j = ckindex(" ",buf,0,0,0);
12236                     p = &buf[j];
12237                     while (isspace(*p))
12238                       p++;
12239                     switch (p[0]) {
12240                       case '1':         /* Informational message */
12241                         break;
12242                       case '2':         /* Success */
12243                         break;
12244                       case '3':         /* Redirection */
12245                       case '4':         /* Client failure */
12246                       case '5':         /* Server failure */
12247                       default:          /* Unknown */
12248                         if (!quiet)
12249                           printf("Failure: Server reports %s\n",p);
12250                         rc = -1;
12251                     }
12252                     http_set_code_reply(p);
12253                 } else {
12254                     if (!ckstrcmp(buf,"Connection:",11,0)) {
12255                         if ( ckindex("close",buf,11,0,0) != 0 )
12256                             closecon = 1;
12257                     } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12258                         len = atoi(&buf[16]);
12259                     } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12260                         if ( ckindex("chunked",buf,18,0,0) != 0 )
12261                             chunked = 1;
12262                     }
12263                     if ( stdio )
12264                         printf("%s\n",buf);
12265                 }
12266                 i = 0;
12267             } else {
12268                 i++;
12269             }
12270         }
12271         if (ch < 0 && first) {
12272             first--;
12273             http_close();
12274             http_reopen();
12275             goto putreq;
12276         }
12277         if ( http_fnd == 0 ) {
12278             closecon = 1;
12279             rc = -1;
12280             goto putexit;
12281         }
12282
12283         /* Any response data? */
12284         if ( dest && dest[0] ) {
12285             if (zopeno(ZOFILE,dest,NULL,NULL))
12286                 zfile = 1;
12287             else
12288                 rc = -1;
12289         }
12290
12291         if ( chunked ) {
12292             while ((len = http_get_chunk_len()) > 0) {
12293                 while (len && (ch = http_inc(0)) >= 0) {
12294                     len--;
12295                     if ( zfile )
12296                         zchout(ZOFILE,(CHAR)ch);
12297                     if ( stdio )
12298                         conoc((CHAR)ch);
12299                 }
12300                 if ((ch = http_inc(0)) != CR)
12301                     break;
12302                 if ((ch = http_inc(0)) != LF)
12303                     break;
12304             }
12305         } else {
12306             while (len && (ch = http_inc(0)) >= 0) {
12307                 len--;
12308                 if ( zfile )
12309                     zchout(ZOFILE,(CHAR)ch);
12310                 if ( stdio )
12311                     conoc((CHAR)ch);
12312             }
12313         }
12314
12315         if ( zfile )
12316             zclose(ZOFILE);
12317
12318         if ( chunked ) {            /* Parse Trailing Headers */
12319             nullline = 0;
12320             while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12321                 buf[i] = ch;
12322                 if ( buf[i] == 10 ) { /* found end of line */
12323                     if (i > 0 && buf[i-1] == 13)
12324                       i--;
12325                     if (i < 1)
12326                       nullline = 1;
12327                     buf[i] = '\0';
12328                     if (array && !nullline && hdcnt < HTTPHEADCNT)
12329                         makestr(&headers[hdcnt++],buf);
12330                     if (!ckstrcmp(buf,"Connection:",11,0)) {
12331                         if ( ckindex("close",buf,11,0,0) != 0 )
12332                             closecon = 1;
12333                     }
12334                     i = 0;
12335                 } else {
12336                     i++;
12337                 }
12338             }
12339         }
12340     } else {
12341         rc = -1;
12342     }
12343
12344   putexit:
12345     if ( array )
12346         http_mkarray(headers,hdcnt,array);
12347
12348     if (closecon)
12349         http_close();
12350     free(request);
12351     for (i = 0; i < hdcnt; i++) {
12352         if (headers[i])
12353           free(headers[i]);
12354     }
12355     return(rc);
12356 }
12357
12358 int
12359 #ifdef CK_ANSIC
12360 http_delete(char * agent, char ** hdrlist, char * user,
12361           char * pwd, char array, char * remote)
12362 #else
12363 http_delete(agent, hdrlist, user, pwd, array, remote)
12364     char * agent; char ** hdrlist; char * user;
12365     char * pwd; char array; char * remote;
12366 #endif /* CK_ANSIC */
12367 {
12368     char * request=NULL;
12369     int    i, j, len = 0, hdcnt = 0, rc = 0;
12370     int    ch;
12371     int    http_fnd = 0;
12372     char   buf[HTTPBUFLEN], *p;
12373     int    nullline;
12374     time_t mod_t;
12375     time_t srv_t;
12376     time_t local_t;
12377     char passwd[64];
12378     char b64in[128];
12379     char b64out[256];
12380     char * headers[HTTPHEADCNT];
12381     int  closecon = 0;
12382     int  chunked = 0;
12383     int  first = 1;
12384
12385     if (httpfd == -1)
12386       return(-1);
12387
12388     if (array) {
12389         for (i = 0; i < HTTPHEADCNT; i++)
12390           headers[i] = NULL;
12391     }
12392
12393     /* Compute length of request header */
12394     len = 11;                            /* DELETE */
12395     len += strlen(HTTP_VERSION);
12396     len += strlen(remote);
12397     len += 16;
12398
12399     if ( hdrlist ) {
12400         for (i = 0; hdrlist[i]; i++)
12401             len += strlen(hdrlist[i]) + 2;
12402     }
12403     len += strlen(http_host_port) + 8;
12404
12405     if (agent)
12406       len += 13 + strlen(agent);
12407     if (user) {
12408         if (!pwd) {
12409             readpass("Password: ",passwd,64);
12410             pwd = passwd;
12411         }
12412         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12413         j = b8tob64(b64in,strlen(b64in),b64out,256);
12414         memset(pwd,0,strlen(pwd));
12415         if (j < 0)
12416           return(-1);
12417         b64out[j] = '\0';
12418         len += j + 24;
12419     }
12420     len += 32;                          /* Date: */
12421 #ifdef HTTP_CLOSE
12422     len += 19;                          /* Connection: close */
12423 #endif
12424     len += 3;                           /* blank line + null */
12425
12426     request = malloc(len);
12427     if (!request)
12428       return(-1);
12429
12430     sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION);
12431     ckstrncat(request,"Date: ",len);
12432 #ifdef CMDATE2TM
12433     ckstrncat(request,http_now(),len);
12434 #else
12435     strcat(request,...);
12436 #endif /* CMDATE2TM */
12437     ckstrncat(request,"\r\n",len);
12438     ckstrncat(request,"Host: ", len);
12439     ckstrncat(request,http_host_port, len);
12440     ckstrncat(request,"\r\n",len);
12441     if (agent) {
12442         ckstrncat(request,"User-agent: ",len);
12443         ckstrncat(request,agent,len);
12444         ckstrncat(request,"\r\n",len);
12445     }
12446     if (user) {
12447         ckstrncat(request,"Authorization: Basic ",len);
12448         ckstrncat(request,b64out,len);
12449         ckstrncat(request,"\r\n",len);
12450     }
12451     if ( hdrlist ) {
12452         for (i = 0; hdrlist[i]; i++) {
12453             ckstrncat(request,hdrlist[i],len);
12454             ckstrncat(request,"\r\n",len);
12455         }
12456     }
12457 #ifdef HTTP_CLOSE
12458     ckstrncat(request,"Connection: close\r\n",len);
12459 #endif
12460     ckstrncat(request,"\r\n",len);
12461   delreq:
12462     if (http_tol((CHAR *)request,strlen(request)) < 0)
12463     {
12464         http_close();
12465         if ( first ) {
12466             first--;
12467             http_reopen();
12468             goto delreq;
12469         }
12470         rc = -1;
12471         goto delexit;
12472     }
12473
12474     /* Process the response headers */
12475     local_t = time(NULL);
12476     nullline = 0;
12477     i = 0;
12478     len = -1;
12479     while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12480         buf[i] = ch;
12481         if (buf[i] == 10) {         /* found end of line */
12482             if (i > 0 && buf[i-1] == 13)
12483               i--;
12484             if (i < 1)
12485               nullline = 1;
12486             buf[i] = '\0';
12487             if (array && !nullline && hdcnt < HTTPHEADCNT)
12488                 makestr(&headers[hdcnt++],buf);
12489             if (!ckstrcmp(buf,"HTTP",4,0)) {
12490                 http_fnd = 1;
12491                 j = ckindex(" ",buf,0,0,0);
12492                 p = &buf[j];
12493                 while (isspace(*p))
12494                   p++;
12495                 switch (p[0]) {
12496                   case '1':             /* Informational message */
12497                     break;
12498                   case '2':             /* Success */
12499                     break;
12500                   case '3':             /* Redirection */
12501                   case '4':             /* Client failure */
12502                   case '5':             /* Server failure */
12503                   default:              /* Unknown */
12504                     if (!quiet)
12505                       printf("Failure: Server reports %s\n",p);
12506                     rc = -1;
12507                 }
12508                 http_set_code_reply(p);
12509             } else {
12510                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12511                     if ( ckindex("close",buf,11,0,0) != 0 )
12512                         closecon = 1;
12513                 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12514                     len = atoi(&buf[16]);
12515                 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12516                     if ( ckindex("chunked",buf,18,0,0) != 0 )
12517                         chunked = 1;
12518                 }
12519                 printf("%s\n",buf);
12520             }
12521             i = 0;
12522         } else {
12523             i++;
12524         }
12525     }
12526     if (ch < 0 && first) {
12527         first--;
12528         http_close();
12529         http_reopen();
12530         goto delreq;
12531     }
12532     if ( http_fnd == 0 ) {
12533         rc = -1;
12534         closecon = 1;
12535         goto delexit;
12536     }
12537
12538     /* Any response data? */
12539     if ( chunked ) {
12540         while ((len = http_get_chunk_len()) > 0) {
12541             while (len && (ch = http_inc(0)) >= 0) {
12542                 len--;
12543                 conoc((CHAR)ch);
12544             }
12545             if ((ch = http_inc(0)) != CR)
12546                 break;
12547             if ((ch = http_inc(0)) != LF)
12548                 break;
12549         }
12550     } else {
12551         while (len && (ch = http_inc(0)) >= 0) {
12552             len--;
12553             conoc((CHAR)ch);
12554         }
12555     }
12556
12557     if ( chunked ) {            /* Parse Trailing Headers */
12558         nullline = 0;
12559         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12560             buf[i] = ch;
12561             if ( buf[i] == 10 ) { /* found end of line */
12562                 if (i > 0 && buf[i-1] == 13)
12563                   i--;
12564                 if (i < 1)
12565                   nullline = 1;
12566                 buf[i] = '\0';
12567                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12568                     makestr(&headers[hdcnt++],buf);
12569                 if (!ckstrcmp(buf,"Connection:",11,0)) {
12570                     if ( ckindex("close",buf,11,0,0) != 0 )
12571                         closecon = 1;
12572                 }
12573                 i = 0;
12574             } else {
12575                 i++;
12576             }
12577         }
12578     }
12579
12580   delexit:
12581     if (array)
12582         http_mkarray(headers,hdcnt,array);
12583
12584     if (closecon)
12585         http_close();
12586     free(request);
12587     for (i = 0; i < hdcnt; i++) {
12588         if (headers[i])
12589           free(headers[i]);
12590     }
12591     return(rc);
12592 }
12593
12594 int
12595 #ifdef CK_ANSIC
12596 http_post(char * agent, char ** hdrlist, char * mime, char * user,
12597           char * pwd, char array, char * local, char * remote,
12598           char * dest, int stdio)
12599 #else
12600 http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest,
12601           stdio)
12602     char * agent; char ** hdrlist; char * mime; char * user;
12603     char * pwd; char array; char * local; char * remote; char * dest;
12604     int stdio;
12605 #endif /* CK_ANSIC */
12606 {
12607     char * request=NULL;
12608     int    i, j, len = 0, hdcnt = 0, rc = 0;
12609     int    ch;
12610     int    http_fnd = 0;
12611     char   buf[HTTPBUFLEN], *p;
12612     int    nullline;
12613     time_t mod_t;
12614     time_t srv_t;
12615     time_t local_t;
12616     char passwd[64];
12617     char b64in[128];
12618     char b64out[256];
12619     int  filelen;
12620     char * headers[HTTPHEADCNT];
12621     int  closecon = 0;
12622     int  chunked = 0;
12623     int  zfile = 0;
12624     int  first = 1;
12625
12626     if (httpfd == -1)
12627       return(-1);
12628
12629     if (array) {
12630         for (i = 0; i < HTTPHEADCNT; i++)
12631           headers[i] = NULL;
12632     }
12633     filelen = zchki(local);
12634     if (filelen < 0)
12635       return(-1);
12636
12637     /* Compute length of request header */
12638     len = 9;                            /* POST */
12639     len += strlen(HTTP_VERSION);
12640     len += strlen(remote);
12641     len += 16;
12642
12643     if ( hdrlist ) {
12644         for (i = 0; hdrlist[i]; i++)
12645             len += strlen(hdrlist[i]) + 2;
12646     }
12647     len += strlen(http_host_port) + 8;
12648
12649     if (agent)
12650       len += 13 + strlen(agent);
12651     if (user) {
12652         if (!pwd) {
12653             readpass("Password: ",passwd,64);
12654             pwd = passwd;
12655         }
12656         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12657         j = b8tob64(b64in,strlen(b64in),b64out,256);
12658         memset(pwd,0,strlen(pwd));
12659         if (j < 0)
12660           return(-1);
12661         b64out[j] = '\0';
12662         len += j + 24;
12663     }
12664     len += 16 + strlen(mime);           /* Content-type: */
12665     len += 32;                          /* Content-length: */
12666     len += 32;                          /* Date: */
12667 #ifdef HTTP_CLOSE
12668     len += 19;                          /* Connection: close */
12669 #endif
12670     len += 3;                           /* blank line + null */
12671
12672     request = malloc(len);
12673     if (!request)
12674       return(-1);
12675
12676     sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
12677     ckstrncat(request,"Date: ",len);
12678     ckstrncat(request,http_now(),len);
12679     ckstrncat(request,"\r\n",len);
12680     ckstrncat(request,"Host: ", len);
12681     ckstrncat(request,http_host_port, len);
12682     ckstrncat(request,"\r\n",len);
12683     if (agent) {
12684         ckstrncat(request,"User-agent: ",len);
12685         ckstrncat(request,agent,len);
12686         ckstrncat(request,"\r\n",len);
12687     }
12688     if (user) {
12689         ckstrncat(request,"Authorization: Basic ",len);
12690         ckstrncat(request,b64out,len);
12691         ckstrncat(request,"\r\n",len);
12692     }
12693     if ( hdrlist ) {
12694         for (i = 0; hdrlist[i]; i++) {
12695             ckstrncat(request,hdrlist[i],len);
12696             ckstrncat(request,"\r\n",len);
12697         }
12698     }
12699     ckstrncat(request,"Content-type: ",len);
12700     ckstrncat(request,mime,len);
12701     ckstrncat(request,"\r\n",len);
12702 #ifdef HTTP_CLOSE
12703     ckstrncat(request,"Connection: close\r\n",len);
12704 #endif
12705     sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12706     ckstrncat(request,buf,len);
12707     ckstrncat(request,"\r\n",len);
12708     ckstrncat(request,"\r\n",len);
12709
12710     /* Now we have the contents of the file */
12711   postopen:
12712     if (zopeni(ZIFILE,local)) {
12713       postreq:
12714         if (http_tol((CHAR *)request,strlen(request)) < 0)
12715         {
12716             http_close();
12717             if ( first ) {
12718                 first--;
12719                 http_reopen();
12720                 goto postreq;
12721             }
12722             rc = -1;
12723             zclose(ZIFILE);
12724             goto postexit;
12725         }
12726
12727         i = 0;
12728         while (zchin(ZIFILE,&ch) == 0) {
12729             buf[i++] = ch;
12730             if (i == HTTPBUFLEN) {
12731                 http_tol((CHAR *)buf,HTTPBUFLEN);
12732                 i = 0;
12733             }
12734         }
12735         if (i > 0)
12736           http_tol((CHAR *)buf,HTTPBUFLEN);
12737         zclose(ZIFILE);
12738
12739         /* Process the response headers */
12740         local_t = time(NULL);
12741         nullline = 0;
12742         i = 0;
12743         len = -1;
12744         while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12745             buf[i] = ch;
12746             if (buf[i] == 10) {         /* found end of line */
12747                 if (i > 0 && buf[i-1] == 13)
12748                   i--;
12749                 if (i < 1)
12750                   nullline = 1;
12751                 buf[i] = '\0';
12752                 if (array && !nullline && hdcnt < HTTPHEADCNT)
12753                   makestr(&headers[hdcnt++],buf);
12754                 if (!ckstrcmp(buf,"HTTP",4,0)) {
12755                     http_fnd = 1;
12756                     j = ckindex(" ",buf,0,0,0);
12757                     p = &buf[j];
12758                     while (isspace(*p))
12759                       p++;
12760                     switch (p[0]) {
12761                       case '1':         /* Informational message */
12762                         break;
12763                       case '2':         /* Success */
12764                         break;
12765                       case '3':         /* Redirection */
12766                       case '4':         /* Client failure */
12767                       case '5':         /* Server failure */
12768                       default:          /* Unknown */
12769                         if (!quiet)
12770                           printf("Failure: Server reports %s\n",p);
12771                         rc = -1;
12772                     }
12773                     http_set_code_reply(p);
12774                 } else {
12775                     if (!ckstrcmp(buf,"Connection:",11,0)) {
12776                         if ( ckindex("close",buf,11,0,0) != 0 )
12777                             closecon = 1;
12778                     } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12779                         len = atoi(&buf[16]);
12780                     } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12781                         if ( ckindex("chunked",buf,18,0,0) != 0 )
12782                             chunked = 1;
12783                     }
12784                     if (stdio)
12785                         printf("%s\n",buf);
12786                 }
12787                 i = 0;
12788             } else {
12789                 i++;
12790             }
12791         }
12792         if (ch < 0 && first) {
12793             first--;
12794             http_close();
12795             http_reopen();
12796             goto postopen;
12797         }
12798         if (http_fnd == 0) {
12799             rc = -1;
12800             closecon = 1;
12801             goto postexit;
12802         }
12803
12804         /* Any response data? */
12805         if ( dest && dest[0] ) {
12806             if (zopeno(ZOFILE,dest,NULL,NULL))
12807                 zfile = 1;
12808             else
12809                 rc = -1;
12810         }
12811
12812         if ( chunked ) {
12813             while ((len = http_get_chunk_len()) > 0) {
12814                 while (len && (ch = http_inc(0)) >= 0) {
12815                     len--;
12816                     if ( zfile )
12817                         zchout(ZOFILE,(CHAR)ch);
12818                     if ( stdio )
12819                         conoc((CHAR)ch);
12820                 }
12821                 if ((ch = http_inc(0)) != CR)
12822                     break;
12823                 if ((ch = http_inc(0)) != LF)
12824                     break;
12825             }
12826         } else {
12827             while (len && (ch = http_inc(0)) >= 0) {
12828                 len--;
12829                 if ( zfile )
12830                     zchout(ZOFILE,(CHAR)ch);
12831                 if ( stdio )
12832                     conoc((CHAR)ch);
12833             }
12834         }
12835
12836         if ( zfile )
12837             zclose(ZOFILE);
12838
12839         if ( chunked ) {            /* Parse Trailing Headers */
12840             nullline = 0;
12841             while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12842                 buf[i] = ch;
12843                 if ( buf[i] == 10 ) { /* found end of line */
12844                     if (i > 0 && buf[i-1] == 13)
12845                       i--;
12846                     if (i < 1)
12847                       nullline = 1;
12848                     buf[i] = '\0';
12849                     if (array && !nullline && hdcnt < HTTPHEADCNT)
12850                         makestr(&headers[hdcnt++],buf);
12851                     if (!ckstrcmp(buf,"Connection:",11,0)) {
12852                         if ( ckindex("close",buf,11,0,0) != 0 )
12853                             closecon = 1;
12854                     }
12855                     i = 0;
12856                 } else {
12857                     i++;
12858                 }
12859             }
12860         }
12861     } else {
12862         rc = -1;
12863     }
12864
12865   postexit:
12866     if (array)
12867         http_mkarray(headers,hdcnt,array);
12868     if (closecon)
12869         http_close();
12870     free(request);
12871     for (i = 0; i < hdcnt; i++) {
12872         if (headers[i])
12873           free(headers[i]);
12874     }
12875     return(rc);
12876 }
12877
12878 int
12879 #ifdef CK_ANSIC
12880 http_connect(int socket, char * agent, char ** hdrlist, char * user,
12881              char * pwd, char array, char * host_port)
12882 #else
12883 http_connect(socket, agent, hdrlist, user, pwd, array, host_port)
12884     int socket;
12885     char * agent; char ** hdrlist; char * user;
12886     char * pwd; char array; char * host_port;
12887 #endif /* CK_ANSIC */
12888 {
12889     char * request=NULL;
12890     int    i, j, len = 0, hdcnt = 0, rc = 0;
12891     int    http_fnd = 0;
12892     char   buf[HTTPBUFLEN], *p, ch;
12893     int    nullline;
12894     time_t mod_t;
12895     time_t srv_t;
12896     time_t local_t;
12897     char passwd[64];
12898     char b64in[128];
12899     char b64out[256];
12900     char * headers[HTTPHEADCNT];
12901     int    connected = 0;
12902     int    chunked = 0;
12903
12904     tcp_http_proxy_errno = 0;
12905
12906     if (socket == -1)
12907       return(-1);
12908
12909     if (array) {
12910         for (i = 0; i < HTTPHEADCNT; i++)
12911           headers[i] = NULL;
12912     }
12913
12914     /* Compute length of request header */
12915     len = 12;                            /* CONNECT */
12916     len += strlen(HTTP_VERSION);
12917     len += strlen(host_port);
12918     len += (int) strlen(http_host_port) + 8;
12919     len += 16;
12920     len += strlen("Proxy-Connection: Keep-Alive\r\n");
12921     if ( hdrlist ) {
12922         for (i = 0; hdrlist[i]; i++)
12923             len += strlen(hdrlist[i]) + 2;
12924     }
12925     if (agent && agent[0])
12926       len += 13 + strlen(agent);
12927     if (user && user[0]) {
12928         if (!pwd) {
12929             readpass("Password: ",passwd,64);
12930             pwd = passwd;
12931         }
12932         ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12933         j = b8tob64(b64in,strlen(b64in),b64out,256);
12934         memset(pwd,0,strlen(pwd));
12935         if (j < 0)
12936           return(-1);
12937         b64out[j] = '\0';
12938         len += j + 72;
12939     }
12940     len += 32;                          /* Date: */
12941     len += 3;                           /* blank line + null */
12942
12943     request = malloc(len);
12944     if (!request)
12945       return(-1);
12946
12947     sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION);
12948     ckstrncat(request,"Date: ",len);
12949 #ifdef CMDATE2TM
12950     ckstrncat(request,http_now(),len);
12951 #else
12952     strcat(request,...);
12953 #endif /* CMDATE2TM */
12954     ckstrncat(request,"\r\n",len);
12955     ckstrncat(request,"Host: ", len);
12956     ckstrncat(request,http_host_port, len);
12957     ckstrncat(request,"\r\n",len);
12958     if (agent && agent[0]) {
12959         ckstrncat(request,"User-agent: ",len);
12960         ckstrncat(request,agent,len);
12961         ckstrncat(request,"\r\n",len);
12962     }
12963     if (user && user[0]) {
12964         ckstrncat(request,"Proxy-authorization: Basic ",len);
12965         ckstrncat(request,b64out,len);
12966         ckstrncat(request,"\r\n",len);
12967         ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len);
12968     }
12969     ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len);
12970     if ( hdrlist ) {
12971         for (i = 0; hdrlist[i]; i++) {
12972             ckstrncat(request,hdrlist[i],len);
12973             ckstrncat(request,"\r\n",len);
12974         }
12975     }
12976     ckstrncat(request,"\r\n",len);
12977     len = strlen(request);
12978
12979 #ifdef TCPIPLIB
12980     /* Send request */
12981     if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) {
12982       rc = -1;
12983       goto connexit;
12984     }
12985 #else
12986     if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */
12987         rc = -1;
12988         goto connexit;
12989     }
12990 #endif /* TCPIPLIB */
12991
12992     /* Process the response headers */
12993     local_t = time(NULL);
12994     nullline = 0;
12995     i = 0;
12996     while (!nullline &&
12997 #ifdef TCPIPLIB
12998            (socket_read(socket,&ch,1) == 1) &&
12999 #else
13000            (read(socket,&ch,1) == 1) &&
13001 #endif /* TCPIPLIB */
13002            i < HTTPBUFLEN) {
13003         buf[i] = ch;
13004         if (buf[i] == 10) {         /* found end of line */
13005             if (i > 0 && buf[i-1] == 13)
13006               i--;
13007             if (i < 1)
13008               nullline = 1;
13009             buf[i] = '\0';
13010
13011             if (array && !nullline && hdcnt < HTTPHEADCNT)
13012                 makestr(&headers[hdcnt++],buf);
13013             if (!ckstrcmp(buf,"HTTP",4,0)) {
13014                 http_fnd = 1;
13015                 j = ckindex(" ",buf,0,0,0);
13016                 p = &buf[j];
13017                 while (isspace(*p))
13018                   p++;
13019                 tcp_http_proxy_errno = atoi(p);
13020                 switch (p[0]) {
13021                   case '1':             /* Informational message */
13022                     break;
13023                   case '2':             /* Success */
13024                     connected = 1;
13025                     break;
13026                   case '3':             /* Redirection */
13027                   case '4':             /* Client failure */
13028                   case '5':             /* Server failure */
13029                   default:              /* Unknown */
13030                     if (!quiet)
13031                       printf("Failure: Server reports %s\n",p);
13032                     rc = -1;
13033                 }
13034                 http_set_code_reply(p);
13035             } else {
13036                 printf("%s\n",buf);
13037             }
13038             i = 0;
13039         } else {
13040             i++;
13041         }
13042     }
13043     if ( http_fnd == 0 )
13044         rc = -1;
13045
13046     if (array)
13047         http_mkarray(headers,hdcnt,array);
13048
13049   connexit:
13050     if ( !connected ) {
13051         if ( socket == ttyfd ) {
13052             ttclos(0);
13053         }
13054         else if ( socket == httpfd ) {
13055             http_close();
13056         }
13057     }
13058
13059     free(request);
13060     for (i = 0; i < hdcnt; i++) {
13061         if (headers[i])
13062           free(headers[i]);
13063     }
13064     return(rc);
13065 }
13066 #endif /* NOHTTP */
13067
13068 #ifdef CK_DNS_SRV
13069
13070 #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
13071 #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
13072 #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
13073
13074 #ifndef CKQUERYTYPE
13075 #ifdef UNIXWARE
13076 #ifndef UW7
13077 #define CKQUERYTYPE CHAR
13078 #endif /* UW7 */
13079 #endif /* UNIXWARE */
13080 #endif /* CKQUERYTYPE */
13081
13082 #ifndef CKQUERYTYPE
13083 #define CKQUERYTYPE char
13084 #endif /* CKQUERYTYPE */
13085
13086 /* 1 is success, 0 is failure */
13087 int
13088 locate_srv_dns(host, service, protocol, addr_pp, naddrs)
13089     char *host;
13090     char *service;
13091     char *protocol;
13092     struct sockaddr **addr_pp;
13093     int *naddrs;
13094 {
13095     int nout, j, count;
13096     union {
13097         unsigned char bytes[2048];
13098         HEADER hdr;
13099     } answer;
13100     unsigned char *p=NULL;
13101     CKQUERYTYPE query[MAX_DNS_NAMELEN];
13102 #ifdef CK_ANSIC
13103     const char * h;
13104 #else
13105     char * h;
13106 #endif /* CK_ANSIC */
13107     struct sockaddr *addr = NULL;
13108     struct sockaddr_in *sin = NULL;
13109     struct hostent *hp = NULL;
13110     int type, class;
13111     int priority, weight, size, len, numanswers, numqueries, rdlen;
13112     unsigned short port;
13113 #ifdef CK_ANSIC
13114     const
13115 #endif /* CK_ANSIC */
13116       int hdrsize = sizeof(HEADER);
13117     struct srv_dns_entry {
13118         struct srv_dns_entry *next;
13119         int priority;
13120         int weight;
13121         unsigned short port;
13122         char *host;
13123     };
13124     struct srv_dns_entry *head = NULL;
13125     struct srv_dns_entry *srv = NULL, *entry = NULL;
13126     char * s = NULL;
13127
13128     nout = 0;
13129     addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
13130     if (addr == NULL)
13131       return 0;
13132
13133     count = 1;
13134
13135     /*
13136      * First build a query of the form:
13137      *
13138      *   service.protocol.host
13139      *
13140      * which will most likely be something like:
13141      *
13142      *   _telnet._tcp.host
13143      *
13144      */
13145     if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
13146         > MAX_DNS_NAMELEN
13147         )
13148       goto dnsout;
13149
13150     /* Realm names don't (normally) end with ".", but if the query
13151        doesn't end with "." and doesn't get an answer as is, the
13152        resolv code will try appending the local domain.  Since the
13153        realm names are absolutes, let's stop that.
13154
13155        But only if a name has been specified.  If we are performing
13156        a search on the prefix alone then the intention is to allow
13157        the local domain or domain search lists to be expanded.
13158     */
13159     h = host + strlen (host);
13160     ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host,
13161               ((h > host) && (h[-1] != '.')?".":NULL),
13162                NULL,NULL,NULL,NULL,NULL);
13163
13164     size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
13165
13166     if (size < hdrsize)
13167       goto dnsout;
13168
13169     /* We got a reply - See how many answers it contains. */
13170
13171     p = answer.bytes;
13172
13173     numqueries = ntohs(answer.hdr.qdcount);
13174     numanswers = ntohs(answer.hdr.ancount);
13175
13176     p += sizeof(HEADER);
13177
13178     /*
13179      * We need to skip over all of the questions, so we have to iterate
13180      * over every query record.  dn_expand() is able to tell us the size
13181      * of compressed DNS names, so we use it.
13182      */
13183     while (numqueries--) {
13184         len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13185         if (len < 0)
13186           goto dnsout;
13187         INCR_CHECK(p, len + 4);
13188     }
13189
13190     /*
13191      * We're now pointing at the answer records.  Only process them if
13192      * they're actually T_SRV records (they might be CNAME records,
13193      * for instance).
13194      *
13195      * But in a DNS reply, if you get a CNAME you always get the associated
13196      * "real" RR for that CNAME.  RFC 1034, 3.6.2:
13197      *
13198      * CNAME RRs cause special action in DNS software.  When a name server
13199      * fails to find a desired RR in the resource set associated with the
13200      * domain name, it checks to see if the resource set consists of a CNAME
13201      * record with a matching class.  If so, the name server includes the CNAME
13202      * record in the response and restarts the query at the domain name
13203      * specified in the data field of the CNAME record.  The one exception to
13204      * this rule is that queries which match the CNAME type are not restarted.
13205      *
13206      * In other words, CNAMEs do not need to be expanded by the client.
13207      */
13208     while (numanswers--) {
13209
13210         /* First is the name; use dn_expand() to get the compressed size. */
13211         len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13212         if (len < 0)
13213           goto dnsout;
13214         INCR_CHECK(p, len);
13215
13216         CHECK(p,2);                     /* Query type */
13217         type = NTOHSP(p,2);
13218
13219         CHECK(p, 6);                    /* Query class */
13220         class = NTOHSP(p,6);            /* Also skip over 4-byte TTL */
13221
13222         CHECK(p,2);                     /* Record data length */
13223         rdlen = NTOHSP(p,2);
13224         /*
13225          * If this is an SRV record, process it.  Record format is:
13226          *
13227          * Priority
13228          * Weight
13229          * Port
13230          * Server name
13231          */
13232         if (class == C_IN && type == T_SRV) {
13233             CHECK(p,2);
13234             priority = NTOHSP(p,2);
13235             CHECK(p, 2);
13236             weight = NTOHSP(p,2);
13237             CHECK(p, 2);
13238             port = NTOHSP(p,2);
13239             len = dn_expand(answer.
13240                             bytes,
13241                             answer.bytes + size,
13242                             p,
13243                             query,
13244                             sizeof(query)
13245                             );
13246             if (len < 0)
13247               goto dnsout;
13248             INCR_CHECK(p, len);
13249             /*
13250              * We got everything.  Insert it into our list, but make sure
13251              * it's in the right order.  Right now we don't do anything
13252              * with the weight field
13253              */
13254             srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
13255             if (srv == NULL)
13256               goto dnsout;
13257
13258             srv->priority = priority;
13259             srv->weight = weight;
13260             srv->port = port;
13261             makestr(&s,(char *)query);  /* strdup() is not portable */
13262             srv->host = s;
13263
13264             if (head == NULL || head->priority > srv->priority) {
13265                 srv->next = head;
13266                 head = srv;
13267             } else
13268                 /*
13269                  * Confusing.  Insert an entry into this spot only if:
13270                  *  . The next person has a higher priority (lower
13271                  *    priorities are preferred), or:
13272                  *  . There is no next entry (we're at the end)
13273                  */
13274               for (entry = head; entry != NULL; entry = entry->next)
13275                 if ((entry->next &&
13276                      entry->next->priority > srv->priority) ||
13277                     entry->next == NULL) {
13278                     srv->next = entry->next;
13279                     entry->next = srv;
13280                     break;
13281                 }
13282         } else
13283           INCR_CHECK(p, rdlen);
13284     }
13285
13286     /*
13287      * Now we've got a linked list of entries sorted by priority.
13288      * Start looking up A records and returning addresses.
13289      */
13290     if (head == NULL)
13291       goto dnsout;
13292
13293     for (entry = head; entry != NULL; entry = entry->next) {
13294         hp = gethostbyname(entry->host);
13295         if (hp != 0) {
13296
13297             /* Watch out - memset() and memcpy() are not portable... */
13298
13299             switch (hp->h_addrtype) {
13300               case AF_INET:
13301                 for (j = 0; hp->h_addr_list[j]; j++) {
13302                     sin = (struct sockaddr_in *) &addr[nout++];
13303                     memset ((char *) sin, 0, sizeof (struct sockaddr));
13304                     sin->sin_family = hp->h_addrtype;
13305                     sin->sin_port = htons(entry->port);
13306                     memcpy((char *) &sin->sin_addr,
13307                            (char *) hp->h_addr_list[j],
13308                            sizeof(struct in_addr));             /* safe */
13309                     if (nout + 1 >= count) {
13310                         count += 5;
13311                         addr = (struct sockaddr *)
13312                           realloc((char *) addr,
13313                                   sizeof(struct sockaddr) * count);
13314                         if (!addr)
13315                           goto dnsout;
13316                     }
13317                 }
13318                 break;
13319               default:
13320                 break;
13321             }
13322         }
13323     }
13324     for (entry = head; entry != NULL;) {
13325         free(entry->host);
13326         entry->host = NULL;
13327         srv = entry;
13328         entry = entry->next;
13329         free(srv);
13330         srv = NULL;
13331     }
13332
13333   dnsout:
13334     if (srv)
13335       free(srv);
13336
13337     if (nout == 0) {                    /* No good servers */
13338         if (addr)
13339           free(addr);
13340         return 0;
13341     }
13342     *addr_pp = addr;
13343     *naddrs = nout;
13344     return 1;
13345 }
13346 #undef INCR_CHECK
13347 #undef CHECK
13348 #undef NTOHSP
13349
13350 #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
13351                          return 0
13352 #define CHECK(x, y) if (x + y > size + answer.bytes) \
13353                          return 0
13354 #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
13355
13356 int
13357 locate_txt_rr(prefix, name, retstr)
13358     char *prefix, *name;
13359     char **retstr;
13360 {
13361     union {
13362         unsigned char bytes[2048];
13363         HEADER hdr;
13364     } answer;
13365     unsigned char *p;
13366     char host[MAX_DNS_NAMELEN], *h;
13367     int size;
13368     int type, class, numanswers, numqueries, rdlen, len;
13369
13370     /*
13371      * Form our query, and send it via DNS
13372      */
13373
13374     if (name == NULL || name[0] == '\0') {
13375         strcpy(host,prefix);
13376     } else {
13377         if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
13378             return 0;
13379
13380         /* Realm names don't (normally) end with ".", but if the query
13381            doesn't end with "." and doesn't get an answer as is, the
13382            resolv code will try appending the local domain.  Since the
13383            realm names are absolutes, let's stop that.
13384
13385            But only if a name has been specified.  If we are performing
13386            a search on the prefix alone then the intention is to allow
13387            the local domain or domain search lists to be expanded.
13388         */
13389         h = host + strlen (host);
13390         ckmakmsg(host,sizeof(host),prefix, ".", name,
13391                  ((h > host) && (h[-1] != '.'))?".":NULL);
13392
13393     }
13394     size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
13395
13396     if (size < 0)
13397         return 0;
13398
13399     p = answer.bytes;
13400
13401     numqueries = ntohs(answer.hdr.qdcount);
13402     numanswers = ntohs(answer.hdr.ancount);
13403
13404     p += sizeof(HEADER);
13405
13406     /*
13407      * We need to skip over the questions before we can get to the answers,
13408      * which means we have to iterate over every query record.  We use
13409      * dn_expand to tell us how long each compressed name is.
13410      */
13411
13412     while (numqueries--) {
13413         len = dn_expand(answer.bytes, answer.bytes + size, p, host,
13414                          sizeof(host));
13415         if (len < 0)
13416             return 0;
13417         INCR_CHECK(p, len + 4);         /* Name plus type plus class */
13418     }
13419
13420     /*
13421      * We're now pointing at the answer records.  Process the first
13422      * TXT record we find.
13423      */
13424
13425     while (numanswers--) {
13426
13427         /* First the name; use dn_expand to get the compressed size */
13428         len = dn_expand(answer.bytes, answer.bytes + size, p,
13429                         host, sizeof(host));
13430         if (len < 0)
13431             return 0;
13432         INCR_CHECK(p, len);
13433
13434         /* Next is the query type */
13435         CHECK(p, 2);
13436         type = NTOHSP(p,2);
13437
13438         /* Next is the query class; also skip over 4 byte TTL */
13439         CHECK(p,6);
13440         class = NTOHSP(p,6);
13441
13442         /* Record data length - make sure we aren't truncated */
13443
13444         CHECK(p,2);
13445         rdlen = NTOHSP(p,2);
13446
13447         if (p + rdlen > answer.bytes + size)
13448             return 0;
13449
13450         /*
13451          * If this is a TXT record, return the string.  Note that the
13452          * string has a 1-byte length in the front
13453          */
13454         /* XXX What about flagging multiple TXT records as an error?  */
13455
13456         if (class == C_IN && type == T_TXT) {
13457             len = *p++;
13458             if (p + len > answer.bytes + size)
13459                 return 0;
13460             *retstr = malloc(len + 1);
13461             if (*retstr == NULL)
13462                 return ENOMEM;
13463             strncpy(*retstr, (char *) p, len);
13464             (*retstr)[len] = '\0';
13465             /* Avoid a common error. */
13466             if ( (*retstr)[len-1] == '.' )
13467                 (*retstr)[len-1] = '\0';
13468             return 1;
13469         }
13470     }
13471
13472     return 0;
13473 }
13474 #undef INCR_CHECK
13475 #undef CHECK
13476 #undef NTOHSP
13477 #endif /* CK_DNS_SRV */
13478
13479 #ifdef TNCODE
13480 #ifdef CK_FORWARD_X
13481 #ifdef UNIX
13482 #include <sys/un.h>
13483 #define FWDX_UNIX_SOCK
13484 #ifndef AF_LOCAL
13485 #define AF_LOCAL AF_UNIX
13486 #endif
13487 #ifndef PF_LOCAL
13488 #define PF_LOCAL PF_UNIX
13489 #endif
13490 #ifndef SUN_LEN
13491 /* Evaluate to actual length of the `sockaddr_un' structure.  */
13492 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)         \
13493                       + strlen ((ptr)->sun_path))
13494 #endif
13495 #endif /* UNIX */
13496 int
13497 fwdx_create_listen_socket(screen) int screen; {
13498 #ifdef NOPUTENV
13499     return(-1);
13500 #else /* NOPUTENV */
13501     struct sockaddr_in saddr;
13502     int display, port, sock=-1, i;
13503     static char env[512];
13504
13505     /*
13506      * X Windows Servers support multiple displays by listening on
13507      * one socket per display.  Display 0 is port 6000; Display 1 is
13508      * port 6001; etc.
13509      *
13510      * We start by trying to open port 6001 so that display 0 is
13511      * reserved for the local X Windows Server.
13512      */
13513
13514     for ( display=1; display < 1000 ; display++  ) {
13515
13516         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13517             debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
13518             return(-1);
13519         }
13520
13521         port = 6000 + display;
13522         bzero((char *)&saddr, sizeof(saddr));
13523         saddr.sin_family = AF_INET;
13524         saddr.sin_addr.s_addr = inet_addr(myipaddr);
13525         saddr.sin_port = htons(port);
13526
13527         if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13528             i = errno;                  /* Save error code */
13529 #ifdef TCPIPLIB
13530             socket_close(sock);
13531 #else /* TCPIPLIB */
13532             close(sock);
13533 #endif /* TCPIPLIB */
13534             sock = -1;
13535             debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
13536             continue;
13537         }
13538
13539         debug(F100,"fdwx_create_listen_socket() bind OK","",0);
13540         break;
13541     }
13542
13543     if ( display > 1000 ) {
13544         debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
13545         return(-1);
13546     }
13547
13548     if (listen(sock, 5) < 0) {
13549         i = errno;                  /* Save error code */
13550 #ifdef TCPIPLIB
13551         socket_close(sock);
13552 #else /* TCPIPLIB */
13553         close(sock);
13554 #endif /* TCPIPLIB */
13555         debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
13556         return(-1);
13557     }
13558     debug(F100,"fwdx_create_listen_socket() listen OK","",0);
13559
13560     TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
13561     if (!myipaddr[0])
13562         getlocalipaddr();
13563     if ( myipaddr[0] )
13564         ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":",
13565                   ckuitoa(display),":",ckuitoa(screen),
13566                   NULL,NULL,NULL,NULL,NULL,NULL);
13567     else
13568         ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":",
13569                  ckuitoa(screen));
13570     putenv(env);
13571     return(0);
13572 #endif /* NOPUTENV */
13573 }
13574
13575
13576 int
13577 fwdx_open_client_channel(channel) int channel; {
13578     char * env;
13579     struct sockaddr_in saddr;
13580 #ifdef FWDX_UNIX_SOCK
13581     struct sockaddr_un saddr_un = { AF_LOCAL };
13582 #endif /* FWDX_UNIX_SOCK */
13583     int colon, dot, display, port, sock, i, screen;
13584     int family;
13585     char buf[256], * host=NULL, * rest=NULL;
13586 #ifdef TCP_NODELAY
13587     int on=1;
13588 #endif /* TCP_NODELAY */
13589
13590     debug(F111,"fwdx_create_client_channel()","channel",channel);
13591
13592     for ( i=0; i<MAXFWDX ; i++ ) {
13593         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
13594             /* Already open */
13595             debug(F110,"fwdx_create_client_channel()","already open",0);
13596             return(0);
13597         }
13598     }
13599
13600     env = getenv("DISPLAY");
13601     if ( !env )
13602         env = tn_get_display();
13603     if ( env )
13604         ckstrncpy(buf,env,256);
13605     else
13606         ckstrncpy(buf,"127.0.0.1:0.0",256);
13607
13608     bzero((char *)&saddr,sizeof(saddr));
13609     saddr.sin_family = AF_INET;
13610
13611     if (!fwdx_parse_displayname(buf,
13612                                 &family,
13613                                 &host,
13614                                 &display,
13615                                 &screen,
13616                                 &rest
13617                                 )
13618         ) {
13619         if ( host ) free(host);
13620         if ( rest ) free(rest);
13621         return(0);
13622     }
13623     if (rest) free(rest);
13624
13625 #ifndef FWDX_UNIX_SOCK
13626   /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13627    * we change things to use inet sockets on the ip loopback interface instead,
13628    * and hope that it works.
13629    */
13630     if (family == FamilyLocal) {
13631         debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
13632         family = FamilyInternet;
13633         if (host) free(host);
13634         if (host = malloc(strlen("localhost") + 1))
13635             strcpy(host, "localhost");
13636         else {
13637             return(-1);
13638         }
13639     }
13640 #else /* FWDX_UNIX_SOCK */
13641     if (family == FamilyLocal) {
13642         if (host) free(host);
13643         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13644         if (sock < 0)
13645             return(-1);
13646
13647         ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13648         strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13649         if (connect(sock,(struct sockaddr *)&saddr_un, SUN_LEN(&saddr_un)) < 0)
13650           return(-1);
13651     } else
13652 #endif  /* FWDX_UNIX_SOCK */
13653     {
13654         /* Otherwise, we are assuming FamilyInternet */
13655         if (host) {
13656             ckstrncpy(buf,host,sizeof(buf));
13657             free(host);
13658         } else
13659             ckstrncpy(buf,myipaddr,sizeof(buf));
13660
13661         debug(F111,"fwdx_create_client_channel()","display",display);
13662
13663         port = 6000 + display;
13664         saddr.sin_port = htons(port);
13665
13666         debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
13667         saddr.sin_addr.s_addr = inet_addr(buf);
13668         if ( saddr.sin_addr.s_addr == (unsigned long) -1
13669 #ifdef INADDR_NONE
13670              || saddr.sin_addr.s_addr == INADDR_NONE
13671 #endif /* INADDR_NONE */
13672              )
13673         {
13674             struct hostent *host;
13675             host = gethostbyname(buf);
13676             if ( host == NULL )
13677                 return(-1);
13678             host = ck_copyhostent(host);
13679 #ifdef HADDRLIST
13680 #ifdef h_addr
13681             /* This is for trying multiple IP addresses - see <netdb.h> */
13682             if (!(host->h_addr_list))
13683                 return(-1);
13684             bcopy(host->h_addr_list[0],
13685                    (caddr_t)&saddr.sin_addr,
13686                    host->h_length
13687                    );
13688 #else
13689             bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13690 #endif /* h_addr */
13691 #else  /* HADDRLIST */
13692             bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13693 #endif /* HADDRLIST */
13694         }
13695
13696         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13697             debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
13698             return(-1);
13699         }
13700
13701         if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13702             debug(F110,"fwdx_create_client_channel()","connect() failed",0);
13703 #ifdef TCPIPLIB
13704             socket_close(sock);
13705 #else /* TCPIPLIB */
13706             close(sock);
13707 #endif /* TCPIPLIB */
13708             return(-1);
13709         }
13710
13711 #ifdef TCP_NODELAY
13712         setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13713 #endif /* TCP_NODELAY */
13714     }
13715
13716     for (i = 0; i < MAXFWDX; i++) {
13717      if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
13718          TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
13719          TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
13720        TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1;
13721          debug(F111,"fwdx_create_client_channel()","socket",sock);
13722          return(0);
13723      }
13724     }
13725     return(-1);
13726 }
13727
13728 int
13729 fwdx_server_avail() {
13730     char * env;
13731     struct sockaddr_in saddr;
13732 #ifdef FWDX_UNIX_SOCK
13733     struct sockaddr_un saddr_un = { AF_LOCAL };
13734 #endif  /* FWDX_UNIX_SOCK */
13735     int colon, dot, display, port, sock, i, screen;
13736     char buf[256], *host=NULL, *rest=NULL;
13737 #ifdef TCP_NODELAY
13738     int on=1;
13739 #endif /* TCP_NODELAY */
13740     int family;
13741
13742     env = getenv("DISPLAY");
13743     if ( !env )
13744         env = tn_get_display();
13745     if ( env )
13746         ckstrncpy(buf,env,256);
13747     else
13748         ckstrncpy(buf,"127.0.0.1:0.0",256);
13749
13750     bzero((char *)&saddr,sizeof(saddr));
13751     saddr.sin_family = AF_INET;
13752
13753     if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) {
13754         if ( host ) free(host);
13755         if ( rest ) free(rest);
13756         return(0);
13757     }
13758     if (rest) free(rest);
13759
13760 #ifndef FWDX_UNIX_SOCK
13761   /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13762    * we change things to use inet sockets on the ip loopback interface instead,
13763    * and hope that it works.
13764    */
13765     if (family == FamilyLocal) {
13766         family = FamilyInternet;
13767         if (host) free(host);
13768         if (host = malloc(strlen("localhost") + 1))
13769             strcpy(host, "localhost");
13770         else {
13771             return(-1);
13772         }
13773     }
13774 #else /* FWDX_UNIX_SOCK */
13775     if (family == FamilyLocal) {
13776         debug(F100,"fwdx_server_avail() FamilyLocal","",0);
13777         if (host) free(host);
13778         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13779         if (sock < 0)
13780             return(0);
13781
13782         ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13783         strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13784         if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0)
13785             return(0);
13786         close(sock);
13787         return(1);
13788     }
13789 #endif  /* FWDX_UNIX_SOCK */
13790
13791     /* Otherwise, we are assuming FamilyInternet */
13792     if (host) {
13793         ckstrncpy(buf,host,sizeof(buf));
13794         free(host);
13795     } else
13796         ckstrncpy(buf,myipaddr,sizeof(buf));
13797
13798     debug(F111,"fwdx_server_avail()","display",display);
13799
13800     port = 6000 + display;
13801     saddr.sin_port = htons(port);
13802
13803     debug(F110,"fwdx_server_avail() ip-address",buf,0);
13804     saddr.sin_addr.s_addr = inet_addr(buf);
13805     if ( saddr.sin_addr.s_addr == (unsigned long) -1
13806 #ifdef INADDR_NONE
13807          || saddr.sin_addr.s_addr == INADDR_NONE
13808 #endif /* INADDR_NONE */
13809          )
13810     {
13811         struct hostent *host;
13812         host = gethostbyname(buf);
13813         if ( host == NULL ) {
13814             debug(F110,"fwdx_server_avail() gethostbyname() failed",
13815                    myipaddr,0);
13816             return(-1);
13817         }
13818         host = ck_copyhostent(host);
13819 #ifdef HADDRLIST
13820 #ifdef h_addr
13821         /* This is for trying multiple IP addresses - see <netdb.h> */
13822         if (!(host->h_addr_list))
13823             return(-1);
13824         bcopy(host->h_addr_list[0],
13825                (caddr_t)&saddr.sin_addr,
13826                host->h_length
13827                );
13828 #else
13829         bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13830 #endif /* h_addr */
13831 #else  /* HADDRLIST */
13832         bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13833 #endif /* HADDRLIST */
13834     }
13835
13836     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13837         debug(F111,"fwdx_server_avail()","socket() < 0",sock);
13838         return(0);
13839     }
13840
13841     if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13842         debug(F110,"fwdx_server_avail()","connect() failed",0);
13843 #ifdef TCPIPLIB
13844         socket_close(sock);
13845 #else /* TCPIPLIB */
13846         close(sock);
13847 #endif /* TCPIPLIB */
13848         return(0);
13849     }
13850
13851 #ifdef TCPIPLIB
13852     socket_close(sock);
13853 #else /* TCPIPLIB */
13854     close(sock);
13855 #endif /* TCPIPLIB */
13856     return(1);
13857 }
13858
13859 int
13860 fwdx_open_server_channel() {
13861     int sock, ready_to_accept, sock2,channel,i;
13862 #ifdef TCP_NODELAY
13863     int on=1;
13864 #endif /* TCP_NODELAY */
13865 #ifdef UCX50
13866     static u_int saddrlen;
13867 #else
13868     static SOCKOPT_T saddrlen;
13869 #endif /* UCX50 */
13870     struct sockaddr_in saddr;
13871     char sb[8];
13872     extern char tn_msg[];
13873 #ifdef BSDSELECT
13874     fd_set rfds;
13875     struct timeval tv;
13876 #else
13877 #ifdef BELLSELCT
13878     fd_set rfds;
13879 #else
13880     fd_set rfds;
13881     struct timeval {
13882         long tv_sec;
13883         long tv_usec;
13884     } tv;
13885 #endif /* BELLSELECT */
13886 #endif /* BSDSELECT */
13887     unsigned short nchannel;
13888     unsigned char * p;
13889
13890     sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
13891
13892   try_again:
13893
13894 #ifdef BSDSELECT
13895     tv.tv_sec  = tv.tv_usec = 0L;
13896     tv.tv_usec = 50;
13897     FD_ZERO(&rfds);
13898     FD_SET(sock, &rfds);
13899     ready_to_accept =
13900         ((select(FD_SETSIZE,
13901 #ifdef HPUX
13902 #ifdef HPUX1010
13903                   (fd_set *)
13904 #else
13905
13906                   (int *)
13907 #endif /* HPUX1010 */
13908 #else
13909 #ifdef __DECC
13910                   (fd_set *)
13911 #endif /* __DECC */
13912 #endif /* HPUX */
13913                   &rfds, NULL, NULL, &tv) > 0) &&
13914           FD_ISSET(sock, &rfds));
13915 #else /* BSDSELECT */
13916 #ifdef IBMSELECT
13917     ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
13918 #else
13919 #ifdef BELLSELECT
13920     FD_ZERO(rfds);
13921     FD_SET(sock, rfds);
13922     ready_to_accept =
13923         ((select(128, rfds, NULL, NULL, 50) > 0) &&
13924           FD_ISSET(sock, rfds));
13925 #else
13926 /* Try this - what's the worst that can happen... */
13927
13928     tv.tv_sec  = tv.tv_usec = 0L;
13929     tv.tv_usec = 50;
13930     FD_ZERO(&rfds);
13931     FD_SET(sock, &rfds);
13932     ready_to_accept =
13933         ((select(FD_SETSIZE,
13934                   (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
13935           FD_ISSET(sock, &rfds));
13936 #endif /* BELLSELECT */
13937 #endif /* IBMSELECT */
13938 #endif /* BSDSELECT */
13939
13940     if ( !ready_to_accept )
13941         return(0);
13942
13943     if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
13944         int i = errno;                  /* save error code */
13945         debug(F101,"tcpsrv_open accept errno","",i);
13946         return(-1);
13947     }
13948
13949     /*
13950      * Now we have the open socket.  We must now find a channel to store
13951      * it in, and then notify the client.
13952      */
13953
13954     for ( channel=0;channel<MAXFWDX;channel++ ) {
13955         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
13956             break;
13957     }
13958
13959     if ( channel == MAXFWDX ) {
13960 #ifdef TCPIPLIB
13961         socket_close(sock2);
13962 #else /* TCPIPLIB */
13963         close(sock2);
13964 #endif /* TCPIPLIB */
13965         return(-1);
13966     }
13967
13968     if ( fwdx_send_open(channel) < 0 ) {
13969 #ifdef TCPIPLIB
13970         socket_close(sock2);
13971 #else /* TCPIPLIB */
13972         close(sock2);
13973 #endif /* TCPIPLIB */
13974     }
13975
13976 #ifdef TCP_NODELAY
13977     setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13978 #endif /* TCP_NODELAY */
13979
13980     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
13981     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
13982     goto try_again;
13983
13984     return(0);  /* never reached */
13985 }
13986
13987 int
13988 fwdx_close_channel(channel) int channel; {
13989     int i,fd;
13990
13991     for ( i=0; i<MAXFWDX ; i++ ) {
13992         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
13993             break;
13994     }
13995     if ( i == MAXFWDX )
13996         return(-1);
13997
13998     fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
13999     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
14000     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
14001     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
14002
14003 #ifdef TCPIPLIB
14004     socket_close(fd);
14005 #else /* TCPIPLIB */
14006     close(fd);
14007 #endif /* TCPIPLIB */
14008     return(0);
14009 }
14010
14011 int
14012 fwdx_close_all() {
14013     int x,fd;
14014
14015     debug(F111,"fwdx_close_all()",
14016           "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
14017           TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14018
14019     if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
14020 #ifdef TCPIPLIB
14021         socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14022 #else /* TCPIPLIB */
14023         close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14024 #endif /* TCPIPLIB */
14025         TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
14026     }
14027
14028     for (x = 0; x < MAXFWDX; x++) {
14029      if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14030       fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14031       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
14032       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
14033       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
14034       TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
14035 #ifdef TCPIPLIB
14036       socket_close(fd);
14037 #else /* TCPIPLIB */
14038       close(fd);
14039 #endif /* TCPIPLIB */
14040      }
14041     }
14042     return(0);
14043 }
14044
14045 /* The following definitions are for Unix */
14046 #ifndef socket_write
14047 #define socket_write(f,s,n)    write(f,s,n)
14048 #endif /* socket_write */
14049 #ifndef socket_read
14050 #define socket_read(f,s,n)     read(f,s,n)
14051 #endif /* socket_read */
14052
14053 int
14054 fwdx_write_data_to_channel(channel, data, len)
14055     int channel; char * data; int len;
14056 {
14057     int sock, count, try=0, length = len, i;
14058
14059     if ( len <= 0 )
14060         return(0);
14061
14062     for ( i=0; i<MAXFWDX ; i++ ) {
14063         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14064             break;
14065     }
14066     if ( i == MAXFWDX ) {
14067         debug(F110,"fwdx_write_data_to_channel",
14068                "attempting to write to closed channel",0);
14069         return(-1);
14070     }
14071
14072     sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14073     debug(F111,"fwdx_write_data_to_channel","socket",sock);
14074     hexdump("fwdx_write_data_to_channel",data,len);
14075
14076   fwdx_write_data_to_channel_retry:
14077
14078     if ((count = socket_write(sock,data,len)) < 0) {
14079         int s_errno = socket_errno; /* maybe a function */
14080         debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
14081 #ifdef BETATEST
14082         printf("fwdx_write_data_to_channel error\r\n");
14083 #endif /* BETATEST */
14084 #ifdef OS2
14085         if (os2socketerror(s_errno) < 0)
14086             return(-2);
14087 #endif /* OS2 */
14088         return(-1);                 /* Call it an i/o error */
14089     }
14090     if (count < len) {
14091         debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
14092         if (count > 0) {
14093             data += count;
14094             len -= count;
14095         }
14096         debug(F111,"fwdx_write_data_to_channel retry",data,len);
14097         if ( len > 0 )
14098             goto fwdx_write_data_to_channel_retry;
14099     }
14100
14101     debug(F111,"fwdx_write_data_to_channel complete",data,length);
14102     return(length); /* success - return total length */
14103 }
14104
14105 VOID
14106 fwdx_check_sockets(fd_set *ibits)
14107 {
14108     int x, sock, channel, bytes;
14109     static char buffer[32000];
14110
14111     debug(F100,"fwdx_check_sockets()","",0);
14112     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14113          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14114         debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
14115         return;
14116     }
14117
14118     for (x = 0; x < MAXFWDX; x++) {
14119         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 ||
14120              TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend )
14121             continue;
14122
14123         sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14124         if (FD_ISSET(sock, ibits))
14125         {
14126             channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
14127             debug(F111,"fwdx_check_sockets()","channel set",channel);
14128
14129             bytes = socket_read(sock, buffer, sizeof(buffer));
14130             if (bytes > 0)
14131                 fwdx_send_data_from_channel(channel, buffer, bytes);
14132             else if (bytes == 0) {
14133                 fwdx_close_channel(channel);
14134                 fwdx_send_close(channel);
14135             }
14136         }
14137     }
14138 }
14139
14140 int
14141 fwdx_init_fd_set(fd_set *ibits)
14142 {
14143     int x,set=0,cnt=0;
14144
14145     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14146          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14147         debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
14148         return(0);
14149     }
14150
14151     if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
14152         set++;
14153         FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
14154     }
14155     for (x = 0; x < MAXFWDX; x++) {
14156         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14157             cnt++;
14158             if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend)
14159                 continue;
14160             set++;
14161             FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
14162         }
14163     }
14164     if (set + cnt == 0) {
14165         return(-1);
14166     } else {
14167         return(set);
14168     }
14169 }
14170
14171 #ifdef NT
14172 VOID
14173 fwdx_thread( VOID * dummy )
14174 {
14175     fd_set ifds;
14176     struct timeval tv;
14177     extern int priority;
14178     int n;
14179
14180     setint();
14181     SetThreadPrty(priority,isWin95() ? 3 : 11);
14182
14183     while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
14184             sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
14185     {
14186         FD_ZERO(&ifds);
14187         n = fwdx_init_fd_set(&ifds);
14188         if (n > 0) {
14189             tv.tv_sec = 0;
14190             tv.tv_usec = 2500;
14191             if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
14192                 fwdx_check_sockets(&ifds);
14193
14194         } else if (n < 0) {
14195             TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
14196             ckThreadEnd(NULL);
14197         } else {
14198             sleep(1);
14199         }
14200     }
14201 }
14202 #endif /* NT */
14203 #endif /* CK_FORWARD_X */
14204 #endif /* TNCODE */
14205 #endif /* NETCONN */