home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit70 / ckcnet.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  331KB  |  10,599 lines

  1. char *cknetv = "Network support, 7.0.194, 30 Dec 1999";
  2.  
  3. /*  C K C N E T  --  Network support  */
  4.  
  5. /*
  6.   Copyright (C) 1985, 1999,
  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@columbia.edu) -- OS/2 & Windows and a lot more.
  28.     netopen() routine for TCP/IP originally by Ken Yap, Rochester University
  29.     (ken@cs.rochester.edu) (no longer at that address).
  30.   Missing pieces for Excelan sockets library from William Bader.
  31.   Telnet protocol by Frank da Cruz and Jeffrey Altman.
  32.   Rlogin protocol by Jeffrey Altman.
  33.   SSL support adapted by Jeffrey Altman from work done by
  34.     Tim Hudson <tjh@cryptosoft.com> +61 7 32781581
  35.   TLS support by Jeffrey Altman.
  36.   HTTP support by Jeffrey Altman.
  37.   TGV MultiNet code by Frank da Cruz.
  38.   MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
  39.   MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
  40.   TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
  41.   CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
  42.   X.25 support by Marcello Frutig, Catholic University,
  43.     Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
  44.     Stefaan Eeckels, Eurokom, Luxembourg.
  45.     David Lane added support for Stratus X.25 1996.
  46.     Stephen Riehm added support for IBM AIX X.25 in April 1998.
  47.   Other contributions as indicated in the code.
  48. */
  49. #define CKCNET_C
  50. #include "ckcsym.h"
  51. #include "ckcdeb.h"
  52. #include "ckcker.h"
  53. #ifdef I386IX                           /* Has to come before ckcnet.h in */
  54. #include <errno.h>                      /* this version, but after in others */
  55. #endif /* I386IX */
  56. #include "ckcnet.h"                     /* which includes ckctel.h */
  57. #ifdef CK_SSL
  58. #include "ck_ssl.h"
  59. #endif /* CK_SSL */
  60.  
  61. #ifdef CK_DNS_SRV
  62. #ifdef OS2
  63. #ifdef NT
  64. #include <wshelper.h>
  65. #else /* NT */
  66. /* !Error OS/2 does not support DNS Service Records. */
  67. #endif /* NT */
  68. #else /* OS2 */
  69. #include <arpa/inet.h>
  70. #include <arpa/nameser.h>
  71. #include <resolv.h>
  72. #ifndef PS2AIX10
  73. #ifndef BSD4
  74. #include <netdb.h>
  75. #endif /* BSD4 */
  76. #endif /* PS2AIX10 */
  77. #endif /* OS2 */
  78. #ifndef T_SRV
  79. #define T_SRV 33
  80. #endif /* T_SRV */
  81.  
  82. /* for old Unixes and friends ... */
  83. #ifndef MAXHOSTNAMELEN
  84. #define MAXHOSTNAMELEN 64
  85. #endif /* MAXHOSTNAMELEN */
  86.  
  87. #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
  88. #endif /* CK_DNS_SRV */
  89.  
  90. #ifdef NOLOCAL
  91. #ifdef TCPIPLIB
  92. #undef TCPIPLIB
  93. #endif /* TCPIPLIB */
  94. #endif /* NOLOCAL */
  95.  
  96. #ifndef NOMHHOST
  97. #ifdef datageneral
  98. #define NOMHHOST
  99. #else
  100. #ifdef HPUX5WINTCP
  101. #define NOMHHOST
  102. #endif /* HPUX5WINTCP */
  103. #endif /* datageneral */
  104. #endif /* NOMHHOST */
  105.  
  106. #ifdef INADDRX
  107.   struct in_addr inaddrx;
  108. #endif /* INADDRX */
  109.  
  110. int ttnet = NET_NONE;                   /* Network type */
  111. int ttnproto = NP_DEFAULT;              /* Network virtual terminal protocol */
  112.  
  113. /* 0 = don't lowercase username for Rlogin/Telnet protocol */
  114. /* nonzero = do lowercase it.  Add a SET command if necessary... */
  115. #ifdef VMS
  116. int ck_lcname = 1;
  117. #else
  118. int ck_lcname = 0;
  119. #endif /* VMS */
  120.  
  121. extern int                              /* External variables */
  122.   duplex, debses, seslog, sessft, wasclosed,
  123.   ttyfd, quiet, msgflg, what, nettype, ttmdm;
  124.  
  125. #ifdef NETCONN
  126. /* Don't need any of this if there is no network support. */
  127.  
  128. /*
  129.   NETLEBUF is (must be) defined for those platforms that call this
  130.   module to do network i/o (e.g. netinc(), nettchk(), etc) rather
  131.   than doing it themselves (ttinc(), ttchk(), etc).  In this case
  132.   the Telnet local-echo buffers and routines are defined and referenced
  133.   here, rather than in the ck?tio.c module.
  134. */
  135. #ifdef NETLEBUF
  136. #define LEBUFSIZ 4096
  137. int ttpush = -1, le_data = 0;           /* These are seen from outside */
  138. static CHAR le_buf[LEBUFSIZ];           /* These are used internally */
  139. static int le_start = 0, le_end = 0;
  140. int tt_push_inited = 0;
  141. #endif /* NETLEBUF */
  142.  
  143. #ifdef CK_SOCKS                         /* SOCKS Internet relay package */
  144. #ifdef CK_SOCKS5                        /* SOCKS 5 */
  145. #define accept  SOCKSaccept
  146. #define bind    SOCKSbind
  147. #define connect SOCKSconnect
  148. #define getsockname SOCKSgetsockname
  149. #define listen SOCKSlisten
  150. #else  /* Not SOCKS 5 */
  151. #define accept  Raccept
  152. #define bind    Rbind
  153. #define connect Rconnect
  154. #define getsockname Rgetsockname
  155. #define listen Rlisten
  156. #endif /* CK_SOCKS5 */
  157. #endif /* CK_SOCKS */
  158.  
  159. #ifdef DEC_TCPIP
  160. #include <time.h>
  161. #include <inet.h>
  162. #endif /* DEC_TCPIP */
  163.  
  164. /* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */
  165.  
  166. #ifdef HPUX
  167. #ifndef HPUX7                           /* HPUX 7.00 doesn't have it */
  168. #include <arpa/inet.h>                  /* For inet_ntoa() prototype */
  169. #endif /* HPUX7 */
  170. #endif /* HPUX */
  171.  
  172. #ifdef CMU_TCPIP
  173. #include <time.h>
  174. #endif /* CMU_TCPIP */
  175.  
  176. #ifdef DCLTIMEVAL                       /* UnixWare 7 */
  177. struct timeval {                        /* And define these ourselves. */
  178.     long tv_sec;                        /* (see comments in ckutio.c) */
  179.     long tv_usec;
  180. };
  181. struct timezone {
  182.     int tz_minuteswest;
  183.     int tz_dsttime;
  184. };
  185. #endif /* DCLTIMEVAL */
  186.  
  187. #ifdef WINTCP
  188.  
  189. #include <setjmp.h>
  190. #include <signal.h>
  191. #include <sys/time.h>
  192. /*
  193.   The WIN/TCP code path is the same as that for MultiNet.
  194.   Only the routine names have changed ...
  195. */
  196. #define socket_read     netread
  197. #define socket_ioctl    ioctl
  198. #define socket_write    netwrite
  199. #define socket_close    netclose
  200.  
  201. #ifdef OLD_TWG                         /* some routines have evolved */
  202.         extern int vmserrno, uerrno;
  203. #define socket_errno    uerrno
  204. #define socket_perror   perror         /* which uses errno, not uerrno! */
  205. #else
  206. #define socket_errno    errno
  207. #define socket_perror   win$perror
  208. #endif /* OLD_TWG */
  209.  
  210. #else /* Not WINTCP */
  211.  
  212. #ifdef OSF13
  213. #ifdef CK_ANSIC
  214. #ifdef _NO_PROTO
  215. #undef _NO_PROTO
  216. #endif /* _NO_PROTO */
  217. #endif /* CK_ANSIC */
  218. #endif /* OSF13 */
  219.  
  220. #ifndef I386IX
  221. #include <errno.h>                      /* Already included above */
  222. #endif /* I386IX */
  223.  
  224. #include <signal.h>                     /* Everybody needs this */
  225.  
  226. #ifdef ZILOG                            /* Zilog has different name for this */
  227. #include <setret.h>
  228. #else
  229. #include <setjmp.h>
  230. #endif /* ZILOG */
  231.  
  232. #endif /* WINTCP */
  233.  
  234. #ifdef datageneral                      /* Data General AOS/VS */
  235. #include <:usr:include:vs_tcp_errno.h>
  236. #include <:usr:include:sys:vs_tcp_types.h>
  237. #ifdef SELECT
  238. /*
  239.   NOTE: This can be compiled and linked OK with SELECT defined
  240.   but it doesn't work at all.  Anybody who cares and knows how
  241.   to fix it, feel free.
  242. */
  243. #include <:usr:include:sys:vs_tcp_time.h>
  244. #endif /* SELECT */
  245. #include <:usr:include:sys:socket.h>
  246. #include <:usr:include:netinet:in.h>
  247. #include <:usr:include:netdb.h>
  248. #endif /* datageneral */
  249.  
  250. #ifndef socket_errno
  251. #define socket_errno errno
  252. #endif /* socket_errno */
  253.  
  254. #ifdef TNCODE
  255. extern int tn_deb;
  256. #endif /* TNCODE */
  257.  
  258. int tcp_rdns =                          /* Reverse DNS lookup */
  259. #ifdef DEC_TCPIP_OLD
  260.     SET_OFF                             /* Doesn't seem to work in UCX */
  261. #else
  262.      SET_AUTO
  263. #endif /* DEC_TCPIP */
  264.       ;
  265. #ifdef CK_DNS_SRV
  266. int tcp_dns_srv = SET_OFF;
  267. #endif /* CK_DNS_SRV */
  268.  
  269. #ifdef RLOGCODE
  270. #ifdef TCPIPLIB
  271. _PROTOTYP( static VOID rlog_oob, (CHAR *, int) );
  272. #else
  273. _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
  274. #endif /* TCPIPLIB */
  275. _PROTOTYP( static int rlog_ini, (CHAR *, int,
  276.                                  struct sockaddr_in *,
  277.                                  struct sockaddr_in *) );
  278. int rlog_mode = RL_COOKED;
  279. int rlog_stopped = 0;
  280. #endif /* RLOGCODE */
  281.  
  282. #ifndef NOICP
  283. extern int doconx;                      /* CONNECT-class command active */
  284. #endif /* NOICP */
  285.  
  286. #ifdef IBMX25
  287. /* This variable should probably be generalised for true client/server
  288.  * support - ie: the fd of the listening server, accepted calls should
  289.  * be forked or at least handled via a second fd (for IBM's X.25 -
  290.  * ttyfd always holds the active fd - ie the server becomes inactive
  291.  * as long as a client is connected, and becomes active again when the
  292.  * connection is closed)
  293.  */
  294. int x25serverfd = 0;            /* extern in ckcnet.h */
  295. int x25seqno = 0;               /* Connection sequence number */
  296. int x25lastmsg = -1;            /* A cheapskate's state table */
  297.  
  298. #define X25_CLOSED      0       /* Default state: no connection, no STREAM */
  299. #define X25_SETUP       1       /* X.25 has been set up (no connection) */
  300. #define X25_CONNECTED   2       /* X.25 connection has been established */
  301. int x25_state = X25_CLOSED;     /* Default state */
  302. #endif /* IBMX25 */
  303.  
  304. #ifndef DEBUG
  305. #define deblog 0
  306. #endif /* DEBUG */
  307.  
  308. #ifdef CK_NAWS                          /* Negotiate About Window Size */
  309. #ifdef RLOGCODE
  310. _PROTOTYP( int rlog_naws, (void) );
  311. #endif /* RLOGCODE */
  312. #endif /* CK_NAWS */
  313.  
  314. #ifdef OS2                              /* For terminal type name string */
  315. #include "ckuusr.h"
  316. #ifndef NT
  317. #include <os2.h>
  318. #undef COMMENT
  319. #endif /* NT */
  320. #include "ckocon.h"
  321. extern int tt_type, max_tt;
  322. extern struct tt_info_rec tt_info[];
  323. extern char ttname[];
  324. #else
  325. #ifdef CK_AUTHENTICATION
  326. #include "ckuusr.h"
  327. #endif /* CK_AUTHENTICATION */
  328. #endif /* OS2 */
  329.  
  330. #ifdef CK_AUTHENTICATION
  331. #include "ckuath.h"
  332. #endif /* CK_AUTHENTICATION */
  333.  
  334. #include "ckcsig.h"
  335.  
  336. #ifndef OS2                             /* For timeout longjumps */
  337. static ckjmpbuf njbuf;
  338. #endif /* OS2 */
  339.  
  340. #define NAMECPYL 100                    /* Local copy of hostname */
  341. char namecopy[NAMECPYL];                /* Referenced by ckctel.c */
  342.  
  343. char ipaddr[20] = { '\0' };             /* Global copy of IP address */
  344. char myipaddr[20] = { '\0' };           /* Global copy of my IP address */
  345. unsigned long myxipaddr = 0L;           /* Ditto as a number */
  346. #endif /* NETCONN */
  347.  
  348. char *tcp_address = NULL;               /* Preferred IP Address */
  349. extern char uidbuf[];                   /* User ID buffer */
  350. extern char pwbuf[];                    /* Password buffer */
  351.  
  352. #ifdef OS2
  353. extern int tt_rows[], tt_cols[];
  354. extern int tt_status;
  355. #else /* OS2 */
  356. extern int tt_rows, tt_cols;            /* Everybody has this */
  357. #endif /* OS2 */
  358.  
  359. extern int cmd_cols, cmd_rows;
  360.  
  361. #ifdef STREAMING                        /* Use blocking writes for streaming */
  362. extern int streaming;
  363. #endif /* STREAMING */
  364.  
  365. #ifdef NT
  366. extern int WSASafeToCancel;
  367. int win95selectbug = 0;                 /* For TCP/IP stacks whose select() */
  368. /* always fails on write requests such as Cisco and Quarterdeck */
  369. #define stricmp _stricmp
  370. #endif /* NT */
  371.  
  372. #ifndef NOTCPOPTS
  373.  
  374. /* Skip all this if NOTCPOPTS specified. */
  375.  
  376. #ifdef SOL_SOCKET
  377.  
  378. #ifdef TCP_NODELAY
  379. int tcp_nodelay = 0;                    /* Nagle algorithm TCP_NODELAY */
  380. #endif /* TCP_NODELAY */
  381.  
  382. #ifdef SO_DONTROUTE
  383. int tcp_dontroute = 0;
  384. #endif /* SO_DONTROUTE */
  385.  
  386. #ifdef SO_LINGER
  387. int tcp_linger  = 0;                    /* SO_LINGER */
  388. int tcp_linger_tmo = 0;                 /* SO_LINGER timeout */
  389. #endif /* SO_LINGER */
  390.  
  391. #ifdef HPUX                             /* But the data structures */
  392. #ifndef HPUX8                           /* needed for linger are not */
  393. #ifndef HPUX9                           /* defined in HP-UX versions */
  394. #ifndef HPUX10                          /* prior to 8.00. */
  395. #ifdef SO_LINGER
  396. #undef SO_LINGER
  397. #endif /* SO_LINGER */
  398. #endif /* HPUX10 */
  399. #endif /* HPUX9 */
  400. #endif /* HPUX8 */
  401. #endif /* HPUX */
  402.  
  403. #ifndef SO_OOBINLINE                    /* Hopefully only HP-UX 7.0 */
  404. #define SO_OOBINLINE 0x0100
  405. #endif /* SO_OOBINLINE */
  406.  
  407. #ifndef TCPSNDBUFSIZ
  408. #ifdef VMS
  409. #ifdef __alpha
  410. #define TCPSNDBUFSIZ 16384
  411. #endif /* __alpha */
  412. #endif /* VMS */
  413. #endif /* TCPSNDBUFSIZ */
  414.  
  415. #ifndef TCPSNDBUFSIZ
  416. #define TCPSNDBUFSIZ -1
  417. #endif /* TCPSNDBUFSIZ */
  418.  
  419. #ifdef SO_SNDBUF
  420. int tcp_sendbuf = TCPSNDBUFSIZ;
  421. #endif /* SO_SNDBUF */
  422.  
  423. #ifdef SO_RCVBUF
  424. int tcp_recvbuf = -1;
  425. #endif /* SO_RCVBUF */
  426.  
  427. #ifdef SO_KEEPALIVE
  428. int tcp_keepalive = 1;
  429. #endif /* SO_KEEPALIVE */
  430.  
  431. #endif /* SOL_SOCKET */
  432. #endif /* NOTCPOPTS */
  433.  
  434. #ifndef NETCONN
  435. /*
  436.   Network support not defined.
  437.   Dummy functions here in case #ifdef's forgotten elsewhere.
  438. */
  439. int                                     /* Open network connection */
  440. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  441.     return(-1);
  442. }
  443. int                                     /* Close network connection */
  444. netclos() {
  445.     return(-1);
  446. }
  447. int                                     /* Check network input buffer */
  448. nettchk() {
  449.     return(-1);
  450. }
  451. int                                     /* Flush network input buffer */
  452. netflui() {
  453.     return(-1);
  454. }
  455. int                                     /* Send network BREAK */
  456. netbreak() {
  457.     return(-1);
  458. }
  459. int                                     /* Input character from network */
  460. netinc(timo) int timo; {
  461.     return(-1);
  462. }
  463. int                                     /* Output character to network */
  464. #ifdef CK_ANSIC
  465. nettoc(CHAR c)
  466. #else
  467. nettoc(c) CHAR c;
  468. #endif /* CK_ANSIC */
  469. /* nettoc */ {
  470.     return(-1);
  471. }
  472. int
  473. nettol(s,n) CHAR *s; int n; {
  474.     return(-1);
  475. }
  476.  
  477. #else /* NETCONN is defined (much of this module...) */
  478.  
  479. #ifdef NETLEBUF
  480. VOID
  481. le_init() {                             /* LocalEchoInit() */
  482.     int i;
  483.     for (i = 0; i < LEBUFSIZ; i++)
  484.       le_buf[i] = '\0';
  485.     le_start = 0;
  486.     le_end = 0;
  487.     le_data = 0;
  488.     tt_push_inited = 1;
  489. }
  490.  
  491. VOID
  492. le_clean() {                            /* LocalEchoCleanup() */
  493.     le_init();
  494.     return;
  495. }
  496.  
  497. int
  498. le_inbuf() {
  499.     int rc = 0;
  500.     if (le_start != le_end) {
  501.         rc = (le_end -
  502.               le_start +
  503.               LEBUFSIZ) % LEBUFSIZ;
  504.     }
  505.     return(rc);
  506. }
  507.  
  508. int
  509. #ifdef CK_ANSIC
  510. le_putchar(CHAR ch)
  511. #else
  512. le_putchar(ch) CHAR ch;
  513. #endif /* CK_ANSIC */
  514. /* le_putchar */ {
  515.     if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
  516.         debug(F110,"le_putchar","buffer is full",0);
  517.         return(-1);
  518.     }
  519.     le_buf[le_end++] = ch;
  520.     if (le_end == LEBUFSIZ)
  521.       le_end = 0;
  522.     le_data = 1;
  523.     return(0);
  524. }
  525.  
  526. int
  527. #ifdef CK_ANSIC
  528. le_puts(CHAR * s, int n)
  529. #else
  530. le_puts(s,n) CHAR * s; int n;
  531. #endif /* CK_ANSIC */
  532. /* le_puts */ {
  533.     int rc = 0;
  534.     int i = 0;
  535.     CHAR * p = (CHAR *)"le_puts";
  536.     hexdump(p,s,n);
  537.     for (i = 0; i < n; i++)
  538.       rc = le_putchar((char)s[i]);
  539.     debug(F101,"le_puts","",rc);
  540.     return(rc);
  541. }
  542.  
  543. int
  544. #ifdef CK_ANSIC
  545. le_putstr(CHAR * s)
  546. #else
  547. le_putstr(s) CHAR * s;
  548. #endif /* CK_ANSIC */
  549. /* le_puts */ {
  550.     CHAR * p;
  551.     int rc = 0;
  552.     p = (CHAR *)"le_putstr";
  553.     hexdump(p,s,(int)strlen((char *)s));
  554.     for (p = s; *p && !rc; p++)
  555.       rc = le_putchar(*p);
  556.     return(rc);
  557. }
  558.  
  559. int
  560. #ifdef CK_ANSIC
  561. le_getchar(CHAR * pch)
  562. #else /* CK_ANSIC */
  563. le_getchar(pch) CHAR * pch;
  564. #endif /* CK_ANSIC */
  565. /* le_gatchar */ {
  566.     int rc = 0;
  567.     if (le_start != le_end) {
  568.         *pch = le_buf[le_start];
  569.         le_buf[le_start] = 0;
  570.         le_start++;
  571.  
  572.         if (le_start == LEBUFSIZ)
  573.           le_start = 0;
  574.  
  575.         if (le_start == le_end) {
  576.             le_data = 0;
  577.         }
  578.         rc++;
  579.     } else {
  580.         *pch = 0;
  581.     }
  582.     return(rc);
  583. }
  584. #endif /* NETLEBUF */
  585.  
  586. #ifdef VMS
  587. /*
  588.   In edit 190, we moved tn_ini() to be called from within netopen().
  589.   But tn_ini() calls ttol(), and ttol() checks to see if it's a net
  590.   connection, but the flag for that isn't set until after netopen()
  591.   is finished.  Since, in this module, we are always doing network
  592.   output anyway, we just call nettol() directly, instead of going thru
  593.   ttol().  Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
  594.   net connections just like regular connections in ttol(), and OS/2
  595.   has a special routine for this.
  596. */
  597. #define ttol nettol
  598. #endif /* VMS */
  599.  
  600. int tcpsrfd = -1;
  601.  
  602. #ifdef CK_KERBEROS
  603.  
  604. char * krb5_d_principal = NULL;         /* Default principal */
  605. char * krb5_d_instance = NULL;          /* Default instance */
  606. char * krb5_d_realm = NULL;             /* Default realm */
  607. char * krb5_d_cc = NULL;                /* Default credentials cache */
  608. char * krb5_d_srv   = NULL;             /* Default Service */
  609. int    krb5_d_lifetime = 600;           /* Default lifetime (10 hours) */
  610. int    krb5_d_forwardable = 0;          /* creds not forwardable */
  611. int    krb5_d_proxiable = 0;            /* creds not proxiable */
  612. int    krb5_d_renewable = 0;            /* creds not renewable (0 min) */
  613. int    krb5_autoget = 1;                /* Autoget TGTs */
  614. int    krb5_autodel = 0;                /* Auto delete TGTs */
  615. int    krb5_d_getk4 = 0;                /* K5 Kinit gets K4 TGTs */
  616. int    krb5_checkaddrs = 1;             /* Check TGT Addrs */
  617.  
  618. int    krb5_errno = 0;                  /* Last K5 errno */
  619. char * krb5_errmsg = NULL;              /* Last K5 errmsg */
  620.  
  621. char * krb4_d_principal = NULL;         /* Default principal */
  622. char * krb4_d_realm = NULL;             /* Default realm */
  623. char * krb4_d_srv   = NULL;             /* Default Service */
  624. int    krb4_d_lifetime = 600;           /* Default lifetime (10 hours) */
  625. int    krb4_d_preauth = 1;              /* Use preauth requests */
  626. char * krb4_d_instance = NULL;          /* Default instance */
  627. int    krb4_autoget = 1;                /* Autoget TGTs */
  628. int    krb4_autodel = 0;                /* Auto delete TGTs */
  629. int    krb4_checkaddrs = 1;             /* Check TGT Addrs */
  630.  
  631. int    krb4_errno = 0;                  /* Last K4 errno */
  632. char * krb4_errmsg = NULL;              /* Last K4 errmsg */
  633.  
  634. struct krb_op_data krb_op = {           /* Operational data structure */
  635.     0, NULL                             /* (version, cachefile) */
  636. };
  637.  
  638. struct krb4_init_data krb4_init = {     /* Kerberos 4 INIT data structure */
  639.     0, NULL, NULL, NULL, NULL
  640. };
  641.  
  642. struct krb5_init_data krb5_init = {     /* Kerberos 5 INIT data structure */
  643.     0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
  644.     { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  645.       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
  646. };
  647.  
  648. struct krb5_list_cred_data krb5_lc = {  /* List Credentials data structure */
  649.     0, 0, 0
  650. };
  651.  
  652. int krb_action = -1;                    /* Kerberos action to perform */
  653.  
  654. #ifndef CK_AUTHENTICATION
  655. char *
  656. ck_krb4_getrealm() {
  657.     return("");
  658. }
  659. char *
  660. ck_krb5_getrealm(cc) char * cc; {
  661.     return("");
  662. }
  663. char *
  664. ck_krb4_getprincipal() {
  665.     return("");
  666. }
  667. char *
  668. ck_krb5_getprincipal(cc) char * cc; {
  669.     return("");
  670. }
  671. #endif /* CK_AUTHENTICATION */
  672.  
  673. /*  I N I _ K E R B  --  Initialize Kerberos data  */
  674.  
  675. VOID
  676. ini_kerb() {
  677.     int i;
  678.  
  679.     krb_action = -1;                    /* No action specified */
  680.  
  681.     krb_op.version = 0;                 /* Kerberos version (none) */
  682.     krb_op.cache = NULL;                /* Cache file (none) */
  683.  
  684. /* Kerberos 5 */
  685.  
  686.     krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
  687.     krb5_init.proxiable   = krb5_d_proxiable;
  688.     krb5_init.lifetime    = krb5_d_lifetime;
  689.     krb5_init.renew       = 0;
  690.     krb5_init.renewable   = krb5_d_renewable;
  691.     krb5_init.validate    = 0;
  692.     if (krb5_init.postdate) {
  693.         free(krb5_init.postdate);
  694.         krb5_init.postdate = NULL;
  695.     }
  696.     if (krb5_init.service) {
  697.         free(krb5_init.service);
  698.         krb5_init.service = NULL;
  699.     }
  700.     if (!krb5_d_cc || !krb5_d_cc[0]) {  /* Set default cache */
  701.         char * p;
  702.         p = ck_krb5_get_cc_name();
  703.         makestr(&krb5_d_cc,p);
  704.     }
  705.     if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
  706.         char * p;
  707.         p = ck_krb5_getrealm(krb5_d_cc);
  708.         makestr(&krb5_d_realm,p);
  709.     }
  710.     makestr(&krb5_init.instance,krb5_d_instance);
  711.     makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
  712.     if (krb5_init.password) {
  713.         memset(krb5_init.password,0xFF,strlen(krb5_init.password));
  714.         free(krb5_init.password);
  715.         krb5_init.password = NULL;
  716.     }
  717.     if (!krb5_d_principal) {            /* Default principal */
  718.         /* a Null principal indicates the user should be prompted */
  719.         char * p = ck_krb5_getprincipal(krb5_d_cc);
  720.         if (!p || !(*p))
  721.           p = (char *)uidbuf;           /* Principal = user */
  722.         makestr(&(krb5_d_principal),p);
  723.     }
  724.     makestr(&(krb5_init.principal),krb5_d_principal);
  725.     for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
  726.         if (krb5_init.addrs[i])
  727.           free(krb5_init.addrs[i]);
  728.         krb5_init.addrs[i] = NULL;
  729.     }
  730.  
  731. /* Kerberos 4 */
  732.  
  733.     krb4_init.lifetime = krb4_d_lifetime;
  734.     krb4_init.preauth  = krb4_d_preauth;
  735.     makestr(&krb4_init.instance,krb4_d_instance);
  736.     if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
  737.         char * p;
  738.         p = ck_krb4_getrealm();
  739.         makestr(&krb4_d_realm,p);
  740.     }
  741.     makestr(&krb4_init.realm,krb4_d_realm);
  742.     if (krb4_init.password) {
  743.         memset(krb4_init.password,0xFF,strlen(krb4_init.password));
  744.         free(krb4_init.password);
  745.         krb4_init.password = NULL;
  746.     }
  747.     if (!krb4_d_principal) {            /* Default principal */
  748.         /* a Null principal indicates the user should be prompted */
  749.         char * p = ck_krb4_getprincipal();
  750.         if (!p || !(*p))
  751.           p = (char *)uidbuf;           /* Principal = user */
  752.         makestr(&(krb4_d_principal),p);
  753.     }
  754.     makestr(&(krb4_init.principal),krb4_d_principal);
  755. }
  756.  
  757. /*  D O A U T H  --  AUTHENTICATE action routine  */
  758.  
  759. int
  760. doauth(cx) int cx; {                    /* AUTHENTICATE action routine */
  761.     int rc = 0;                         /* Return code */
  762.  
  763. #ifdef CK_AUTHENTICATION
  764. #ifdef OS2
  765.     if (!ck_auth_loaddll())             /* Load Kerberos DLL */
  766.       return(rc);
  767. #endif /* OS2 */
  768.     if (krb_op.version == 4) {          /* Version = 4 */
  769. #ifdef COMMENT
  770.         sho_auth(AUTHTYPE_KERBEROS_V4);
  771. #endif /* COMMENT */
  772.         if (!ck_krb4_is_installed()) {
  773.             printf("?Kerberos 4 is not installed\n");
  774.             return(0);
  775.         }
  776.         switch (krb_action) {           /* Perform V4 functions */
  777.           case KRB_A_IN:                /* INIT */
  778.             rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
  779.             break;
  780.           case KRB_A_DE:                /* DESTROY */
  781.             rc |= !(ck_krb4_destroy(&krb_op) < 0);
  782.             break;
  783.           case KRB_A_LC:                /* LIST-CREDENTIALS */
  784.             rc |= !(ck_krb4_list_creds(&krb_op) < 0);
  785.             break;
  786.         }
  787.     }
  788.     if (krb_op.version == 5) {          /* V5 functions */
  789. #ifdef COMMENT
  790.         sho_auth(AUTHTYPE_KERBEROS_V5);
  791. #endif /* COMMENT */
  792.         if (!ck_krb5_is_installed()) {
  793.             printf("?Kerberos 5 is not installed\n");
  794.             return(0);
  795.         }
  796.         switch (krb_action) {
  797.           case KRB_A_IN:                /* INIT */
  798.             rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init) < 0);
  799.             if ( krb5_init.getk4 )
  800.                 rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
  801.             break;
  802.           case KRB_A_DE:                /* DESTROY */
  803.             rc |= !(ck_krb5_destroy(&krb_op) < 0);
  804.             break;
  805.           case KRB_A_LC:                /* LIST-CREDENTIALS */
  806.             if (krb_op.version == 0)
  807.               printf("\n");
  808.             rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
  809.             break;
  810.         }
  811.     }
  812. #else
  813. #ifndef NOICP
  814. #ifndef NOSHOW
  815.     rc = sho_auth(0);                   /* Show all */
  816. #endif /* NOSHOW */
  817. #endif /* NOICP */
  818. #endif /* CK_AUTHENTICATION */
  819.     return(rc);
  820. }
  821. #endif /* CK_KERBEROS */
  822.  
  823. #ifdef TCPSOCKET
  824. #ifndef OS2
  825. #ifndef NOLISTEN                        /* For incoming connections */
  826.  
  827. #ifndef INADDR_ANY
  828. #define INADDR_ANY 0
  829. #endif /* INADDR_ANY */
  830.  
  831. _PROTOTYP( int ttbufr, ( VOID ) );
  832. _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
  833.  
  834. static unsigned short tcpsrv_port = 0;
  835.  
  836. #endif /* NOLISTEN */
  837. #endif /* OS2 */
  838.  
  839. static char svcbuf[80];                 /* TCP service string */
  840. static int svcnum = 0;                  /* TCP port number */
  841.  
  842. #endif /* TCPSOCKET */
  843.  
  844. /*
  845.   TCPIPLIB means use separate socket calls for i/o, while on UNIX the
  846.   normal file system calls are used for TCP/IP sockets too.
  847.   Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
  848. */
  849.  
  850. #ifdef TCPIPLIB
  851.  
  852. /* For buffered network reads... */
  853. /*
  854.   If the buffering code is written right, it shouldn't matter
  855.   how long this buffer is.
  856. */
  857. #ifdef OS2
  858. #ifdef NT
  859. #define TTIBUFL 64240                   /* 44 * 1460 (MSS) */
  860. #else
  861. #define TTIBUFL 32120                   /* 22 * 1460 (MSS) */
  862. #endif /* NT */
  863. #else /* OS2 */
  864. #define TTIBUFL 8191                    /* Let's use 8K. */
  865. #endif /* OS2 */
  866.  
  867. CHAR ttibuf[TTIBUFL+1];
  868.  
  869. /*
  870.   select() is used in preference to alarm()/signal(), but different systems
  871.   use different forms of select()...
  872. */
  873. #ifndef NOSELECT         /* Option to override BSDSELECT */
  874. #ifdef BELLV10
  875. /*
  876.   Note: Although BELLV10 does have TCP/IP support, and does use the unique
  877.   form of select() that is evident in this module (and in ckutio.c), it does
  878.   not have a sockets library and so we can't build Kermit TCP/IP support for
  879.   it.  For this, somebody would have to write TCP/IP streams code.
  880. */
  881. #define BELLSELECT
  882. #ifndef FD_SETSIZE
  883. #define FD_SETSIZE 128
  884. #endif /* FD_SETSIZE */
  885. #else
  886. #ifdef WINTCP                           /* VMS with Wollongong WIN/TCP */
  887. #ifndef OLD_TWG                         /* TWG 3.2 has only select(read) */
  888. #define BSDSELECT
  889. #endif /* OLD_TWG */
  890. #else
  891. #ifdef CMU_TCPIP                        /* LIBCMU can do select */
  892. #define BSDSELECT
  893. #else
  894. #ifdef DEC_TCPIP
  895. #define BSDSELECT
  896. #else
  897. #ifdef OS2                              /* OS/2 with TCP/IP */
  898. #ifdef NT
  899. #define BSDSELECT
  900. #else /* NT */
  901. #define IBMSELECT
  902. #endif /* NT */
  903. #endif /* OS2 */
  904. #endif /* DEC_TCPIP */
  905. #endif /* CMU_TCPIP */
  906. #endif /* WINTCP */
  907. #endif /* BELLV10 */
  908. #endif /* NOSELECT */
  909. /*
  910.   Others (TGV, TCPware, ...) use alarm()/signal().  The BSDSELECT case does not
  911.   compile at all; the IBMSELECT case compiles and links but crashes at runtime.
  912.   NOTE: If any of these can be converted to select(), they should be for two
  913.   reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
  914.   their socket_read() calls to be interrupted; subsequent socket_read()'s tend
  915.   to fail with EBUSY.  This happened in the UCX case before it was converted
  916.   to use select().
  917. */
  918. #ifndef OS2
  919. #ifndef VMS
  920. static                                  /* These are used in CKVTIO.C */
  921. #endif /* VMS */                        /* And in CKONET.C            */
  922. #endif /* OS2 */
  923. int
  924.   ttibp = 0,
  925.   ttibn = 0;
  926. /*
  927.   Read bytes from network into internal buffer ttibuf[].
  928.   To be called when input buffer is empty, i.e. when ttibn == 0.
  929.  
  930.   Other network reading routines, like ttinc, ttinl, ttxin, should check the
  931.   internal buffer first, and call this routine for a refill if necessary.
  932.  
  933.   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
  934.   returns number of bytes read, and sets global ttibn to that number and
  935.   ttibp (the buffer pointer) to zero.
  936. */
  937. _PROTOTYP( int ttbufr, ( VOID ) );
  938. int
  939. ttbufr() {                              /* TT Buffer Read */
  940.     int count;
  941.  
  942.     if (ttnet != NET_TCPB)              /* First make sure current net is */
  943.       return(-1);                       /* TCP/IP; if not, do nothing. */
  944.  
  945.     if (ttibn > 0)                      /* Our internal buffer is not empty, */
  946.       return(ttibn);                    /* so keep using it. */
  947.  
  948.     ttibp = 0;                          /* Else reset pointer to beginning */
  949.  
  950.     if (ttyfd == -1)                    /* No connection, error */
  951.         return(-2);
  952.  
  953. #ifdef WINTCP
  954.     count = 512;                        /* This works for WIN/TCP */
  955. #else
  956. #ifdef DEC_TCPIP
  957.     count = 512;                        /* UCX */
  958. #else
  959. #ifdef OS2
  960.     count = TTIBUFL;
  961. #else                                   /* Multinet, etc. */
  962.     count = ttchk();                    /* Check network input buffer, */
  963.     if (ttibn > 0) {                    /* which can put a char there! */
  964.         debug(F111,"ttbufr","ttchk() returns",count);
  965.         return(ttibn);
  966.     }
  967.     if (count < 0)                      /* Read error - connection closed */
  968.       return(-2);
  969.     else if (count > TTIBUFL)           /* Too many to read */
  970.       count = TTIBUFL;
  971.     else if (count == 0)                /* None, so force blocking read */
  972.       count = 1;
  973. #endif /* OS2 */
  974. #endif /* DEC_TCPIP */
  975. #endif /* WINTCP */
  976.     debug(F101,"ttbufr count 1","",count);
  977.  
  978. #ifdef CK_SSL
  979.     if (ssl_active_flag || tls_active_flag) {
  980.         int error;
  981.         if (ssl_active_flag)
  982.           count = SSL_read(ssl_con, ttibuf, count);
  983.         else
  984.           count = SSL_read(tls_con, ttibuf, count);
  985.         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,count)) {
  986.           case SSL_ERROR_NONE:
  987.             debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
  988.             if (count > 0) {
  989.                 ttibp = 0;              /* Reset buffer pointer. */
  990.                 ttibn = count;
  991.                 return(ttibn);          /* Return buffer count. */
  992.             } else if (count < 0) {
  993.                 return(-1);
  994.             } else {
  995.                 netclos();
  996.                 return(-2);
  997.             }
  998.           case SSL_ERROR_WANT_WRITE:
  999.             debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
  1000.             return(-1);
  1001.           case SSL_ERROR_WANT_READ:
  1002.             debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
  1003.             return(-1);
  1004.           case SSL_ERROR_SYSCALL:
  1005. #ifdef NT
  1006.             debug(F111,"ttbufr SSL_ERROR_SYSCALL",
  1007.                   "GetLastError()",GetLastError());
  1008. #endif /* NT */
  1009.             netclos();
  1010.             return(-2);
  1011.           case SSL_ERROR_WANT_X509_LOOKUP:
  1012.             debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
  1013.             netclos();
  1014.             return(-2);
  1015.           case SSL_ERROR_SSL:
  1016.             debug(F100,"ttbufr SSL_ERROR_SSL","",0);
  1017.             netclos();
  1018.             return(-2);
  1019.           case SSL_ERROR_ZERO_RETURN:
  1020.             debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
  1021.             netclos();
  1022.             return(-2);
  1023.           default:
  1024.             debug(F100,"ttbufr SSL_ERROR_?????","",0);
  1025.             netclos();
  1026.             return(-2);
  1027.         }
  1028.     }
  1029. #endif /* CK_SSL */
  1030.  
  1031. #ifdef COMMENT
  1032. /*
  1033.  This is for nonblocking reads, which we don't do any more.  This code didn't
  1034.  work anyway, in the sense that a broken connection was never sensed.
  1035. */
  1036.     if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
  1037.         if (count == -1 && socket_errno == EWOULDBLOCK) {
  1038.             debug(F100,"ttbufr finds nothing","",0);
  1039.             return(0);
  1040.         } else {
  1041.             debug(F101,"ttbufr socket_read error","",socket_errno);
  1042.             return(-1);
  1043.         }
  1044.  
  1045.     } else if (count == 0) {
  1046.         debug(F100,"ttbufr socket eof","",0);
  1047.         return(-1);
  1048.     }
  1049. #else /* COMMENT */
  1050.  
  1051. /* This is for blocking reads */
  1052.  
  1053. #ifndef VMS
  1054. #ifdef SO_OOBINLINE
  1055.     {
  1056.         int outofband = 0;
  1057. #ifdef BELLSELECT
  1058.         if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
  1059.           outofband = 1;
  1060. #else
  1061. #ifdef BSDSELECT
  1062.         fd_set efds;
  1063.         struct timeval tv;
  1064.         FD_ZERO(&efds);
  1065.         FD_SET(ttyfd, &efds);
  1066.         tv.tv_sec  = tv.tv_usec = 0L;
  1067.         debug(F100,"Out-of-Band BSDSELECT","",0);
  1068. #ifdef NT
  1069.         WSASafeToCancel = 1;
  1070. #endif /* NT */
  1071.         if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
  1072.             FD_ISSET(ttyfd, &efds))
  1073.           outofband = 1;
  1074. #ifdef NT
  1075.         WSASafeToCancel = 0;
  1076. #endif /* NT */
  1077. #else /* !BSDSELECT */
  1078. #ifdef IBMSELECT
  1079. /* Was used by OS/2, currently not used, but might come in handy some day... */
  1080. /* ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set */
  1081. /* and timeval stuff since this is the only place where it is used. */
  1082.         int socket = ttyfd;
  1083.         debug(F100,"Out-of-Band IBMSELECT","",0);
  1084.         if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
  1085.           outofband = 1;
  1086. #else /* !IBMSELECT */
  1087. /*
  1088.   If we can't use select(), then we use the regular alarm()/signal()
  1089.   timeout mechanism.
  1090. */
  1091.       debug(F101,"Out-of-Band data not supported","",0);
  1092.       outofband = 0;
  1093.  
  1094. #endif /* IBMSELECT */
  1095. #endif /* BSDSELECT */
  1096. #endif /* BELLSELECT */
  1097.       if (outofband) {
  1098.          /* Get the Urgent Data */
  1099.          /* if OOBINLINE is disabled this should be only a single byte      */
  1100.          /* MS Winsock has a bug in Windows 95.  Extra bytes are delivered  */
  1101.          /* That were never sent.                                           */
  1102. #ifdef OS2
  1103.           RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
  1104. #endif /* OS2 */
  1105.           count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
  1106. #ifdef OS2
  1107.           ReleaseTCPIPMutex();
  1108. #endif /* OS2 */
  1109.           if (count <= 0) {
  1110.               int s_errno = socket_errno;
  1111.               debug(F101, "ttbufr socket_recv MSG_OOB","",count);
  1112.               debug(F101, "ttbufr socket_errno","",s_errno);
  1113. #ifdef OS2ONLY
  1114.               if (count < 0 && (s_errno == 0 || s_errno == 23)) {
  1115.                   /* These appear in OS/2 - don't know why   */
  1116.                   /* ignore it and read as normal data       */
  1117.                   /* and break, then we will attempt to read */
  1118.                   /* the port using normal read() techniques */
  1119.                   debug(F100,"ttbufr handing as in-band data","",0);
  1120.                   count = 1;
  1121.               } else {
  1122.                   netclos();                    /* *** *** */
  1123.                   return(-2);
  1124.               }
  1125. #else /* OS2ONLY */
  1126.               netclos();                        /* *** *** */
  1127.               return(-2);
  1128. #endif /* OS2ONLY */
  1129.           } else {                      /* we got out-of-band data */
  1130.               hexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
  1131. #ifdef BETATEST
  1132.               bleep(BP_NOTE);
  1133. #endif /* BETATEST */
  1134. #ifdef RLOGCODE                         /* blah */
  1135.               if (ttnproto == NP_RLOGIN  ||
  1136.                   ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
  1137.                   ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
  1138.                    ) {
  1139.                   /*
  1140.                     When urgent data is read with MSG_OOB and not OOBINLINE
  1141.                     then urgent data and normal data are not mixed.  So
  1142.                     treat the entire buffer as urgent data.
  1143.                   */
  1144.                   rlog_oob(&ttibuf[ttibp+ttibn], count);
  1145.                   return ttbufr();
  1146.               } else
  1147. #endif /* RLOGCODE */ /* blah */
  1148. #ifdef COMMENT
  1149.             /*
  1150.                I haven't written this yet, nor do I know what it should do
  1151.              */
  1152.                 if (ttnproto == NP_TELNET) {
  1153.                     tn_oob();
  1154.                     return 0;
  1155.                 } else
  1156. #endif /* COMMENT */
  1157.                   {
  1158.                    /* For any protocols we don't have a special out-of-band  */
  1159.                    /* handler for, just put the bytes in the normal buffer   */
  1160.                    /* and return                                             */
  1161.  
  1162. #ifdef OS2
  1163.                       RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
  1164. #endif /* OS2 */
  1165.                       ttibp += 0;       /* Reset buffer pointer. */
  1166.                       ttibn += count;
  1167. #ifdef OS2
  1168.                       ReleaseTCPIPMutex();
  1169. #endif /* OS2 */
  1170. #ifdef DEBUG
  1171.                       /* Got some bytes. */
  1172.                       debug(F101,"ttbufr count 2","",count);
  1173.                       if (count > 0)
  1174.                         ttibuf[ttibp+ttibn] = '\0';
  1175.                       debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
  1176. #endif /* DEBUG */
  1177.                       return(ttibn);    /* Return buffer count. */
  1178.                   }
  1179.           }
  1180.       }
  1181.     }
  1182. #endif /* SO_OOBINLINE */
  1183. #endif /* VMS */
  1184.  
  1185. #ifdef OS2
  1186.     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
  1187. #endif /* OS2 */
  1188.     count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
  1189. #ifdef OS2
  1190.     ReleaseTCPIPMutex();
  1191. #endif /* OS2 */
  1192.     if (count <= 0) {
  1193.         int s_errno = socket_errno;
  1194.         debug(F101,"ttbufr socket_read","",count);
  1195.         debug(F101,"ttbufr socket_errno","",s_errno);
  1196. #ifdef OS2
  1197.         if (count == 0 || os2socketerror(s_errno) < 0) {
  1198.             netclos();
  1199.             return(-2);
  1200.         }
  1201.         return(-1);
  1202. #else /* OS2 */
  1203.         netclos();                      /* *** *** */
  1204.         return(-2);
  1205. #endif /* OS2 */
  1206.     }
  1207. #endif /* COMMENT */ /* (blocking vs nonblock reads...) */
  1208.     else {
  1209. #ifdef OS2
  1210.     RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
  1211. #endif /* OS2 */
  1212.         ttibp = 0;                      /* Reset buffer pointer. */
  1213.         ttibn += count;
  1214. #ifdef OS2
  1215.     ReleaseTCPIPMutex();
  1216. #endif /* OS2 */
  1217. #ifdef DEBUG
  1218.         debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
  1219.         if (count > 0)
  1220.           ttibuf[ttibp+ttibn] = '\0';
  1221.         debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
  1222. #endif /* DEBUG */
  1223.         return(ttibn);                  /* Return buffer count. */
  1224.     }
  1225. }
  1226. #endif /* TCPIPLIB */
  1227.  
  1228. #ifndef IBMSELECT
  1229. #ifndef BELLSELECT
  1230. #ifndef BSDSELECT               /* Non-TCPIPLIB case */
  1231. #ifdef SELECT
  1232. #define BSDSELECT
  1233. #endif /* SELECT */
  1234. #endif /* BSDSELECT */
  1235. #endif /* BELLSELECT */
  1236. #endif /* IBMSELECT */
  1237.  
  1238. #define TELNET_PORT 23          /* Should do lookup, but it won't change */
  1239. #define RLOGIN_PORT 513
  1240. #define KERMIT_PORT 1649
  1241. #define KLOGIN_PORT 543
  1242. #define EKLOGIN_PORT 2105
  1243.  
  1244. /* Type needed as 5th argument (length) to get/setsockopt() */
  1245.  
  1246. #ifndef SOCKOPT_T
  1247. #define SOCKOPT_T int
  1248. #ifdef AIX42
  1249. #undef SOCKOPT_T
  1250. #define SOCKOPT_T unsigned long
  1251. #else
  1252. #ifdef PTX
  1253. #undef SOCKOPT_T
  1254. #define SOCKOPT_T size_t
  1255. #else
  1256. #ifdef NT
  1257. #undef SOCKOPT_T
  1258. #define SOCKOPT_T int
  1259. #else /* NT */
  1260. #ifdef UNIXWARE
  1261. #undef SOCKOPT_T
  1262. #define SOCKOPT_T size_t
  1263. #else /* UNIXWARE */
  1264. #ifdef VMS
  1265. #ifdef DEC_TCPIP
  1266. #ifdef __DECC_VER
  1267. #undef SOCKOPT_T
  1268. #define SOCKOPT_T size_t
  1269. #endif /* __DECC_VER */
  1270. #endif /* DEC_TCPIP */
  1271. #endif /* VMS */
  1272. #endif /* UNIXWARE */
  1273. #endif /* NT */
  1274. #endif /* PTX */
  1275. #endif /* AIX42 */
  1276. #endif /* SOCKOPT_T */
  1277.  
  1278. /* Ditto for getsockname() */
  1279.  
  1280. #ifndef GSOCKNAME_T
  1281. #define GSOCKNAME_T int
  1282. #ifdef PTX
  1283. #undef GSOCKNAME_T
  1284. #define GSOCKNAME_T size_t
  1285. #else
  1286. #ifdef AIX42                            /* size_t in 4.2++, int in 4.1-- */
  1287. #undef GSOCKNAME_T
  1288. #define GSOCKNAME_T size_t
  1289. #else
  1290. #ifdef UNIXWARE
  1291. #undef GSOCKNAME_T
  1292. #define GSOCKNAME_T size_t
  1293. #else
  1294. #ifdef VMS
  1295. #ifdef DEC_TCPIP
  1296. #ifdef __DECC_VER
  1297. #undef GSOCKNAME_T
  1298. #define GSOCKNAME_T size_t
  1299. #endif /* __DECC_VER */
  1300. #endif /* DEC_TCPIP */
  1301. #endif /* VMS */
  1302. #endif /* UNIXWARE */
  1303. #endif /* AIX41 */
  1304. #endif /* PTX */
  1305. #endif /* GSOCKNAME_T */
  1306.  
  1307. #ifndef NOLOCAL
  1308. /*
  1309.   C-Kermit network open/close functions for BSD-sockets.
  1310.   Much of this code shared by SunLink X.25, which also uses the socket library.
  1311. */
  1312.  
  1313. /*  N E T O P N  --  Open a network connection.  */
  1314. /*
  1315.   Call with:
  1316.     name of host (or host:service),
  1317.     lcl - local-mode flag to be set if this function succeeds,
  1318.     network type - value defined in ckunet.h.
  1319. */
  1320. #ifdef TCPSOCKET
  1321. #ifdef EXCELAN
  1322. /*
  1323.   Most other BSD sockets implementations define these in header files
  1324.   and libraries.
  1325. */
  1326. struct servent {
  1327.     unsigned short s_port;
  1328. };
  1329.  
  1330. struct hostent {
  1331.     short h_addrtype;
  1332.     struct in_addr h_addr;
  1333.     int h_length;
  1334. };
  1335.  
  1336. struct servent *
  1337. getservbyname(service, connection) char *service,*connection; {
  1338.     static struct servent servrec;
  1339.     int port;
  1340.  
  1341.     port = 0;
  1342.     if (strcmp(service, "telnet") == 0) port = 23;
  1343.     else if (strcmp(service, "smtp") == 0) port = 25;
  1344.     else port = atoi(service);
  1345.  
  1346.     debug(F101,"getservbyname return port ","",port);
  1347.  
  1348.     if (port > 0) {
  1349.         servrec.s_port = htons(port);
  1350.         return(&servrec);
  1351.     }
  1352.     return((struct servent *) NULL);
  1353. }
  1354.  
  1355. struct hostent *
  1356. gethostbyname(hostname) char *hostname; {
  1357.     return((struct hostent *) NULL);
  1358. }
  1359.  
  1360. unsigned long
  1361. inet_addr(name) char *name; {
  1362.     unsigned long addr;
  1363.  
  1364.     addr = rhost(&name);
  1365.     debug(F111,"inet_addr ",name,(int)addr);
  1366.     return(addr);
  1367. }
  1368.  
  1369. char *
  1370. inet_ntoa(in) struct in_addr in; {
  1371.     static char name[80];
  1372.     sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
  1373.     return(name);
  1374. }
  1375. #else
  1376. #ifdef DEC_TCPIP                        /* UCX */
  1377.  
  1378. int ucx_port_bug = 0;                   /* Explained below */
  1379.  
  1380. #ifndef __DECC                          /* VAXC or GCC */
  1381.  
  1382. #define getservbyname my_getservbyname
  1383.  
  1384. #ifdef CK_ANSIC
  1385. globalref int (*C$$GA_UCX_GETSERVBYNAME)();
  1386. extern void C$$TRANSLATE();
  1387. extern void C$$SOCK_TRANSLATE();
  1388. #else
  1389. globalref int (*C$$GA_UCX_GETSERVBYNAME)();
  1390. extern VOID C$$TRANSLATE();
  1391. extern VOID C$$SOCK_TRANSLATE();
  1392. #endif /* CK_ANSIC */
  1393.  
  1394. struct servent *
  1395. my_getservbyname (service, proto) char *service, *proto; {
  1396.     static struct servent sent;
  1397.     struct iosb {
  1398.         union {
  1399.             unsigned long status;
  1400.             unsigned short st[2];
  1401.         } sb;
  1402.         unsigned long spare;
  1403.     } s;
  1404.     struct {
  1405.         struct iosb *s;
  1406.         char *serv;
  1407.         char *prot;
  1408.     } par;
  1409.     unsigned long e;
  1410.     char sbuf[30], pbuf[30];
  1411.     char *p;
  1412.  
  1413.     debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
  1414.  
  1415.     p = sbuf;
  1416.     ckstrncpy(p, service, 29);
  1417.     while (*p = toupper(*p), *p++) {}
  1418.     p = pbuf;
  1419.     ckstrncpy(p, proto, 29);
  1420.     while (*p = toupper(*p), *p++) {}
  1421.  
  1422.     par.s = &s;
  1423.  
  1424.     par.serv = "";
  1425.     par.prot = "";
  1426.     /* reset file pointer or something like that!?!? */
  1427.     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
  1428.     par.serv = sbuf;
  1429.     par.prot = pbuf;            /* that is don't care */
  1430.     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
  1431.     if ((long)e == -1L)
  1432.       return NULL;
  1433.     if ((e & 1) == 0L) {
  1434.         C$$TRANSLATE(e);
  1435.         return NULL;
  1436.     }
  1437.     if ((s.sb.st[0] & 1) == 0) {
  1438.         C$$SOCK_TRANSLATE(&s.sb.st[0]);
  1439.         return NULL;
  1440.     }
  1441. /*
  1442.   sent.s_port is supposed to be returned by UCX in network byte order.
  1443.   However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
  1444.   But there is no way of knowing which UCX version, so we have a user-settable
  1445.   runtime variable.  Note: UCX 2.0 was only for the VAX.
  1446. */
  1447.     debug(F101,"UCX getservbyname port","",sent.s_port);
  1448.     debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
  1449.     if (ucx_port_bug) {
  1450.         sent.s_port = htons(sent.s_port);
  1451.         debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
  1452.         debug(F101,"UCX swapped port","",sent.s_port);
  1453.         debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
  1454.     }
  1455.     return &sent;
  1456. }
  1457. #endif /* __DECC */
  1458. #endif /* DEC_TCPIP */
  1459. #endif /* EXCELAN */
  1460. #endif /* TCPSOCKET */
  1461.  
  1462. #ifndef NOTCPOPTS
  1463. #ifndef datageneral
  1464. int
  1465. ck_linger(onoff, timo) int onoff; int timo; {
  1466. /*
  1467.   The following, from William Bader, turns off the socket linger parameter,
  1468.   which makes a close() block until all data is sent.  "I don't think that
  1469.   disabling linger can ever cause kermit to lose data, but you telnet to a
  1470.   flaky server (or to our modem server when the modem is in use), disabling
  1471.   linger prevents kermit from hanging on the close if you try to exit."
  1472.  
  1473.   Modified by Jeff Altman to be generally useful.
  1474. */
  1475. #ifdef SOL_SOCKET
  1476. #ifdef SO_LINGER
  1477.     struct linger set_linger_opt;
  1478.     struct linger get_linger_opt;
  1479.     SOCKOPT_T x;
  1480.  
  1481.     if (ttyfd == -1 ||
  1482.         nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1483.         tcp_linger = onoff;
  1484.         tcp_linger_tmo = timo;
  1485.         return(1);
  1486.     }
  1487.     x = sizeof(get_linger_opt);
  1488.     if (getsockopt(ttyfd, SOL_SOCKET, SO_LINGER,
  1489.                     (char *)&get_linger_opt, &x)) {
  1490.         debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
  1491.     } else if (x != sizeof(get_linger_opt)) {
  1492. #ifdef OS2
  1493.         struct _linger16 {
  1494.             short s_linger;
  1495.             short s_onoff;
  1496.         } get_linger_opt16, set_linger_opt16;
  1497.         if ( x == sizeof(get_linger_opt16) ) {
  1498.             debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
  1499.             if (getsockopt(ttyfd,
  1500.                            SOL_SOCKET, SO_LINGER,
  1501.                            (char *)&get_linger_opt16, &x)
  1502.                 ) {
  1503.                 debug(F111,
  1504.                       "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
  1505.             } else if (get_linger_opt16.s_onoff != onoff ||
  1506.                        get_linger_opt16.s_linger != timo)
  1507.             {
  1508.                 set_linger_opt16.s_onoff  = onoff;
  1509.                 set_linger_opt16.s_linger = timo;
  1510.                 if (setsockopt(ttyfd,
  1511.                                SOL_SOCKET,
  1512.                                SO_LINGER,
  1513.                                (char *)&set_linger_opt16,
  1514.                                sizeof(set_linger_opt16))
  1515.                     ) {
  1516.                     debug(F111,
  1517.                           "TCP ck_linger can't set SO_LINGER",
  1518.                           ck_errstr(),
  1519.                           errno
  1520.                           );
  1521.                     tcp_linger = get_linger_opt16.s_onoff;
  1522.                     tcp_linger_tmo = get_linger_opt16.s_linger;
  1523.                 } else {
  1524.                     debug(F101,
  1525.                           "TCP ck_linger new SO_LINGER","",
  1526.                           set_linger_opt16.s_onoff);
  1527.                     tcp_linger = set_linger_opt16.s_onoff;
  1528.                     tcp_linger_tmo = set_linger_opt16.s_linger;
  1529.                     return 1;
  1530.                 }
  1531.             } else {
  1532.                 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
  1533.                        get_linger_opt16.s_onoff);
  1534.                 tcp_linger = get_linger_opt16.s_onoff;
  1535.                 tcp_linger_tmo = get_linger_opt16.s_linger;
  1536.                 return 1;
  1537.             }
  1538.             return(0);
  1539.         }
  1540. #endif /* OS2 */
  1541.         debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
  1542.         debug(F111,"TCP ck_linger SO_LINGER",
  1543.               "expected len",sizeof(get_linger_opt));
  1544.         debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
  1545.               get_linger_opt.l_onoff);
  1546.         debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
  1547.                get_linger_opt.l_linger);
  1548.     } else if (get_linger_opt.l_onoff != onoff ||
  1549.                get_linger_opt.l_linger != timo) {
  1550.         set_linger_opt.l_onoff  = onoff;
  1551.         set_linger_opt.l_linger = timo;
  1552.         if (setsockopt(ttyfd,
  1553.                        SOL_SOCKET,
  1554.                        SO_LINGER,
  1555.                        (char *)&set_linger_opt,
  1556.                        sizeof(set_linger_opt))) {
  1557.             debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
  1558.             tcp_linger = get_linger_opt.l_onoff;
  1559.             tcp_linger_tmo = get_linger_opt.l_linger;
  1560.          } else {
  1561.              debug(F101,
  1562.                    "TCP ck_linger new SO_LINGER",
  1563.                    "",
  1564.                    set_linger_opt.l_onoff
  1565.                    );
  1566.              tcp_linger = set_linger_opt.l_onoff;
  1567.              tcp_linger_tmo = set_linger_opt.l_linger;
  1568.              return 1;
  1569.          }
  1570.     } else {
  1571.         debug(F101,"TCP ck_linger SO_LINGER unchanged","",
  1572.               get_linger_opt.l_onoff);
  1573.         tcp_linger = get_linger_opt.l_onoff;
  1574.         tcp_linger_tmo = get_linger_opt.l_linger;
  1575.         return 1;
  1576.     }
  1577. #else
  1578.     debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
  1579. #endif /* SO_LINGER */
  1580. #else
  1581.     debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
  1582. #endif /* SOL_SOCKET */
  1583.     return(0);
  1584. }
  1585.  
  1586. int
  1587. sendbuf(size) int size; {
  1588. /*
  1589.   The following, from William Bader, allows changing of socket buffer sizes,
  1590.   in case that might affect performance.
  1591.  
  1592.   Modified by Jeff Altman to be generally useful.
  1593. */
  1594. #ifdef SOL_SOCKET
  1595. #ifdef SO_SNDBUF
  1596.     int i, j, rc = 0;
  1597.     SOCKOPT_T x;
  1598.  
  1599.     if (ttyfd == -1 ||
  1600.         nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1601.         tcp_sendbuf = size;
  1602.         return 1;
  1603.     }
  1604.     x = sizeof(i);
  1605.     if (getsockopt(ttyfd, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
  1606.         debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
  1607.     } else if (x != sizeof(i)) {
  1608. #ifdef OS2
  1609.         short i16,j16;
  1610.         if (x == sizeof(i16)) {
  1611.             debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
  1612.             if (getsockopt(ttyfd,
  1613.                            SOL_SOCKET, SO_SNDBUF,
  1614.                            (char *)&i16, &x)
  1615.                 ) {
  1616.                 debug(F111,"TCP sendbuf can't get SO_SNDBUF",
  1617.                       ck_errstr(),errno);
  1618.             } else if (size <= 0) {
  1619.                 tcp_sendbuf = i16;
  1620.                 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
  1621.                 return 1;
  1622.             } else if (i16 != size) {
  1623.                 j16 = size;
  1624.                 if (setsockopt(ttyfd,
  1625.                                SOL_SOCKET,
  1626.                                SO_SNDBUF,
  1627.                                (char *)&j16,
  1628.                                sizeof(j16))
  1629.                     ) {
  1630.                     debug(F111,"TCP sendbuf can't set SO_SNDBUF",
  1631.                           ck_errstr(),errno);
  1632.                 } else {
  1633.                     debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
  1634.                     debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
  1635.                     tcp_sendbuf = size;
  1636.                     return 1;
  1637.                 }
  1638.             } else {
  1639.                 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
  1640.                 tcp_sendbuf = size;
  1641.                 return 1;
  1642.             }
  1643.             return(0);
  1644.         }
  1645. #endif /* OS2 */
  1646.         debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
  1647.         debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
  1648.         debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
  1649.     } else if (size <= 0) {
  1650.         tcp_sendbuf = i;
  1651.         debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
  1652.         return 1;
  1653.     } else if (i != size) {
  1654.         j = size;
  1655.         if (setsockopt(ttyfd, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
  1656.             debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
  1657.             tcp_sendbuf = i;
  1658.         } else {
  1659.             debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
  1660.             debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
  1661.             tcp_sendbuf = size;
  1662.             return 1;
  1663.         }
  1664.     } else {
  1665.         debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
  1666.         tcp_sendbuf = size;
  1667.         return 1;
  1668.     }
  1669. #else
  1670.     debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
  1671. #endif /* SO_SNDBUF */
  1672. #else
  1673.     debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
  1674. #endif /* SOL_SOCKET */
  1675.     return(0);
  1676. }
  1677.  
  1678. int
  1679. recvbuf(size) int size; {
  1680. /*
  1681.   The following, from William Bader, allows changing of socket buffer sizes,
  1682.   in case that might affect performance.
  1683.  
  1684.   Modified by Jeff Altman to be generally useful.
  1685. */
  1686. #ifdef SOL_SOCKET
  1687. #ifdef SO_RCVBUF
  1688.     int i, j, rc = 0;
  1689.     SOCKOPT_T x;
  1690.  
  1691.     if (ttyfd == -1 ||
  1692.         nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1693.         tcp_recvbuf = size;
  1694.         return(1);
  1695.     }
  1696.     x = sizeof(i);
  1697.     if (getsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
  1698.         debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
  1699.     } else if (x != sizeof(i)) {
  1700. #ifdef OS2
  1701.         short i16,j16;
  1702.         if ( x == sizeof(i16) ) {
  1703.             debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
  1704.             if (getsockopt(ttyfd,
  1705.                            SOL_SOCKET, SO_RCVBUF,
  1706.                            (char *)&i16, &x)
  1707.                 ) {
  1708.                 debug(F111,"TCP recvbuf can't get SO_RCVBUF",
  1709.                       ck_errstr(),errno);
  1710.             } else if (size <= 0) {
  1711.                 tcp_recvbuf = i16;
  1712.                 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
  1713.                 return 1;
  1714.             } else if (i16 != size) {
  1715.                 j16 = size;
  1716.                 if (setsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
  1717.                                sizeof(j16))) {
  1718.                     debug(F111,"TCP recvbuf can' set SO_RCVBUF",
  1719.                           ck_errstr(),errno);
  1720.                 } else {
  1721.                     debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
  1722.                     debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
  1723.                     tcp_recvbuf = size;
  1724.                     return 1;
  1725.                 }
  1726.             } else {
  1727.                 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
  1728.                 tcp_recvbuf = size;
  1729.                 return 1;
  1730.             }
  1731.             return(0);
  1732.         }
  1733. #endif /* OS2 */
  1734.         debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
  1735.         debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
  1736.         debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
  1737.     } else if (size <= 0) {
  1738.         tcp_recvbuf = i;
  1739.         debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
  1740.         return 1;
  1741.     } else if (i != size) {
  1742.         j = size;
  1743.         if (setsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
  1744.             debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
  1745.             tcp_recvbuf = i;
  1746.         } else {
  1747.             debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
  1748.             debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
  1749.             tcp_recvbuf = size;
  1750.             return 1;
  1751.         }
  1752.     } else {
  1753.         debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
  1754.         tcp_recvbuf = size;
  1755.         return 1;
  1756.     }
  1757. #else
  1758.     debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
  1759. #endif /* SO_RCVBUF */
  1760. #else
  1761.     debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
  1762. #endif /* SOL_SOCKET */
  1763.     return 0;
  1764. }
  1765.  
  1766. int
  1767. keepalive(onoff) int onoff; {
  1768. #ifdef SOL_SOCKET
  1769. #ifdef SO_KEEPALIVE
  1770.     int get_keepalive_opt;
  1771.     int set_keepalive_opt;
  1772.     SOCKOPT_T x;
  1773.  
  1774.     if (ttyfd == -1 ||
  1775.         nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1776.         tcp_keepalive = onoff;
  1777.         return 1;
  1778.     }
  1779.     x = sizeof(get_keepalive_opt);
  1780.     if (getsockopt(ttyfd,
  1781.                    SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
  1782.         debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
  1783.     } else if (x != sizeof(get_keepalive_opt)) {
  1784. #ifdef OS2
  1785.         short get_keepalive_opt16;
  1786.         short set_keepalive_opt16;
  1787.         if (x == sizeof(get_keepalive_opt16)) {
  1788.             debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
  1789.                   "len is 16-bit",x);
  1790.             if (getsockopt(ttyfd,
  1791.                            SOL_SOCKET, SO_KEEPALIVE,
  1792.                            (char *)&get_keepalive_opt16, &x)
  1793.                 ) {
  1794.                 debug(F111,
  1795.                       "TCP keepalive can't get SO_KEEPALIVE",
  1796.                       ck_errstr(),
  1797.                       errno
  1798.                       );
  1799.             } else if (get_keepalive_opt16 != onoff) {
  1800.                 set_keepalive_opt16 = onoff;
  1801.                 if (setsockopt(ttyfd,
  1802.                                SOL_SOCKET,
  1803.                                SO_KEEPALIVE,
  1804.                                (char *)&set_keepalive_opt16,
  1805.                                sizeof(set_keepalive_opt16))
  1806.                     ) {
  1807.                     debug(F111,
  1808.                           "TCP keepalive can't clear SO_KEEPALIVE",
  1809.                           ck_errstr(),
  1810.                           errno
  1811.                           );
  1812.                     tcp_keepalive = get_keepalive_opt16;
  1813.                 } else {
  1814.                     debug(F101,
  1815.                           "TCP keepalive new SO_KEEPALIVE","",
  1816.                           set_keepalive_opt16);
  1817.                     tcp_keepalive = set_keepalive_opt16;
  1818.                     return 1;
  1819.                 }
  1820.             } else {
  1821.                 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
  1822.                       get_keepalive_opt16);
  1823.                 tcp_keepalive = onoff;
  1824.                 return 1;
  1825.             }
  1826.             return(0);
  1827.         }
  1828. #endif /* OS2 */
  1829.         debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
  1830.         debug(F111,
  1831.               "TCP keepalive SO_KEEPALIVE",
  1832.               "expected len",
  1833.               sizeof(get_keepalive_opt)
  1834.               );
  1835.         debug(F111,
  1836.               "TCP keepalive SO_KEEPALIVE",
  1837.               "keepalive_opt",
  1838.               get_keepalive_opt
  1839.               );
  1840.     } else if (get_keepalive_opt != onoff) {
  1841.             set_keepalive_opt = onoff;
  1842.             if (setsockopt(ttyfd,
  1843.                             SOL_SOCKET,
  1844.                             SO_KEEPALIVE,
  1845.                             (char *)&set_keepalive_opt,
  1846.                             sizeof(set_keepalive_opt))
  1847.                 ) {
  1848.                 debug(F111,
  1849.                       "TCP keepalive can't clear SO_KEEPALIVE",
  1850.                       ck_errstr(),
  1851.                       errno
  1852.                       );
  1853.                 tcp_keepalive = get_keepalive_opt;
  1854.             } else {
  1855.                 debug(F101,
  1856.                       "TCP keepalive new SO_KEEPALIVE",
  1857.                       "",
  1858.                       set_keepalive_opt
  1859.                       );
  1860.                 tcp_keepalive = onoff;
  1861.                 return 1;
  1862.             }
  1863.         } else {
  1864.             debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
  1865.                   "",
  1866.                   get_keepalive_opt
  1867.                   );
  1868.             tcp_keepalive = onoff;
  1869.             return 1;
  1870.     }
  1871. #else
  1872.     debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
  1873. #endif /* SO_KEEPALIVE */
  1874. #else
  1875.     debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
  1876. #endif /* SOL_SOCKET */
  1877.     return(0);
  1878. }
  1879.  
  1880. int
  1881. dontroute(onoff) int onoff; {
  1882. #ifdef SOL_SOCKET
  1883. #ifdef SO_DONTROUTE
  1884.     int get_dontroute_opt;
  1885.     int set_dontroute_opt;
  1886.     SOCKOPT_T x;
  1887.  
  1888.     if (ttyfd == -1 ||
  1889.         nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1890.         tcp_dontroute = onoff;
  1891.         return 1;
  1892.     }
  1893.     x = sizeof(get_dontroute_opt);
  1894.     if (getsockopt(ttyfd,
  1895.                    SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
  1896.         debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
  1897.     } else if (x != sizeof(get_dontroute_opt)) {
  1898. #ifdef OS2
  1899.         short get_dontroute_opt16;
  1900.         short set_dontroute_opt16;
  1901.         if (x == sizeof(get_dontroute_opt16)) {
  1902.             debug(F111,"TCP dontroute warning: SO_DONTROUTE",
  1903.                   "len is 16-bit",x);
  1904.             if (getsockopt(ttyfd,
  1905.                            SOL_SOCKET, SO_DONTROUTE,
  1906.                            (char *)&get_dontroute_opt16, &x)
  1907.                 ) {
  1908.                 debug(F111,
  1909.                       "TCP dontroute can't get SO_DONTROUTE",
  1910.                       ck_errstr(),
  1911.                       errno
  1912.                       );
  1913.             } else if (get_dontroute_opt16 != onoff) {
  1914.                 set_dontroute_opt16 = onoff;
  1915.                 if (setsockopt(ttyfd,
  1916.                                SOL_SOCKET,
  1917.                                SO_DONTROUTE,
  1918.                                (char *)&set_dontroute_opt16,
  1919.                                sizeof(set_dontroute_opt16))
  1920.                     ) {
  1921.                     debug(F111,
  1922.                           "TCP dontroute can't clear SO_DONTROUTE",
  1923.                           ck_errstr(),
  1924.                           errno
  1925.                           );
  1926.                     tcp_dontroute = get_dontroute_opt16;
  1927.                 } else {
  1928.                     debug(F101,
  1929.                           "TCP dontroute new SO_DONTROUTE","",
  1930.                           set_dontroute_opt16);
  1931.                     tcp_dontroute = set_dontroute_opt16;
  1932.                     return 1;
  1933.                 }
  1934.             } else {
  1935.                 debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
  1936.                       get_dontroute_opt16);
  1937.                 tcp_dontroute = onoff;
  1938.                 return 1;
  1939.             }
  1940.             return(0);
  1941.         }
  1942. #endif /* OS2 */
  1943.         debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
  1944.         debug(F111,
  1945.               "TCP dontroute SO_DONTROUTE",
  1946.               "expected len",
  1947.               sizeof(get_dontroute_opt)
  1948.               );
  1949.         debug(F111,
  1950.               "TCP dontroute SO_DONTROUTE",
  1951.               "dontroute_opt",
  1952.               get_dontroute_opt
  1953.               );
  1954.     } else if (get_dontroute_opt != onoff) {
  1955.             set_dontroute_opt = onoff;
  1956.             if (setsockopt(ttyfd,
  1957.                             SOL_SOCKET,
  1958.                             SO_DONTROUTE,
  1959.                             (char *)&set_dontroute_opt,
  1960.                             sizeof(set_dontroute_opt))
  1961.                 ) {
  1962.                 debug(F111,
  1963.                       "TCP dontroute can't clear SO_DONTROUTE",
  1964.                       ck_errstr(),
  1965.                       errno
  1966.                       );
  1967.                 tcp_dontroute = get_dontroute_opt;
  1968.             } else {
  1969.                 debug(F101,
  1970.                       "TCP dontroute new SO_DONTROUTE",
  1971.                       "",
  1972.                       set_dontroute_opt
  1973.                       );
  1974.                 tcp_dontroute = onoff;
  1975.                 return 1;
  1976.             }
  1977.         } else {
  1978.             debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
  1979.                   "",
  1980.                   get_dontroute_opt
  1981.                   );
  1982.             tcp_dontroute = onoff;
  1983.             return 1;
  1984.     }
  1985. #else
  1986.     debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
  1987. #endif /* SO_DONTROUTE */
  1988. #else
  1989.     debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
  1990. #endif /* SOL_SOCKET */
  1991.     return(0);
  1992. }
  1993.  
  1994. int
  1995. no_delay(onoff)  int onoff; {
  1996. #ifdef SOL_SOCKET
  1997. #ifdef TCP_NODELAY
  1998.     int get_nodelay_opt;
  1999.     int set_nodelay_opt;
  2000.     SOCKOPT_T x;
  2001.  
  2002.     if (ttyfd == -1 ||
  2003.         nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  2004.         tcp_nodelay = onoff;
  2005.         return(1);
  2006.     }
  2007.     x = sizeof(get_nodelay_opt);
  2008.     if (getsockopt(ttyfd,IPPROTO_TCP,TCP_NODELAY,
  2009.                    (char *)&get_nodelay_opt,&x)) {
  2010.         debug(F111,
  2011.               "TCP no_delay can't get TCP_NODELAY",
  2012.               ck_errstr(),
  2013.               errno);
  2014.     } else if (x != sizeof(get_nodelay_opt)) {
  2015. #ifdef OS2
  2016.         short get_nodelay_opt16;
  2017.         short set_nodelay_opt16;
  2018.         if (x == sizeof(get_nodelay_opt16)) {
  2019.             debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
  2020.             if (getsockopt(ttyfd,
  2021.                            IPPROTO_TCP, TCP_NODELAY,
  2022.                            (char *)&get_nodelay_opt16, &x)
  2023.                 ) {
  2024.                 debug(F111,
  2025.                       "TCP no_delay can't get TCP_NODELAY",
  2026.                       ck_errstr(),
  2027.                       errno);
  2028.             } else if (get_nodelay_opt16 != onoff) {
  2029.                 set_nodelay_opt16 = onoff;
  2030.                 if (setsockopt(ttyfd,
  2031.                                IPPROTO_TCP,
  2032.                                TCP_NODELAY,
  2033.                                (char *)&set_nodelay_opt16,
  2034.                                sizeof(set_nodelay_opt16))
  2035.                     ) {
  2036.                     debug(F111,
  2037.                           "TCP no_delay can't clear TCP_NODELAY",
  2038.                           ck_errstr(),
  2039.                           errno);
  2040.                     tcp_nodelay = get_nodelay_opt16;
  2041.                 } else {
  2042.                     debug(F101,
  2043.                           "TCP no_delay new TCP_NODELAY",
  2044.                           "",
  2045.                           set_nodelay_opt16);
  2046.                     tcp_nodelay = onoff;
  2047.                     return 1;
  2048.                 }
  2049.             } else {
  2050.                 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
  2051.                       get_nodelay_opt16);
  2052.                 tcp_nodelay = onoff;
  2053.                 return 1;
  2054.             }
  2055.             return(0);
  2056.         }
  2057. #endif /* OS2 */
  2058.         debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
  2059.         debug(F111,"TCP no_delay TCP_NODELAY","expected len",
  2060.               sizeof(get_nodelay_opt));
  2061.         debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
  2062.     } else if (get_nodelay_opt != onoff) {
  2063.         set_nodelay_opt = onoff;
  2064.         if (setsockopt(ttyfd,
  2065.                        IPPROTO_TCP,
  2066.                        TCP_NODELAY,
  2067.                        (char *)&set_nodelay_opt,
  2068.                        sizeof(set_nodelay_opt))) {
  2069.             debug(F111,
  2070.                   "TCP no_delay can't clear TCP_NODELAY",
  2071.                   ck_errstr(),
  2072.                   errno
  2073.                   );
  2074.             tcp_nodelay = get_nodelay_opt;
  2075.         } else {
  2076.             debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
  2077.             tcp_nodelay = onoff;
  2078.             return 1;
  2079.         }
  2080.     } else {
  2081.         debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
  2082.         tcp_nodelay = onoff;
  2083.         return(1);
  2084.     }
  2085. #else
  2086.     debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
  2087. #endif /* TCP_NODELAY */
  2088. #else
  2089.     debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
  2090. #endif /* SOL_SOCKET */
  2091.     return 0;
  2092. }
  2093. #endif /* datageneral */
  2094. #endif /* NOTCPOPTS */
  2095.  
  2096. #ifdef SUNX25
  2097. #ifndef X25_WR_FACILITY
  2098. /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
  2099. void
  2100. bzero(s,n) char *s; int n; {
  2101.     memset(s,0,n);
  2102. }
  2103. #endif /* X25_WR_FACILITY */
  2104. #endif /* SUNX25 */
  2105.  
  2106. #ifdef TCPSOCKET
  2107. #ifndef OS2
  2108. #ifndef NOLISTEN
  2109.  
  2110. #ifdef BSDSELECT
  2111. #ifndef VMS
  2112. #ifndef BELLV10
  2113. #ifndef datageneral
  2114. #ifdef hp9000s500                       /* HP-9000/500 HP-U 5.21 */
  2115. #include <time.h>
  2116. #else
  2117.  
  2118. /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
  2119. *       ------------------------------------------------------
  2120. *
  2121. *       Due to OS9's Lack of a select() call, the following seems to be
  2122. *       enough to fool the rest of the code into compiling. The only
  2123. *       effect that I can see is using control L to refresh the status
  2124. *       display gets qued up until some network packets arrive.
  2125. *
  2126. *       This solution is by no means elegant but works enough to be
  2127. *       a (the) solution.
  2128. *
  2129. *       Also with the defines I had specified in my makefile I had to
  2130. *       have an #endif right at the end of the file when compiling.
  2131. *       I did not bother speding time to find out why.
  2132. *
  2133. *       COPTS   = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
  2134. *          -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
  2135. *          -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
  2136. *          -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
  2137. *          -l=termlib.l -l=math.l -l=sys_clib.l
  2138. *
  2139. *       stever@ozemail.com.au
  2140. */
  2141.  
  2142. #ifdef  OSK
  2143. #define BSDSELECT                       /* switch on BSD select code */
  2144. #define FD_SETSIZE 32                   /* Max # of paths in OS9 */
  2145. #define FD_ZERO(p)                      ((*p)=0)
  2146. #define FD_SET(n,b)                     ((*b)|=(1<<(n)))
  2147. #define FD_ISSET(n,b)           1       /* always say data is ready */
  2148. #define select(a,b,c,d,e)       1       /* always say 1 path has data */
  2149. typedef int     fd_set;                 /* keep BSD Code Happy */
  2150. struct timeval {int tv_sec,tv_usec;};   /* keep BSD Code Happy */
  2151.  
  2152. /****** END OF OS9 MODS FROM STEVE RANCE **************************/
  2153. #endif /* OSK */
  2154.  
  2155. #include <sys/time.h>
  2156. #endif /* hp9000s500 */
  2157. #endif /* datageneral */
  2158. #endif /* BELLV10 */
  2159. #endif /* VMS */
  2160. #ifdef SELECT_H
  2161. #include <sys/select.h>
  2162. #endif /* SELECT_H */
  2163. #endif /* BSDSELECT */
  2164.  
  2165. #ifdef SELECT
  2166. #ifdef CK_SCOV5
  2167. #include <sys/select.h>
  2168. #endif /* CK_SCOV5 */
  2169. #endif /* SELECT */
  2170. #ifdef NOTUSED
  2171.  
  2172. /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
  2173.  
  2174. int
  2175. tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
  2176.     int on = 1;
  2177.     static struct servent *service, servrec;
  2178.     static struct hostent *host;
  2179.     static struct sockaddr_in saddr;
  2180.     static
  2181. #ifdef UCX50
  2182.       unsigned
  2183. #endif /* UCX50 */
  2184.       int saddrlen;
  2185. #ifdef BSDSELECT
  2186.     fd_set rfds;
  2187.     struct timeval tv;
  2188. #else
  2189. #ifdef BELLSELECT
  2190.     fd_set rfds;
  2191. #else
  2192.     fd_set rfds;
  2193.     fd_set rfds;
  2194.     struct timeval {
  2195.         long tv_sec;
  2196.         long tv_usec;
  2197.     } tv;
  2198. #endif /* BELLSELECT */
  2199. #endif /* BSDSELECT */
  2200.  
  2201.     debug(F101,"tcpsocket_open nett","",nett);
  2202.     *ipaddr = '\0';
  2203.  
  2204.     if (nett != NET_TCPB)
  2205.       return(-1);                       /* BSD socket support */
  2206.  
  2207.     netclos();                          /* Close any previous connection. */
  2208.     ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
  2209.     if (ttnproto != NP_TCPRAW)
  2210.       ttnproto = NP_NONE;               /* No protocol selected yet. */
  2211.     debug(F110,"tcpsocket_open namecopy",namecopy,0);
  2212.  
  2213.     /* Assign the socket number to ttyfd and then fill in tcp structures */
  2214.     ttyfd = atoi(&name[1]);
  2215.     debug(F111,"tcpsocket_open","ttyfd",ttyfd);
  2216.  
  2217. #ifndef NOTCPOPTS
  2218. #ifdef SOL_SOCKET
  2219.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2220.  
  2221. #ifndef datageneral
  2222. #ifdef TCP_NODELAY
  2223.     no_delay(tcp_nodelay);
  2224. #endif /* TCP_NODELAY */
  2225. #ifdef SO_KEEPALIVE
  2226.     keepalive(tcp_keepalive);
  2227. #endif /* SO_KEEPALIVE */
  2228. #ifdef SO_LINGER
  2229.     ck_linger(tcp_linger, tcp_linger_tmo);
  2230. #endif /* SO_LINGER */
  2231. #ifdef SO_SNDBUF
  2232.     sendbuf(tcp_sendbuf);
  2233. #endif /* SO_SNDBUF */
  2234. #ifdef SO_RCVBUF
  2235.     recvbuf(tcp_recvbuf);
  2236. #endif /* SO_RCVBUF */
  2237. #endif /* datageneral */
  2238. #endif /* SOL_SOCKET */
  2239. #endif /* NOTCPOPTS */
  2240.  
  2241. #ifdef NT_TCP_OVERLAPPED
  2242.     OverlappedWriteInit();
  2243.     OverlappedReadInit();
  2244. #endif /* NT_TCP_OVERLAPPED */
  2245.  
  2246.  
  2247.     /* Get the name of the host we are connected to */
  2248.  
  2249.     saddrlen = sizeof(saddr);
  2250.     getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
  2251.  
  2252.     ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
  2253.  
  2254.     if (tcp_rdns == SET_ON
  2255. #ifdef CK_KERBEROS
  2256.         || tcp_rdns == SET_AUTO &&
  2257.          (ck_krb5_is_installed() || ck_krb4_is_installed())
  2258. #endif /* CK_KERBEROS */
  2259.          ) {                            /* Reverse DNS */
  2260.         if (!quiet) {
  2261.             printf(" Reverse DNS Lookup... ");
  2262.             fflush(stdout);
  2263.         }
  2264.         host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
  2265.         debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
  2266.         if (host) {
  2267.             debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
  2268.             if (!quiet) {
  2269.                 printf("(OK)\n");
  2270.                 fflush(stdout);
  2271.             }
  2272.             ckstrncpy(name, host->h_name, 79);
  2273.             strncat(name, ":", 80 - strlen(name));
  2274. #ifdef COMMENT
  2275.             itoa(ntohs(saddr.sin_port), name + strlen(name), 10);
  2276. #else
  2277.             sprintf(name + strlen(name),"%d",ntohs(saddr.sin_port));
  2278. #endif /* COMMENT */
  2279.             if (!quiet
  2280. #ifndef NOICP
  2281.                 && !doconx
  2282. #endif /* NOICP */
  2283.                 )
  2284.               printf("%s connected on port %d\n",
  2285.                    host->h_name,
  2286.                    ntohs(saddr.sin_port)
  2287.                    );
  2288.         } else if (!quiet)
  2289.           printf("Failed\n");
  2290.     } else if (!quiet)
  2291.       printf("(OK)\n");
  2292.  
  2293.     if (tcp_rdns != SET_ON || !host) {
  2294.         ckstrncpy(name,ipaddr,79);
  2295.         strncat(name,":",80-strlen(name));
  2296. #ifdef COMMENT
  2297.         itoa(ntohs(saddr.sin_port), name + strlen(name), 10);
  2298. #else
  2299.         sprintf(name + strlen(name),"%d",ntohs(saddr.sin_port));
  2300. #endif /* COMMENT */
  2301.         if (!quiet
  2302. #ifdef NOICP
  2303.             && !doconx
  2304. #endif /* NOICP */
  2305.             )
  2306.           printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
  2307.     }
  2308.     if (!quiet) fflush(stdout);
  2309.     ttnet = nett;                       /* TCP/IP (sockets) network */
  2310.  
  2311. #ifdef RLOGCODE
  2312.     if (ntohs(saddr.sin_port) == 513)
  2313.         ttnproto = NP_LOGIN;
  2314.     else
  2315. #endif /* RLOGCODE */
  2316.     /* Assume the service is TELNET. */
  2317.     if (ttnproto != NP_TCPRAW)
  2318.         ttnproto = NP_TELNET;           /* Yes, set global flag. */
  2319. #ifdef CK_AUTHENTICATION
  2320.     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
  2321.     ck_auth_init((host && host->h_name && host->h_name[0]) ?
  2322.                 host->h_name : ipaddr,
  2323.                 ipaddr,
  2324.                 uidbuf,
  2325.                 ttyfd
  2326.                 );
  2327. #endif /* CK_AUTHENTICATION */
  2328.     if (tn_ini() < 0)                   /* Start/Reset TELNET negotiations */
  2329.       if (ttchk() < 0)                  /* Did it fail due to connect loss? */
  2330.         return(-1);
  2331.  
  2332.     if (*lcl < 0) *lcl = 1;             /* Local mode. */
  2333.  
  2334.     return(0);                          /* Done. */
  2335. }
  2336. #endif /* NOTUSED */
  2337.  
  2338. /*  T C P S R V _ O P E N  --  Open a TCP/IP Server connection  */
  2339. /*
  2340.   Calling conventions same as ttopen(), except third argument is network
  2341.   type rather than modem type.
  2342. */
  2343. int
  2344. tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
  2345.     char *p;
  2346.     int i, x;
  2347.     SOCKOPT_T on = 1;
  2348.     int ready_to_accept = 0;
  2349.     static struct servent *service, servrec;
  2350.     static struct hostent *host;
  2351.     static struct sockaddr_in saddr;
  2352.     struct sockaddr_in l_addr;
  2353.     GSOCKNAME_T l_slen;
  2354. #ifdef UCX50
  2355.     static u_int saddrlen;
  2356. #else
  2357.     static SOCKOPT_T saddrlen;
  2358. #endif /* UCX50 */
  2359.  
  2360. #ifdef BSDSELECT
  2361.     fd_set rfds;
  2362.     struct timeval tv;
  2363. #else
  2364. #ifdef BELLSELCT
  2365.     fd_set rfds;
  2366. #else
  2367.     fd_set rfds;
  2368.     struct timeval {
  2369.         long tv_sec;
  2370.         long tv_usec;
  2371.     } tv;
  2372. #endif /* BELLSELECT */
  2373. #endif /* BSDSELECT */
  2374. #ifdef CK_SSL
  2375.     int ssl_failed = 0;
  2376. #endif /* CK_SSL */
  2377.  
  2378.     debug(F101,"tcpsrv_open nett","",nett);
  2379.     *ipaddr = '\0';
  2380.  
  2381.     if (nett != NET_TCPB)
  2382.       return(-1);                       /* BSD socket support */
  2383.  
  2384.     netclos();                          /* Close any previous connection. */
  2385.     ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
  2386. #ifdef COMMENT
  2387.     /* Don't do this. */
  2388.     if (ttnproto != NP_TCPRAW)
  2389.       ttnproto = NP_NONE;               /* No protocol selected yet. */
  2390. #endif /* COMMENT */
  2391.     debug(F110,"tcpsrv_open namecopy",namecopy,0);
  2392.  
  2393.     p = namecopy;                       /* Was a service requested? */
  2394.     while (*p != '\0' && *p != ':')
  2395.       p++; /* Look for colon */
  2396.     if (*p == ':') {                    /* Have a colon */
  2397.         *p++ = '\0';                    /* Get service name or number */
  2398.     } else {                            /* Otherwise use kermit */
  2399.         p = "kermit";
  2400.     }
  2401.     debug(F110,"tcpsrv_open service requested",p,0);
  2402.     if (isdigit(*p)) {                  /* Use socket number without lookup */
  2403.         service = &servrec;
  2404.         service->s_port = htons((unsigned short)atoi(p));
  2405.     } else {                            /* Otherwise lookup the service name */
  2406.         service = getservbyname(p, "tcp");
  2407.     }
  2408.     if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
  2409.         service = &servrec;
  2410.         service->s_port = htons(1649);
  2411.     }
  2412. #ifdef RLOGCODE
  2413.     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
  2414.         fprintf(stderr,
  2415.                 "  Warning: login service on port %d instead of port 513\n",
  2416.                  ntohs(service->s_port));
  2417.         fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
  2418.         debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
  2419.     }
  2420. #endif /* RLOGCODE */
  2421.     if (!service) {
  2422.         fprintf(stderr, "Cannot find port for service: %s\n", p);
  2423.         debug(F111,"tcpsrv_open can't get service",p,errno);
  2424.         errno = 0;                      /* rather than mislead */
  2425.         return(-1);
  2426.     }
  2427.  
  2428.     /* If we currently have a listen active but port has changed then close */
  2429.  
  2430.     debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
  2431.     debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
  2432.     if (tcpsrfd != -1 &&
  2433.         tcpsrv_port != ntohs((unsigned short)service->s_port)) {
  2434.         debug(F100,"tcpsrv_open closing previous connection","",0);
  2435. #ifdef TCPIPLIB
  2436.         socket_close(tcpsrfd);
  2437. #else
  2438.         close(tcpsrfd);
  2439. #endif /* TCPIPLIB */
  2440.         tcpsrfd = -1;
  2441.     }
  2442.     debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
  2443.     if (tcpsrfd == -1) {
  2444.  
  2445.         /* Set up socket structure and get host address */
  2446.  
  2447.         bzero((char *)&saddr, sizeof(saddr));
  2448.         debug(F100,"tcpsrv_open bzero ok","",0);
  2449.         saddr.sin_family = AF_INET;
  2450.         if (tcp_address) {
  2451. #ifdef INADDRX
  2452.             inaddrx = inet_addr(tcp_address);
  2453.             saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
  2454. #else
  2455.             saddr.sin_addr.s_addr = inet_addr(tcp_address);
  2456. #endif /* INADDRX */
  2457.         } else
  2458.           saddr.sin_addr.s_addr = INADDR_ANY;
  2459.  
  2460.         /* Get a file descriptor for the connection. */
  2461.  
  2462.         saddr.sin_port = service->s_port;
  2463.         ipaddr[0] = '\0';
  2464.  
  2465.         debug(F100,"tcpsrv_open calling socket","",0);
  2466.         if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  2467.             perror("TCP socket error");
  2468.             debug(F101,"tcpsrv_open socket error","",errno);
  2469.             return (-1);
  2470.         }
  2471.         errno = 0;
  2472.  
  2473.         /* Specify the Port may be reused */
  2474.  
  2475.         debug(F100,"tcpsrv_open calling setsockopt","",0);
  2476.         x = setsockopt(tcpsrfd,
  2477.                        SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
  2478.         debug(F101,"tcpsrv_open setsockopt","",x);
  2479.  
  2480.        /* Now bind to the socket */
  2481.         printf("\nBinding socket to port %d ...\n",
  2482.                ntohs((unsigned short)service->s_port));
  2483.         if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
  2484.             i = errno;                  /* Save error code */
  2485. #ifdef TCPIPLIB
  2486.             socket_close(tcpsrfd);
  2487. #else /* TCPIPLIB */
  2488.             close(tcpsrfd);
  2489. #endif /* TCPIPLIB */
  2490.             tcpsrfd = -1;
  2491.             tcpsrv_port = 0;
  2492.             ttyfd = -1;
  2493.             wasclosed = 1;
  2494.             errno = i;                  /* and report this error */
  2495.             debug(F101,"tcpsrv_open bind errno","",errno);
  2496.             printf("?Unable to bind to socket (errno = %d)\n",errno);
  2497.             return(-1);
  2498.         }
  2499.         debug(F100,"tcpsrv_open bind OK","",0);
  2500.         printf("Listening ...\n");
  2501.         if (listen(tcpsrfd, 15) < 0) {
  2502.             i = errno;                  /* Save error code */
  2503. #ifdef TCPIPLIB
  2504.             socket_close(tcpsrfd);
  2505. #else /* TCPIPLIB */
  2506.             close(tcpsrfd);
  2507. #endif /* TCPIPLIB */
  2508.             tcpsrfd = -1;
  2509.             tcpsrv_port = 0;
  2510.             ttyfd = -1;
  2511.             wasclosed = 1;
  2512.             errno = i;                  /* And report this error */
  2513.             debug(F101,"tcpsrv_open listen errno","",errno);
  2514.             return(-1);
  2515.         }
  2516.         debug(F100,"tcpsrv_open listen OK","",0);
  2517.         tcpsrv_port = ntohs((unsigned short)service->s_port);
  2518.     }
  2519.  
  2520. #ifdef CK_SSL
  2521.     if (ck_ssleay_is_installed()) {
  2522.         if (!ssl_do_init(1)) {
  2523.             ssl_failed = 1;
  2524.             if (bio_err!=NULL) {
  2525.                 BIO_printf(bio_err,"do_ssleay_init() failed\n");
  2526.                 ERR_print_errors(bio_err);
  2527.             } else {
  2528.                 fflush(stderr);
  2529.                 fprintf(stderr,"do_ssleay_init() failed\n");
  2530.                 ERR_print_errors_fp(stderr);
  2531.             }
  2532.             /* we will continue to accept the connection */
  2533.             /* without SSL or TLS support.               */
  2534.             TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
  2535.             TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
  2536.             TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
  2537.             TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
  2538.         }
  2539.     }
  2540. #endif /* CK_SSL */
  2541.  
  2542.     printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
  2543.            ntohs((unsigned short)service->s_port));
  2544.     saddrlen = sizeof(saddr);
  2545.  
  2546. #ifdef BSDSELECT
  2547.     tv.tv_sec  = tv.tv_usec = 0L;
  2548.     if (timo < 0)
  2549.       tv.tv_usec = (long) -timo * 10000L;
  2550.     else
  2551.       tv.tv_sec = timo;
  2552.     debug(F101,"tcpsrv_open BSDSELECT","",timo);
  2553. #else
  2554.     debug(F101,"tcpsrv_open not BSDSELECT","",timo);
  2555. #endif /* BSDSELECT */
  2556.  
  2557.     if (timo) {
  2558.         while (!ready_to_accept) {
  2559. #ifdef BSDSELECT
  2560.             FD_ZERO(&rfds);
  2561.             FD_SET(tcpsrfd, &rfds);
  2562.             ready_to_accept =
  2563.               ((select(FD_SETSIZE,
  2564. #ifdef HPUX
  2565. #ifdef HPUX1010
  2566.                        (fd_set *)
  2567. #else
  2568.  
  2569.                        (int *)
  2570. #endif /* HPUX1010 */
  2571. #else
  2572. #ifdef __DECC
  2573.                        (fd_set *)
  2574. #endif /* __DECC */
  2575. #endif /* HPUX */
  2576.                        &rfds, NULL, NULL, &tv) > 0) &&
  2577.                FD_ISSET(tcpsrfd, &rfds));
  2578. #else /* BSDSELECT */
  2579. #ifdef IBMSELECT
  2580. #define ck_sleepint 250
  2581.             ready_to_accept =
  2582.               (select(&tcpsrfd, 1, 0, 0,
  2583.                       timo < 0 ? -timo :
  2584.                       (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
  2585.                );
  2586. #else
  2587. #ifdef BELLSELECT
  2588.             FD_ZERO(rfds);
  2589.             FD_SET(tcpsrfd, rfds);
  2590.             ready_to_accept =
  2591.               ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
  2592.                       (timo > 0 ? timo * 1000L)) > 0) &&
  2593.                FD_ISSET(tcpsrfd, rfds));
  2594. #else
  2595. /* Try this - what's the worst that can happen... */
  2596.  
  2597.             FD_ZERO(&rfds);
  2598.             FD_SET(tcpsrfd, &rfds);
  2599.             ready_to_accept =
  2600.               ((select(FD_SETSIZE,
  2601.                        (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
  2602.                FD_ISSET(tcpsrfd, &rfds));
  2603.  
  2604. #endif /* BELLSELECT */
  2605. #endif /* IBMSELECT */
  2606. #endif /* BSDSELECT */
  2607.         }
  2608.     }
  2609.     if (ready_to_accept || timo == 0) {
  2610.         if ((ttyfd = accept(tcpsrfd,
  2611.                             (struct sockaddr *)&saddr,&saddrlen)) < 0) {
  2612.             i = errno;                  /* save error code */
  2613. #ifdef TCPIPLIB
  2614.             socket_close(tcpsrfd);
  2615. #else /* TCPIPLIB */
  2616.             close(tcpsrfd);
  2617. #endif /* TCPIPLIB */
  2618.             ttyfd = -1;
  2619.             wasclosed = 1;
  2620.             tcpsrfd = -1;
  2621.             tcpsrv_port = 0;
  2622.             errno = i;                  /* and report this error */
  2623.             debug(F101,"tcpsrv_open accept errno","",errno);
  2624.             return(-1);
  2625.         }
  2626.         setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2627.  
  2628. #ifndef NOTCPOPTS
  2629. #ifndef datageneral
  2630. #ifdef SOL_SOCKET
  2631. #ifdef TCP_NODELAY
  2632.         no_delay(tcp_nodelay);
  2633.         debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
  2634. #endif /* TCP_NODELAY */
  2635. #ifdef SO_KEEPALIVE
  2636.         keepalive(tcp_keepalive);
  2637.         debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
  2638. #endif /* SO_KEEPALIVE */
  2639. #ifdef SO_LINGER
  2640.         ck_linger(tcp_linger, tcp_linger_tmo);
  2641.         debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
  2642. #endif /* SO_LINGER */
  2643. #ifdef SO_SNDBUF
  2644.         sendbuf(tcp_sendbuf);
  2645. #endif /* SO_SNDBUF */
  2646. #ifdef SO_RCVBUF
  2647.         recvbuf(tcp_recvbuf);
  2648. #endif /* SO_RCVBUF */
  2649. #endif /* SOL_SOCKET */
  2650. #endif /* datageneral */
  2651. #endif /* NOTCPOPTS */
  2652.  
  2653.         ttnet = nett;                   /* TCP/IP (sockets) network */
  2654.         tcp_incoming = 1;               /* This is an incoming connection */
  2655.         sstelnet = 1;                   /* Do server-side Telnet protocol */
  2656.  
  2657.         /* See if the service is TELNET. */
  2658.         if ((x = (unsigned short)service->s_port) ==
  2659.             getservbyname("telnet", "tcp")->s_port) {
  2660.             if (ttnproto != NP_TCPRAW)  /* Yes and if raw port not requested */
  2661.               ttnproto = NP_TELNET;     /* Set protocol to TELNET. */
  2662.         }
  2663. #ifdef CK_AUTHENTICATION
  2664.         /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
  2665.         ck_auth_init((host && host->h_name && host->h_name[0]) ?
  2666.                      (char *)host->h_name : ipaddr,
  2667.                      ipaddr,
  2668.                      uidbuf,
  2669.                      ttyfd
  2670.                      );
  2671. #endif /* CK_AUTHENTICATION */
  2672.  
  2673. #ifdef CK_SSL
  2674.         if (ck_ssleay_is_installed() && !ssl_failed) {
  2675.             if (ck_ssl_incoming(ttyfd) < 0) {
  2676. #ifdef TCPIPLIB
  2677.                     socket_close(ttyfd);
  2678.                     socket_close(tcpsrfd);
  2679. #else /* TCPIPLIB */
  2680.                     close(ttyfd);
  2681.                     close(tcpsrfd);
  2682. #endif /* TCPIPLIB */
  2683.                     ttyfd = -1;
  2684.                     wasclosed = 1;
  2685.                     tcpsrfd = -1;
  2686.                     tcpsrv_port = 0;
  2687.                     return(-1);
  2688.             }
  2689.         }
  2690. #endif /* CK_SSL */
  2691.  
  2692. #ifndef datageneral
  2693.         /* Find out our own IP address. */
  2694.         l_slen = sizeof(l_addr);
  2695.         bzero((char *)&l_addr, l_slen);
  2696. #ifndef EXCELAN
  2697.         if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
  2698.             char * s = (char *)inet_ntoa(l_addr.sin_addr);
  2699.             ckstrncpy(myipaddr, s,20);
  2700.             debug(F110,"getsockname",myipaddr,0);
  2701.         }
  2702. #endif /* EXCELAN */
  2703. #endif /* datageneral */
  2704.  
  2705.         if (tn_ini() < 0)               /* Start TELNET negotiations. */
  2706.           if (ttchk() < 0) {            /* Disconnected? */
  2707.               i = errno;                /* save error code */
  2708. #ifdef TCPIPLIB
  2709.               socket_close(tcpsrfd);
  2710. #else /* TCPIPLIB */
  2711.               close(tcpsrfd);
  2712. #endif /* TCPIPLIB */
  2713.               ttyfd = -1;
  2714.               wasclosed = 1;
  2715.               tcpsrfd = -1;
  2716.               tcpsrv_port = 0;
  2717.               errno = i;                /* and report this error */
  2718.               debug(F101,"tcpsrv_open accept errno","",errno);
  2719.               return(-1);
  2720.           }
  2721.         debug(F101,"tcpsrv_open service","",x);
  2722.         if (*lcl < 0)                   /* Set local mode. */
  2723.           *lcl = 1;
  2724.  
  2725. #ifdef COMMENT
  2726. #ifdef TCPIPLIB
  2727.         socket_close(tcpsrfd);
  2728. #else /* TCPIPLIB */
  2729.         close(tcpsrfd);
  2730. #endif /* TCPIPLIB */
  2731.         tcpsrfd = -1;
  2732.         tcpsrv_port = 0;
  2733. #endif /* COMMENT */
  2734.  
  2735.         ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
  2736.         if (tcp_rdns) {
  2737.             if (!quiet) {
  2738.                 printf(" Reverse DNS Lookup... ");
  2739.                 fflush(stdout);
  2740.             }
  2741.             if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
  2742.                 debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
  2743.                 if (!quiet) {
  2744.                     printf("(OK)\n");
  2745.                     fflush(stdout);
  2746.                 }
  2747.                 name[0] = '*';
  2748.                 ckstrncpy(&name[1],host->h_name,78);
  2749.                 strncat(name,":",80-strlen(name));
  2750.                 strncat(name,p,80-strlen(name));
  2751.                 if (!quiet
  2752. #ifndef NOICP
  2753.                     && !doconx
  2754. #endif /* NOICP */
  2755.                     )
  2756.                   printf("%s connected on port %s\n",host->h_name,p);
  2757.             } else {
  2758.                 if (!quiet) printf("Failed.\n");
  2759.             }
  2760.         } else if (!quiet) printf("(OK)\n");
  2761.  
  2762.         if (!tcp_rdns || !host) {
  2763.             ckstrncpy(name,ipaddr,79);
  2764.             strncat(name,":",80-strlen(name));
  2765. #ifdef COMMENT
  2766.             itoa(ntohs(saddr.sin_port), name + strlen(name), 10);
  2767. #else
  2768.             sprintf(name + strlen(name),"%d",ntohs(saddr.sin_port));
  2769. #endif /* COMMENT */
  2770.             if (!quiet
  2771. #ifndef NOICP
  2772.                 && !doconx
  2773. #endif /* NOICP */
  2774.                 )
  2775.               printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
  2776.         }
  2777.         if (!quiet) fflush(stdout);
  2778.         return(0);                      /* Done. */
  2779.     } else {
  2780.         i = errno;                      /* save error code */
  2781. #ifdef TCPIPLIB
  2782.         socket_close(tcpsrfd);
  2783. #else /* TCPIPLIB */
  2784.         close(tcpsrfd);
  2785. #endif /* TCPIPLIB */
  2786.         ttyfd = -1;
  2787.         wasclosed = 1;
  2788.         tcpsrfd = -1;
  2789.         tcpsrv_port = 0;
  2790.         errno = i;                      /* and report this error */
  2791.         debug(F101,"tcpsrv_open accept errno","",errno);
  2792.         return(-1);
  2793.     }
  2794. }
  2795. #endif /* NOLISTEN */
  2796. #endif /* OS2 */
  2797. #endif /* TCPSOCKET */
  2798.  
  2799. #endif /* NOLOCAL */
  2800.  
  2801. unsigned long peerxipaddr = 0L;
  2802.  
  2803. char *
  2804. ckgetpeer() {
  2805. #ifdef TCPSOCKET
  2806.     static char namebuf[256];
  2807.     static struct hostent *host;
  2808.     static struct sockaddr_in saddr;
  2809. #ifdef PTX
  2810.     static size_t saddrlen;
  2811. #else
  2812. #ifdef AIX42
  2813.     /* It's size_t in 4.2 but int in 4.1 and earlier. */
  2814.     /* Note: the 4.2 man page lies; believe socket.h. */
  2815.     static size_t saddrlen;
  2816. #else
  2817. #ifdef UNIXWARE
  2818.     static size_t saddrlen;
  2819. #else  /* UNIXWARE */
  2820. #ifdef DEC_TCPIP
  2821.     static unsigned int saddrlen;
  2822. #else
  2823.     static int saddrlen;
  2824. #endif /* VMS */
  2825. #endif /* UNIXWARE */
  2826. #endif /* AIX42 */
  2827. #endif /* PTX */
  2828.     saddrlen = sizeof(saddr);
  2829.     if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
  2830.         debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
  2831.         return(NULL);
  2832.     }
  2833.     host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
  2834.     if (host) {
  2835.         ckstrncpy(namebuf,(char *)host->h_name,80);
  2836.     } else {
  2837.         ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
  2838.     }
  2839.     peerxipaddr = ntohl(saddr.sin_addr.s_addr);
  2840.     debug(F111,"ckgetpeer",namebuf,peerxipaddr);
  2841.     return(namebuf);
  2842. #else
  2843.     return(NULL);
  2844. #endif /* TCPSOCKET */
  2845. }
  2846.  
  2847. #ifndef NOLOCAL
  2848.  
  2849. char *
  2850. #ifdef CK_ANSIC
  2851. ckgetfqhostname(char * name)
  2852. #else
  2853. ckgetfqhostname(name) char * name;
  2854. #endif /* CK_ANSIC */
  2855. {
  2856.     static char namebuf[256];
  2857.     struct hostent *host=NULL;
  2858.     struct sockaddr_in r_addr;
  2859.     int i;
  2860.  
  2861.     debug(F110,"ckgetfqhn()",name,0);
  2862.  
  2863.     ckstrncpy(namebuf,name,256);
  2864.     namebuf[255] = '\0';
  2865.     i = ckindex(":",namebuf,0,0,0);
  2866.     if (i)
  2867.       namebuf[i-1] = '\0';
  2868.  
  2869.     bzero((char *)&r_addr, sizeof(r_addr));
  2870.  
  2871.     host = gethostbyname(namebuf);
  2872.     if (host) {
  2873.         debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
  2874.         r_addr.sin_family = host->h_addrtype;
  2875. #ifdef HADDRLIST
  2876. #ifdef h_addr
  2877.         /* This is for trying multiple IP addresses - see <netdb.h> */
  2878.         if (!(host->h_addr_list))
  2879.           goto exit_func;
  2880.         bcopy(host->h_addr_list[0],
  2881.               (caddr_t)&r_addr.sin_addr,
  2882.               host->h_length
  2883.               );
  2884. #else
  2885.         bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
  2886. #endif /* h_addr */
  2887. #else  /* HADDRLIST */
  2888.         bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
  2889. #endif /* HADDRLIST */
  2890. #ifndef EXCELAN
  2891.         debug(F111,"BCOPY","host->h_addr",host->h_addr);
  2892. #endif /* EXCELAN */
  2893.         debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
  2894.               (caddr_t)&r_addr.sin_addr);
  2895.         debug(F111,"BCOPY","host->h_length",host->h_length);
  2896.  
  2897. #ifdef NT
  2898.         /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
  2899.         /* provided DNS functions.  Otherwise, the TTL of the DNS response */
  2900.         /* is ignored. */
  2901.         if (isWin95())
  2902.           sleep(1);
  2903. #endif /* NT */
  2904.         host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
  2905.         if (host) {
  2906.             debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
  2907.             ckstrncpy(namebuf, host->h_name, 256);
  2908.         }
  2909.     }
  2910.  
  2911. #ifdef HADDRLIST
  2912. #ifdef h_addr
  2913.   exit_func:
  2914. #endif /* h_addr */
  2915. #endif /* HADDRLIST */
  2916.  
  2917.     if (i > 0)
  2918.       strncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
  2919.     debug(F110,"ckgetfqhn()",namebuf,0);
  2920.     return(namebuf);
  2921. }
  2922.  
  2923. VOID
  2924. #ifdef CK_ANSIC
  2925. setnproto(char * p)
  2926. #else
  2927. setnproto(p) char * p;
  2928. #endif /* CK_ANSIC */
  2929. {
  2930.     if (!isdigit(*p)) {
  2931.         if (!strcmp("kermit",p))
  2932.           ttnproto = NP_KERMIT;
  2933.         else if (!strcmp("telnet",p))
  2934.           ttnproto = NP_TELNET;
  2935.         else if (!strcmp("http",p))
  2936.           ttnproto = NP_TCPRAW;
  2937. #ifdef RLOGCODE
  2938.         else if (!strcmp("login",p))
  2939.           ttnproto = NP_RLOGIN;
  2940. #endif /* RLOGCODE */
  2941. #ifdef CK_SSL
  2942.         /* Commonly used SSL ports (might not be in services file) */
  2943.         else if (!strcmp("https",p))
  2944.           ttnproto = NP_SSL;
  2945.         else if (!strcmp("ssl-telnet",p))
  2946.           ttnproto = NP_SSL;
  2947.         else if (!strcmp("telnets",p))
  2948.           ttnproto = NP_SSL;
  2949. #endif /* CK_SSL */
  2950. #ifdef CK_KERBEROS
  2951. #ifdef RLOGCODE
  2952.         else if (!strcmp("klogin",p)) {
  2953.             if (ck_krb5_is_installed())
  2954.               ttnproto = NP_K5LOGIN;
  2955.             else if (ck_krb4_is_installed())
  2956.               ttnproto = NP_K4LOGIN;
  2957.             else
  2958.               ttnproto = NP_RLOGIN;
  2959.         } else if (!strcmp("eklogin",p)) {
  2960.             if (ck_krb5_is_installed())
  2961.               ttnproto = NP_EK5LOGIN;
  2962.             else if (ck_krb4_is_installed())
  2963.               ttnproto = NP_EK4LOGIN;
  2964.             else
  2965.               ttnproto = NP_RLOGIN;
  2966.         }
  2967. #endif /* RLOGCODE */
  2968. #endif /* CK_KERBEROS */
  2969.         else
  2970.           ttnproto = NP_NONE;
  2971.     } else {
  2972.         switch (atoi(p)) {
  2973.           case 23:                      /* Telnet */
  2974.             ttnproto = NP_TELNET;
  2975.             break;
  2976.           case 513:
  2977.             ttnproto = NP_RLOGIN;
  2978.             break;
  2979.           case 1649:
  2980.             ttnproto = NP_KERMIT;
  2981.             break;
  2982. #ifdef CK_SSL
  2983.           case 443:
  2984.             ttnproto = NP_SSL;
  2985.             ssl_only_flag = 1;
  2986.             break;
  2987.           case 151:
  2988.           case 992:
  2989.             ttnproto = NP_TELNET;
  2990.             break;
  2991. #endif /* CK_SSL */
  2992. #ifdef CK_KERBEROS
  2993.           case 543:
  2994.             if (ck_krb5_is_installed())
  2995.               ttnproto = NP_K5LOGIN;
  2996.             else if (ck_krb4_is_installed())
  2997.               ttnproto = NP_K4LOGIN;
  2998.             else
  2999.               ttnproto = NP_RLOGIN;
  3000.             break;
  3001.           case 2105:
  3002.             if (ck_krb5_is_installed())
  3003.               ttnproto = NP_EK5LOGIN;
  3004.             else if (ck_krb4_is_installed())
  3005.               ttnproto = NP_EK4LOGIN;
  3006.             else
  3007.               ttnproto = NP_RLOGIN;
  3008.             break;
  3009. #endif /* CK_KERBEROS */
  3010.           case 80:                      /* HTTP */
  3011.             ttnproto = NP_TCPRAW;
  3012.             break;
  3013.           default:
  3014.             ttnproto = NP_NONE;
  3015.             break;
  3016.         }
  3017.     }
  3018. }
  3019.  
  3020.  
  3021. /*  N E T O P E N  --  Open a network connection  */
  3022. /*
  3023.   Calling conventions same as ttopen(), except third argument is network
  3024.   type rather than modem type.  Designed to be called from within ttopen.
  3025. */
  3026. int
  3027. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  3028.     char *p;
  3029.     int i, x, dns = 0;
  3030. #ifdef TCPSOCKET
  3031.     int isconnect = 0;
  3032. #ifdef SO_OOBINLINE
  3033.     int on = 1;
  3034. #endif /* SO_OOBINLINE */
  3035.     struct servent *service=NULL, servrec;
  3036.     struct hostent *host=NULL;
  3037.     struct sockaddr_in r_addr;
  3038.     struct sockaddr_in sin;
  3039.     struct sockaddr_in l_addr;
  3040.     GSOCKNAME_T l_slen;
  3041. #ifdef CK_DNS_SRV
  3042.     struct sockaddr * dns_addrs = NULL;
  3043.     int dns_naddrs = 0;
  3044. #endif /* CK_DNS_SRV */
  3045. #ifdef EXCELAN
  3046.     struct sockaddr_in send_socket;
  3047. #endif /* EXCELAN */
  3048.  
  3049. #ifdef INADDRX
  3050. /* inet_addr() is of type struct in_addr */
  3051. #ifdef datageneral
  3052.     extern struct in_addr inet_addr();
  3053. #else
  3054. #ifdef HPUX5WINTCP
  3055.     extern struct in_addr inet_addr();
  3056. #endif /* HPUX5WINTCP */
  3057. #endif /* datageneral */
  3058.     struct in_addr iax;
  3059. #else
  3060. #ifdef INADDR_NONE
  3061.     struct in_addr iax;
  3062. #else /* INADDR_NONE */
  3063.     long iax;
  3064. #endif /* INADDR_NONE */
  3065. #endif /* INADDRX */
  3066. #endif /* TCPSOCKET */
  3067.  
  3068. #ifdef COMMENT
  3069. /* This causes big trouble */
  3070. #ifndef INADDR_NONE
  3071. #define INADDR_NONE 0xffffffff
  3072. #endif /* INADDR_NONE */
  3073. #endif /* COMMENT */
  3074.  
  3075. #ifdef SUNX25                           /* Code for SunLink X.25 support */
  3076. #define X29PID 1                        /* X.29 Protocol ID */
  3077. _PROTOTYP(SIGTYP x25oobh, (int) );
  3078.     CONN_DB x25host;
  3079. #ifndef X25_WR_FACILITY
  3080.     FACILITY x25facil;
  3081. #else
  3082.     FACILITY_DB x25facil;
  3083. #endif /* X25_WR_FACILITY */
  3084.     static int needh = 1;
  3085.     PID_T pid;
  3086.     extern int linkid, lcn, x25ver;
  3087. #endif /* SUNX25 */
  3088. #ifdef ANYX25
  3089.     extern int revcall, closgr, cudata;
  3090.     extern char udata[];
  3091. #endif /* ANYX25 */
  3092.  
  3093. #ifdef IBMX25                           /* Variables for IBM X25 */
  3094.     extern int x25port;                 /* Logical port to use */
  3095.     extern x25addr_t local_nua;         /* Local X.25 address */
  3096.     extern x25addr_t remote_nua;        /* Remote X.25 address */
  3097.     extern char x25name[];              /* X25 device name (sx25a0) */
  3098.     extern char x25dev[];               /* X25 device file /dev/x25pkt */
  3099.     ulong bind_flags = 0;               /* Flags for binding the X25 stream */
  3100.     ulong token = 0;                    /* Temporary return code */
  3101. #endif /* IBMX25 */
  3102.  
  3103.     debug(F101,"netopen nett","",nett);
  3104.     *ipaddr = '\0';                     /* Initialize IP address string */
  3105.  
  3106. #ifdef SUNX25
  3107.     if (nett == NET_SX25) {             /* If network type is X.25 */
  3108.         netclos();                      /* Close any previous net connection */
  3109.         ttnproto = NP_NONE;             /* No protocol selected yet */
  3110.  
  3111.         /* Set up host structure */
  3112.         bzero((char *)&x25host,sizeof(x25host));
  3113.         if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
  3114.             fprintf (stderr,"Invalid X.121 host address %s\n",name);
  3115.             errno = 0;
  3116.             return (-1);
  3117.         }
  3118.         x25host.datalen = X29PIDLEN;
  3119.         x25host.data[0] = X29PID;
  3120.  
  3121.         /* Set call user data if specified */
  3122.         if (cudata) {
  3123.             ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
  3124.             x25host.datalen += (int)strlen(udata);
  3125.         }
  3126.  
  3127.         /* Open SunLink X.25 socket */
  3128.         if (!quiet && *name) {
  3129.             printf(" Trying %s... ", name);
  3130.             fflush(stdout);
  3131.         }
  3132.         if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
  3133.             debug(F101,"netopen socket error","",errno);
  3134.             perror ("X.25 socket error");
  3135.             return (-1);
  3136.         }
  3137.  
  3138.         /* Setting X.25 out-of-band data handler */
  3139.         pid = getpid();
  3140.         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
  3141.             perror("X.25 set process group id error");
  3142.             return(-1);
  3143.         }
  3144.         (VOID) signal(SIGURG,x25oobh);
  3145.  
  3146.         /* Set reverse charge call and closed user group if requested */
  3147.         bzero ((char *)&x25facil,sizeof(x25facil));
  3148.  
  3149. #ifndef X25_WR_FACILITY
  3150. /*  New SunLink (7.0 or 8.0, not sure which)... */
  3151.         x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
  3152.         x25facil.f_reverse_charge = revcall ? 1 : 0;
  3153.         if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
  3154.             perror ("Setting X.25 reverse charge");
  3155.             return (-1);
  3156.         }
  3157.         if (closgr > -1) {              /* Closed User Group (Outgoing) */
  3158.             bzero ((char *)&x25facil,sizeof(x25facil));
  3159.             x25facil.type = T_CUG;
  3160.             x25facil.f_cug_req = CUG_REQ_ACS;
  3161.             x25facil.f_cug_index = closgr;
  3162.             if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
  3163.                 perror ("Setting X.25 closed user group");
  3164.                 return (-1);
  3165.             }
  3166.         }
  3167. #else
  3168. /*  Old SunLink 6.0 (or 7.0?)... */
  3169.         if (revcall) x25facil.reverse_charge = revcall;
  3170.         if (closgr > -1) {
  3171.             x25facil.cug_req = 1;
  3172.             x25facil.cug_index = closgr;
  3173.         }
  3174.         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
  3175.             perror ("Setting X.25 facilities");
  3176.             return (-1);
  3177.         }
  3178. #endif /* X25_WR_FACILITY */
  3179.  
  3180.         /*  Need X.25 header with bits Q and M */
  3181.         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
  3182.             perror ("Setting X.25 header");
  3183.             return (-1);
  3184.         }
  3185.  
  3186.         /* Connects to remote host via SunLink X.25 */
  3187.         if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
  3188.             i = errno;
  3189.             debug(F101,"netopen connect errno","",i);
  3190.             if (i) {
  3191.                 perror("netopen x25 connect");
  3192.                 x25diag();
  3193.             }
  3194.             (VOID) netclos();
  3195.             ttyfd = -1;
  3196.             wasclosed = 1;
  3197.             ttnproto = NP_NONE;
  3198.             errno = i;
  3199.             return (-1);
  3200.         }
  3201.  
  3202.         /* Get X.25 link identification used for the connection */
  3203.         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
  3204.             perror ("Getting X.25 link id");
  3205.             return (-1);
  3206.         }
  3207.  
  3208.         /* Get X.25 logical channel number used for the connection */
  3209.         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
  3210.             perror ("Getting X.25 lcn");
  3211.             return (-1);
  3212.         }
  3213.  
  3214.         /* Get SunLink X.25 version */
  3215.         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
  3216.             perror ("Getting SunLink X.25 version");
  3217.             return (-1);
  3218.         }
  3219.         ttnet = nett;                   /* Sunlink X.25 network */
  3220.         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
  3221.         if (*lcl < 0) *lcl = 1;         /* Local mode */
  3222.         return(0);
  3223.     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
  3224. #endif /* SUNX25 */
  3225.  
  3226. #ifdef IBMX25
  3227.     /* riehm */
  3228.     if (nett == NET_IX25) {             /* IBM AIX X.25 */
  3229.         netclos();                      /* Close any previous net connection */
  3230.         ttnproto = NP_NONE;             /* No protocol selected yet */
  3231.  
  3232.         /* find out who we are - this is not so easy on AIX */
  3233.         /* riehm: need to write the code that finds this out
  3234.          * automatically, or at least allow it to be configured
  3235.          * somehow
  3236.          */
  3237.         if (!local_nua[0] && !x25local_nua(local_nua)) {
  3238.             return(-1);
  3239.         }
  3240.  
  3241.         /* Initialise the X25 API (once per process? once per connection?) */
  3242.  
  3243.         debug(F110, "Opening ", x25dev, 0 );
  3244.         /* set O_NDELAY to allow polling? */
  3245.         if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
  3246.             perror ("X.25 device open error");
  3247.             debug(F101,"netopen: device open error","",errno);
  3248.             return (-1);
  3249.         }
  3250.  
  3251.         /* push the NPI onto the STREAM */
  3252.         if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
  3253.             close(ttyfd);
  3254.             ttyfd = -1;
  3255.             wasclosed = 1;
  3256.             perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
  3257.             debug(F101,"netopen: can't push npi on the X25 stream","",errno);
  3258.             return (-1);
  3259.         }
  3260.  
  3261.         /* set up server mode - bind the x25 port and wait for
  3262.          * incoming connections
  3263.          */
  3264.         if (name[0] == '*') {           /* Server */
  3265.             /* set up a server - see the warning in x25bind() */
  3266.             bind_flags |= TOKEN_REQUEST;
  3267.  
  3268.             /* bind kermit to the local X25 address */
  3269.             token = x25bind(ttyfd,
  3270.                             local_nua,
  3271.                             udata,
  3272.                             (int)strlen( udata ),
  3273.                             1,
  3274.                             x25port,
  3275.                             bind_flags
  3276.                             );
  3277.             if (token < 0) {
  3278.                 debug(F100,"netopen: couldn't bind to local X25 address","",0);
  3279.                 netclos();
  3280.                 return(-1);
  3281.             }
  3282.             /* Currently not connected to a remote host */
  3283.  
  3284.             remote_nua[0] = '\0';
  3285.  
  3286.             /* store the fd so that incoming calls can have their own fd
  3287.              * This is almost support for a true server (ie: a'la ftpd)
  3288.              * but we're not quite there yet.
  3289.              * used in netclos()
  3290.              */
  3291.             x25serverfd = ttyfd;
  3292.             /*
  3293.              * wait for an incoming call
  3294.              * this should happen in the "server" command and not in
  3295.              * the "set host *" command.
  3296.              */
  3297.             if ((ttyfd = x25getcall(ttyfd)) < 0) {
  3298.                 netclos();
  3299.                 return(-1);
  3300.             }
  3301.         } else {                        /* Client */
  3302.             /* Bind kermit to the local X25 address */
  3303.             token = x25bind(
  3304.                             ttyfd,
  3305.                             local_nua,
  3306.                             (char *)NULL,
  3307.                             0,
  3308.                             0,
  3309.                             x25port,
  3310.                             bind_flags
  3311.                             );
  3312.             if (token < 0) {
  3313.                 debug(F100,"netopen: couldn't bind to local X25 address","",0);
  3314.                 netclos();
  3315.                 return(-1);
  3316.             }
  3317. /* riehm: this should be done via the CONNECT command, not HOST! */
  3318.             {
  3319.                 x25serverfd = 0;
  3320.                 /* call the remote host */
  3321.                 /* name == address of remote host as char* */
  3322.                 if (x25call(ttyfd, name, udata) < 0 ) {
  3323.                     debug(F100,
  3324.                           "netopen: couldn't connect to remote X25 address",
  3325.                           "", 0);
  3326.                     netclos();
  3327.                     return(-1);
  3328.                 }
  3329.                 strcpy(remote_nua, name);
  3330.             }
  3331.         }
  3332.         ttnet = nett;                   /* AIX X.25 network */
  3333.         if (*lcl < 0)
  3334.           *lcl = 1;                     /* Local mode */
  3335.         return(0);
  3336.  
  3337.     } else /* Note that IBMX25 support can coexist with TCP/IP support. */
  3338. #endif /* IBMX25 */
  3339.  
  3340. /*   Add support for other networks here. */
  3341.  
  3342.       if (nett != NET_TCPB) return(-1); /* BSD socket support */
  3343.  
  3344. #ifdef TCPSOCKET
  3345.     netclos();                          /* Close any previous connection. */
  3346.     ckstrncpy(namecopy, name, NAMECPYL);        /* Copy the hostname. */
  3347.     debug(F110,"netopen namecopy",namecopy,0);
  3348.  
  3349. #ifndef NOLISTEN
  3350.     if (name[0] == '*')
  3351.       return(tcpsrv_open(name, lcl, nett, 0));
  3352. #endif /* NOLISTEN */
  3353.  
  3354.     p = namecopy;                       /* Was a service requested? */
  3355.     while (*p != '\0' && *p != ':') p++; /* Look for colon */
  3356.     if (*p == ':') {                    /* Have a colon */
  3357.         debug(F110,"netopen name has colon",namecopy,0);
  3358.         *p++ = '\0';                    /* Get service name or number */
  3359. #ifdef CK_URL
  3360.         /*
  3361.            Here we have to check for various popular syntaxes:
  3362.            host:port (our original syntax)
  3363.            URL such as telnet:host or telnet://host/
  3364.            Or even telnet://user:password@host:port/
  3365.            Or a malformed URL such as generated by Netscape 4.0 like:
  3366.            telnet:telnet or telnet::host.
  3367.         */
  3368.         if (*p == ':')                  /* a second colon */
  3369.           *p++ = '\0';                  /* get rid of that one too */
  3370.         while (*p == '/') *p++ = '\0';  /* and slashes */
  3371.         x = strlen(p);                  /* Length of remainder */
  3372.         if (p[x-1] == '/')              /* If there is a trailing slash */
  3373.           p[x-1] = '\0';                /* remove it. */
  3374.         debug(F110,"netopen namecopy after stripping",namecopy,0);
  3375.         debug(F110,"netopen p after stripping",p,0);
  3376.         service = getservbyname(namecopy,"tcp");
  3377.         if (service || !ckstrcmp("rlogin",namecopy,NAMECPYL,0)) {
  3378.             char temphost[80], tempservice[80];
  3379.             char * q = p, *r = p, *w = p;
  3380.             /* Check for userid and possibly password */
  3381.             while (*p != '\0' && *p != '@') p++; /* look for @ */
  3382.             if (*p == '@') {
  3383.                 /* found username and perhaps password */
  3384.                 debug(F110,"netopen namecopy found @","",0);
  3385.                 *p = '\0'; p++;
  3386.                 while (*w != '\0' && *w != ':')
  3387.                   w++;
  3388.                 if (*w == ':')
  3389.                   *w++ = '\0';
  3390.                 /* r now points to username, save it and discard password */
  3391.                 debug(F110,"netopen namecopy username",r,0);
  3392.                 debug(F110,"netopen namecopy password",w,0);
  3393.                 ckstrncpy(uidbuf,r,UIDBUFLEN);
  3394.                 q = p;                  /* Host after user and pwd */
  3395.             } else {
  3396.                 p = q;                  /* No username or password */
  3397.             }
  3398.             /* Now we must look for the optional port. */
  3399.             debug(F110,"netopen x p",p,0);
  3400.             debug(F110,"netopen x q",q,0);
  3401.             while (*p != '\0' && *p != ':') /* Look for another colon */
  3402.               p++;
  3403.             if (*p == ':') {
  3404.                 debug(F110,"netopen found port",q,0);
  3405.                 *p++ = '\0';            /* Found a port name or number */
  3406.                 debug(F110,"netopen port",p,0);
  3407.                 ckstrncpy(tempservice,p,79);
  3408.                 ckstrncpy(temphost,q,79);
  3409.                 ckstrncpy(namecopy,temphost,NAMECPYL);
  3410.                 debug(F110,"netopen tempservice",tempservice,0);
  3411.                 debug(F110,"netopen temphost",temphost,0);
  3412.                 x = strlen(namecopy);
  3413.                 p = namecopy + x + 1;
  3414.                 ckstrncpy(p, tempservice, NAMECPYL - x);
  3415.             } else {
  3416.                 /* We didn't find another port, but if q is a service */
  3417.                 /* then assume that namecopy is actually a host.      */
  3418.                 if (getservbyname(q,"tcp")) {
  3419.                     p = q;
  3420.                 } else {
  3421. #ifdef RLOGCODE
  3422.                     /* rlogin is not a valid service */
  3423.                     if (!ckstrcmp("rlogin",namecopy,6,0)) {
  3424.                         ckstrncpy(namecopy,"login",NAMECPYL);
  3425.                     }
  3426. #endif /* RLOGCODE */
  3427.                     /* Reconstruct namecopy */
  3428.                     ckstrncpy(tempservice,namecopy,79);
  3429.                     ckstrncpy(temphost,q,79);
  3430.                     ckstrncpy(namecopy,temphost,NAMECPYL);
  3431.                     debug(F110,"netopen tempservice",tempservice,0);
  3432.                     debug(F110,"netopen temphost",temphost,0);
  3433.                     x = strlen(namecopy);
  3434.                     p = namecopy + x + 1;
  3435.                     ckstrncpy(p, tempservice, NAMECPYL - x - 1);
  3436.                 }
  3437.             }
  3438.             debug(F110,"netopen URL result",namecopy,0);
  3439.         }
  3440. #endif /* CK_URL */
  3441.     } else {                            /* Otherwise use telnet */
  3442.         p = "telnet";
  3443.     }
  3444. /*
  3445.   By the time we get here, namecopy[] should hold the null-terminated
  3446.   hostname or address, and p should point to the service name or number.
  3447. */
  3448.     debug(F110,"netopen host",namecopy,0);
  3449.     debug(F110,"netopen service requested",p,0);
  3450.     if (isdigit(*p)) {                  /* Use socket number without lookup */
  3451.         service = &servrec;
  3452.         service->s_port = htons((unsigned short)atoi(p));
  3453.     } else {                            /* Otherwise lookup the service name */
  3454. #ifdef CK_DNS_SRV
  3455.         if (tcp_dns_srv && !quiet) {
  3456.             printf(" DNS SRV Lookup... ");
  3457.             fflush(stdout);
  3458.         }
  3459.         if (tcp_dns_srv &&
  3460.             locate_srv_dns(namecopy,p,"tcp",&dns_addrs,&dns_naddrs)) {
  3461.             /* Use the first one.  Eventually we should cycle through all */
  3462.             /* the returned IP addresses and port numbers. */
  3463.             struct sockaddr_in *sin = NULL;
  3464. #ifdef BETATEST
  3465.             int i;
  3466.             printf("\r\n");
  3467.             for ( i=0;i<dns_naddrs;i++ ) {
  3468.                 sin = (struct sockaddr_in *) &dns_addrs[i];
  3469.                 printf("dns_addrs[%d] = %s %d\r\n", i,
  3470.                         (char *)inet_ntoa(sin->sin_addr),
  3471.                         ntohs(sin->sin_port));
  3472.             }
  3473. #endif /* BETATEST */
  3474.             /* Since the DNS SRV record will replace the service name with */
  3475.             /* a numeric port number we need to set the protocol before we */
  3476.             /* replace the service name */
  3477.             if (ttnproto == NP_DEFAULT)
  3478.               setnproto(p);
  3479.  
  3480.             sin = (struct sockaddr_in *) &dns_addrs[0];
  3481.             ckstrncpy(namecopy,(char *)inet_ntoa(sin->sin_addr),NAMECPYL);
  3482.             p = namecopy+strlen(namecopy)+1;
  3483.             sprintf(p,"%d",ntohs(sin->sin_port));
  3484.             service = &servrec;
  3485.             service->s_port = sin->sin_port;
  3486.  
  3487.             free(dns_addrs);
  3488.             dns_addrs = NULL;
  3489.             dns_naddrs = 0;
  3490.         } else
  3491. #endif /* CK_DNS_SRV */
  3492.             service = getservbyname(p, "tcp");
  3493.     }
  3494.     if (!service) {
  3495.         if (!strcmp("kermit",p)) {      /* Use Kermit service port */
  3496.             service = &servrec;
  3497.             service->s_port = htons(1649);
  3498.         } else if (!strcmp("telnet",p)) { /* Use Telnet port */
  3499.             service = &servrec;
  3500.             service->s_port = htons(23);
  3501.         } else if (!strcmp("http",p)) {
  3502.             service = &servrec;
  3503.             service->s_port = htons(80);
  3504.         }
  3505. #ifdef RLOGCODE
  3506.         else if (!strcmp("login",p)) {
  3507.             service = &servrec;
  3508.             service->s_port = htons(513);
  3509.         }
  3510. #endif /* RLOGCODE */
  3511. #ifdef CK_SSL
  3512.         /* Commonly used SSL ports (might not be in services file) */
  3513.         else if (!strcmp("https",p)) {
  3514.             service = &servrec;
  3515.             service->s_port = htons(443);
  3516.         } else if (!strcmp("ssl-telnet",p)) {
  3517.             service = &servrec;
  3518.             service->s_port = htons(151);
  3519.         } else if (!strcmp("telnets",p)) {
  3520.             service = &servrec;
  3521.             service->s_port = htons(992);
  3522.         }
  3523. #endif /* CK_SSL */
  3524. #ifdef CK_KERBEROS
  3525. #ifdef RLOGCODE
  3526.         else if (!strcmp("klogin",p)) {
  3527.             service = &servrec;
  3528.             service->s_port = htons(543);
  3529.         } else if (!strcmp("eklogin",p)) {
  3530.             service = &servrec;
  3531.             service->s_port = htons(2105);
  3532.         }
  3533. #endif /* RLOGCODE */
  3534. #endif /* CK_KERBEROS */
  3535.  
  3536.         if (!service) {
  3537.             fprintf(stderr, "Can't find port for service %s\n", p);
  3538. #ifdef TGVORWIN
  3539.             debug(F101,"netopen can't get service","",socket_errno);
  3540. #else
  3541.             debug(F101,"netopen can't get service","",errno);
  3542. #endif /* TGVORWIN */
  3543.             errno = 0;                  /* (rather than mislead) */
  3544.             return(-1);
  3545.         }
  3546.     }
  3547.     ckstrncpy(svcbuf,p,79);
  3548.     debug(F110,"netopen service ok",svcbuf,0);
  3549.  
  3550.     /* Use the service port to set the default protocol type if necessary */
  3551.     if (ttnproto == NP_DEFAULT)
  3552.       setnproto(p);
  3553.  
  3554. #ifdef RLOGCODE
  3555.     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
  3556.         fprintf(stderr,
  3557.                 "  Warning: login service on port %d instead of port 513\n",
  3558.                  ntohs(service->s_port)
  3559.                 );
  3560.         fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
  3561.         debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
  3562.     }
  3563. #endif /* RLOGCODE */
  3564.  
  3565.     /* Set up socket structure and get host address */
  3566.  
  3567.     bzero((char *)&r_addr, sizeof(r_addr));
  3568.     debug(F100,"netopen bzero ok","",0);
  3569. /*
  3570.    NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
  3571.    all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
  3572.    address without going through the multihomed host sequence and winding up
  3573.    at a different place than the one requested.
  3574. */
  3575. #ifdef INADDR_NONE
  3576.     debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
  3577. #else /* INADDR_NONE */
  3578.     debug(F100,"netopen INADDR_NONE not defined","",0);
  3579. #endif /* INADDR_NONE */
  3580. #ifdef INADDRX
  3581.     debug(F100,"netopen INADDRX defined","",0);
  3582. #else /* INADDRX */
  3583.     debug(F100,"netopen INADDRX not defined","",0);
  3584. #endif /* INADDRX */
  3585.  
  3586. #ifndef NOMHHOST
  3587. #ifdef INADDRX
  3588.     iax = inet_addr(namecopy);
  3589.     debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
  3590. #else /* INADDRX */
  3591. #ifdef INADDR_NONE
  3592.     iax.s_addr = inet_addr(namecopy);
  3593.     debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
  3594. #else /* INADDR_NONE */
  3595. #ifndef datageneral
  3596.     iax = (unsigned int) inet_addr(namecopy);
  3597. #else
  3598.     iax = -1L;
  3599. #endif /* datageneral */
  3600.     debug(F111,"netopen inet_addr",namecopy,iax);
  3601. #endif /* INADDR_NONE */
  3602. #endif /* INADDRX */
  3603.  
  3604.     dns = 0;
  3605.     if (
  3606. #ifdef INADDR_NONE
  3607.         iax.s_addr == INADDR_NONE || iax.s_addr == (unsigned long) -1L
  3608. #else /* INADDR_NONE */
  3609.         iax < 0
  3610. #endif /* INADDR_NONE */
  3611.         ) {
  3612.         if (!quiet) {
  3613.             printf(" DNS Lookup... ");
  3614.             fflush(stdout);
  3615.         }
  3616.         if ((host = gethostbyname(namecopy)) != NULL) {
  3617.             debug(F100,"netopen gethostbyname != NULL","",0);
  3618.             dns = 1;                    /* Remember we performed dns lookup */
  3619. #ifdef OS2
  3620.             ckstrncpy(name,host->h_name,80);
  3621.             strncat(name,":",80-strlen(name));
  3622.             strncat(name,p,80-strlen(name));
  3623. #endif /* OS2 */
  3624.             r_addr.sin_family = host->h_addrtype;
  3625. #ifdef HADDRLIST
  3626. #ifdef h_addr
  3627.             /* This is for trying multiple IP addresses - see <netdb.h> */
  3628.             if (!(host->h_addr_list))
  3629.               return(-1);
  3630.             bcopy(host->h_addr_list[0],
  3631.                   (caddr_t)&r_addr.sin_addr,
  3632.                   host->h_length
  3633.                   );
  3634. #else
  3635.             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
  3636. #endif /* h_addr */
  3637. #else  /* HADDRLIST */
  3638.             bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
  3639. #endif /* HADDRLIST */
  3640. #ifndef EXCELAN
  3641.             debug(F111,"BCOPY","host->h_addr",host->h_addr);
  3642. #endif /* EXCELAN */
  3643.             debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
  3644.                   (caddr_t)&r_addr.sin_addr);
  3645.             debug(F111,"BCOPY","host->h_length",host->h_length);
  3646.         }
  3647.     }
  3648. #endif /* NOMHHOST */
  3649.  
  3650.     if (!dns) {
  3651. #ifdef INADDRX
  3652. /* inet_addr() is of type struct in_addr */
  3653.         struct in_addr ina;
  3654.         unsigned long uu;
  3655.         debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
  3656.         ina = inet_addr(namecopy);
  3657.         uu = *(unsigned int *)&ina;
  3658. #else /* Not INADDRX */
  3659. /* inet_addr() is unsigned long */
  3660.         unsigned long uu;
  3661.         debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
  3662.         uu = inet_addr(namecopy);
  3663. #endif /* INADDRX */
  3664.         debug(F101,"netopen uu","",uu);
  3665.         if (
  3666. #ifdef INADDR_NONE
  3667.             !(uu == INADDR_NONE || uu == (unsigned int) -1L)
  3668. #else   /* INADDR_NONE */
  3669.             uu != ((unsigned long)-1)
  3670. #endif /* INADDR_NONE */
  3671.             ) {
  3672.             r_addr.sin_addr.s_addr = uu;
  3673.             r_addr.sin_family = AF_INET;
  3674.         } else {
  3675.             fprintf(stderr, "Can't get address for %s\n", namecopy);
  3676. #ifdef TGVORWIN
  3677.             debug(F101,"netopen can't get address","",socket_errno);
  3678. #else
  3679.             debug(F101,"netopen can't get address","",errno);
  3680. #endif /* TGVORWIN */
  3681.             errno = 0;                  /* Rather than mislead */
  3682.             return(-1);
  3683.         }
  3684.     }
  3685.  
  3686.     /* Get a file descriptor for the connection. */
  3687.  
  3688.     r_addr.sin_port = service->s_port;
  3689.     ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
  3690.     debug(F110,"netopen trying",ipaddr,0);
  3691.     if (!quiet && *ipaddr) {
  3692.         printf(" Trying %s... ", ipaddr);
  3693.         fflush(stdout);
  3694.     }
  3695.  
  3696.     /* Loop to try additional IP addresses, if any. */
  3697.  
  3698.     do {
  3699. #ifdef EXCELAN
  3700.         send_socket.sin_family = AF_INET;
  3701.         send_socket.sin_addr.s_addr = 0;
  3702.         send_socket.sin_port = 0;
  3703.         if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
  3704.                             &send_socket, SO_REUSEADDR)) < 0)
  3705. #else  /* EXCELAN */
  3706. #ifdef NT
  3707. #ifdef COMMENT_X
  3708.        /*
  3709.          Must make sure that all sockets are opened in
  3710.          Non-overlapped mode since we use the standard
  3711.          C RTL functions to read and write data.
  3712.          But it doesn't seem to work as planned.
  3713.        */
  3714.           {
  3715.               int optionValue = SO_SYNCHRONOUS_NONALERT;
  3716.               if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
  3717.                              (char *) &optionValue, sizeof(optionValue))
  3718.                   != NO_ERROR)
  3719.                 return(-1);
  3720.           }
  3721. #endif /* COMMENT */
  3722. #endif /* NT */
  3723.  
  3724.         if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  3725. #endif /* EXCELAN */
  3726.             {
  3727. #ifdef EXCELAN
  3728.                 experror("TCP socket error");
  3729. #else
  3730. #ifdef TGVORWIN
  3731. #ifdef OLD_TWG
  3732.                 errno = socket_errno;
  3733. #endif /* OLD_TWG */
  3734.                 socket_perror("TCP socket error");
  3735.                 debug(F101,"netopen socket error","",socket_errno);
  3736. #else
  3737.                 perror("TCP socket error");
  3738.                 debug(F101,"netopen socket error","",errno);
  3739. #endif /* TGVORWIN */
  3740. #endif /* EXCELAN */
  3741.                 return (-1);
  3742.             }
  3743.         errno = 0;
  3744.  
  3745. #ifdef RLOGCODE
  3746.        /* Not part of the RLOGIN RFC, but the BSD implementation     */
  3747.        /* requires that the client port be a priviliged port (<1024) */
  3748.        /* on a Unix system this would require SuperUser permissions  */
  3749.        /* thereby saying that the root of the Unix system has given  */
  3750.        /* permission for this connection to be created               */
  3751.        if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
  3752.            static unsigned short lport = 1024;  /* max reserved port */
  3753.            int s_errno;
  3754.  
  3755.            lport--;                     /* Make sure we do not reuse a port */
  3756.            if (lport == 512)
  3757.              lport = 1023;
  3758.  
  3759.            sin.sin_family = AF_INET;
  3760.            if (tcp_address) {
  3761. #ifdef INADDRX
  3762.                inaddrx = inet_addr(tcp_address);
  3763.                sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
  3764. #else
  3765.                sin.sin_addr.s_addr = inet_addr(tcp_address);
  3766. #endif /* INADDRX */
  3767.            } else
  3768.              sin.sin_addr.s_addr = INADDR_ANY;
  3769.            while (1) {
  3770.                sin.sin_port = htons(lport);
  3771.                if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  3772.                  break;
  3773. #ifdef OS2
  3774.                s_errno = socket_errno;
  3775.                if (s_errno && /* OS2 bind fails with 0, if already in use */
  3776. #ifdef NT
  3777.                    s_errno != WSAEADDRINUSE
  3778. #else
  3779.                    s_errno != SOCEADDRINUSE &&
  3780.                    s_errno != (SOCEADDRINUSE - SOCBASEERR)
  3781. #endif /* NT */
  3782.                    )
  3783. #else /* OS2 */
  3784. #ifdef TGVORWIN
  3785.                  if (socket_errno != EADDRINUSE)
  3786. #else
  3787.                  if (errno != EADDRINUSE)
  3788. #endif /* TGVORWIN */
  3789. #endif /* OS2 */
  3790.                    {
  3791.                        printf("\nBind failed with errno %d  for port %d.\n",
  3792. #ifdef OS2
  3793.                               s_errno
  3794. #else
  3795. #ifdef TGVORWIN
  3796.                               socket_errno
  3797. #else
  3798.                               errno
  3799. #endif /* TGVORWIN */
  3800. #endif /* OS2 */
  3801.                               , lport
  3802.                               );
  3803. #ifdef OS2
  3804.                        debug(F101,"rlogin bind failed","",s_errno);
  3805. #else
  3806. #ifdef TGVORWIN
  3807.                        debug(F101,"rlogin bind failed","",socket_errno);
  3808. #ifdef OLD_TWG
  3809.                        errno = socket_errno;
  3810. #endif /* OLD_TWG */
  3811.                        socket_perror("rlogin bind");
  3812. #else
  3813.                        debug(F101,"rlogin bind failed","",errno);
  3814.                        perror("rlogin bind");
  3815. #endif /* TGVORWIN */
  3816. #endif /* OS2 */
  3817.                        netclos();
  3818.                        return -1;
  3819.                    }
  3820.                lport--;
  3821.                if (lport == 512 /* lowest reserved port to use */ ) {
  3822.                    printf("\nNo reserved ports available.\n");
  3823.                    netclos();
  3824.                    return -1;
  3825.                }
  3826.            }
  3827.            debug(F101,"rlogin lport","",lport);
  3828.            ttnproto = NP_RLOGIN;
  3829.        } else
  3830. #endif /* RLOGCODE  */
  3831.  
  3832.        /* If a specific TCP address on the local host is desired we */
  3833.        /* must bind it to the socket.                               */
  3834. #ifndef datageneral
  3835.          if (tcp_address) {
  3836.              int s_errno;
  3837.  
  3838.              debug(F110,"netopen binding socket to",tcp_address,0);
  3839.              bzero((char *)&sin,sizeof(sin));
  3840.              sin.sin_family = AF_INET;
  3841. #ifdef INADDRX
  3842.              inaddrx = inet_addr(tcp_address);
  3843.              sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
  3844. #else
  3845.              sin.sin_addr.s_addr = inet_addr(tcp_address);
  3846. #endif /* INADDRX */
  3847.              sin.sin_port = 0;
  3848.              if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  3849.                  s_errno = socket_errno; /* Save error code */
  3850. #ifdef TCPIPLIB
  3851.                  socket_close(ttyfd);
  3852. #else /* TCPIPLIB */
  3853.                  close(ttyfd);
  3854. #endif /* TCPIPLIB */
  3855.                  ttyfd = -1;
  3856.                  wasclosed = 1;
  3857.                  errno = s_errno;       /* and report this error */
  3858.                  debug(F101,"netopen bind errno","",errno);
  3859.                  return(-1);
  3860.              }
  3861.          }
  3862. #endif /* datageneral */
  3863.  
  3864. /* Now connect to the socket on the other end. */
  3865.  
  3866. #ifdef EXCELAN
  3867.         if (connect(ttyfd, &r_addr) < 0)
  3868. #else
  3869. #ifdef NT
  3870.           WSASafeToCancel = 1;
  3871. #endif /* NT */
  3872.         if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
  3873. #endif /* EXCELAN */
  3874.           {
  3875. #ifdef NT
  3876.               WSASafeToCancel = 0;
  3877. #endif /* NT */
  3878. #ifdef OS2
  3879.               i = socket_errno;
  3880. #else /* OS2 */
  3881. #ifdef TGVORWIN
  3882.               i = socket_errno;
  3883. #else
  3884.               i = errno;                /* Save error code */
  3885. #endif /* TGVORWIN */
  3886. #endif /* OS2 */
  3887. #ifdef RLOGCODE
  3888.               if (
  3889. #ifdef OS2
  3890.                  i && /* OS2 bind fails with 0, if already in use */
  3891. #ifdef NT
  3892.                  i == WSAEADDRINUSE
  3893. #else
  3894.                  (i == SOCEADDRINUSE ||
  3895.                  i == (SOCEADDRINUSE - SOCBASEERR))
  3896. #endif /* NT */
  3897. #else /* OS2 */
  3898. #ifdef TGVORWIN
  3899.                   socket_errno == EADDRINUSE
  3900. #else
  3901.                   errno == EADDRINUSE
  3902. #endif /* TGVORWIN */
  3903. #endif /* OS2 */
  3904.                   && ttnproto == NP_RLOGIN) {
  3905. #ifdef TCPIPLIB
  3906.                    socket_close(ttyfd); /* Close it. */
  3907. #else
  3908.                    close(ttyfd);
  3909. #endif /* TCPIPLIB */
  3910.                    continue;            /* Try a different lport */
  3911.                }
  3912. #endif /* RLOGCODE */
  3913. #ifdef HADDRLIST
  3914. #ifdef h_addr
  3915.               if (host && host->h_addr_list && host->h_addr_list[1]) {
  3916.                   perror("");
  3917.                   host->h_addr_list++;
  3918.                   bcopy(host->h_addr_list[0],
  3919.                         (caddr_t)&r_addr.sin_addr,
  3920.                         host->h_length);
  3921.  
  3922.                   ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
  3923.                   debug(F110,"netopen h_addr_list",ipaddr,0);
  3924.                   if (!quiet && *ipaddr) {
  3925.                       printf(" Trying %s... ", ipaddr);
  3926.                       fflush(stdout);
  3927.                   }
  3928. #ifdef TCPIPLIB
  3929.                   socket_close(ttyfd); /* Close it. */
  3930. #else
  3931.                   close(ttyfd);
  3932. #endif /* TCPIPLIB */
  3933.                   continue;
  3934.               }
  3935. #endif /* h_addr */
  3936. #endif  /* HADDRLIST */
  3937.               netclos();
  3938.               ttyfd = -1;
  3939.               wasclosed = 1;
  3940.               ttnproto = NP_NONE;
  3941.               errno = i;                /* And report this error */
  3942. #ifdef EXCELAN
  3943.               if (errno) experror("netopen connect");
  3944. #else
  3945. #ifdef TGVORWIN
  3946.               debug(F101,"netopen connect error","",socket_errno);
  3947.               /* if (errno) socket_perror("netopen connect"); */
  3948. #ifdef OLD_TWG
  3949.               errno = socket_errno;
  3950. #endif /* OLD_TWG */
  3951.               socket_perror("netopen connect");
  3952. #else /* TGVORWIN */
  3953.               debug(F101,"netopen connect errno","",errno);
  3954. #ifdef VMS
  3955.               perror("\r\nFailed");
  3956. #else
  3957.               perror("Failed");
  3958. #endif /* VMS */
  3959. #ifdef DEC_TCPIP
  3960.               perror("netopen connect");
  3961. #endif /* DEC_TCPIP */
  3962. #ifdef CMU_TCPIP
  3963.               perror("netopen connect");
  3964. #endif /* CMU_TCPIP */
  3965. #endif /* TGVORWIN */
  3966. #endif /* EXCELAN */
  3967.               return(-1);
  3968.           }
  3969. #ifdef NT
  3970.         WSASafeToCancel = 0;
  3971. #endif /* NT */
  3972.         isconnect = 1;
  3973.     } while (!isconnect);
  3974.  
  3975.  
  3976.     /* There are certain magic port numbers that when used require */
  3977.     /* the use of specific protocols.  Check this now before we    */
  3978.     /* set the SO_OOBINLINE state or we might get it wrong.        */
  3979.     x = ntohs((unsigned short)service->s_port);
  3980.     svcnum = x;
  3981.     /* See if the service is TELNET. */
  3982.     if (x == TELNET_PORT) {
  3983.         if (ttnproto != NP_TCPRAW)      /* Yes, so if raw port not requested */
  3984.           ttnproto = NP_TELNET;         /* select TELNET protocol. */
  3985.     }
  3986. #ifdef RLOGCODE
  3987.     else if (x == RLOGIN_PORT) {
  3988.         ttnproto = NP_RLOGIN;
  3989.     }
  3990. #ifdef CK_KERBEROS
  3991.     /* There is no good way to do this.  If the user didn't tell    */
  3992.     /* which one to use up front.  We may guess wrong if the user   */
  3993.     /* has both Kerberos versions installed and valid TGTs for each */
  3994.     else if (x == KLOGIN_PORT &&
  3995.              ttnproto != NP_K4LOGIN &&
  3996.              ttnproto != NP_K5LOGIN) {
  3997.         if (ck_krb5_is_installed() &&
  3998.             ck_krb5_is_tgt_valid())
  3999.           ttnproto = NP_K5LOGIN;
  4000.         else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
  4001.           ttnproto = NP_K4LOGIN;
  4002.         else
  4003.           ttnproto = NP_K4LOGIN;
  4004.     } else if (x == EKLOGIN_PORT &&
  4005.                ttnproto != NP_EK4LOGIN &&
  4006.                ttnproto != NP_EK5LOGIN) {
  4007.         if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
  4008.           ttnproto = NP_EK5LOGIN;
  4009.         else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
  4010.           ttnproto = NP_EK4LOGIN;
  4011.         else
  4012.           ttnproto = NP_EK4LOGIN;
  4013.     }
  4014. #endif /* CK_KERBEROS */
  4015. #endif /* RLOGCODE */
  4016. #ifdef IKS_OPTION
  4017.     else if (x == KERMIT_PORT) {        /* IKS uses Telnet protocol */
  4018.         if (ttnproto == NP_NONE)
  4019.           ttnproto = NP_KERMIT;
  4020.     }
  4021. #endif /* IKS_OPTION */
  4022.  
  4023. #ifdef SO_OOBINLINE
  4024. /*
  4025.   The symbol SO_OOBINLINE is not known to Ultrix 2.0.
  4026.   It means "leave out of band data inline".  The normal value is 0x0100,
  4027.   but don't try this on systems where the symbol is undefined.
  4028. */
  4029. /*
  4030.   Note from Jeff Altman: 12/13/95
  4031.   In implementing rlogin protocol I have come to the conclusion that it is
  4032.   a really bad idea to read out-of-band data inline.
  4033.   At least Windows and OS/2 does not handle this well.
  4034.   And if you need to know that data is out-of-band, then it becomes
  4035.   absolutely pointless.
  4036.  
  4037.   Therefore, at least on OS2 and Windows (NT) I have changed the value of
  4038.   on to 0, so that out-of-band data stays out-of-band.
  4039.  
  4040.   12/18/95
  4041.   Actually, OOB data should be read inline when possible.  Especially with
  4042.   protocols that don't care about the Urgent flag.  This is true with Telnet.
  4043.   With Rlogin, you need to be able to catch OOB data.  However, the best
  4044.   way to do this is to set a signal handler on SIGURG.  This isn't possible
  4045.   on OS/2 and Windows.  But it is in UNIX.  We will also need OOB data for
  4046.   FTP so better create a general mechanism.
  4047.  
  4048.   The reason for making OOB data be inline is that the standard ttinc/ttoc
  4049.   calls can be used for reading that data on UNIX systems.  If we didn't
  4050.   have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
  4051.   to read it.
  4052. */
  4053. #ifdef RLOGCODE
  4054. #ifdef TCPIPLIB
  4055.     if (ttnproto == NP_RLOGIN  ||
  4056. #ifdef CK_KERBEROS
  4057.         ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
  4058.         ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN ||
  4059. #endif /* CK_KERBEROS */
  4060.         ttnproto == NP_FTP)
  4061.       on = 0;
  4062. #else /* TCPIPLIB */
  4063.     if (ttnproto == NP_RLOGIN
  4064. #ifdef CK_KERBEROS
  4065.          || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
  4066.          || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
  4067. #endif /* CK_KERBEROS */
  4068.          ) {
  4069.         debug(F100,"Installing rlogoobh on SIGURG","",0);
  4070.         signal(SIGURG, rlogoobh);
  4071.         on = 0;
  4072.     } else
  4073. #ifdef FTPCODE
  4074.       if (ttnproto == NP_FTP) {
  4075.           debug(F100,"Installing ftpoobh on SIGURG","",0);
  4076.           signal(SIGURG, ftpoobh);
  4077.           on = 0;
  4078.       } else
  4079. #endif /* FTPCODE */
  4080.         {
  4081.             debug(F100,"Ignoring SIGURG","",0);
  4082.             signal(SIGURG, SIG_DFL);
  4083.         }
  4084. #endif /* TCPIPLIB */
  4085. #endif /* RLOGCODE */
  4086.  
  4087. #ifdef datageneral
  4088.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4089. #else
  4090. #ifdef BSD43
  4091.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4092. #else
  4093. #ifdef OSF1
  4094.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4095. #else
  4096. #ifdef POSIX
  4097.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4098. #else
  4099. #ifdef MOTSV88R4
  4100.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4101. #else
  4102. #ifdef SOLARIS
  4103. /*
  4104.   Maybe this applies to all SVR4 versions, but the other (else) way has been
  4105.   compiling and working fine on all the others, so best not to change it.
  4106. */
  4107.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4108. #else
  4109. #ifdef OSK
  4110.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4111. #else
  4112. #ifdef OS2
  4113.     {
  4114.         int rc;
  4115.         rc = setsockopt(ttyfd,
  4116.                         SOL_SOCKET,
  4117.                         SO_OOBINLINE,
  4118.                         (char *) &on,
  4119.                         sizeof on
  4120.                         );
  4121.         debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
  4122.     }
  4123. #else
  4124. #ifdef VMS /* or, at least, VMS with gcc */
  4125.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4126. #else
  4127. #ifdef CLIX /* or, at least, VMS with gcc */
  4128.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  4129. #else
  4130.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
  4131. #endif /* CLIX */
  4132. #endif /* VMS */
  4133. #endif /* OS2 */
  4134. #endif /* OSK */
  4135. #endif /* SOLARIS */
  4136. #endif /* MOTSV88R4 */
  4137. #endif /* POSIX */
  4138. #endif /* BSD43 */
  4139. #endif /* OSF1 */
  4140. #endif /* datageneral */
  4141. #endif /* SO_OOBINLINE */
  4142.  
  4143. #ifndef NOTCPOPTS
  4144. #ifndef datageneral
  4145. #ifdef SOL_SOCKET
  4146. #ifdef TCP_NODELAY
  4147.     no_delay(tcp_nodelay);
  4148. #endif /* TCP_NODELAY */
  4149. #ifdef SO_KEEPALIVE
  4150.     keepalive(tcp_keepalive);
  4151. #endif /* SO_KEEPALIVE */
  4152. #ifdef SO_LINGER
  4153.     ck_linger(tcp_linger, tcp_linger_tmo);
  4154. #endif /* SO_LINGER */
  4155. #ifdef SO_SNDBUF
  4156.     sendbuf(tcp_sendbuf);
  4157. #endif /* SO_SNDBUF */
  4158. #ifdef SO_RCVBUF
  4159.     recvbuf(tcp_recvbuf);
  4160. #endif /* SO_RCVBUF */
  4161. #endif /* SOL_SOCKET */
  4162. #endif /* datageneral */
  4163. #endif /* NOTCPOPTS */
  4164.  
  4165. #ifdef NON_BLOCK_IO
  4166.     on = 1;
  4167.     x = socket_ioctl(ttyfd,FIONBIO,&on);
  4168.     debug(F101,"netopen FIONBIO","",x);
  4169. #endif /* NON_BLOCK_IO */
  4170.  
  4171. #ifdef NT_TCP_OVERLAPPED
  4172.     OverlappedWriteInit();
  4173.     OverlappedReadInit();
  4174. #endif /* NT_TCP_OVERLAPPED */
  4175.  
  4176.     ttnet = nett;                       /* TCP/IP (sockets) network */
  4177.  
  4178. #ifndef datageneral
  4179.     /* Find out our own IP address. */
  4180.     /* We need the l_addr structure for [E]KLOGIN. */
  4181.     l_slen = sizeof(l_addr);
  4182.     bzero((char *)&l_addr, l_slen);
  4183. #ifndef EXCELAN
  4184.     if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
  4185.         char * s = (char *)inet_ntoa(l_addr.sin_addr);
  4186.         ckstrncpy(myipaddr, s, 20);
  4187.         debug(F110,"getsockname",myipaddr,0);
  4188.     }
  4189. #endif /* EXCELAN */
  4190. #endif /* datageneral */
  4191.  
  4192. /*
  4193.   This is really only needed for Kerberos IV but is useful information in any
  4194.   case.  If we connect to a name that is really a pool, we need to get the
  4195.   name of the machine we are actually connecting to for K4 to authenticate
  4196.   properly.  This way we also update the names properly.
  4197.  
  4198.   Note: This does not work on Windows 95 or Windows NT 3.5x.  This is because
  4199.   of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
  4200.   and Winsock 2.0 on those platforms.  Their algorithm is:
  4201.  
  4202.   1. Check the HOSTENT cache.
  4203.   2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
  4204.   3. Do a DNS query if the DNS server is configured for name resolution.
  4205.   4. Do an additional NetBIOS remote adapter status to an IP address for its
  4206.      NetBIOS name table. This step is specific only to the Windows NT version
  4207.      3.51 implementation.
  4208.  
  4209.   The problem is the use of the HOSTENT cache.  It means that gethostbyaddr()
  4210.   can not be used to resolve the real name of machine if it was originally
  4211.   accessed by an alias used to represent a cluster.
  4212. */
  4213.      if (tcp_rdns && dns || tcp_rdns == SET_ON
  4214. #ifdef CK_KERBEROS
  4215.          || tcp_rdns == SET_AUTO &&
  4216.           (ck_krb5_is_installed() || ck_krb4_is_installed())
  4217. #endif /* CK_KERBEROS */
  4218.          ) {
  4219. #ifdef NT
  4220.         if (isWin95())
  4221.           sleep(1);
  4222. #endif /* NT */
  4223.         if (!quiet) {
  4224.             printf(" Reverse DNS Lookup... ");
  4225.             fflush(stdout);
  4226.         }
  4227.         if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
  4228.             char * s;
  4229.             debug(F100,"netopen gethostbyname != NULL","",0);
  4230.             if (!quiet) {
  4231.                 printf("(OK)\n");
  4232.                 fflush(stdout);
  4233.             }
  4234.             s = host->h_name;
  4235.             if (!s) {                   /* This can happen... */
  4236.                 debug(F100,"netopen host->h_name is NULL","",0);
  4237.                 s = "";
  4238.             }
  4239.             /* Something is wrong with inet_ntoa() on HPUX 10.xx */
  4240.             /* The compiler says "Integral value implicitly converted to */
  4241.             /* pointer in assignment."  The prototype is right there */
  4242.             /* in <arpa/inet.h> so what's the problem? */
  4243.             /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
  4244.             if (!*s) {                  /* No name so substitute the address */
  4245.                 debug(F100,"netopen host->h_name is empty","",0);
  4246.                 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
  4247.                 if (!s)                 /* Trust No 1 */
  4248.                   s = "";
  4249.                 if (*s) {               /* If it worked, use this string */
  4250.                     ckstrncpy(ipaddr,s,20);
  4251.                 }
  4252.                 s = ipaddr;             /* Otherwise stick with the IP */
  4253.                 if (!*s)                /* or failing that */
  4254.                   s = namecopy;         /* the name we were called with. */
  4255.             }
  4256.             if (*s) {                   /* Copying into our argument? */
  4257.                 ckstrncpy(name,s,80);   /* Bad Bad Bad */
  4258.                 strncat(name,":",80-strlen(name));
  4259.                 strncat(name,p,80-strlen(name));
  4260.             }
  4261.             if (!quiet && *s
  4262. #ifndef NOICP
  4263.                 && !doconx
  4264. #endif /* NOICP */
  4265.                 ) {
  4266.                 printf(" %s connected on port %s\n",s,p);
  4267. #ifdef BETATEST
  4268.                 /* This is simply for testing the DNS entries */
  4269.                 if (host->h_aliases) {
  4270.                     char ** a = host->h_aliases;
  4271.                     while (*a) {
  4272.                         printf(" alias => %s\n",*a);
  4273.                         a++;
  4274.                     }
  4275.                 }
  4276. #endif /* BETATEST */
  4277.             }
  4278.         } else {
  4279.             if (!quiet) printf("Failed.\n");
  4280.         }
  4281.     } else if (!quiet) printf("(OK)\n");
  4282.     if (!quiet) fflush(stdout);
  4283.  
  4284.     /* This should already have been done but just in case */
  4285.     ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
  4286.  
  4287. #ifdef CK_AUTHENTICATION
  4288.     /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
  4289.     ck_auth_init((host && host->h_name && host->h_name[0]) ?
  4290.                 (char *)host->h_name : ipaddr,
  4291.                 ipaddr,
  4292.                 uidbuf,
  4293.                 ttyfd
  4294.                 );
  4295. #endif /* CK_AUTHENTICATION */
  4296. #ifdef CK_SSL
  4297.     if (ck_ssleay_is_installed()) {
  4298.         if ( ck_ssl_outgoing(ttyfd) < 0 ) {
  4299.             netclos();
  4300.             return(-1);
  4301.         }
  4302.     }
  4303. #endif /* CK_SSL */
  4304.  
  4305. #ifdef RLOGCODE
  4306.     if (ttnproto == NP_RLOGIN
  4307. #ifdef CK_KERBEROS
  4308.         || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
  4309.         || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
  4310. #endif /* CK_KERBEROS */
  4311.         ) {                             /* Similar deal for rlogin */
  4312.         if (rlog_ini(((host && host->h_name && host->h_name[0]) ?
  4313.                       (CHAR *)host->h_name : (CHAR *)ipaddr),
  4314.                      service->s_port,
  4315.                      &l_addr,&r_addr
  4316.                      ) < 0) {
  4317.             debug(F100,"rlogin initialization failed","",0);
  4318.             netclos();
  4319.             return(-1);
  4320.         }
  4321.     } else
  4322. #endif /* RLOGCODE */
  4323.     if (tn_ini() < 0)                   /* Start Telnet negotiations. */
  4324. #ifdef OS2
  4325.       if (ttchk() < 0)                  /* Failed - check connection. */
  4326. #endif /* OS2 */
  4327.         return(-1);                     /* Gone, so open failed.  */
  4328.  
  4329.     debug(F101,"netopen service","",svcnum);
  4330.     debug(F110,"netopen name",name,0);
  4331.  
  4332.     if (*lcl < 0)                       /* Local mode. */
  4333.       *lcl = 1;
  4334. #endif /* TCPSOCKET */
  4335.     return(0);                          /* Done. */
  4336. }
  4337.  
  4338. /*  N E T C L O S  --  Close current network connection.  */
  4339.  
  4340. #ifndef NOICP
  4341. _PROTOTYP(VOID slrestor,(VOID));
  4342. #ifdef CK_SSL
  4343. int tls_norestore = 0;
  4344. #endif /* CK_SSL */
  4345. #endif /* NOICP */
  4346.  
  4347. int
  4348. netclos() {
  4349.     static int close_in_progress = 0;
  4350.     int x = 0;
  4351.     debug(F101,"netclos","",ttyfd);
  4352.  
  4353. #ifdef NETLEBUF
  4354.     if (!tt_push_inited)
  4355.       le_init();
  4356. #endif /* NETLEBUF */
  4357.  
  4358.     if (ttyfd == -1)                    /* Was open? */
  4359.       return(0);                        /* Wasn't. */
  4360.  
  4361.     if (close_in_progress)
  4362.       return(0);
  4363.     close_in_progress = 1;              /* Remember */
  4364.  
  4365. #ifndef NOICP
  4366.     /* This function call should not be here since this is a direct call */
  4367.     /* from an I/O routine to a user interface level function.  However, */
  4368.     /* the reality is that we do not have pure interfaces.  If we ever   */
  4369.     /* decide to clean this up the UI level should assign this function  */
  4370.     /* via a pointer assignment.  - Jeff 9/10/1999                       */
  4371. #ifdef CK_SSL
  4372.     if (!tls_norestore)
  4373. #endif /* CK_SSL */
  4374.       slrestor();
  4375. #endif /* NOICP */
  4376. #ifndef OS2
  4377.     if (ttyfd > -1)                     /* Was. */
  4378. #endif /* OS2 */
  4379.       {
  4380. #ifdef TNCODE
  4381.           tn_push();                    /* Place any waiting data into input*/
  4382.           tn_sopt(DO,TELOPT_LOGOUT);    /* Send LOGOUT option before close */
  4383.           TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
  4384.           tn_reset();                   /* The Reset Telnet Option table.  */
  4385. #endif /* TNCODE */
  4386. #ifdef CK_SSL
  4387.           if (ssl_active_flag) {
  4388.               if (ssl_debug_flag)
  4389.                 BIO_printf(bio_err,"calling SSL_shutdown\n");
  4390.               SSL_shutdown(ssl_con);
  4391.               SSL_free(ssl_con);
  4392.               ssl_con = NULL;
  4393.               ssl_active_flag = 0;
  4394.           }
  4395.           if (tls_active_flag) {
  4396.               if (ssl_debug_flag)
  4397.                 BIO_printf(bio_err,"calling SSL_shutdown\n");
  4398.               SSL_shutdown(tls_con);
  4399.               SSL_free(tls_con);
  4400.               tls_con = NULL;
  4401.               tls_active_flag = 0;
  4402.           }
  4403. #endif /* CK_SSL */
  4404. #ifdef VMS
  4405.           ck_cancio();                  /* Cancel any outstanding reads. */
  4406. #endif /* VMS */
  4407. #ifdef TCPIPLIB
  4408.           x = socket_close(ttyfd);      /* Close it. */
  4409. #else
  4410. #ifndef OS2
  4411. #ifdef IBMX25
  4412.         if (ttnet == NET_IX25) {
  4413.             /* riehm: should send a disc_req - but only if link is still OK */
  4414.             x = x25clear();
  4415.             close(ttyfd);
  4416.             if (x25serverfd) {
  4417.                   /* we were the passive client of a server, now we
  4418.                    * go back to being the normal client.
  4419.                    * I hope that kermit can cope with the logic that
  4420.                    * there can still be a connection after netclos
  4421.                    * has been called.
  4422.                    */
  4423.                   ttyfd = x25serverfd;
  4424.                   x25serverfd = 0;
  4425.                   /*
  4426.                    * need to close the server connection too - because
  4427.                    * all file descriptors connected to the NPI have the
  4428.                    * same status.
  4429.                    *
  4430.                    * The problem is that any waiting connections get
  4431.                    * lost, the client doesn't realise, and hangs.
  4432.                    */
  4433.                   netclos();
  4434.               }
  4435.             x25_state = X25_CLOSED;     /* riehm: dead code? */
  4436.         } else
  4437. #endif /* IBMX25 */
  4438.           x = close(ttyfd);
  4439. #endif /* OS2 */
  4440. #endif /* TCPIPLIB */
  4441.       }
  4442.     ttyfd = -1;                         /* Mark it as closed. */
  4443.     wasclosed = 1;
  4444. #ifdef TNCODE
  4445.     debug(F100,"netclose setting tn_init = 0","",0);
  4446.     tn_init = 0;                        /* Remember about telnet protocol... */
  4447.     sstelnet = 0;                       /* Client-side Telnet */
  4448. #ifdef CK_FORWARD_X
  4449.     fwdx_close_all();                   /* Shut down any Forward X sockets */
  4450. #endif /* CK_FORWARD_X */
  4451. #endif /* TNCODE */
  4452.     *ipaddr = '\0';                     /* Zero the IP address string */
  4453.     tcp_incoming = 0;                   /* No longer incoming */
  4454.     /* Don't reset ttnproto so that we can remember which protocol is in use */
  4455.  
  4456. #ifdef TCPIPLIB
  4457. /*
  4458.   Empty the internal buffers so they won't be used as invalid input on
  4459.   the next connect attempt (rlogin).
  4460. */
  4461.     ttibp = 0;
  4462.     ttibn = 0;
  4463. #endif /* TCPIPLIB */
  4464. #ifdef CK_KERBEROS
  4465.     /* If we are automatically destroying Kerberos credentials on Close */
  4466.     /* do it now. */
  4467. #ifdef KRB4
  4468.     if (krb4_autodel == KRB_DEL_CL) {
  4469.         extern struct krb_op_data krb_op;
  4470.         krb_op.version = 4;
  4471.         krb_op.cache = NULL;
  4472.         ck_krb4_destroy(&krb_op);
  4473.     }
  4474. #endif /* KRB4 */
  4475. #ifdef KRB5
  4476.     if (krb5_autodel == KRB_DEL_CL) {
  4477.         extern struct krb_op_data krb_op;
  4478.         extern char * krb5_d_cc;
  4479.         krb_op.version = 5;
  4480.         krb_op.cache = krb5_d_cc;
  4481.         ck_krb5_destroy(&krb_op);
  4482.     }
  4483. #endif /* KRB5 */
  4484. #endif /* CK_KERBEROS */
  4485.     close_in_progress = 0;              /* Remember we are done. */
  4486.     return(x);
  4487. }
  4488.  
  4489. #ifdef OS2
  4490. int
  4491. os2socketerror( int s_errno ) {
  4492.     switch (s_errno) {
  4493.       case 0:                /* NO ERROR */
  4494.         debug(F100,"os2socketerror NOERROR","",0);
  4495.         return(0);
  4496. #ifdef OS2ONLY
  4497.       case EOS2ERR:
  4498.         debug(F100,"os2socketerror EOS2ERR","",0);
  4499.         return(0);
  4500.       case ENOENT:            /* ENOENT */
  4501.         debug(F100,"os2socketerror ENOENT","",0);
  4502.         return(0);
  4503.       case EPASTEOF:            /* EPASTEOF */
  4504.         debug(F100,"os2socketerror EPASTEOF","",0);
  4505.         return(0);
  4506. #endif /* OS2ONLY */
  4507. #ifdef NT
  4508.       case WSAECONNRESET:
  4509. #else /* NT */
  4510.       case SOCECONNRESET:
  4511.       case SOCECONNRESET - SOCBASEERR:
  4512. #endif /* NT */
  4513.         debug(F100,"os2socketerror ECONRESET","",0);
  4514.         tn_debug("ECONRESET");
  4515.         netclos();              /* *** *** */
  4516.         return(-1);             /* Connection is broken. */
  4517. #ifdef NT
  4518.       case WSAECONNABORTED:
  4519. #else /* NT */
  4520.       case SOCECONNABORTED:
  4521.       case SOCECONNABORTED - SOCBASEERR:
  4522. #endif /* NT */
  4523.         debug(F100,"os2socketerror ECONNABORTED","",0);
  4524.         tn_debug("ECONNABORTED");
  4525.         netclos();              /* *** *** */
  4526.         return(-1);             /* Connection is broken. */
  4527. #ifdef NT
  4528.       case WSAENETRESET:
  4529. #else /* NT */
  4530.       case SOCENETRESET:
  4531.       case SOCENETRESET - SOCBASEERR:
  4532. #endif /* NT */
  4533.         debug(F100,"os2socketerror ENETRESET","",0);
  4534.         tn_debug("ENETRESET");
  4535.         netclos();              /* *** *** */
  4536.         return(-1);             /* Connection is broken. */
  4537. #ifdef NT
  4538.       case WSAENOTCONN:
  4539. #else /* NT */
  4540.       case SOCENOTCONN:
  4541.       case SOCENOTCONN - SOCBASEERR:
  4542. #endif /* NT */
  4543.         debug(F100,"os2socketerror ENOTCONN","",0);
  4544.         tn_debug("ENOTCONN");
  4545.         netclos();              /* *** *** */
  4546.         return(-1);             /* Connection is broken. */
  4547. #ifdef NT
  4548.       case WSAESHUTDOWN:
  4549.         debug(F100,"os2socketerror ESHUTDOWN","",0);
  4550.         tn_debug("ESHUTDOWN");
  4551.         netclos();              /* *** *** */
  4552.         return(-1);             /* Connection is broken. */
  4553. #endif /* NT */
  4554. #ifdef NT
  4555.       case WSAEWOULDBLOCK:
  4556. #else
  4557.       case SOCEWOULDBLOCK:
  4558.       case SOCEWOULDBLOCK - SOCBASEERR:
  4559. #endif /* NT */
  4560.         debug(F100,"os2socketerror EWOULDBLOCK","",0);
  4561.         return(0);
  4562. #ifdef NT
  4563.       case ERROR_IO_INCOMPLETE:
  4564.       case ERROR_IO_PENDING:
  4565.       case ERROR_OPERATION_ABORTED:
  4566.         return(0);
  4567. #endif /* NT */
  4568.       default:
  4569.         return(-2);
  4570.     }
  4571.     return(0);
  4572. }
  4573. #endif /* OS2 */
  4574.  
  4575. /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
  4576. /*
  4577.   Returns number of bytes waiting, or -1 if connection has been dropped.
  4578. */
  4579. int                                     /* Check how many bytes are ready */
  4580. nettchk() {                             /* for reading from network */
  4581. #ifdef TCPIPLIB
  4582.     long count = 0;
  4583.     int x = 0;
  4584.     long y;
  4585.     char c;
  4586. #ifdef NT
  4587.     extern int ionoblock;               /* For Overlapped I/O */
  4588. #endif /* NT */
  4589.  
  4590.     debug(F101,"nettchk entry ttibn","",ttibn);
  4591.     debug(F101,"nettchk entry ttibp","",ttibp);
  4592.  
  4593. #ifdef NETLEBUF
  4594.     {
  4595.         int n = 0;
  4596.         if (ttpush >= 0)
  4597.           n++;
  4598.         n += le_inbuf();
  4599.         if (n > 0)
  4600.           return(n);
  4601.     }
  4602. #endif /* NETLEBUF */
  4603.  
  4604. #ifndef OS2
  4605. #ifndef BEOSORBEBOX
  4606.     socket_errno = 0; /* This is a function call in NT, and BeOS */
  4607. #endif /* BEOSORBEBOX */
  4608. #endif /* OS2 */
  4609.  
  4610.     if (ttyfd == -1) {
  4611.         debug(F100,"nettchk socket is closed","",0);
  4612.         return(-1);
  4613.     }
  4614. /*
  4615.   Note: this socket_ioctl() call does NOT return an error if the
  4616.   connection has been broken.  (At least not in MultiNet.)
  4617. */
  4618. #ifdef COMMENT
  4619. /*  Another trick that can be tried here is something like this: */
  4620.  
  4621.     if (ttnet == NET_TCPB) {
  4622.         char dummy;
  4623.         x = read(ttyfd,&dummy,0);       /* Try to read nothing */
  4624.         if (x < 0) {                    /* "Connection reset by peer" */
  4625.             perror("TCP/IP");           /* or somesuch... */
  4626.             ttclos(0);                  /* Close our end too. */
  4627.             return(-1);
  4628.         }
  4629.     }
  4630. #endif /* COMMENT */
  4631.  
  4632. #ifdef CK_SSL
  4633.     if (ssl_active_flag) {
  4634.         count = SSL_pending(ssl_con);
  4635.         if (count < 0) {
  4636.             debug(F111,"nettchk","SSL_pending error",count);
  4637.             netclos();
  4638.             return(-1);
  4639.         }
  4640. #ifdef COMMENT
  4641.         else if (count == 0) {
  4642.             int ch = netinc(-50);
  4643.             if ( ch >= 0 )
  4644.                 le_putchar((CHAR)(ch & 0xFF));
  4645.         }
  4646. #endif /* COMMENT */
  4647.     } else if (tls_active_flag) {
  4648.         count = SSL_pending(tls_con);
  4649.         if (count < 0) {
  4650.             debug(F111,"nettchk","TLS_pending error",count);
  4651.             netclos();
  4652.             return(-1);
  4653.         }
  4654. #ifdef COMMENT
  4655.         else if (count == 0) {
  4656.             int ch = netinc(-50);
  4657.             if ( ch >= 0 )
  4658.                 le_putchar((CHAR)(ch & 0xFF));
  4659.         }
  4660. #endif /* COMMENT */
  4661.     } else
  4662. #endif /* CK_SSL */
  4663.  
  4664.     if (socket_ioctl(ttyfd,FIONREAD,
  4665. #ifdef COMMENT
  4666.     /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
  4667. #ifdef __DECC
  4668.     /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
  4669.                      /* Cast needed for DECC 4.1 & later? */
  4670.                      /* Maybe, but __DECC_VER only exists in 5.0 and later */
  4671.                      (char *)
  4672. #endif /* __DECC */
  4673. #endif /* COMMENT */
  4674.                      &count
  4675.                      ) < 0) {
  4676.         debug(F101,"nettchk socket_ioctl error","",socket_errno);
  4677.         /* If the connection is gone, the connection is gone. */
  4678.         netclos();
  4679. #ifdef NT_TCP_OVERLAPPED
  4680.         /* Is there anything in the overlapped I/O buffers? */
  4681.         count += OverlappedDataWaiting();
  4682. #endif /* NT_TCP_OVERLAPPED */
  4683.         count += ttibn;
  4684.         return(count>0?count:-1);
  4685.     }
  4686.     debug(F101,"nettchk count","",count);
  4687. #ifdef NT_TCP_OVERLAPPED
  4688.     /* Is there anything in the overlapped I/O buffers? */
  4689.     count += OverlappedDataWaiting();
  4690.     debug(F101,"nettchk count w/overlapped","",count);
  4691. #endif /* NT_TCP_OVERLAPPED */
  4692.  
  4693. /* For the sake of efficiency, if there is still data in the ttibuf */
  4694. /* do not go to the bother of checking to see of the connection is  */
  4695. /* still valid.  The handle is still good, so just return the count */
  4696. /* of the bytes that we already have left to process.               */
  4697. #ifdef OS2
  4698.     if ( ttibn > 0 ) {
  4699.         debug(F101,"nettchk (ttibn > 0) returns","",count+ttibn);
  4700.         return(count+ttibn);
  4701.     } else {
  4702.         if ( ttibn == 0 )
  4703.             ttibp = 0;      /* reset for next read */
  4704.     }
  4705. #else /* OS2 */
  4706.     if ( ttibn ) {
  4707.         debug(F101,"nettchk returns","",count+ttibn);
  4708.         return(count+ttibn);
  4709.     }
  4710. #endif /* OS2 */
  4711.  
  4712. /*
  4713.   The following code works well in most settings, but messes things up in
  4714.   others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
  4715.   make it impossible to ever make a new connection to the same host again with
  4716.   CONNECT, once it has been logged out from the first time.  Not even if you
  4717.   HANGUP first, or SET HOST<CR>, or SET LINE<CR>.  Reportedly, however, it
  4718.   does work OK in later releases of UCX.  But there is no way we can
  4719.   accommodate both old and new -- we might have static linking or dynamic
  4720.   linking, etc etc.  If we have static, I only have access to 2.0, where this
  4721.   doesn't work, etc etc blah blah.
  4722.  
  4723.   In the following lines, we define a symbol NOCOUNT for builds where we want
  4724.   to omit this code.  By default, it is omitted for CMU/Tek.  You can force
  4725.   omission of it for other combinations by defining NOCOUNT in CFLAGS.  You
  4726.   can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
  4727.   in CFLAGS.
  4728. */
  4729. #ifdef NONOCOUNT
  4730. #ifdef NOCOUNT
  4731. #undef NOCOUNT
  4732. #endif /* NOCOUNT */
  4733. #else
  4734. #ifndef NOCOUNT
  4735. #ifdef CMU_TCPIP
  4736. #define NOCOUNT
  4737. #endif /* CMU_TCPIP */
  4738. #endif /* NOCOUNT */
  4739. #endif /* NONOCOUNT */
  4740.  
  4741.     /* we know now that count >= 0 and that ttibn == 0 */
  4742.  
  4743.     if (count == 0
  4744. #ifdef CK_SSL
  4745.         && ttnproto != NP_SSL && ttnproto != NP_TLS
  4746.         && !tls_active_flag && !ssl_active_flag
  4747. #endif /* CK_SSL */
  4748. #ifdef RLOGCODE
  4749. #ifdef CK_KERBEROS
  4750.         && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
  4751. #endif /* CK_KERBEROS */
  4752. #endif /* RLOGCODE */
  4753.         ) {
  4754.         int s_errno = 0;
  4755. #ifdef OS2
  4756.         RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
  4757. #endif /* OS2 */
  4758. #ifndef NOCOUNT
  4759. /*
  4760.   Here we need to tell the difference between a 0 count on an active
  4761.   connection, and a 0 count because the remote end of the socket broke the
  4762.   connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
  4763.   the status of the connection, so we have to do a read.  -1 means there was
  4764.   no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
  4765.   down.  But if, by chance, we actually get a character, we have to put it
  4766.   where it won't be lost.
  4767. */
  4768. #ifndef NON_BLOCK_IO
  4769.         y = 1;                          /* Turn on nonblocking reads */
  4770.         x = socket_ioctl(ttyfd,FIONBIO,&y);
  4771.         debug(F101,"nettchk FIONBIO","",x);
  4772. #endif /* NON_BLOCK_IO */
  4773. #ifdef NT_TCP_OVERLAPPED
  4774.         ionoblock = 1;                  /* For Overlapped I/O */
  4775. #endif /* NT_TCP_OVERLAPPED */
  4776. #ifdef OS2
  4777.         x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
  4778.                          TTIBUFL-ttibp-ttibn);  /* Returns -1 if no data */
  4779. #else /* OS2 */
  4780.         x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
  4781. #endif /* OS2 */
  4782.         s_errno = socket_errno;         /* socket_errno may be a function */
  4783.         debug(F101,"nettchk socket_read","",x);
  4784.  
  4785. #ifndef NON_BLOCK_IO
  4786.         y = 0;                          /* Turn them back off */
  4787.         socket_ioctl(ttyfd,FIONBIO,&y);
  4788. #endif /* NON_BLOCK_IO */
  4789. #ifdef NT_TCP_OVERLAPPED
  4790.         ionoblock = 0;                  /* For Overlapped I/O */
  4791. #endif /* NT_TCP_OVERLAPPED */
  4792.  
  4793.         if (x == -1) {
  4794.             debug(F101,"nettchk socket_read errno","",s_errno);
  4795. #ifdef OS2
  4796.             if (os2socketerror(s_errno) < 0) {
  4797.                 ReleaseTCPIPMutex();
  4798.                 return(-1);
  4799.             }
  4800. #endif /* OS2 */
  4801.         } else if (x == 0) {
  4802.             debug(F100,"nettchk connection closed","",0);
  4803. #ifdef OS2
  4804.             ReleaseTCPIPMutex();
  4805. #endif /* OS2 */
  4806.             netclos();                  /* *** *** */
  4807.             return(-1);                 /* Connection is broken. */
  4808.         }
  4809.         if (x >= 1) {                   /* Oops, actually got a byte? */
  4810. #ifdef OS2
  4811.             /* In OS/2 we read directly into ttibuf[] */
  4812.             hexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
  4813.             ttibn += x;
  4814. #else /* OS2 */
  4815.             debug(F101,"nettchk socket_read char","",c);
  4816.             debug(F101,"nettchk ttibp","",ttibp);
  4817.             debug(F101,"nettchk ttibn","",ttibn);
  4818. /*
  4819.   In the case of Overlapped I/O the character would have come from
  4820.   the beginning of the buffer, so put it back.
  4821. */
  4822.             if (ttibp > 0) {
  4823.                 ttibp--;
  4824.                 ttibuf[ttibp] = c;
  4825.                 ttibn++;
  4826.             } else {
  4827.                 ttibuf[ttibp+ttibn] = c;
  4828.                 ttibn++;
  4829.             }
  4830. #endif /* OS2 */
  4831.         }
  4832. #ifdef OS2
  4833.         ReleaseTCPIPMutex();
  4834. #endif /* OS2 */
  4835. #else /* NOCOUNT */
  4836.         if (ttnet == NET_TCPB) {
  4837.             char dummy;
  4838.             x = read(ttyfd,&dummy,0);   /* Try to read nothing */
  4839.             if (x < 0) {                /* "Connection reset by peer" */
  4840.                 perror("TCP/IP");       /* or somesuch... */
  4841. #ifdef OS2
  4842.                 ReleaseTCPIPMutex();
  4843. #endif /* OS2 */
  4844.                 ttclos(0);              /* Close our end too. */
  4845.                 return(-1);
  4846.             }
  4847.         }
  4848. #endif /* NOCOUNT */
  4849. #ifdef OS2
  4850.         ReleaseTCPIPMutex();
  4851. #endif /* OS2 */
  4852.     }
  4853. #ifdef CK_KERBEROS
  4854. #ifdef KRB4
  4855.     if (ttnproto == NP_EK4LOGIN)
  4856.       count += krb4_des_avail(ttyfd);
  4857. #endif /* KRB4 */
  4858. #ifdef KRB5
  4859.     if (ttnproto == NP_EK5LOGIN)
  4860.       count += krb5_des_avail(ttyfd);
  4861. #endif /* KRB5 */
  4862. #endif /* CK_KERBEROS */
  4863.  
  4864.     debug(F101,"nettchk returns","",count+ttibn);
  4865.     return(count + ttibn);
  4866.  
  4867. #else /* Not TCPIPLIB */
  4868. /*
  4869.   UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
  4870.   seem to work OK.
  4871. */
  4872.     return(0);
  4873. #endif /* TCPIPLIB */
  4874. /*
  4875.   But what about X.25?
  4876. */
  4877. }
  4878.  
  4879. #ifndef OS2
  4880. VOID
  4881. nettout(i) int i; {                     /* Catch the alarm interrupts */
  4882.     debug(F100,"nettout caught timeout","",0);
  4883.     ttimoff();
  4884.     cklongjmp(njbuf, -1);
  4885. }
  4886. #endif /* !OS2 */
  4887.  
  4888. #ifdef TCPIPLIB
  4889.  
  4890. VOID
  4891. #ifdef CK_ANSIC
  4892. donetinc(void * threadinfo)
  4893. #else /* CK_ANSIC */
  4894. donetinc(threadinfo) VOID * threadinfo;
  4895. #endif /* CK_ANSIC */
  4896. /* donetinc */ {
  4897. #ifdef IKSD
  4898.     extern int inserver;
  4899. #endif /* IKSD */
  4900. #ifdef NTSIG
  4901.     extern int TlsIndex;
  4902.     setint();
  4903.     if (threadinfo) {                   /* Thread local storage... */
  4904.         TlsSetValue(TlsIndex,threadinfo);
  4905.     }
  4906. #endif /* NTSIG */
  4907. #ifdef CK_LOGIN
  4908. #ifdef NT
  4909. #ifdef IKSD
  4910.     if (inserver)
  4911.       setntcreds();
  4912. #endif /* IKSD */
  4913. #endif /* NT */
  4914. #endif /* CK_LOGIN */
  4915.     while (1) {
  4916.         if (ttbufr() < 0)               /* Keep trying to refill it. */
  4917.           break;                        /* Till we get an error. */
  4918.         if (ttibn > 0)                  /* Or we get a character. */
  4919.           break;
  4920.     }
  4921. }
  4922. #endif /* TCPIPLIB */
  4923.  
  4924. VOID
  4925. #ifdef CK_ANSIC
  4926. failnetinc(void * threadinfo)
  4927. #else /* CK_ANSIC */
  4928. failnetinc(threadinfo) VOID * threadinfo;
  4929. #endif /* CK_ANSIC */
  4930. /* failnetinc */ {
  4931.     ; /* Nothing to do on an error */
  4932. }
  4933.  
  4934. /* N E T X I N -- Input block of characters from network */
  4935.  
  4936. int
  4937. netxin(n,buf) int n; CHAR * buf; {
  4938.     int len;
  4939.     int rc;
  4940.     int i, j;
  4941.     if (ttyfd == -1) {
  4942.         debug(F100,"netinc socket is closed","",0);
  4943.         return(-2);
  4944.     }
  4945. #ifdef RLOGCODE
  4946. #ifdef CK_KERBEROS
  4947. #ifdef KRB4
  4948.     if (ttnproto == NP_EK4LOGIN) {
  4949.         if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
  4950.           return(-1);
  4951.         else
  4952.           return(len);
  4953.     }
  4954. #endif /* KRB4 */
  4955. #ifdef KRB5
  4956.     if (ttnproto == NP_EK5LOGIN) {
  4957.         if ((len = krb5_des_read(ttyfd,buf,n)) < 0)
  4958.           return(-1);
  4959.         else
  4960.           return(len);
  4961.     }
  4962. #endif /* KRB5 */
  4963. #endif /* CK_KERBEROS */
  4964. #endif /* RLOGCODE */
  4965.  
  4966. #ifdef TCPIPLIB
  4967.     if (!ttibn)
  4968.       if ((rc = ttbufr()) <= 0)
  4969.         return(rc);
  4970.  
  4971.     if (ttibn <= n) {
  4972.         len = ttibn;
  4973.         memcpy(buf,&ttibuf[ttibp],len);
  4974.         ttibp += len;
  4975.         ttibn = 0;
  4976.     } else {
  4977.         memcpy(buf,&ttibuf[ttibp],n);
  4978.         ttibp += n;
  4979.         ttibn -= n;
  4980.         len = n;
  4981.     }
  4982. #else /* TCPIPLIB */
  4983.     for (i = 0; i < n; i++) {
  4984.         if ((j = netinc(0)) < 0) {
  4985.             if (j < -1)
  4986.               return(j);
  4987.             else
  4988.               break;
  4989.         }
  4990.         buf[i] = j;
  4991.     }
  4992.     len = i;
  4993. #endif /* TCPIPLIB */
  4994.  
  4995. #ifdef COMMENT
  4996. #ifdef CK_ENCRYPTION
  4997.     /* This would be great if it worked.  But what if the buffer we read  */
  4998.     /* contains a telnet negotiation that changes the state of the        */
  4999.     /* encryption.  If so, we would be either decrypting unencrypted text */
  5000.     /* or not decrypting encrypted text.  So we must move this call to    */
  5001.     /* all functions that call ttxin().  In OS2 that means os2_netxin()   */
  5002.     /* where the Telnet Negotiations are handled.                         */
  5003.     if (u_encrypt)
  5004.       ck_tn_decrypt(buf,len);
  5005. #endif /* CK_ENCRYPTION */
  5006. #endif /* COMMENT */
  5007.  
  5008.     return(len);
  5009. }
  5010.  
  5011. /*  N E T I N C --  Input character from network */
  5012.  
  5013. #ifdef NETLEBUF
  5014. #define LEBUF
  5015. #endif /* NETLEBUF */
  5016. #ifdef TTLEBUF
  5017. #define LEBUF
  5018. #endif /* TTLEBUF */
  5019. #ifndef LEBUF
  5020. #ifdef OS2
  5021. #define LEBUF
  5022. #endif /* OS2 */
  5023. #endif /* LEBUF */
  5024.  
  5025. int
  5026. netinc(timo) int timo; {
  5027. #ifdef TCPIPLIB
  5028.     int x; unsigned char c;             /* The locals. */
  5029.  
  5030. #ifdef NETLEBUF
  5031.     if (ttpush >= 0) {
  5032.         debug(F111,"netinc","ttpush",ttpush);
  5033.         c = ttpush;
  5034.         ttpush = -1;
  5035.         return(c);
  5036.     }
  5037.     if (le_data) {
  5038.         if (le_getchar((CHAR *)&c) > 0) {
  5039.             debug(F111,"netinc le_getchar","c",c);
  5040.             return(c);
  5041.         }
  5042.     }
  5043. #endif /* NETLEBUF */
  5044.  
  5045.     if (ttyfd == -1) {
  5046.         debug(F100,"netinc socket is closed","",0);
  5047.         return(-2);
  5048.     }
  5049.  
  5050. #ifdef RLOGCODE
  5051. #ifdef CK_KERBEROS
  5052. #ifdef KRB4
  5053.     if (ttnproto == NP_EK4LOGIN) {
  5054.         if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
  5055.           return(-1);
  5056.         else if (x < 0)
  5057.           return(-2);
  5058.         else
  5059.           return(c);
  5060.     }
  5061. #endif /* KRB4 */
  5062. #ifdef KRB5
  5063.     if (ttnproto == NP_EK5LOGIN) {
  5064.         if ((x = krb5_des_read(ttyfd,&c,1)) == 0)
  5065.           return(-1);
  5066.         else if (x < 0)
  5067.           return(-2);
  5068.         else
  5069.           return(c);
  5070.     }
  5071. #endif /* KRB5 */
  5072. #endif /* CK_KERBEROS */
  5073. #endif /* RLOGCODE */
  5074.  
  5075.     if (ttibn > 0) {                    /* Something in internal buffer? */
  5076. #ifdef COMMENT
  5077.         debug(F100,"netinc char in buf","",0); /* Yes. */
  5078. #endif /* COMMENT */
  5079.         x = 0;                          /* Success. */
  5080.     } else {                            /* Else must read from network. */
  5081.         x = -1;                         /* Assume failure. */
  5082. #ifdef DEBUG
  5083.         debug(F101,"netinc goes to net, timo","",timo);
  5084.         ttibuf[ttibp+ttibn+1] = '\0';
  5085.         debug(F111,"netinc ttibuf",ttibuf,ttibp);
  5086. #endif /* DEBUG */
  5087. #ifdef CK_SSL
  5088.         if (ssl_active_flag) {
  5089.             x = SSL_pending(ssl_con);
  5090.             if (x < 0) {
  5091.                 debug(F111,"netinc","SSL_pending error",x);
  5092.                 netclos();
  5093.                 return(-1);
  5094.             } else if ( x > 0 ) {
  5095.                 if ( ttbufr() >= 0 )
  5096.                     return(netinc(timo));
  5097.             }
  5098.             x = -1;
  5099.         } else if (tls_active_flag) {
  5100.             x = SSL_pending(tls_con);
  5101.             if (x < 0) {
  5102.                 debug(F111,"netinc","TLS_pending error",x);
  5103.                 netclos();
  5104.                 return(-1);
  5105.             } else if ( x > 0 ) {
  5106.                 if ( ttbufr() >= 0 )
  5107.                     return(netinc(timo));
  5108.             }
  5109.             x = -1;
  5110.         }
  5111. #endif /* CK_SSL */
  5112. #ifndef LEBUF
  5113.         if (timo == 0) {                /* Untimed case. */
  5114.             while (1) {                 /* Wait forever if necessary. */
  5115.                 if (ttbufr() < 0)       /* Refill buffer. */
  5116.                   break;                /* Error, fail. */
  5117.                 if (ttibn > 0) {        /* Success. */
  5118.                     x = 0;
  5119.                     break;
  5120.                 }
  5121.             }
  5122.         } else                          /* Timed case... */
  5123. #endif /* LEBUF */
  5124.           {
  5125. #ifdef NT_TCP_OVERLAPPED
  5126.             /* This code is for use on NT when we are using */
  5127.             /* Overlapped I/O to handle reads.  In the case */
  5128.             /* of outstanding reads select() doesn't work   */
  5129.  
  5130.             if (WaitForOverlappedReadData(timo)) {
  5131.                 while (1) {
  5132.                     if (ttbufr() < 0)   /* Keep trying to refill it. */
  5133.                         break;          /* Till we get an error. */
  5134.                     if (ttibn > 0) {    /* Or we get a character. */
  5135.                         x = 0;
  5136.                         break;
  5137.                     }
  5138.                 }
  5139.             }
  5140. #else /* NT_TCP_OVERLAPPED */
  5141. #ifdef BSDSELECT
  5142.             fd_set rfds;
  5143.             struct timeval tv;
  5144.             int timeout = timo < 0 ? -timo : 1000 * timo;
  5145.             debug(F101,"netinc BSDSELECT","",timo);
  5146.  
  5147.             for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
  5148.                 int rc;
  5149.                 debug(F111,"netinc","timeout",timeout);
  5150.                 /* Don't move select() initialization out of the loop. */
  5151.                 FD_ZERO(&rfds);
  5152.                 FD_SET(ttyfd, &rfds);
  5153.                 tv.tv_sec  = tv.tv_usec = 0L;
  5154.                 if (timo)
  5155.                   tv.tv_usec = (long) 100000L;
  5156.                 else
  5157.                   tv.tv_sec = 30;
  5158. #ifdef NT
  5159.                 WSASafeToCancel = 1;
  5160. #endif /* NT */
  5161.                 rc = select(FD_SETSIZE,
  5162. #ifndef __DECC
  5163.                             (fd_set *)
  5164. #endif /* __DECC */
  5165.                             &rfds, NULL, NULL, &tv);
  5166.                 if (rc < 0) {
  5167.                     int s_errno = socket_errno;
  5168.                     debug(F111,"netinc","select",rc);
  5169.                     debug(F111,"netinc","socket_errno",s_errno);
  5170.                     if (s_errno)
  5171.                       return(-1);
  5172.                 }
  5173.                 debug(F111,"netinc","select",rc);
  5174. #ifdef NT
  5175.                 WSASafeToCancel = 0;
  5176. #endif /* NT */
  5177.                 if (!FD_ISSET(ttyfd, &rfds)) {
  5178. #ifdef LEBUF
  5179.                     if (le_inbuf() > 0) {
  5180.                         timeout = -1;
  5181.                         break;
  5182.                     }
  5183. #endif /* LEBUF */
  5184.                     /* If waiting forever we have no way of knowing if the */
  5185.                     /* socket closed so try writing a 0-length TCP packet  */
  5186.                     /* which should force an error if the socket is closed */
  5187.                     if (!timo) {
  5188.                         if ((rc = socket_write(ttyfd,"",0)) < 0) {
  5189.                             int s_errno = socket_errno;
  5190.                             debug(F101,"netinc socket_write error","",s_errno);
  5191. #ifdef OS2
  5192.                             if (os2socketerror(s_errno) < 0)
  5193.                               return(-2);
  5194. #endif /* OS2 */
  5195.                             return(-1); /* Call it an i/o error */
  5196.                         }
  5197.                     }
  5198.                     continue;
  5199.                 }
  5200.                 while (1) {
  5201.                     if (ttbufr() < 0) { /* Keep trying to refill it. */
  5202.                         timeout = -1;
  5203.                         break;          /* Till we get an error. */
  5204.                     }
  5205.                     if (ttibn > 0) {    /* Or we get a character. */
  5206.                         x = 0;
  5207.                         timeout = -1;
  5208.                         break;
  5209.                     }
  5210.                 }
  5211.             }
  5212. #ifdef NT
  5213.             WSASafeToCancel = 0;
  5214. #endif /* NT */
  5215. #else /* !BSDSELECT */
  5216. #ifdef IBMSELECT
  5217. /*
  5218.   Was used by OS/2, currently not used, but might come in handy some day...
  5219.   ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
  5220.   and timeval stuff since this is the only place where it is used.
  5221. */
  5222.             int socket = ttyfd;
  5223.             int timeout = timo < 0 ? -timo : 1000 * timo;
  5224.  
  5225.             debug(F101,"netinc IBMSELECT","",timo);
  5226.             for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
  5227.                 if (select(&socket, 1, 0, 0, 100L) == 1) {
  5228.                     while (1) {
  5229.                         if (ttbufr() < 0) { /* Keep trying to refill it. */
  5230.                             timeout = -1;
  5231.                             break;      /* Till we get an error. */
  5232.                         }
  5233.                         if (ttibn > 0) { /* Or we get a character. */
  5234.                             x = 0;
  5235.                             timeout = -1;
  5236.                             break;
  5237.                         }
  5238.                     }
  5239.                 }
  5240. #ifdef LEBUF
  5241.                 else if (le_inbuf() > 0)  {
  5242.                     timeout = -1;
  5243.                     break;
  5244.                 }
  5245. #endif /* LEBUF */
  5246.             }
  5247. #else /* !IBMSELECT */
  5248. #ifdef WINSOCK
  5249.        /* Actually, under WinSock we have a better mechanism than select() */
  5250.        /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
  5251.             SOCKET socket = ttyfd;
  5252.             debug(F101,"netinc NTSELECT","",timo);
  5253.             if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
  5254.                             sizeof(timo))  == NO_ERROR)
  5255.               while (1) {
  5256.                   if (ttbufr() < 0)     /* Keep trying to refill it. */
  5257.                     break;              /* Till we get an error. */
  5258.                   if (ttibn > 0) {      /* Or we get a character. */
  5259.                       x = 0;
  5260.                       break;
  5261.                   }
  5262.               }
  5263. #else /* WINSOCK */
  5264. /*
  5265.   If we can't use select(), then we use the regular alarm()/signal()
  5266.   timeout mechanism.
  5267. */
  5268.             debug(F101,"netinc alarm","",timo);
  5269.             x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
  5270.             ttimoff();                  /* Timer off. */
  5271. #endif /* WINSOCK */
  5272. #endif /* IBMSELECT */
  5273. #endif /* BSDSELECT */
  5274. #endif /* NT_TCP_OVERLAPPED */
  5275.         }
  5276.     }
  5277.  
  5278. #ifdef LEBUF
  5279.     if (le_inbuf() > 0) {               /* If data was inserted into the */
  5280.         if (le_getchar((CHAR *)&c) > 0) /* Local Echo buffer while the   */
  5281.           return(c);                    /* was taking place do not mix   */
  5282.     }                                   /* the le data with the net data */
  5283. #endif /* LEBUF */
  5284.     if (x < 0) {                        /* Return -1 if we failed. */
  5285.         debug(F100,"netinc timed out","",0);
  5286.         return(-1);
  5287.     } else {                            /* Otherwise */
  5288.         c = ttibuf[ttibp];              /* Return the first char in ttibuf[] */
  5289.         if (deblog) {
  5290. #ifndef COMMENT
  5291.             debug(F101,"netinc returning","",c);
  5292. #endif /* COMMENT */
  5293.             if (c == 0) {
  5294.                 debug(F101,"netinc 0 ttibn","",ttibn);
  5295.                 debug(F101,"netinc 0 ttibp","",ttibp);
  5296. #ifdef BETATEST
  5297.                 {
  5298. #ifdef OS2
  5299.                     extern int tt_type_mode;
  5300.                     if ( !ISVTNT(tt_type_mode) )
  5301. #endif /* OS2 */
  5302.                     hexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
  5303.                 }
  5304. #endif /* BETATEST */
  5305.             }
  5306.         }
  5307.         ttibp++;
  5308.         ttibn--;
  5309.  
  5310. #ifdef CK_ENCRYPTION
  5311.         if (TELOPT_U(TELOPT_ENCRYPTION))
  5312.           ck_tn_decrypt(&c,1);
  5313. #endif /* CK_ENCRYPTION */
  5314.         return(c);
  5315.     }
  5316. #else /* Not using TCPIPLIB */
  5317.     return(-1);
  5318. #endif /* TCPIPLIB */
  5319. }
  5320.  
  5321. /*  N E T T O L  --  Output a string of bytes to the network  */
  5322. /*
  5323.   Call with s = pointer to string, n = length.
  5324.   Returns number of bytes actually written on success, or
  5325.   -1 on i/o error, -2 if called improperly.
  5326. */
  5327.  
  5328. int
  5329. nettol(s,n) CHAR *s; int n; {
  5330. #ifdef TCPIPLIB
  5331.     int count = 0;
  5332.     int len = n;
  5333.     int try = 0;
  5334.  
  5335.     if (ttyfd == -1) {
  5336.         debug(F100,"nettol socket is closed","",0);
  5337.         return -1;
  5338.     }
  5339.     debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
  5340. #ifdef COMMENT
  5341.     hexdump("nettol",s,n);
  5342. #endif /* COMMENT */
  5343.  
  5344. #ifdef RLOGCODE
  5345. #ifdef CK_KERBEROS
  5346. #ifdef KRB4
  5347.     if (ttnproto == NP_EK4LOGIN) {
  5348.         return(krb4_des_write(ttyfd,s,n));
  5349.     }
  5350. #endif /* KRB4 */
  5351. #ifdef KRB5
  5352.     if (ttnproto == NP_EK5LOGIN) {
  5353.         return(krb5_des_write(ttyfd,s,n));
  5354.     }
  5355. #endif /* KRB5 */
  5356. #endif /* CK_KERBEROS */
  5357. #endif /* RLOGCODE */
  5358.  
  5359. #ifdef CK_ENCRYPTION
  5360.     if (TELOPT_ME(TELOPT_ENCRYPTION))
  5361.       ck_tn_encrypt(s,n);
  5362. #endif /* CK_ENCRYPTION */
  5363.  
  5364. #ifdef CK_SSL
  5365.     if (ssl_active_flag || tls_active_flag) {
  5366.         int error;
  5367.         /* Write using SSL */
  5368.         if (ssl_active_flag)
  5369.           len = SSL_write(ssl_con, s, len);
  5370.         else
  5371.           len = SSL_write(tls_con, s, len);
  5372.         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
  5373.           case SSL_ERROR_NONE:
  5374.             debug(F111,"nettol","SSL_write",len);
  5375.             return(len);
  5376.           case SSL_ERROR_WANT_WRITE:
  5377.             debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
  5378.             return(-1);
  5379.           case SSL_ERROR_WANT_READ:
  5380.             debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
  5381.             return(-1);
  5382.           case SSL_ERROR_SYSCALL:
  5383. #ifdef NT
  5384.             debug(F111,"nettol SSL_ERROR_SYSCALL",
  5385.                   "GetLastError()",GetLastError());
  5386. #endif /* NT */
  5387.             netclos();
  5388.             return(-2);
  5389.           case SSL_ERROR_WANT_X509_LOOKUP:
  5390.             debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
  5391.             netclos();
  5392.             return(-2);
  5393.           case SSL_ERROR_SSL:
  5394.             debug(F100,"nettol SSL_ERROR_SSL","",0);
  5395.             netclos();
  5396.             return(-2);
  5397.           case SSL_ERROR_ZERO_RETURN:
  5398.             debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
  5399.             netclos();
  5400.             return(-2);
  5401.           default:
  5402.             debug(F100,"nettol SSL_ERROR_?????","",0);
  5403.             netclos();
  5404.             return(-2);
  5405.         }
  5406.     }
  5407. #endif /* CK_SSL */
  5408.  
  5409.   nettol_retry:
  5410.     try++;                              /* Increase the try counter */
  5411.  
  5412.     if (ttnet == NET_TCPB) {
  5413. #ifdef BSDSELECT
  5414.         fd_set wfds;
  5415.         struct timeval tv;
  5416.  
  5417.         debug(F101,"nettol BSDSELECT","",0);
  5418.         tv.tv_usec = 0L;
  5419.         tv.tv_sec=30;
  5420. #ifdef NT
  5421.         WSASafeToCancel = 1;
  5422. #endif /* NT */
  5423. #ifdef STREAMING
  5424.       do_select:
  5425. #endif /* STREAMING */
  5426.         FD_ZERO(&wfds);
  5427.         FD_SET(ttyfd, &wfds);
  5428.         if (select(FD_SETSIZE, NULL,
  5429. #ifdef __DECC
  5430. #ifndef __DECC_VER
  5431.                     (int *)
  5432. #endif /* __DECC_VER */
  5433. #endif /* __DECC */
  5434.                    &wfds, NULL, &tv) < 0) {
  5435.             int s_errno = socket_errno;
  5436.             debug(F101,"nettol select failed","",s_errno);
  5437. #ifdef BETATEST
  5438.             printf("nettol select failed: %d\n", s_errno);
  5439. #endif /* BETATEST */
  5440. #ifdef NT
  5441.             WSASafeToCancel = 0;
  5442.             if (!win95selectbug)
  5443. #endif /* NT */
  5444.               return(-1);
  5445.         }
  5446.         if (!FD_ISSET(ttyfd, &wfds)) {
  5447. #ifdef STREAMING
  5448.             if (streaming)
  5449.               goto do_select;
  5450. #endif /* STREAMING */
  5451.             debug(F111,"nettol","!FD_ISSET",ttyfd);
  5452. #ifdef NT
  5453.             WSASafeToCancel = 0;
  5454.             if (!win95selectbug)
  5455. #endif /* NT */
  5456.               return(-1);
  5457.         }
  5458. #ifdef NT
  5459.         WSASafeToCancel = 0;
  5460. #endif /* NT */
  5461. #else /* BSDSELECT */
  5462. #ifdef IBMSELECT
  5463.         {
  5464.             int tries = 0;
  5465.             debug(F101,"nettol IBMSELECT","",0);
  5466.             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
  5467.                 int count;
  5468.                 if (tries++ >= 60) {
  5469.                     /* if after 60 seconds we can't get permission to write */
  5470.                     debug(F101,"nettol select failed","",socket_errno);
  5471.                     return(-1);
  5472.                 }
  5473.                 if ((count = nettchk()) < 0) {
  5474.                     debug(F111,"nettol","nettchk()",count);
  5475.                     return(count);
  5476.                 }
  5477.             }
  5478.         }
  5479. #endif /* IBMSELECT */
  5480. #endif /* BSDSELECT */
  5481.         if ((count = socket_write(ttyfd,s,n)) < 0) {
  5482.             int s_errno = socket_errno; /* maybe a function */
  5483.             debug(F101,"nettol socket_write error","",s_errno);
  5484. #ifdef OS2
  5485.             if (os2socketerror(s_errno) < 0)
  5486.               return(-2);
  5487. #endif /* OS2 */
  5488.             return(-1);                 /* Call it an i/o error */
  5489.         }
  5490.         if (count < n) {
  5491.             debug(F111,"nettol socket_write",s,count);
  5492.             if (try > 25) {
  5493.                 /* don't try more than 25 times */
  5494.                 debug(F100,"nettol tried more than 25 times","",0);
  5495.                 return(-1);
  5496.             }
  5497.             if (count > 0) {
  5498.                 s += count;
  5499.                 n -= count;
  5500.             }
  5501.             debug(F111,"nettol retry",s,n);
  5502.             goto nettol_retry;
  5503.         } else {
  5504.             debug(F111,"nettol socket_write",s,count);
  5505.             return(len); /* success - return total length */
  5506.         }
  5507.     } else
  5508.       return(-2);
  5509. #else
  5510.     debug(F100,"nettol TCPIPLIB not defined","",0);
  5511.     return(-2);
  5512. #endif /* TCPIPLIB */
  5513. }
  5514.  
  5515. /*  N E T T O C  --   Output character to network */
  5516. /*
  5517.   Call with character to be transmitted.
  5518.   Returns 0 if transmission was successful, or
  5519.   -1 upon i/o error, or -2 if called improperly.
  5520. */
  5521. int
  5522. #ifdef CK_ANSIC
  5523. nettoc(CHAR c)
  5524. #else
  5525. nettoc(c) CHAR c;
  5526. #endif /* CK_ANSIC */
  5527. /* nettoc */ {
  5528. #ifdef UNIX
  5529.     return(ttoc(c));
  5530. #else
  5531. #ifdef TCPIPLIB
  5532.     unsigned char cc;
  5533.     if (ttyfd == -1) {
  5534.         debug(F100,"nettoc socket is closed","",0);
  5535.         return -1;
  5536.     }
  5537.     cc = c;
  5538.     debug(F101,"nettoc cc","",cc);
  5539.  
  5540. #ifdef RLOGCODE
  5541. #ifdef CK_KERBEROS
  5542. #ifdef KRB4
  5543.     if (ttnproto == NP_EK4LOGIN) {
  5544.         return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
  5545.     }
  5546. #endif /* KRB4 */
  5547. #ifdef KRB5
  5548.     if (ttnproto == NP_EK5LOGIN) {
  5549.         return(krb5_des_write(ttyfd,&cc,1)==1?0:-1);
  5550.     }
  5551. #endif /* KRB5 */
  5552. #endif /* CK_KERBEROS */
  5553. #endif /* RLOGCODE */
  5554.  
  5555. #ifdef CK_ENCRYPTION
  5556.         if ( TELOPT_ME(TELOPT_ENCRYPTION) )
  5557.             ck_tn_encrypt(&cc,1);
  5558. #endif /* CK_ENCRYPTION */
  5559. #ifdef CK_SSL
  5560.     if (ssl_active_flag || tls_active_flag) {
  5561.         int len, error;
  5562.         /* Write using SSL */
  5563.         if (ssl_active_flag)
  5564.           len = SSL_write(ssl_con, &cc, 1);
  5565.         else
  5566.           len = SSL_write(tls_con, &cc, 1);
  5567.         switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
  5568.           case SSL_ERROR_NONE:
  5569.             debug(F111,"nettoc","SSL_write",len);
  5570.             return(len == 1 ? 0 : -1);
  5571.           case SSL_ERROR_WANT_WRITE:
  5572.           case SSL_ERROR_WANT_READ:
  5573.             return(-1);
  5574.           case SSL_ERROR_SYSCALL:
  5575.           case SSL_ERROR_WANT_X509_LOOKUP:
  5576.           case SSL_ERROR_SSL:
  5577.           case SSL_ERROR_ZERO_RETURN:
  5578.           default:
  5579.             netclos();
  5580.             return(-2);
  5581.         }
  5582.     }
  5583. #endif /* CK_SSL */
  5584.     if (ttnet == NET_TCPB) {
  5585. #ifdef BSDSELECT
  5586.         fd_set wfds;
  5587.         struct timeval tv;
  5588.  
  5589.         debug(F101,"nettoc BSDSELECT","",0);
  5590.         tv.tv_usec = 0L;
  5591.         tv.tv_sec = 30;
  5592.  
  5593. #ifdef STREAMING
  5594.       do_select:
  5595. #endif /* STREAMING */
  5596.  
  5597.         FD_ZERO(&wfds);
  5598.         FD_SET(ttyfd, &wfds);
  5599.         if (select(FD_SETSIZE, NULL,
  5600. #ifdef __DECC
  5601. #ifndef __DECC_VER
  5602.                    (int *)
  5603. #endif /* __DECC_VER */
  5604. #endif /* __DECC */
  5605.                    &wfds, NULL, &tv) < 0) {
  5606.             int s_errno = socket_errno;
  5607.             debug(F101,"nettoc select failed","",s_errno);
  5608. #ifdef BETATEST
  5609.             printf("nettoc select failed: %d\n", s_errno);
  5610. #endif /* BETATEST */
  5611. #ifdef NT
  5612.             WSASafeToCancel = 0;
  5613.             if (!win95selectbug)
  5614. #endif /* NT */
  5615.               return(-1);
  5616.         }
  5617.         if (!FD_ISSET(ttyfd, &wfds)) {
  5618. #ifdef STREAMING
  5619.             if (streaming)
  5620.               goto do_select;
  5621. #endif /* STREAMING */
  5622.             debug(F111,"nettoc","!FD_ISSET",ttyfd);
  5623. #ifdef NT
  5624.             WSASafeToCancel = 0;
  5625.             if (!win95selectbug)
  5626. #endif /* NT */
  5627.               return(-1);
  5628.         }
  5629. #ifdef NT
  5630.         WSASafeToCancel = 0;
  5631. #endif /* NT */
  5632. #else /* BSDSELECT */
  5633. #ifdef IBMSELECT
  5634.         {
  5635.             int tries = 0;
  5636.             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
  5637.                 int count;
  5638.                 if (tries++ >= 60) {
  5639.                     /* if after 60 seconds we can't get permission to write */
  5640.                     debug(F101,"nettoc select failed","",socket_errno);
  5641.                     return(-1);
  5642.                 }
  5643.                 if ((count = nettchk()) < 0) {
  5644.                     debug(F111,"nettoc","nettchk()",count);
  5645.                     return(count);
  5646.                 }
  5647.             }
  5648.         }
  5649. #endif /* IBMSELECT */
  5650. #endif /* BSDSELECT */
  5651.         if (socket_write(ttyfd,&cc,1) < 1) {
  5652.             int s_errno = socket_errno;         /* maybe a function */
  5653.             debug(F101,"nettoc socket_write error","",s_errno);
  5654. #ifdef OS2
  5655.             if (os2socketerror(s_errno) < 0)
  5656.               return(-2);
  5657. #endif /* OS2 */
  5658.             return(-1);
  5659.         }
  5660.         debug(F101,"nettoc socket_write","", cc);
  5661.         return(0);
  5662.     } else return(-2);
  5663. #else
  5664.     return(-2);
  5665. #endif /* TCPIPLIB */
  5666. #endif /* UNIX */
  5667. }
  5668.  
  5669. /*  N E T F L U I  --  Flush network input buffer  */
  5670.  
  5671. #ifdef TNCODE
  5672. static int
  5673. #ifdef CK_ANSIC
  5674. netgetc(int timo)                       /* Input function to point to... */
  5675. #else  /* CK_ANSIC */
  5676. netgetc(timo) int timo;
  5677. #endif /* CK_ANSIC */
  5678. {                                       /* ...in the tn_doop() call */
  5679. #ifdef TCPIPLIB
  5680.     return netinc(timo);
  5681. #else /* TCPIPLIB */
  5682.     return ttinc(timo);
  5683. #endif /* TCPIPLIB */
  5684. }
  5685. #endif /* TNCODE */
  5686.  
  5687. int
  5688. netflui() {
  5689.     int n;
  5690.     int ch;
  5691. #ifdef NETLEBUF
  5692.     ttpush = -1;                        /* Clear the peek-ahead char */
  5693.     while (le_data && (le_inbuf() > 0)) {
  5694.         CHAR ch = '\0';
  5695.         if (le_getchar(&ch) > 0) {
  5696.             debug(F101,"ttflui le_inbuf ch","",ch);
  5697.         }
  5698.     }
  5699. #endif /* NETLEBUF */
  5700.  
  5701. #ifdef TCPIPLIB
  5702. #ifdef TNCODE
  5703.     if (ttnproto == NP_TELNET) {
  5704.         /* Netflui must process Telnet negotiations or get out of sync */
  5705.         if ((n = nettchk()) <= 0) return(0);
  5706.         while (n-- > 0) {
  5707.             ch = netinc(1);
  5708.             if (ch == IAC) {
  5709.                 extern int duplex;  /* this really shouldn't be here but ... */
  5710.                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
  5711.                 if (tx == 1) duplex = 1;
  5712.                 else if (tx == 2) duplex = 0;
  5713.                 n = nettchk();
  5714.             }
  5715.         }
  5716.     } else
  5717. #endif /* TNCODE */
  5718.     {
  5719.         ttibuf[ttibp+ttibn] = '\0';
  5720.         debug(F111,"netflui 1",ttibuf,ttibn);
  5721. #ifdef CK_ENCRYPTION
  5722.         if (TELOPT_U(TELOPT_ENCRYPTION)) {
  5723.             ck_tn_decrypt(&ttibuf[ttibp],ttibn);
  5724.         }
  5725. #endif /* CK_ENCRYPTION */
  5726.         ttibn = ttibp = 0;              /* Flush internal buffer *FIRST* */
  5727.         if (ttyfd < 1)
  5728.             return(0);
  5729.         if ((n = nettchk()) > 0) {      /* Now see what's waiting on the net */
  5730.             if (n > TTIBUFL) n = TTIBUFL;       /* and sponge it up */
  5731.             debug(F101,"netflui 2","",n);       /* ... */
  5732.             n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
  5733.             if (n >= 0) ttibuf[n] = '\0';
  5734.             debug(F111,"netflui 3",ttibuf,n);
  5735. #ifdef CK_ENCRYPTION
  5736.             if (TELOPT_U(TELOPT_ENCRYPTION)) {
  5737.                 ck_tn_decrypt(&ttibuf[ttibp],n);
  5738.             }
  5739. #endif /* CK_ENCRYPTION */
  5740.             ttibuf[0] = '\0';
  5741.         }
  5742.     }
  5743. #else  /* !TCPIPLIB */
  5744.     if (ttyfd < 1)
  5745.       return(0);
  5746. #ifdef TNCODE
  5747.     if (ttnproto == NP_TELNET) {
  5748.         if ((n = ttchk()) <= 0) return(0);
  5749.         while (n-- >= 0) {
  5750.             /* Netflui must process Telnet negotiations or get out of sync */
  5751.             ch = ttinc(1);
  5752.             if (ch == IAC) {
  5753.                 extern int duplex;  /* this really shouldn't be here but ... */
  5754.                 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
  5755.                 if (tx == 1) duplex = 1;
  5756.                 else if (tx == 2) duplex = 0;
  5757.                 n = ttchk();
  5758.             }
  5759.         };
  5760.     } else
  5761. #endif /* TNCODE */
  5762.     if ((n = ttchk()) > 0) {
  5763.         debug(F101,"netflui non-TCPIPLIB","",n);
  5764.         while ((n--) && ttinc(1) > -1)  /* Don't worry, ttinc() is buffered */
  5765.           ;                             /* and it handles the decryption... */
  5766.     }
  5767. #endif /* TCPIPLIB */
  5768.     return(0);
  5769. }
  5770. #endif /* NOLOCAL */
  5771.  
  5772. /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
  5773.  *   If the host is multi-homed it returns only one address.
  5774.  *
  5775.  * Two techniques are used.
  5776.  * (1) get the local host name and perform a DNS lookup, then take
  5777.  *     the first entry;
  5778.  * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
  5779.  *    no data is sent), then retrieve the local address from the socket.
  5780.  * Note: the second technique won't work on Microsoft systems.  See
  5781.  * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
  5782.  */
  5783.  
  5784. /* Technique number one cannot work reliably if the machine is a laptop
  5785.  * and the hostname is associated with a physical adapter which is not
  5786.  * installed and a PPP connection is being used instead.  This is because
  5787.  * the hostname DNS lookup will succeed for the physical adapter even though
  5788.  * it would be impossible to use it.  In NT4 SP4, the gethostbyname()
  5789.  * when given the result of gethostname() returns not the real DNS entries
  5790.  * for that name+domain.  Instead it returns all of the static and dynamic
  5791.  * IP addresses assigned to any physical or virtual adapter defined in the
  5792.  * system regardless of whether or not it is installed.  The order of the
  5793.  * addresses is fixed according to the binding order in the NT registry.
  5794.  */
  5795.  
  5796. /*
  5797.  * It appears that calling gethostbyname(NULL) is more reliable than
  5798.  * calling gethostbyname(gethostname()) on Windows.  So on Windows we will
  5799.  * only call gethostbyname(NULL).
  5800.  */
  5801.  
  5802. int
  5803. getlocalipaddr() {
  5804. #ifndef datageneral
  5805.     struct sockaddr_in l_sa;
  5806.     struct sockaddr_in r_sa;
  5807.     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
  5808.     int sock;
  5809.     int rc;
  5810.     struct in_addr laddr;
  5811.  
  5812.     /* if still not resolved, then try second strategy */
  5813.     /* This second strategy does not work on Windows */
  5814.  
  5815.     memset(&l_sa,0,slen);
  5816.     memset(&r_sa,0,slen);
  5817.  
  5818.     /* get a UDP socket */
  5819.     sock = socket(AF_INET, SOCK_DGRAM, 0);
  5820.     if (sock != -1) {
  5821.         /* connect to arbirary port and address (NOT loopback) */
  5822.         r_sa.sin_family = AF_INET;
  5823.         r_sa.sin_port = htons(IPPORT_ECHO);
  5824.  
  5825.         /* The following is an "illegal conversion" in AOS/VS */
  5826.         /* (and who knows where else) */
  5827.  
  5828. #ifdef INADDRX
  5829.         inaddrx = inet_addr("128.127.50.1");
  5830.         r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
  5831. #else
  5832.         r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
  5833. #endif /* INADDRX */
  5834.         rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
  5835.         if (!rc) {                      /* get local address */
  5836.             getsockname(sock,(struct sockaddr *)&l_sa,&slen);
  5837. #ifdef TCPIPLIB
  5838.             socket_close(sock);         /* We're done with the socket */
  5839. #else
  5840.             close(sock);
  5841. #endif /* TCPIPLIB */
  5842.             if (l_sa.sin_addr.s_addr != INADDR_ANY) {
  5843.                 myxipaddr = ntohl(l_sa.sin_addr.s_addr);
  5844.                 ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
  5845.                 debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
  5846.                 return(0);
  5847.             }
  5848.         }
  5849.     }
  5850.     return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
  5851. #else /* datageneral */
  5852.     return(-1);
  5853. #endif /* datageneral */
  5854. }
  5855.  
  5856. int
  5857. getlocalipaddrs(buf,bufsz,index)
  5858.     char * buf;
  5859.     int    bufsz;
  5860.     int    index;
  5861. /* getlocalipaddrs */ {
  5862. #ifndef datageneral
  5863.     char localhost[256];
  5864.     struct hostent * host=NULL;
  5865.     struct sockaddr_in l_sa;
  5866.     struct sockaddr_in r_sa;
  5867.     GSOCKNAME_T slen = sizeof(struct sockaddr_in);
  5868.     int sock;
  5869.     int rc;
  5870.     char messageBuf[60];
  5871.     struct in_addr laddr;
  5872.  
  5873.     memset(&l_sa,0,slen);
  5874.     memset(&r_sa,0,slen);
  5875.  
  5876.     /* init local address (to zero) */
  5877.     l_sa.sin_addr.s_addr = INADDR_ANY;
  5878.  
  5879. #ifdef CKGHNLHOST
  5880.     rc = gethostname(localhost, 256);
  5881.     debug(F110,"getlocalipaddrs localhost",localhost,0);
  5882. #else
  5883.     /* This doesn't work on some platforms, e.g. Solaris */
  5884.     rc = 0;
  5885.     localhost[0] = '\0';
  5886. #endif /* CKGHNLHOST */
  5887.     if (!rc) {
  5888.         /* resolve host name for local address */
  5889.         host = gethostbyname(localhost);
  5890.         if (host) {
  5891. #ifdef HADDRLIST
  5892.             if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
  5893.                 buf[0] = '\0';
  5894.                 return(-1);
  5895.             }
  5896.             l_sa.sin_addr.s_addr =
  5897.               *((unsigned long *) (host->h_addr_list[index]));
  5898.             ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
  5899.             debug(F110,"getlocalipaddrs setting buf to",buf,0);
  5900.  
  5901. #ifdef COMMENT
  5902.             /* This is for reporting multiple IP Address */
  5903.             while (host->h_addr_list && host->h_addr_list[0]) {
  5904.                 l_sa.sin_addr.s_addr =
  5905.                   *((unsigned long *) (host->h_addr_list[0]));
  5906.                 ckstrncpy(messageBuf,
  5907.                         (char *)inet_ntoa(l_sa.sin_addr),60);
  5908.                 if (tcp_address) {
  5909.                     if (!strcmp(messageBuf,tcp_address))
  5910.                       ckstrncpy(myipaddr,tcp_address,20);
  5911.                 }
  5912.                 debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
  5913.                 host->h_addr_list++;
  5914.             }
  5915. #endif /* COMMENT */
  5916. #else   /* HADDRLIST */
  5917.             if (index != 0) {
  5918.                 buf[0] = '\0';
  5919.                 return(-1);
  5920.             }
  5921.             l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
  5922.             ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
  5923.             debug(F110,"getlocalipaddrs setting buf to",buf,0);
  5924. #endif  /* HADDRLIST */
  5925.             return(0);
  5926.         } else debug(F110,
  5927.                      "getlocalipaddrs: gethostbyname() failed",
  5928.                      localhost,
  5929.                      0
  5930.                      );
  5931.     }
  5932. #endif /* datageneral */
  5933.     return(-1);
  5934. }
  5935.  
  5936. #ifdef RLOGCODE                 /* TCP/IP RLOGIN protocol support code */
  5937. int
  5938. rlog_naws() {
  5939.     struct rlog_naws {
  5940.         char id[4];
  5941.         unsigned short rows, cols, ypix, xpix;
  5942.     } nawsbuf;
  5943.  
  5944.     if (ttnet != NET_TCPB)
  5945.       return 0;
  5946.     if (ttnproto != NP_RLOGIN
  5947. #ifdef CK_KERBEROS
  5948.         && ttnproto != NP_K4LOGIN
  5949.         && ttnproto != NP_EK4LOGIN
  5950.         && ttnproto != NP_K5LOGIN
  5951.         && ttnproto != NP_EK5LOGIN
  5952. #endif /* CK_KERBEROS */
  5953.          )
  5954.       return 0;
  5955.     if (!TELOPT_ME(TELOPT_NAWS))
  5956.       return 0;
  5957.  
  5958.     debug(F100,"rlogin Window Size sent","",0);
  5959.  
  5960.     nawsbuf.id[0] = nawsbuf.id[1] = 0xFF;
  5961.     nawsbuf.id[2] = nawsbuf.id[3] = 's';
  5962. #ifdef OS2
  5963.     nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
  5964.                           -(tt_status?1:0)));
  5965.     nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
  5966. #else /* OS2 */
  5967.     nawsbuf.rows = htons((unsigned short) tt_rows);
  5968.     nawsbuf.cols = htons((unsigned short) tt_cols);
  5969. #endif /* OS2 */
  5970.     nawsbuf.ypix = htons(0);            /* y pixels */
  5971.  
  5972.     nawsbuf.xpix = htons(0);            /* x pixels */
  5973.     if (ttol((CHAR *)(&nawsbuf), 12) < 0)
  5974.       return(-1);
  5975.     return(0);
  5976. }
  5977.  
  5978. #ifdef OS2ORUNIX
  5979. #define RLOGOUTBUF
  5980. #endif /* OS2 */
  5981. static int
  5982. #ifdef CK_ANSIC
  5983. rlog_ini(CHAR * hostname, int port,
  5984.          struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
  5985. #else /* CK_ANSIC */
  5986. rlog_ini(hostname, port, l_addr, r_addr)
  5987.     CHAR * hostname;
  5988.     int port;
  5989.     struct sockaddr_in * l_addr;
  5990.     struct sockaddr_in * r_addr;
  5991. #endif /* CK_ANSIC */
  5992. /* rlog_ini */ {
  5993.  
  5994. #ifdef RLOGOUTBUF
  5995.     char outbuf[512];
  5996.     int  outbytes=0;
  5997. #endif /* RLOGOUTBUF */
  5998.     int flag = 0;
  5999. #define TERMLEN 16
  6000. #define CONSPDLEN 16
  6001.     CHAR localuser[UIDBUFLEN+1];
  6002.     CHAR remoteuser[UIDBUFLEN+1];
  6003.     int userlen = 0;
  6004.     CHAR term_speed[TERMLEN+CONSPDLEN+1];
  6005. #ifdef CONGSPD
  6006.     long conspd = -1L;
  6007. #endif /* CONGSPD */
  6008. #ifdef OS2
  6009.     extern int tt_type, max_tt;
  6010.     extern struct tt_info_rec tt_info[];
  6011. #endif /* OS2 */
  6012.     int i, n;
  6013.  
  6014.     int rc = 0;
  6015.     tn_reset();                 /* This call will reset all of the Telnet */
  6016.                                 /* options and then quit.  We need to do  */
  6017.                                 /* this since we use the Telnet options   */
  6018.                                 /* to hold various state information      */
  6019.     duplex = 0;                 /* Rlogin is always remote echo */
  6020.  
  6021. #ifdef CK_TTGWSIZ
  6022. /*
  6023.   But compute the values anyway before the first read since the out-
  6024.   of-band NAWS request would arrive before the first data byte (NULL).
  6025. */
  6026. #ifdef OS2
  6027.     /* Console terminal screen rows and columns */
  6028.     debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
  6029.            -(tt_status?1:0));
  6030.     debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
  6031.     /* Not known yet */
  6032.     if (VscrnGetWidth(VTERM) < 0 ||
  6033.         VscrnGetHeight(VTERM)-(tt_status?1:0) < 0) {
  6034.         ttgwsiz();                      /* Try to get screen dimensions */
  6035.     }
  6036.     debug(F101,"rlog_ini tt_rows 2","",VscrnGetHeight(VTERM)-(tt_status?1:0));
  6037.     debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
  6038. #else /* OS2 */
  6039.     debug(F101,"rlog_ini tt_rows 1","",tt_rows);
  6040.     debug(F101,"rlog_ini tt_cols 1","",tt_cols);
  6041.     if (tt_rows < 0 || tt_cols < 0) {   /* Not known yet */
  6042.         ttgwsiz();                      /* Try to find out */
  6043.     }
  6044.     debug(F101,"rlog_ini tt_rows 2","",tt_rows);
  6045.     debug(F101,"rlog_ini tt_cols 2","",tt_cols);
  6046. #endif /* OS2 */
  6047. #endif /* CK_TTGWSIZ */
  6048.  
  6049.     ttflui();                           /* Start by flushing the buffers */
  6050.  
  6051.     rlog_mode = RL_COOKED;
  6052.  
  6053.     /* Followed by client username ... */
  6054.  
  6055.     localuser[0] = '\0';
  6056. #ifdef NT
  6057.     {
  6058.         char localuid[UIDBUFLEN+1];
  6059.         unsigned long len = UIDBUFLEN;
  6060.         localuid[0] = '\0';
  6061. #ifdef COMMENT
  6062.         WNetGetUser(NULL, localuid, &len);
  6063. #else /* COMMENT */
  6064.         GetUserName(localuid,&len);
  6065. #endif /* COMMENT */
  6066.         ckstrncpy((char *)localuser,localuid,UIDBUFLEN);
  6067.     }
  6068. #else /* NT */
  6069.     {
  6070.         char * user = getenv("USER");
  6071.         if (!user)
  6072.           user = "";
  6073.         userlen = strlen(user);
  6074.         debug(F111,"rlogin getenv(USER)",user,userlen);
  6075.         ckstrncpy((char *)localuser,user,UIDBUFLEN);
  6076.         debug(F110,"rlog_ini localuser 1",localuser,0);
  6077.         if (ck_lcname) {
  6078.             cklower((char *)localuser);
  6079.             debug(F110,"rlog_ini localuser 2",localuser,0);
  6080.         }
  6081.     }
  6082. #endif /* NT */
  6083.  
  6084.     /* Then the server userid... */
  6085.  
  6086.     if (uidbuf[0]) {
  6087.         ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
  6088.         debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
  6089.     } else if (localuser[0]) {
  6090.         ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
  6091.         debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
  6092.     } else {
  6093.         remoteuser[0] = '\0';
  6094.         debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
  6095.     }
  6096.     if (ck_lcname)
  6097.       cklower((char *)remoteuser);
  6098.     debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
  6099.  
  6100.     /* Finally the terminal type and speed */
  6101.  
  6102.     term_speed[0] = '\0';
  6103.     if (tn_term) {                      /* SET TELNET TERMINAL-TYPE value */
  6104.         if (*tn_term) {                 /* (if any) takes precedence. */
  6105.             ckstrncpy((char *)term_speed, tn_term, TERMLEN);
  6106.             flag = 1;
  6107.         }
  6108.     } else {                            /* Otherwise the local terminal type */
  6109. #ifdef OS2
  6110.         /* In terminal-emulating versions, it's the SET TERM TYPE value */
  6111.         ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
  6112.                 tt_info[tt_type].x_name : "network", TERMLEN);
  6113. #else
  6114.         /* In the others, we just look at the TERM environment variable */
  6115.         {
  6116.             char *p = getenv("TERM");
  6117.             if (p)
  6118.               ckstrncpy((char *)term_speed,p,TERMLEN);
  6119.             else
  6120.               term_speed[0] = '\0';
  6121. #ifdef VMS
  6122.             for (p = (char *) term_speed; *p; p++) {
  6123.                 if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
  6124.                   break;
  6125.                 else if (isupper(*p))
  6126.                   *p = tolower(*p);
  6127.             }
  6128.             *p = '\0';
  6129. #endif /* VMS */
  6130.         }
  6131. #endif /* OS2 */
  6132.     }
  6133.     n = strlen((char *)term_speed);
  6134.     if (n > 0) {                        /* We have a terminal type */
  6135.         if (!flag) {                    /* If not user-specified */
  6136.             for (i = 0; i < n; i++)     /* then lowercase it.    */
  6137.               if (isupper(term_speed[i]))
  6138.                 term_speed[i] = tolower(term_speed[i]);
  6139.         }
  6140.         debug(F110,"rlog_ini term_speed 1",term_speed,0);
  6141.  
  6142. #ifdef CONGSPD
  6143.         /* conspd() is not yet defined in all ck*tio.c modules */
  6144.         conspd = congspd();
  6145.         if (conspd > 0L) {
  6146.             sprintf((char *)(&term_speed[strlen((char *)term_speed)]),
  6147.                     "/%ld",
  6148.                     conspd
  6149.                     );
  6150.         } else
  6151. #endif /* CONGSPD */
  6152.           strcat((char *)term_speed,"/19200");
  6153.         debug(F110,"rlog_ini term_speed 2",term_speed,0);
  6154.     } else {
  6155.         term_speed[0] = '\0';
  6156.         debug(F110,"rlog_ini term_speed 3",term_speed,0);
  6157.     }
  6158.  
  6159. #ifdef CK_KERBEROS
  6160.     if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
  6161.         ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
  6162.         int kver, encrypt, rc;
  6163.         switch (ttnproto) {
  6164.           case NP_K4LOGIN:
  6165.             kver = 4;
  6166.             encrypt = 0;
  6167.             break;
  6168.           case NP_EK4LOGIN:
  6169.             kver = 4;
  6170.             encrypt = 1;
  6171.             break;
  6172.           case NP_K5LOGIN:
  6173.             kver = 5;
  6174.             encrypt = 0;
  6175.             break;
  6176.           case NP_EK5LOGIN:
  6177.             kver = 5;
  6178.             encrypt = 1;
  6179.             break;
  6180.         default:
  6181.             kver = 0;
  6182.             encrypt = 0;
  6183.         }
  6184.         rc = ck_krb_rlogin(hostname, port,
  6185.                            localuser, remoteuser, term_speed,
  6186.                            l_addr, r_addr, kver, encrypt);
  6187.         if (!rc) {                      /* success */
  6188.             TELOPT_ME(TELOPT_NAWS) = 1;
  6189.             rc = rlog_naws();
  6190.         }
  6191.         return(rc);
  6192.     } else
  6193. #endif /* CK_KERBEROS */
  6194.     if (ttnproto == NP_RLOGIN) {
  6195. #ifdef RLOGOUTBUF
  6196.         outbuf[outbytes++] = 0;
  6197.         strcpy((char *)outbuf+outbytes,(char *)localuser);
  6198.         outbytes += strlen((char *)localuser) + 1;
  6199.         strcpy((char *)outbuf+outbytes,(char *)remoteuser);
  6200.         outbytes += strlen((char *)remoteuser) + 1;
  6201.         strcpy((char *)outbuf+outbytes,(char *)term_speed);
  6202.         outbytes += strlen((char *)term_speed) + 1;
  6203.         rc = ttol((CHAR *)outbuf,outbytes);
  6204. #else /* RLOGOUTBUF */
  6205.         ttoc(0);                        /* Send an initial NUL as wake-up */
  6206.         /* Send each variable with the trailing NUL */
  6207.         rc = ttol(localuser,strlen((char *)localuser)+1);
  6208.         if (rc > 0)
  6209.           rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
  6210.         if (rc > 0)
  6211.           rc = ttol(term_speed,strlen((char *)term_speed)+1);
  6212. #endif /* RLOGOUTBUF */
  6213.  
  6214.         /* Now we are supposed to get back a single NUL as confirmation */
  6215.         errno = 0;
  6216.         rc = ttinc(60);
  6217.         debug(F101,"rlogin first ttinc","",rc);
  6218.         if (rc > 0) {
  6219.             debug(F101,"rlogin ttinc 1","",rc);
  6220.             printf(
  6221.                "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
  6222.             return(-1);
  6223.         } else if (rc < 0) {
  6224.             debug(F101,"rlogin ttinc errno","",errno);
  6225.             /* printf("Network error: %d\n", errno); */
  6226.             return(-1);
  6227.         }
  6228.     }
  6229.     return(0);
  6230. }
  6231.  
  6232. #ifdef TCPIPLIB
  6233. static VOID
  6234. rlog_oob(oobdata, count) CHAR * oobdata; int count; {
  6235.     int i;
  6236.  
  6237.     debug(F111,"rlogin out_of_band","count",count);
  6238.  
  6239.     for (i = 0; i<count; i++)   {
  6240.         debug(F101,"rlogin out_of_band","",oobdata[i]);
  6241.         if (oobdata[i] == 0x02) { /* Flush Buffered Data not yet displayed */
  6242.             debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
  6243.  
  6244.             /* Only flush the data if in fact we are in a mode that won't */
  6245.             /* get out of sync.  Ie, not when we are in protocol mode.    */
  6246.             switch ( what ) {
  6247.             case W_NOTHING:
  6248.             case W_CONNECT:
  6249.             case W_COMMAND:
  6250.                 ttflui();
  6251.                 break;
  6252.             }
  6253.         }
  6254.         if (oobdata[i] & 0x10) {        /* Switch to RAW mode */
  6255.             debug(F101,"rlogin Raw Mode command","",oobdata[i]);
  6256.             rlog_mode = RL_RAW;
  6257.         }
  6258.  
  6259.         if (oobdata[i] & 0x20) {        /* Switch to COOKED mode */
  6260.             debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
  6261.             rlog_mode = RL_COOKED;
  6262.         }
  6263.         if (oobdata[i] & 0x80) {        /* Send Window Size Info */
  6264.             debug(F101,"rlogin Window Size command","",oobdata[i]);
  6265.             /* Remember to send WS Info when Window Size changes */
  6266.             TELOPT_ME(TELOPT_NAWS) = 1;
  6267.             rlog_naws();
  6268.         }
  6269.     }
  6270. }
  6271. #else /* TCPIPLIB */
  6272. static SIGTYP
  6273. rlogoobh(sig) int sig; {
  6274. #ifdef SOLARIS
  6275.     char                                /* Or should it be char for all? */
  6276. #else
  6277.     CHAR
  6278. #endif /* SOLARIS */
  6279.       oobdata;
  6280.  
  6281.     int  count = 0;
  6282.  
  6283.     while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
  6284.       /*
  6285.        * We need to do some special processing here.
  6286.        * Just in case the socket is blocked for input
  6287.        *
  6288.        */
  6289.         switch (errno) {
  6290.           case EWOULDBLOCK:
  6291.             break;
  6292.           default:
  6293.             return;
  6294.         }
  6295.     }
  6296.     debug(F101,"rlogin out_of_band","",oobdata);
  6297.     if (oobdata == 0x02) {      /* Flush Buffered Data not yet displayed */
  6298.         debug(F101,"rlogin Flush Buffered Data command","",oobdata);
  6299.         netflui();
  6300.     }
  6301.     if (oobdata & 0x10) {               /* Switch to raw mode */
  6302.         debug(F101,"rlogin Raw Mode command","",oobdata);
  6303.         rlog_mode = RL_RAW;
  6304.     }
  6305.     if (oobdata & 0x20) {               /* Switch to cooked mode */
  6306.         debug(F101,"rlogin Cooked Mode command","",oobdata);
  6307.         rlog_mode = RL_COOKED;
  6308.     }
  6309.     if (oobdata & 0x80) {                 /* Send Window Size Info */
  6310.         debug(F101,"rlogin Window Size command","",oobdata);
  6311.         /* Remember to send WS Info when Window Size changes */
  6312.         TELOPT_ME(TELOPT_NAWS) = 1;
  6313.         rlog_naws();
  6314.     }
  6315. }
  6316. #endif /* TCPIPLIB */
  6317. #endif /* RLOGCODE */
  6318.  
  6319. /* Send network BREAK */
  6320. /*
  6321.   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
  6322. */
  6323. int
  6324. netbreak() {
  6325.     CHAR buf[3];
  6326.     if (ttnet == NET_TCPB) {
  6327.         if (ttnproto == NP_TELNET) {
  6328. #ifdef TNCODE
  6329.             buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
  6330.             if (
  6331. #ifdef OS2
  6332.                 nettol((char *) buf, 2)
  6333. #else
  6334.                 ttol(buf, 2)
  6335. #endif /* OS2 */
  6336.                 < 2)
  6337.               return(-1);
  6338.             if (tn_deb || debses || deblog) {
  6339.                 extern char tn_msg[];
  6340.                 sprintf(tn_msg,"TELNET SENT %s",TELCMD(BREAK));
  6341.                 debug(F101,tn_msg,"",BREAK);
  6342.                 if (debses || tn_deb) tn_debug(tn_msg);
  6343.             }
  6344.             return(1);
  6345. #else
  6346.             debug(F100,"netbreak no TNCODE","",0);
  6347.             return(0);
  6348. #endif /* TNCODE */
  6349.         }
  6350.         /* Insert other TCP/IP protocols here */
  6351.     }
  6352.     /* Insert other networks here */
  6353.     return(0);
  6354. }
  6355. #endif /* NETCONN */
  6356.  
  6357.  
  6358. #ifdef NETCONN
  6359. #ifdef SUNX25
  6360. /*
  6361.   SunLink X.25 support by Marcello Frutig, Catholic University,
  6362.   Rio de Janeiro, Brazil, 1990.
  6363. */
  6364.  
  6365. /* PAD X.3, X.28 and X.29 support */
  6366.  
  6367. static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
  6368.  
  6369. /* Initialize PAD */
  6370.  
  6371. extern CHAR padparms[];
  6372.  
  6373. VOID
  6374. initpad() {
  6375.   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
  6376.   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
  6377.   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
  6378.   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
  6379.   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
  6380.   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
  6381.   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
  6382.   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
  6383.   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
  6384.   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
  6385.   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
  6386.   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
  6387.   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
  6388.   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
  6389.   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
  6390.   padparms[PAD_EDITING]                = 1;  /* can edit */
  6391.   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
  6392.   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
  6393.   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
  6394. }
  6395.  
  6396. /* Set PAD parameters */
  6397.  
  6398. VOID
  6399. setpad(s,n) CHAR *s; int n; {
  6400.     int i;
  6401.     CHAR *ps = s;
  6402.  
  6403.     if (n < 1) {
  6404.         initpad();
  6405.     } else {
  6406.         for (i = 0; i < n; i++) {
  6407.             if (*ps > MAXPADPARMS)
  6408.               x29err[i+2] = *ps;
  6409.             else
  6410.               padparms[*ps] = *(ps+1);
  6411.             ps += 2;
  6412.         }
  6413.     }
  6414. }
  6415.  
  6416. /* Read PAD parameters */
  6417.  
  6418. VOID
  6419. readpad(s,n,r) CHAR *s; int n; CHAR *r; {
  6420.     int i;
  6421.     CHAR *ps = s;
  6422.     CHAR *pr = r;
  6423.  
  6424.     *pr++ = X29_PARAMETER_INDICATION;
  6425.     if (n > 0) {
  6426.         for (i = 0; i < n; i++, ps++) {
  6427.             if (*ps > MAXPADPARMS) {
  6428.                 x29err[i+2] = *ps++;
  6429.             } else {
  6430.                 *pr++ = *ps;
  6431.                 *pr++ = padparms[*ps++];
  6432.             }
  6433.         }
  6434.     } else {
  6435.         for (i = 1; i < MAXPADPARMS; i++) {
  6436.             *pr++ = i;
  6437.             *pr++ = padparms[i];
  6438.         }
  6439.     }
  6440. }
  6441.  
  6442. int
  6443. qbitpkt(s,n) CHAR *s; int n; {
  6444.     CHAR *ps = s;
  6445.     int x29cmd = *ps;
  6446.     CHAR *psa = s+1;
  6447.     CHAR x29resp[(MAXPADPARMS*2)+1];
  6448.  
  6449.     switch (x29cmd) {
  6450.  
  6451.         case X29_SET_PARMS:
  6452.             setpad (ps+1,n/2);
  6453.             if ((int)strlen((char *)x29err) > 2) {
  6454.                 ttol(x29err,(int)strlen((char *)x29err));
  6455.                 x29err[2] = '\0';
  6456.             }
  6457.             return (-2);
  6458.         case X29_READ_PARMS:
  6459.             readpad (ps+1,n/2,x29resp);
  6460.             setqbit ();
  6461.             ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
  6462.             if ((int)strlen((char *)x29err) > 2) {
  6463.                 ttol(x29err,(int)strlen((char *)x29err));
  6464.                 x29err[2] = '\0';
  6465.             }
  6466.             resetqbit();
  6467.             break;
  6468.         case X29_SET_AND_READ_PARMS:
  6469.             setpad (ps+1,n/2);
  6470.             readpad (ps+1,n/2,x29resp);
  6471.             setqbit();
  6472.             ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
  6473.             if ((int)strlen((char *)x29err) > 2) {
  6474.                 ttol (x29err,(int)strlen((char *)x29err));
  6475.                 x29err [2] = '\0';
  6476.             }
  6477.             resetqbit();
  6478.             return (-2);
  6479.         case X29_INVITATION_TO_CLEAR:
  6480.             (VOID) x25clear();
  6481.             return (-1);
  6482.         case X29_INDICATION_OF_BREAK:
  6483.             break;
  6484.     }
  6485.     return (0);
  6486. }
  6487.  
  6488. /* PAD break action processor */
  6489.  
  6490. VOID
  6491. breakact() {
  6492.     extern char x25obuf[MAXOX25];
  6493.     extern int obufl;
  6494.     extern int active;
  6495.     extern unsigned char tosend;
  6496.     static CHAR indbrk[3] = {
  6497.         X29_INDICATION_OF_BREAK,
  6498.         PAD_SUPPRESSION_OF_DATA,
  6499.         1
  6500.     };
  6501.     CHAR intudat, cause, diag;
  6502.  
  6503.     if (x25stat() < 0) return;  /* Ignore if no virtual call established */
  6504.  
  6505.     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
  6506.         if (ttol((CHAR *)x25obuf,obufl) < 0) {
  6507.             perror ("\r\nCan't send characters");
  6508.             active = 0;
  6509.         } else {
  6510.             bzero (x25obuf,sizeof(x25obuf));
  6511.             obufl = 0;
  6512.             tosend = 0;
  6513.         };
  6514.  
  6515.     switch (padparms[PAD_BREAK_ACTION]) {
  6516.  
  6517.        case 0 : break;                  /* do nothing */
  6518.        case 1 : /* send interrupt packet with interrupt user data field = 1 */
  6519.                 intudat = 1;
  6520.                 x25intr (intudat);
  6521.                 break;
  6522.        case 2 : /* send reset packet with cause and diag = 0 */
  6523.                 cause = diag = 0;
  6524.                 x25reset (cause,diag);
  6525.                 break;
  6526.        case 5 : /* send interrupt packet with interrupt user data field = 0 */
  6527.                 intudat = 0;
  6528.                 x25intr (intudat);
  6529.                 setqbit ();
  6530.                 /* send indication of break without a parameter field */
  6531.                 ttoc(X29_INDICATION_OF_BREAK);
  6532.                 resetqbit ();
  6533.                 break;
  6534.        case 8 : active = 0;             /* leave data transfer */
  6535.                 conol ("\r\n");
  6536.                 break;
  6537.        case 21: /* send interrupt packet with interrupt user data field = 0 */
  6538.                 intudat = 0;
  6539.                 x25intr (intudat);
  6540.                 setpad (indbrk+1,2);    /* set pad to discard input */
  6541.                 setqbit ();
  6542.                 /* send indication of break with parameter field */
  6543.                 ttol (indbrk,sizeof(indbrk));
  6544.                 resetqbit ();
  6545.                 break;
  6546.      }
  6547. }
  6548.  
  6549. /* X.25 support functions */
  6550.  
  6551. X25_CAUSE_DIAG diag;
  6552.  
  6553. /*
  6554.   Convert a null-terminated string representing an X.121 address
  6555.   to a packed BCD form.
  6556. */
  6557. int
  6558. pkx121(str,bcd) char *str; CHAR *bcd; {
  6559.     int i, j;
  6560.     u_char c;
  6561.  
  6562.     i = j = 0;
  6563.     while (str[i]) {
  6564.         if (i >= 15 || str [i] < '0' || str [i] > '9')
  6565.           return (-1);
  6566.         c = str [i] - '0';
  6567.         if (i & 1)
  6568.           bcd [j++] |= c;
  6569.         else
  6570.           bcd [j] = c << 4;
  6571.         i++;
  6572.     }
  6573.     return (i);
  6574. }
  6575.  
  6576. /* Reads and prints X.25 diagnostic */
  6577.  
  6578. int
  6579. x25diag () {
  6580.     int i;
  6581.  
  6582.     bzero ((char *)&diag,sizeof(diag));
  6583.     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
  6584.         perror ("Reading X.25 diagnostic");
  6585.         return(-1);
  6586.     }
  6587.     if (diag.datalen > 0) {
  6588.         printf ("X.25 Diagnostic :");
  6589.         for (i = 0; i < (int)diag.datalen; i++)
  6590.           printf(" %02h",diag.data[i])+
  6591.         printf ("\r\n");
  6592.     }
  6593.     return(0);
  6594. }
  6595.  
  6596. /* X.25 Out-of-Band Signal Handler */
  6597.  
  6598. SIGTYP
  6599. x25oobh(foo) int foo; {
  6600.     int oobtype;
  6601.     u_char oobdata;
  6602.     int t;
  6603.  
  6604.     (VOID) signal(SIGURG,x25oobh);
  6605.     do {
  6606.         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
  6607.             perror ("Getting signal type");
  6608.             return;
  6609.         }
  6610.         switch (oobtype) {
  6611.           case INT_DATA:
  6612.             if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
  6613.                 perror ("Receiving X.25 interrupt data");
  6614.                 return;
  6615.             }
  6616.             t = oobdata;
  6617.             printf ("\r\nInterrupt received, data = %d\r\n", t);
  6618.             break;
  6619.           case VC_RESET:
  6620.             printf ("\r\nVirtual circuit reset\r\n");
  6621.             x25diag ();
  6622.             break;
  6623.           case N_RESETS:
  6624.             printf ("\r\nReset timeout\r\n");
  6625.             break;
  6626.           case N_CLEARS:
  6627.             printf ("\r\nClear timeout\r\n");
  6628.             break;
  6629.           case MSG_TOO_LONG:
  6630.             printf ("\r\nMessage discarded, too long\r\n");
  6631.             break;
  6632.           default:
  6633.             if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
  6634.             break;
  6635.         }
  6636.     } while (oobtype);
  6637. }
  6638.  
  6639. /* Send a X.25 interrupt packet */
  6640.  
  6641. int
  6642. #ifdef CK_ANSIC
  6643. x25intr(char intr)
  6644. #else
  6645. x25intr(intr) char intr;
  6646. #endif /* CK_ANSIC */
  6647. /* x25intr */ {
  6648.     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
  6649.     debug(F100,"X.25 intr","",0);
  6650.     return(0);
  6651. }
  6652.  
  6653. /* Reset X.25 virtual circuit */
  6654. int
  6655. #ifdef CK_ANSIC
  6656. x25reset(char cause, char diagn)
  6657. #else
  6658. x25reset(cause, diagn) char cause; char diagn;
  6659. #endif /* CK_ANSIC */
  6660. /* x25reset */ {
  6661.     bzero ((char *)&diag,sizeof(diag));
  6662.     diag.flags   = 0;
  6663.     diag.datalen = 2;
  6664.     diag.data[0] = cause;
  6665.     diag.data[1] = diagn;
  6666.     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
  6667.       return(-1);
  6668.     debug(F100,"X.25 reset","",0);
  6669.     return(0);
  6670. }
  6671.  
  6672. /* Clear X.25 virtual circuit */
  6673. int
  6674. x25clear() {
  6675.     int i;
  6676.     debug(F100,"X.25 clear","",0);
  6677.     bzero ((char *)&diag,sizeof(diag));
  6678.     diag.flags = (1 << DIAG_TYPE);
  6679.     diag.datalen = 2;
  6680.     diag.data[0] = 0;
  6681.     diag.data[1] = 0;
  6682.     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
  6683.     return(ttclos(0));                  /* Close socket */
  6684. }
  6685.  
  6686. /* X.25 status */
  6687. int
  6688. x25stat() {
  6689.     if (ttyfd == -1) return (-1);
  6690.     return(0);
  6691. }
  6692.  
  6693. /* Set Q_BIT on */
  6694. VOID
  6695. setqbit() {
  6696.     static int qbiton = 1 << Q_BIT;
  6697.     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
  6698. }
  6699.  
  6700. /* Set Q_BIT off */
  6701. VOID
  6702. resetqbit() {
  6703.     static int qbitoff = 0;
  6704.     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
  6705. }
  6706.  
  6707. /* Read n characters from X.25 circuit into buf */
  6708.  
  6709. int
  6710. x25xin(n,buf) int n; CHAR *buf; {
  6711.     register int x, c;
  6712.     int qpkt;
  6713.  
  6714.     do {
  6715.         x = read(ttyfd,buf,n);
  6716.         if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
  6717.             /* If return -1 : invitation to clear; -2 : PAD changes */
  6718.             if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
  6719.             qpkt = 1;
  6720.         } else qpkt = 0;
  6721.     } while (qpkt);
  6722.  
  6723. #ifdef COMMENT                  /* Disabled by Stephen Riehm 19.12.97 */
  6724.     /* BUG!
  6725.      * if buf[] is full, then this null lands in nirvana!
  6726.      * I was unable to find any code which needs a trailing null in buf[]
  6727.      */
  6728.     if (x > 0) buf[x] = '\0';
  6729. #endif /* COMMENT */
  6730.     if (x < 1) x = -1;
  6731.     debug(F101,"x25xin x","",x);
  6732.  
  6733.     return(x);
  6734. }
  6735.  
  6736. #ifdef COMMENT /* NO LONGER NEEDED! */
  6737. /* X.25 read a line */
  6738.  
  6739. int
  6740. #ifdef PARSENSE
  6741. #ifdef CK_ANSIC
  6742. x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
  6743. #else
  6744. x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
  6745. #endif /* CK_ANSIC */
  6746. #else /* not PARSENSE */
  6747. #ifdef CK_ANSIC
  6748. x25inl(CHAR *dest, int max,int timo, CHAR eol)
  6749. #else
  6750. x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
  6751. #endif /* __SDTC__ */
  6752. #endif /*PARSENSE */
  6753.  /* x25inl */ {
  6754.     CHAR *pdest;
  6755.     int pktype, goteol, rest, n;
  6756.     int i, flag = 0;
  6757.     extern int ttprty, ttpflg;
  6758.     int ttpmsk;
  6759.  
  6760.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
  6761.  
  6762.     debug(F101,"x25inl max","",max);
  6763.     debug(F101,"x25inl eol","",eol);
  6764.     pdest  = dest;
  6765.     rest   = max;
  6766.     goteol = 0;
  6767.     do {
  6768.         n = read(ttyfd,pdest,rest);
  6769.         n--;
  6770.         pktype = *pdest & 0x7f;
  6771.         switch (pktype) {
  6772.           case 1 << Q_BIT:
  6773.             if (qbitpkt(pdest+1,--n) < 0) return(-2);
  6774.             break;
  6775.           default:
  6776.             if (flag == 0) { /* if not in packet, search start */
  6777.                 for (i = 1; (i < n) &&
  6778.                      !(flag = ((dest[i] & 0x7f) == start));
  6779.                      i++);
  6780.                 if (flag == 0) { /* not found, discard junk */
  6781.                     debug(F101,"x25inl skipping","",n);
  6782.                     continue;
  6783.                 } else {                /* found, discard junk before start */
  6784.                     int k;
  6785.                     n = n - i + 1;
  6786.                     for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
  6787.                 }
  6788.             }
  6789.             for (i = 0; (i < n) && /* search for eol */
  6790.                  !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
  6791.                  i++,pdest++);
  6792.             *pdest = '\0';
  6793.             rest -= n;
  6794.         }
  6795.     } while ((rest > 0) && (!goteol));
  6796.  
  6797.     if (goteol) {
  6798.         n = max - rest;
  6799.         debug (F111,"x25inl X.25 got",(char *) dest,n);
  6800.         if (timo) ttimoff();
  6801.         if (ttpflg++ == 0 && ttprty == 0) {
  6802.             if ((ttprty = parchk(dest,start,n)) > 0) {
  6803.                 int j;
  6804.                 debug(F101,"x25inl senses parity","",ttprty);
  6805.                 debug(F110,"x25inl packet before",(char *)dest,0);
  6806.                 ttpmsk = 0x7f;
  6807.                 for (j = 0; j < n; j++)
  6808.                   dest[j] &= 0x7f; /* Strip parity from packet */
  6809.                 debug(F110,"x25inl packet after ",dest,0);
  6810.             } else {
  6811.                 debug(F101,"parchk","",ttprty);
  6812.                 if (ttprty < 0) { ttprty = 0; n = -1; }
  6813.             }
  6814.         }
  6815.         ttimoff();
  6816.         return(n);
  6817.     }
  6818.     ttimoff();
  6819.     return(-1);
  6820. }
  6821. #endif /* COMMENT */
  6822. #endif /* SUNX25 */
  6823.  
  6824. #ifdef IBMX25
  6825. /*
  6826.  * IBM X25 support - using the NPI streams interface
  6827.  * written by Stephen Riehm, pc-plus, Munich Germany
  6828.  */
  6829.  
  6830. /* riehm: missing functions / TODO list */
  6831.  
  6832. /*
  6833.   x25intr() - Send an interrupt packet
  6834. */
  6835.  
  6836. /* return an error message depending on packet type */
  6837. char *
  6838. x25err(n) int n; {
  6839.     static char buf[30];
  6840.     switch (n) {
  6841.       case NBADADDR:     return "invalid address";
  6842.       case NBADOPT:      return "invalid options";
  6843.       case NACCESS:      return "no permission";
  6844.       case NNOADDR:      return "unable to allocate address";
  6845.       case NOUTSTATE:    return "invalid state";
  6846.       case NBADSEQ:      return "invalid sequence number";
  6847.       case NSYSERR:      return "system error";
  6848.       case NBADDATA:     return "invalid data size";
  6849.       case NBADFLAG:     return "invalid flag";
  6850.       case NNOTSUPPORT:  return "unsupported primitive";
  6851.       case NBOUND:       return "address in use";
  6852.       case NBADQOSPARAM: return "bad QOS parameters";
  6853.       case NBADQOSTYPE:  return "bad QOS type";
  6854.       case NBADTOKEN:    return "bad token value";
  6855.       case NNOPROTOID:   return "protocol id could not be allocated";
  6856.       case NODDCUD:      return "odd length call user data";
  6857.       default: (void) sprintf(buf, "Unknown NPI error %d", n); return buf;
  6858.     }
  6859. }
  6860.  
  6861. /* turn a meaningless primitive number into a meaningful primitive name */
  6862. char *
  6863. x25prim(n) int n; {
  6864.     static char buf[30];
  6865.     switch(n) {
  6866.       case N_BIND_ACK:     return "N_BIND_ACK";
  6867.       case N_BIND_REQ:     return "N_BIND_REQ";
  6868.       case N_CONN_CON:     return "N_CONN_CON";
  6869.       case N_CONN_IND:     return "N_CONN_IND";
  6870.       case N_CONN_REQ:     return "N_CONN_REQ";
  6871.       case N_CONN_RES:     return "N_CONN_RES";
  6872.       case N_DATACK_IND:   return "N_DATAACK_IND";
  6873.       case N_DATACK_REQ:   return "N_DATAACK_REQ";
  6874.       case N_DATA_IND:     return "N_DATA_IND";
  6875.       case N_DATA_REQ:     return "N_DATA_REQ";
  6876.       case N_DISCON_IND:   return "N_DISCON_IND";
  6877.       case N_DISCON_REQ:   return "N_DISCON_REQ";
  6878.       case N_ERROR_ACK:    return "N_ERROR_ACK";
  6879.       case N_EXDATA_IND:   return "N_EXDATA_IND";
  6880.       case N_EXDATA_REQ:   return "N_EXDATA_REQ";
  6881.       case N_INFO_ACK:     return "N_INFO_ACK";
  6882.       case N_INFO_REQ:     return "N_INFO_REQ";
  6883.       case N_OK_ACK:       return "N_OK_ACK";
  6884.       case N_OPTMGMT_REQ:  return "N_OPTMGMT_REQ";
  6885.       case N_RESET_CON:    return "N_RESET_CON";
  6886.       case N_RESET_IND:    return "N_RESET_IND";
  6887.       case N_RESET_REQ:    return "N_RESET_REQ";
  6888.       case N_RESET_RES:    return "N_RESET_RES";
  6889.       case N_UDERROR_IND:  return "N_UDERROR_IND";
  6890.       case N_UNBIND_REQ:   return "N_UNBIND_REQ";
  6891.       case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
  6892.       case N_UNITDATA_IND: return "N_UNITDATA_IND";
  6893.       default: (void) sprintf(buf, "UNKNOWN (%d)", n); return buf;
  6894.     }
  6895. }
  6896.  
  6897. /*****************************************************************************
  6898.  * Function: x25getmsg()
  6899.  * Description: get a STREAMS message, and check it for errors
  6900.  *
  6901.  * Parameters:
  6902.  * fd           - file descriptor to x25 device (opened)
  6903.  * control      - control buffer (pre-allocated)
  6904.  * ctl_size     - size of control buffer
  6905.  * data         - data buffer (pre-allocated)
  6906.  * data_size    - size of data buffer
  6907.  * flags        - flags for getmsg()
  6908.  * expected     - expected Primitive type
  6909.  *
  6910.  * Return Value:
  6911.  *      >= 0    OK (size of data returned)
  6912.  *      -1      error
  6913.  *
  6914.  */
  6915. int
  6916. x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
  6917.     int                 fd;             /* X25 device (opened) */
  6918.     N_npi_ctl_t         *control;       /* control buffer (pre-allocated) */
  6919.     int                 ctl_size;       /* size of control buffer */
  6920.     N_npi_data_t        *data;          /* data buffer (pre-allocated) */
  6921.     int                 data_size;      /* size of data buffer */
  6922.     int                 *get_flags;     /* getmsg() flags */
  6923.     int                 expected;       /* expected primitive type */
  6924. /* x25getmsg */ {
  6925.     int                 rc = 0;         /* return code */
  6926.     struct strbuf       *get_ctl=NULL;  /* getmsg control */
  6927.     struct strbuf       *get_data=NULL; /* getmsg data */
  6928.     int                 more = 0;       /* flag for more data etc */
  6929.     int                 file_status = -1; /* file async status */
  6930.     N_npi_ctl_t         * result;       /* pointer to simplify switch() */
  6931.     int                 packet_type = -1; /* unknown packet thus far */
  6932.  
  6933. #ifdef TRACE
  6934.     printf( "TRACE: entering x25getmsg\n" );
  6935. #endif /* TRACE */
  6936.  
  6937.     debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
  6938.     /* prepare the control structures for getmsg */
  6939.     if (control) {
  6940.         if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
  6941.           {
  6942.               perror("kermit x25getmsg(): get_ctl malloc failed\n");
  6943.               debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
  6944.               return(-1);
  6945.           }
  6946.         /* allow getmsg to return an unexpected packet type (which may be
  6947.          * larger than the expected one)
  6948.          */
  6949.         get_ctl->maxlen = NPI_MAX_CTL;
  6950.         get_ctl->len = 0;
  6951.         get_ctl->buf = (char *)control;
  6952.     } else {
  6953.         printf(
  6954.  "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
  6955.                );
  6956.         debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
  6957.         return( -1 );
  6958.     }
  6959.     if (data) {
  6960.         if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
  6961.           {
  6962.             perror("kermit x25getmsg(): get_data malloc failed\n");
  6963.             debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
  6964.             return(-1);
  6965.         }
  6966.         get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
  6967.           NPI_MAX_DATA :
  6968.             data_size;
  6969.         get_data->len = 0;
  6970.         get_data->buf = (char *)data;
  6971.     }
  6972.  
  6973.     /* get an X.25 packet -
  6974.      * it may be any kind of packet, so check for special cases
  6975.      * it may be split into multiple parts - so loop if necessary
  6976.      */
  6977.     do {
  6978. #ifdef DEBUG
  6979.         printf( "kermit: x25getmsg(): getting a message\n" );
  6980. #endif /* DEBUG */
  6981.         errno = 0;
  6982.         if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
  6983. #ifdef DEBUG
  6984.             printf( "kermit: x25getmsg(): getmsg returned an error\n" );
  6985.             perror( "getmsg error was" );
  6986. #endif /* DEBUG */
  6987.             debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
  6988.             if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
  6989.                 /* was in non-blocking mode, nothing to get, but we're
  6990.                  * already waiting for the rest of the packet -
  6991.                  * switch to blocking mode for the next read.
  6992.                  * file_status used to reset file status before returning
  6993.                  */
  6994.                 if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
  6995.                     || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
  6996.                   {
  6997.                       perror("x25getmsg(): couldn't change x25 blocking mode");
  6998.                       debug(F101,
  6999.                             "x25getmsg fcntl returned an error\n", "", errno);
  7000.                       /* netclos(); */
  7001.                       rc = -1;
  7002.                       break;
  7003.                   } else {
  7004.                       /* loop again into a blocking getmsg() */
  7005.                       continue;
  7006.                   }
  7007.             } else {
  7008.                 /* no data to get in non-blocking mode - return empty handed */
  7009.                 perror( "x25getmsg(): getmsg failed" );
  7010.                 debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
  7011.                 rc = -1;
  7012.                 break;
  7013.             }
  7014.         } else if (more & MORECTL) {
  7015.             /* panic - the control information was larger than the
  7016.              * maximum control buffer size!
  7017.              */
  7018.             /* riehm: close connection? */
  7019. #ifdef DEBUG
  7020.             printf("x25getmsg(): received partial control packet - panic\n");
  7021. #endif /* DEBUG */
  7022.             debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
  7023.             rc = -1;
  7024.             break;
  7025.         }
  7026.  
  7027.         if (result = (N_npi_ctl_t *)control) {
  7028.             packet_type = result->bind_ack.PRIM_type;
  7029.             if (packet_type != N_OK_ACK) {
  7030.                 x25lastmsg = packet_type;
  7031.             }
  7032.         }
  7033. #ifdef DEBUG
  7034.         /* printf( "kermit: x25getmsg(): getting " ); */
  7035.         if (get_ctl->len > 0) {
  7036.             x25dump_prim(result);
  7037.         }
  7038.         debug(F110,
  7039.               "x25getmsg got packet ",
  7040.               x25prim( result->bind_ack.PRIM_type ),
  7041.               0
  7042.               );
  7043. #endif /* DEBUG */
  7044.  
  7045.         if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
  7046.             /* not as pretty as a switch(), but switch can't handle
  7047.              * runtime variable values :-(
  7048.              */
  7049.             if (packet_type == expected ) {
  7050.                 /* got what we wanted, special case for DATA_IND
  7051.                  * packets though */
  7052.                 /* riehm: check Q-bit ? */
  7053. #ifdef DEBUG
  7054.                 printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
  7055. #endif /* DEBUG */
  7056.                 if (packet_type == N_DATA_IND ) {
  7057.                     /* data received. May be incomplete, even though
  7058.                      * getmsg returned OK
  7059.                      */
  7060.                     if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
  7061.                         more |= MOREDATA;
  7062.                     if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
  7063.                         printf( "x25getmsg(): data packet wants ack\n" );
  7064.                 }
  7065.             } else if( packet_type == N_DISCON_IND) {
  7066.                 printf( "X25 diconnected\n" );
  7067.                 /* riehm: need to acknowledge a disconnection? */
  7068.                 x25clear();
  7069.                 /* x25unbind( ttyfd ); */
  7070.                 rc = -1;
  7071.             } else if( packet_type == N_ERROR_ACK) {
  7072.                 errno = result->error_ack.UNIX_error;
  7073.                 perror( "X25 error received" );
  7074.                 rc = -1;
  7075.             } else {
  7076.                 printf("x25getmsg(): failed %s\n", x25err(packet_type));
  7077.                 rc = -1;
  7078.             }
  7079.         }
  7080. #ifdef COMMENT
  7081.         else {
  7082.             /* Panic - no control data */
  7083.             printf( "kermit: x25getmsg(): no control data with packet\n" );
  7084.             rc = -1;
  7085.         }
  7086. #endif /* COMMENT */
  7087.  
  7088.         if (get_data && (get_data->len >= 0)) {
  7089.             get_data->buf += get_data->len;
  7090.             get_data->maxlen -= get_data->len;
  7091.         }
  7092.     } while ((rc == 0)
  7093.              && (get_data && (get_data->maxlen > 0))
  7094.              && (more & MOREDATA)
  7095.              );
  7096.  
  7097.     /* return the file status to its original value, unless its still
  7098.      * set to -1, or one of the fcntl's failed */
  7099.     if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
  7100.         rc = -1;
  7101.  
  7102.     /*
  7103.      * Verify that we received an expected primitive
  7104.      * there is apparantly an error case where the primitive is set
  7105.      * correctly, but there is not enough data in the control structure
  7106.      */
  7107.     if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
  7108.         fprintf(stderr,
  7109.                 "x25getmsg(): %s NOT received. Primitive received was %s\n",
  7110.                 x25prim( expected ), x25prim( packet_type ));
  7111.         debug(F110, "x25getmsg got an unexpected packet ",
  7112.               x25prim(packet_type),
  7113.               0
  7114.               );
  7115.         rc = -1;
  7116.     }
  7117.  
  7118.     if (rc == 0) {
  7119.         if (get_data && ( get_data->len >= 0)) {
  7120.             rc = get_data->len;
  7121.         }
  7122.     }
  7123.  
  7124.     if (get_ctl)  { free(get_ctl); get_ctl = NULL; }
  7125.     if (get_data) { free(get_data); get_data = NULL; }
  7126.  
  7127. #ifdef COMMENT
  7128. #ifdef DEBUG
  7129.     printf( "kermit x25getmsg(): returning %d\n", rc );
  7130. #endif /* DEBUG */
  7131. #endif /* COMMENT */
  7132.     debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
  7133.  
  7134. #ifdef TRACE
  7135.     printf( "TRACE: leaving x25getmsg\n" );
  7136. #endif /* TRACE */
  7137.     return(rc);
  7138. }
  7139.  
  7140. /*****************************************************************************
  7141.  * Function: x25putmsg()
  7142.  *
  7143.  * Description:
  7144.  *      send a message to a X25 STREAM
  7145.  *
  7146.  * Parameters:
  7147.  *      fd              - file descriptor to x25 device (opened)
  7148.  *      control         - control buffer (pre-allocated)
  7149.  *      data            - data buffer (pre-allocated)
  7150.  *      data_len        - length of data to be transmitted
  7151.  *      put_flags       - flags for putmsg()
  7152.  *
  7153.  * Return Value:
  7154.  *      >= 0    number of bytes transmitted
  7155.  *      -1      error
  7156.  */
  7157. int
  7158. x25putmsg(fd, control, data, data_len, put_flags)
  7159.     int                 fd;             /* X25 device (opened) */
  7160.     N_npi_ctl_t         *control;       /* control buffer (pre-allocated) */
  7161.     N_npi_data_t        *data;          /* data buffer (pre-allocated) */
  7162.     int                 data_len;       /* length of data (not the size of
  7163.                                            the buffer) */
  7164.     int                 *put_flags;     /* putmsg() flags */
  7165. /* x25putmsg */ {
  7166.     int                 rc = 0;         /* return code */
  7167.     ulong               type;           /* primitive type */
  7168.     struct strbuf       *put_ctl = NULL; /* putmsg control */
  7169.     struct strbuf       *put_data = NULL; /* putmsg data */
  7170.  
  7171. #ifdef TRACE
  7172.     printf( "TRACE: entering x25putmsg\n" );
  7173. #endif /* TRACE */
  7174.  
  7175. #ifdef DEBUG
  7176.     printf( "kermit: x25putmsg(): putting " );
  7177.     x25dump_prim( control );
  7178.     printf( "\tdata:\t\t" );
  7179.     x25dump_data( data, 0, data_len );
  7180.     debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
  7181. #endif /* DEBUG */
  7182.  
  7183.     if (control) {
  7184.         put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
  7185.         if (put_ctl == NULL) {
  7186.             perror("kermit x25putmsg(): put_ctl malloc failed\n");
  7187.             return(-1);
  7188.         }
  7189.         put_ctl->maxlen = 0;                    /* unused by putmsg */
  7190.         put_ctl->len = NPI_MAX_CTL;
  7191.         put_ctl->buf = (char *)control;
  7192.     }
  7193.     if (data && ( data_len > 0)) {
  7194.         put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
  7195.         if( put_data == NULL) {
  7196.             perror("kermit x25putmsg(): put_data malloc failed\n");
  7197.             return(-1);
  7198.         }
  7199.         put_data->maxlen = 0;                   /* unused by putmsg */
  7200.         put_data->len = data_len;
  7201.         put_data->buf = (char *)data;
  7202.     }
  7203.  
  7204.     errno = 0;
  7205.     rc = putmsg (fd, put_ctl, put_data, 0);
  7206.     if (rc < 0) {
  7207.         printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
  7208.         perror("kermit: x25putmsg(): putmsg failed");
  7209.         return(-1);
  7210.     }
  7211.  
  7212.     /* riehm: this should perhaps be discounted! */
  7213.     x25lastmsg = control->PRIM_type;
  7214.  
  7215. #ifdef COMMENT
  7216. #ifdef DEBUG
  7217.     printf( "kermit debug: x25putmsg() returning %d\n", data_len );
  7218. #endif /* DEBUG */
  7219. #endif /* COMMENT */
  7220.     debug( F101, "x25putmsg block size put ", "", data_len);
  7221.  
  7222. #ifdef TRACE
  7223.     printf( "TRACE: leaving x25putmsg\n" );
  7224. #endif /* TRACE */
  7225.  
  7226.     return( data_len );
  7227. }
  7228.  
  7229. /*****************************************************************************
  7230. * Function: x25bind
  7231. * Description:  The bind submitted to NPI provides the information required
  7232. *               by the packet layer for it to listen for suitable incoming
  7233. *               calls.
  7234. *
  7235. * WARNING:
  7236. *
  7237. * This routine needs to be called in a completely different manner for
  7238. * the client and server side. When starting a client, the
  7239. * num_waiting_calls and CUD information should all be set to 0! The
  7240. * client's CUD must be inserted in the CONN_REQ data block.
  7241. * When starting a server, the CUD must be set to a CUD pattern, and
  7242. * the number of waiting calls should be set to a number other than 0.
  7243. * (num waiting calls is the number of incomming calls which are to be
  7244. * put on hold while the server is servicing another client.)
  7245. *
  7246. * Who invented this crap?
  7247. *
  7248. * Parameters:
  7249. *       fd              - X25 device (opened)
  7250. *       addr            - local address
  7251. *       cud             - User Data (null terminated)
  7252. *       cud_len         - User Data length
  7253. *       num_waiting_calls - number of outstanding calls allowed on this stream
  7254. *       line            - logical port number (1)
  7255. *       flags           - 0, DEFAULT_LISTENER or TOKEN_REQUEST
  7256. *
  7257. * Return Value:
  7258. *       if binding is successful, 0 is returned for a client, and a token is
  7259. *       returned for a server
  7260. *
  7261. * Return code: 0 if successful
  7262. *              -1 if unsuccessful
  7263. *****************************************************************************/
  7264.  
  7265. ulong
  7266. x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
  7267.     int fd;                             /* X25 device (opened) */
  7268.     char * addr;                        /* local address */
  7269.     char * cud;                         /* Call User Data (null terminated) */
  7270.     int cud_len;                        /* User Data length */
  7271.     int num_waiting_calls;              /* Outstanding calls allowed */
  7272.     int line;                           /* logical port number */
  7273.     ulong bind_flags;           /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
  7274. /* x25bind */ {
  7275.     ulong rc;                           /* return code */
  7276.     int get_flags;                      /* priority flag passed to getmsg */
  7277.     int put_flags = 0;                  /* output flags for putmsg, always 0 */
  7278.     ulong type;                         /* primitive type */
  7279.     N_bind_req_t *bind_req;             /* pointer to N_BIND_REQ primitive */
  7280.     N_bind_ack_t *bind_ack;             /* pointer to N_BIND_ACK primitive */
  7281.     char *addtl_info;                   /* pointer to info in addition to
  7282.                                          * the N_BIND_REQ primitive that is
  7283.                                          * passed in the control structure
  7284.                                          * to putmsg */
  7285.     int addr_len = 0;                   /* length of address string */
  7286.     ulong bind_req_t_size;              /* for debugging only */
  7287.  
  7288. #ifdef TRACE
  7289.     printf("TRACE: entering x25bind\n" );
  7290. #endif /* TRACE */
  7291.  
  7292. #ifdef DEBUG
  7293.     printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
  7294.            fd, addr, cud, line, bind_flags
  7295.            );
  7296. #endif /* DEBUG */
  7297.  
  7298.     /*
  7299.      * Allocate  and zero out space to hold the control portion of the
  7300.      * message passed to putmsg. This will contain the N_BIND_REQ
  7301.      * primitive and any additional info required for that.
  7302.      *
  7303.      * Note: allocated space is the size of the union typedef
  7304.      * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
  7305.      */
  7306.     bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
  7307.     if (bind_req == NULL) {
  7308.         perror("kermit: x25bind(): bind_req malloc failed");
  7309.         debug(F100, "x25bind bind_req malloc failed", "", 0);
  7310.         return(-1);
  7311.     }
  7312.     bzero((char *)bind_req, sizeof(N_npi_ctl_t));
  7313.  
  7314.     /* Build the Bind Request Primitive */
  7315.     bind_req->PRIM_type = (ulong) N_BIND_REQ;
  7316.  
  7317.     /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
  7318.      * the actual address in an N_BIND_REQ. The first byte contains the
  7319.      * line number being used with this address, and the second byte is the
  7320.      * X.121 address prefix, which must be zero.
  7321.      */
  7322.     addr_len = strlen(addr);
  7323.     bind_req->ADDR_length = (ulong) (addr_len + 2);
  7324.     bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
  7325.     bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
  7326.     bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
  7327.     bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
  7328.     if (cud_len == 0) {
  7329.         bind_req->PROTOID_offset = (ulong) 0;
  7330.     } else {
  7331.         /* need to remember the trailing NULL in the address - not
  7332.          * counted in the address length
  7333.          */
  7334.         bind_req->PROTOID_offset
  7335.           = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
  7336.     }
  7337.  
  7338.     /*
  7339.      * Now fill in the additional information required with this primitive
  7340.      * (address and protocol information (Call User Data))
  7341.      */
  7342.     addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
  7343.     /*
  7344.      * The bitwise "&" ensures that the line number is only one byte long
  7345.      */
  7346.     *addtl_info++ = (char) line & 0xff;
  7347.     *addtl_info++ = (char) 0; /* X.121 format */
  7348.     bcopy( addr, addtl_info, addr_len ); /* include trailing null */
  7349.     addtl_info += addr_len;
  7350.     if (cud_len > 0)
  7351.       bcopy( cud, addtl_info, cud_len );
  7352.     /*
  7353.      * Call putmsg() to put the bind request message on the stream
  7354.      */
  7355.     if (x25putmsg(fd,
  7356.                   (N_npi_ctl_t*)bind_req,
  7357.                   (N_npi_data_t *)NULL,
  7358.                   0,
  7359.                   &put_flags
  7360.                   ) < 0) {
  7361.         printf( "kermit: x25bind(): x25putmsg failed\n" );
  7362.         return(-1);
  7363.     }
  7364.  
  7365.     /*
  7366.      * Allocate and zero out space for the N_BIND_ACK primitive
  7367.      */
  7368.     bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
  7369.     if (bind_ack == NULL){
  7370.         perror("kermit: x25bind(): bind_ack malloc failed");
  7371.         return(-1);
  7372.     }
  7373.     bzero(bind_ack, sizeof(N_npi_ctl_t));
  7374.     /*
  7375.      * Initialize the control structure and flag variable sent to getmsg
  7376.      */
  7377.     get_flags=0;
  7378.  
  7379.     /* get the ACK for the bind */
  7380. #ifdef DEBUG
  7381.     printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
  7382. #endif /* DEBUG */
  7383.     rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
  7384.             (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
  7385.             N_BIND_ACK );
  7386.  
  7387.     /* turn quantitive return code into a qualitative one */
  7388.     if (rc > 0) rc = 0;
  7389.  
  7390.     /* if all went well, get the token from the acknowledgement packet */
  7391.     if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
  7392.         rc = bind_ack->TOKEN_value;
  7393.     }
  7394.  
  7395.     /* free up the memory we allocated earlier */
  7396.     free(bind_req);
  7397.     free(bind_ack);
  7398.  
  7399. #ifdef TRACE
  7400.     printf( "TRACE: leaving x25bind\n" );
  7401. #endif /* TRACE */
  7402.  
  7403.     return( rc );
  7404. }
  7405.  
  7406. /*****************************************************************************
  7407. * Function: x25call
  7408. * Description:  This routine builds and sends an N_CONN_REQ primitive, then
  7409. *               checks for an N_CONN_CON primitive in return.
  7410. *
  7411. * Parameters:
  7412. * fd    - file descriptor of stream
  7413. * caddr - called address (remote address)
  7414. *
  7415. * Functions Referenced:
  7416. * malloc()
  7417. * bzero()
  7418. * getmsg()
  7419. * putmsg()
  7420. *
  7421. * Return code:
  7422. * 0 - if successful
  7423. * -1 if not successful
  7424. *****************************************************************************/
  7425. int
  7426. x25call(fd, remote_nua, cud)
  7427.     int fd;                             /* X25 device (opened) */
  7428.     char * remote_nua;                  /* remote address to call */
  7429.     char * cud;                         /* call user data */
  7430. /* x25call */ {
  7431.     int rc;                             /* return code */
  7432.     int flags;                          /* Connection flags */
  7433.     int get_flags;                      /* priority flags for getmsg */
  7434.     ulong type;                         /* primitive type */
  7435.     N_conn_req_t *connreq_ctl;          /* pointer to N_CONN_REQ primitive */
  7436.     N_npi_data_t *connreq_data;         /* pointer to N_CONN_REQ data (CUD) */
  7437.     int connreq_data_len;               /* length of filled data buffer */
  7438.     N_conn_con_t *conncon_ctl;          /* pointer to N_CONN_CON primitive */
  7439.     N_npi_data_t *conncon_data;         /* pointer to any data associated with
  7440.                                          * the N_CONN_CON primitive */
  7441.     char *addtl_info;                   /* pointer to additional info needed
  7442.                                          * for N_CONN_REQ primitive */
  7443.     int addr_len;                       /* length of address */
  7444.  
  7445. #ifdef TRACE
  7446.     printf( "TRACE: entering x25call\n" );
  7447. #endif /* TRACE */
  7448.  
  7449. #ifdef DEBUG
  7450.     printf( "x25call( %d, %s )\n", fd, remote_nua );
  7451.     printf( "connecting to %s on fd %d\n", remote_nua, fd );
  7452. #endif /* DEBUG */
  7453.  
  7454.     /*
  7455.      * Allocate and zero out space for the N_CONN_REQ primitive
  7456.      * use the size of the generic NPI primitive control buffer
  7457.      */
  7458.     connreq_ctl  = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
  7459.     if (connreq_ctl == NULL){
  7460.         perror("kermit: x25call(): connreq_ctl malloc failed");
  7461.         return(-1);
  7462.     }
  7463.     bzero(connreq_ctl,sizeof(N_npi_ctl_t));
  7464.     /*
  7465.      * Build the Connection Request Primitive
  7466.      */
  7467.     flags = 0;
  7468.     connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
  7469.  
  7470.     /* Note that the address length is nchai+1 and not n+2. The line number
  7471.      * is only passed with the address for the bind. The first byte of
  7472.      * the address for the N_CONN primitives contains the X.121
  7473.      * address prefix, which must be zero. The remaining bytes are the
  7474.      * address itself.
  7475.      */
  7476.     addr_len = strlen( remote_nua );
  7477.     connreq_ctl->DEST_length = (ulong) (addr_len + 1);
  7478.     connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
  7479.     /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
  7480.     connreq_ctl->CONN_flags = (ulong) 0;
  7481.     connreq_ctl->QOS_length = (ulong) 0;        /* unsupported in AIX 4.1 */
  7482.     connreq_ctl->QOS_offset = (ulong) 0;        /* unsupported in AIX 4.1 */
  7483.  
  7484.     addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
  7485.     *addtl_info++ = (char) 0; /* X.121 format */
  7486.     bcopy( remote_nua, addtl_info, addr_len );
  7487.  
  7488.     /*
  7489.      * setup the data buffer for the connection request
  7490.      */
  7491.     connreq_data  = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
  7492.     if (connreq_data == NULL){
  7493.         perror("kermit: x25call(): connreq_data malloc failed");
  7494.         return(-1);
  7495.     }
  7496.     bzero(connreq_data,sizeof(N_npi_data_t));
  7497.  
  7498.     /* facility selection needs to be put in the front of connreq_data */
  7499.     connreq_data_len = 0;
  7500.     connreq_data_len += x25facilities( (char *)connreq_data );
  7501.     if (cud && *cud) {
  7502.         bcopy(cud,
  7503.               (char *)((char *)connreq_data + connreq_data_len),
  7504.               strlen(cud)
  7505.               );
  7506.         connreq_data_len += strlen( cud );
  7507.         }
  7508.  
  7509.     /*
  7510.      * Call putmsg() to put the connection request message on the stream
  7511.      */
  7512.     rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
  7513.             connreq_data_len, &flags );
  7514.     if (rc < 0) {
  7515.         return(-1);
  7516.     }
  7517.  
  7518.     /*
  7519.      * Allocate and zero out space for the N_CONN_CON primitive
  7520.      */
  7521.     if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
  7522.         perror("kermit: x25call(): conncon_ctl malloc failed");
  7523.         return(-1);
  7524.     }
  7525.     bzero(conncon_ctl, sizeof(N_npi_ctl_t));
  7526.  
  7527.     /*
  7528.      * Allocate and zero out space for any data associated with N_CONN_CON
  7529.      */
  7530.     if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
  7531.         perror("kermit: x25call(): conncon_data malloc failed");
  7532.         return(-1);
  7533.     }
  7534.     bzero(conncon_data, NPI_MAX_DATA);
  7535.  
  7536.     /* Initialize and build the structures for getmsg */
  7537.     get_flags=0;
  7538.  
  7539.     rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
  7540.             conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
  7541.  
  7542.     /* turn quantitive return code into a qualitative one */
  7543.     if (rc > 0) rc = 0;
  7544.  
  7545.     /* Free the space that we no longer need */
  7546.     if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
  7547.     if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
  7548.     if (conncon_data) { free(conncon_data); conncon_data = NULL; }
  7549.  
  7550. #ifdef TRACE
  7551.     printf( "TRACE: leaving x25call\n" );
  7552. #endif /* TRACE */
  7553.  
  7554.     return(rc);
  7555. }
  7556.  
  7557. /*****************************************************************************
  7558.  * Function: x25getcall
  7559.  *
  7560.  * Description: This routine checks for an incomming call, verified
  7561.  * that it is a CONNIND (connection indication) message, and then
  7562.  * accepts the call and returns the file descriptor of the new stream
  7563.  *
  7564.  * Parameters:
  7565.  * fd   - file descriptor of listening stream
  7566.  *
  7567.  * Return Codes:
  7568.  * callfd       - file descriptor of connected incomming call.
  7569.  *              - set to -1 if an error occured
  7570.  *
  7571.  *****************************************************************************/
  7572. int
  7573. x25getcall(fd) int fd; {
  7574.     int x25callfd;                      /* fd of incomming call */
  7575.     N_conn_ind_t *connind_ctl;          /* connind controll buffer */
  7576.     N_npi_data_t *connind_data;         /* connind data buffer */
  7577.     int get_flags;                      /* flags for getmsg */
  7578.     ulong flags;                        /* connection flags */
  7579.     int rc;                             /* return code */
  7580.  
  7581.     extern x25addr_t remote_nua;        /* remote X.25 addr global var */
  7582.  
  7583. #ifdef TRACE
  7584.     printf( "TRACE: entering x25getcall\n" );
  7585. #endif /* TRACE */
  7586.  
  7587.     /* allocate space for connection indication buffers */
  7588.     if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
  7589.         perror("kermit: x25getcall(): connind_ctl malloc failed");
  7590.         return (-1);
  7591.     }
  7592.     bzero(connind_ctl, sizeof(N_npi_ctl_t));
  7593.  
  7594.     if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
  7595.         perror("kermit: x25getcall(): connind_data malloc failed");
  7596.         return (-1);
  7597.     }
  7598.     bzero(connind_data, NPI_MAX_DATA);
  7599.  
  7600.     /* initialise control structures */
  7601.     get_flags = 0;
  7602.  
  7603.     /* call getmsg to check for a connection indication */
  7604.     if (x25getmsg(fd,
  7605.                   (N_npi_ctl_t*)connind_ctl,
  7606.                   (int)sizeof(N_conn_ind_t),
  7607.                   connind_data,
  7608.                   NPI_MAX_DATA,
  7609.                   &get_flags,
  7610.                   N_CONN_IND
  7611.                   ) < 0) {
  7612. #ifdef DEBUG
  7613.         printf( "x25getcall(): errno is: %d\n", errno );
  7614. #endif /* DEBUG */
  7615.         perror ("x25getcall(): getmsg failed");
  7616.         return(-1);
  7617.     }
  7618.  
  7619.     /* a connection indication was received
  7620.      * - pull it to bits and answer the call
  7621.      */
  7622.     x25seqno = connind_ctl->SEQ_number;
  7623.     flags = connind_ctl->CONN_flags;
  7624. #ifdef DEBUG
  7625.     printf( "setting remote_nua to a new value due to incomming call\n" );
  7626. #endif /* DEBUG */
  7627.     /*
  7628.      * no guarantee that the address is null terminated, ensure that
  7629.      * after copying that it is (assumption: remote_nua is longer than
  7630.      * the address + 1)
  7631.      */
  7632.     bzero(remote_nua, sizeof(remote_nua));
  7633.     /* note: connind_ctl contains a x121 address, which has a null as
  7634.      * the FIRST character - strip it off!
  7635.      */
  7636.     ckstrncpy(remote_nua,
  7637.             (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
  7638.             connind_ctl->SRC_length - 1
  7639.             );
  7640. #ifdef DEBUG
  7641.     printf( "remote_nua set to new value of %s\n", remote_nua );
  7642. #endif /* DEBUG */
  7643.  
  7644.     /* errors handled by callee */
  7645.     x25callfd = x25accept(x25seqno, flags);
  7646.  
  7647.     /* free the malloc'd buffers */
  7648.     if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
  7649.     if (connind_data) { free(connind_data); connind_data = NULL; }
  7650.  
  7651. #ifdef TRACE
  7652.     printf( "TRACE: leaving x25getcall\n" );
  7653. #endif /* TRACE */
  7654.  
  7655.     /* return the file descriptor (or error if < 0) */
  7656.     return( x25callfd );
  7657. }
  7658.  
  7659. /*****************************************************************************
  7660.  * Function: x25accept
  7661.  *
  7662.  * Description: accept an incomming call
  7663.  *              This essentially means opening a new STREAM and sending
  7664.  *              an acknowledge back to the caller.
  7665.  *
  7666.  * Parameters:
  7667.  *      seqno   - sequence number for acknowledgement
  7668.  *      flags   - flags passed to us by the caller
  7669.  *
  7670.  * Return Codes:
  7671.  *      fd      - file descriptor of new STREAM
  7672.  *                set to -1 if an error occured
  7673.  *
  7674.  *****************************************************************************/
  7675. int
  7676. x25accept(seqno,flags)
  7677.     ulong seqno;                        /* connection sequence number */
  7678.     ulong flags;                        /* connection flags */
  7679. /* x25accept */ {
  7680.     int x25callfd;                      /* fd for incomming call */
  7681.     int get_flags;                      /* priority flags for getmsg */
  7682.     int put_flags = 0;                  /* flags for putmsg, always 0 */
  7683.     int addr_len;                       /* length of local address */
  7684.     ulong token;                        /* connection token */
  7685.     N_conn_res_t *conn_res;             /* N_CONN_RES primitive */
  7686.     N_ok_ack_t *ok_ack;                 /* N_OK_ACK primitive */
  7687.     char *addtl_info;                   /* temp pointer */
  7688.     int rc;                             /* temporary return code */
  7689.  
  7690. /* global variables from ckcmai.c */
  7691.     extern int revcall, closgr, cudata;
  7692.     extern char udata[];
  7693.     extern x25addr_t local_nua;         /* local X.25 address */
  7694.     extern char x25name[];              /* x25 device name (sx25a0) */
  7695.     extern char x25dev[];               /* x25 device file /dev/x25pkt */
  7696.     extern int x25port;                 /* logical port to use */
  7697.     ulong bind_flags = 0;               /* flags for binding the X25 stream */
  7698.  
  7699. #ifdef TRACE
  7700.     printf( "TRACE: entering x25accept\n" );
  7701. #endif /* TRACE */
  7702.  
  7703.     /* open a new packet level stream */
  7704.     if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
  7705.         perror ("kermit: x25accept(): X.25 device open error");
  7706.         debug(F101,"x25accept() device open error","",errno);
  7707.         return(-1);
  7708.     }
  7709.  
  7710.     /* push the NPI onto the STREAM */
  7711.     if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
  7712.         perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
  7713.         debug(F101,"x25accept can't push npi on the X25 stream","",errno);
  7714.         return (-1);
  7715.     }
  7716.  
  7717.     /* bind kermit server to the local X25 address */
  7718.     /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
  7719.     bind_flags |= TOKEN_REQUEST;
  7720.     token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
  7721.     if (token < 0) {
  7722.         printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
  7723.         netclos();
  7724.         return(-1);
  7725.     }
  7726.  
  7727.     /* allocate connection response primitive */
  7728.     if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
  7729.         perror("kermit: x25accept(): conn_res malloc failed");
  7730.         return (-1);
  7731.     }
  7732.     bzero((char *)conn_res, NPI_MAX_CTL);
  7733.  
  7734.     /* setup connection response primitive */
  7735.     addr_len = strlen( local_nua );
  7736.     conn_res->PRIM_type = (ulong)N_CONN_RES;
  7737.     conn_res->TOKEN_value = token;
  7738.     /* note address length is n+1 to accomodate the X.121 address prefix */
  7739.     conn_res->RES_length = (ulong)(addr_len + 1);
  7740.     conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
  7741.     conn_res->SEQ_number = seqno;
  7742.     conn_res->CONN_flags = 0;
  7743.     conn_res->QOS_length = 0;           /* unsupported - must be 0 (!?) */
  7744.     conn_res->QOS_offset = 0;
  7745.  
  7746.     addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
  7747.     *addtl_info++ = (char)0;    /* X.121 address prefix */
  7748.     bcopy( local_nua, addtl_info, addr_len );
  7749.  
  7750.     /*
  7751.      * send off the connect response
  7752.      */
  7753.     if (x25putmsg(x25callfd,
  7754.                   (N_npi_ctl_t*)conn_res,
  7755.                   (N_npi_data_t *)NULL,
  7756.                   0,
  7757.                   &put_flags
  7758.                   ) < 0 ) {
  7759.         perror("kermit: x25accept(): putmsg connect response failed");
  7760.         return(-1);
  7761.     }
  7762.  
  7763.     /*
  7764.      * Allocate and zero out space for the OK_ACK primitive
  7765.      */
  7766.     if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
  7767.         perror("kermit: x25call(): ok_ack malloc failed");
  7768.         return(-1);
  7769.     }
  7770.     bzero(ok_ack, sizeof(N_npi_ctl_t));
  7771.  
  7772.     /* Initialize and build the structures for getmsg */
  7773.     get_flags=0;
  7774.  
  7775.     rc = (int)x25getmsg(x25callfd,
  7776.                         (N_npi_ctl_t*)ok_ack,
  7777.                         (int)sizeof(N_ok_ack_t),
  7778.                         (N_npi_data_t*)NULL,
  7779.                         0,
  7780.                         &get_flags,
  7781.                         N_OK_ACK
  7782.                         );
  7783.     if (rc == 0) {
  7784.         /* sequence number is only for disconnecting when not connected !? */
  7785.         x25seqno = 0;
  7786.     }
  7787.  
  7788.     /* free up malloc'ed buffer space */
  7789.     if (conn_res) { free(conn_res); conn_res = NULL; }
  7790.     if (ok_ack) { free(ok_ack); ok_ack = NULL; }
  7791.  
  7792. #ifdef TRACE
  7793.     printf( "TRACE: leaving x25accept\n" );
  7794. #endif /* TRACE */
  7795.  
  7796.     return( ( rc >= 0 ) ? x25callfd : -1 );
  7797. }
  7798.  
  7799. /*****************************************************************************
  7800.  * Function: x25unbind
  7801.  *
  7802.  * Description:  This subroutine builds and sends an unbind request and gets
  7803.  * the acknowledgement for it.
  7804.  *
  7805.  * Parameters:
  7806.  * fd - File descriptor of the stream
  7807.  *
  7808.  * Functions Referenced:
  7809.  * getmsg()
  7810.  * putmsg()
  7811.  * malloc()
  7812.  * bzero()
  7813.  *
  7814.  * Return code:
  7815.  * 0 - if successful
  7816.  * -1 - if not successful
  7817.  *****************************************************************************/
  7818. int
  7819. x25unbind(fd) int fd; {                 /* X25 device (opened) */
  7820.     int rc;                             /* return code */
  7821.     int flags;                          /* bind flags */
  7822.     int get_flags;                      /* priority flag for getmsg */
  7823.     ulong type;                         /* primitive type */
  7824.     N_unbind_req_t *unbind_req;         /* pointer to N_UNBIND_REQ */
  7825.     N_ok_ack_t *ok_ack;                 /* pointer to N_OK_ACK */
  7826.  
  7827. #ifdef TRACE
  7828.     printf( "TRACE: entering x25unbind\n" );
  7829. #endif /* TRACE */
  7830.  
  7831. #ifdef DEBUG
  7832.     /* printf( "x25unbind( %d )\n", fd ); */
  7833. #endif /* DEBUG */
  7834.     debug(F101,"x25unbind closing x25 connection #","",fd);
  7835.  
  7836.     /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
  7837.     unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
  7838.     if (unbind_req == NULL) {
  7839.         perror("kermit: x25unbind(): unbind_req malloc failed");
  7840.         return(-1);
  7841.     }
  7842.     bzero(unbind_req, sizeof(N_npi_ctl_t));
  7843.  
  7844.     /*
  7845.      * Build the Unbind Request Primitive
  7846.      */
  7847.     flags = 0;
  7848.     unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
  7849.  
  7850.     /*
  7851.      * Call putmsg() to put the bind request message on the stream
  7852.      */
  7853.     if (x25putmsg(fd,
  7854.                   (N_npi_ctl_t*)unbind_req,
  7855.                   (N_npi_data_t *)NULL,
  7856.                   0,
  7857.                   &flags
  7858.                   ) < 0) {
  7859.         perror ("kermit: x25unbind(): putmsg failed");
  7860.         return(-1);
  7861.     }
  7862.  
  7863.     /* Allocate and Zero out space for the N_OK_ACK primitive */
  7864.     ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
  7865.     if (ok_ack == NULL) {
  7866.         perror("kermit x25unbind(): ok_ack malloc failed\n");
  7867.         return(-1);
  7868.     }
  7869.     bzero(ok_ack, sizeof(N_npi_ctl_t));
  7870.  
  7871.     /* Initialize and build the control structure for getmsg */
  7872.     get_flags=0;
  7873.  
  7874.     /* Call getmsg() to check for an acknowledgement */
  7875.     rc = x25getmsg(fd,
  7876.                    (N_npi_ctl_t*)ok_ack,
  7877.                    (int)sizeof(N_ok_ack_t),
  7878.                    (N_npi_data_t*)NULL,
  7879.                    0,
  7880.                    &get_flags,
  7881.                    N_OK_ACK
  7882.                    );
  7883.     if (rc < 0) {
  7884.         perror ("kermit: x25unbind: getmsg failed");
  7885.         return(-1);
  7886.     }
  7887.  
  7888.     /* Free up the space that we no longer need */
  7889.     if (unbind_req) { free(unbind_req); unbind_req = NULL; }
  7890.     if (ok_ack) { free(ok_ack); ok_ack = NULL; }
  7891.  
  7892. #ifdef TRACE
  7893.     printf( "TRACE: leaving x25unbind\n" );
  7894. #endif /* TRACE */
  7895.  
  7896.     return(0);
  7897. }
  7898.  
  7899. /*****************************************************************************
  7900.  * Function: x25xin
  7901.  *
  7902.  * Description:
  7903.  *      Read n characters from X.25 circuit into buf (AIX only)
  7904.  *
  7905.  * Parameters:
  7906.  *      data_buf_len    maximum size of data buffer
  7907.  *      data_buf        pointer to pre-allocated buffer space
  7908.  *
  7909.  * Return Value:
  7910.  *      the number of characters actually read
  7911.  */
  7912. int
  7913. x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
  7914.     struct strbuf getmsg_ctl;           /* streams control structure */
  7915.     struct strbuf getmsg_data;          /* streams data structure */
  7916.     int rc = 0;                         /* return code */
  7917.     int getmsg_flags;                   /* packet priority flags */
  7918.     char * ctl_buf;                     /* npi control buffer */
  7919.     N_npi_ctl_t * result;               /* pointer to simplify switch() */
  7920.  
  7921. #ifdef TRACE
  7922.     printf( "TRACE: entering x25xin\n" );
  7923. #endif /* TRACE */
  7924.  
  7925.     /* ensure that no maximum's are overridden */
  7926.     data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
  7927.  
  7928.     /* allocate space for packet control info */
  7929.     if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
  7930.         perror( "kermit: x25xin(): ctl_buf malloc" );
  7931.         return(-1);
  7932.     }
  7933. #ifdef COMMENT
  7934.     /* riehm: need zeroed buffer for getmsg? */
  7935.     bzero( ctl_buf, NPI_MAX_CTL );
  7936.     /* clear data buffer */
  7937.     bzero( data_buf, data_buf_len );
  7938. #endif /* COMMENT */
  7939.  
  7940.     getmsg_flags = 0;                   /* get the first packet available */
  7941.  
  7942.     rc = x25getmsg(ttyfd,
  7943.                    ctl_buf,
  7944.                    NPI_MAX_CTL,
  7945.                    data_buf,
  7946.                    data_buf_len,
  7947.                    &getmsg_flags,
  7948.                    N_DATA_IND
  7949.                    );
  7950. #ifdef COMMENT
  7951. #ifdef DEBUG
  7952.     if (rc >= 0) {
  7953.         printf( "kermit: x25xin(): got " );
  7954.         x25dump_data( data_buf, 0, rc );
  7955.     } else {
  7956.         printf( "x25xin(): attempt to get data resulted in an error\n" );
  7957.     }
  7958. #endif /* DEBUG */
  7959. #endif /* COMMENT */
  7960.  
  7961.     /* free buffers */
  7962.     if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
  7963.  
  7964. #ifdef TRACE
  7965.     printf( "TRACE: leaving x25xi\n" );
  7966. #endif /* TRACE */
  7967.  
  7968.     return(rc);
  7969. }
  7970.  
  7971. /*****************************************************************************
  7972.  * Function: x25write
  7973.  *
  7974.  * Description:
  7975.  *      write a block of characters to the X25 STREAM (AIX)
  7976.  *
  7977.  * Parameters:
  7978.  *      fd              file descriptor to write to
  7979.  *      databuf         buffer containing data to write
  7980.  *      databufsize             size of the buffer to write
  7981.  *
  7982.  * Return Value:
  7983.  *      size            the number of bytes actually transmitted
  7984.  */
  7985. int
  7986. x25write(fd, databuf, databufsize)
  7987.     int         fd;                  /* X25 STREAMS file descriptor (ttyfd) */
  7988.     char        *databuf;               /* buffer to write */
  7989.     int         databufsize;            /* buffer size */
  7990. /* x25write */ {
  7991.     N_data_req_t *data_req_ctl;
  7992.     int rc;                             /* return code (size transmitted) */
  7993.     int write_flags = 0;                /* always 0 !? */
  7994.  
  7995. #ifdef TRACE
  7996.     printf( "TRACE: entering x25write\n" );
  7997. #endif /* TRACE */
  7998.  
  7999.     if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
  8000.         perror( "kermit: x25write(): data_req_ctl malloc" );
  8001.         return(-1);
  8002.     }
  8003.     data_req_ctl->PRIM_type = N_DATA_REQ;
  8004.     data_req_ctl->DATA_xfer_flags = 0;
  8005.  
  8006.     /* riehm: possible extension
  8007.      * possibly need to think about splitting up the data buffer
  8008.      * into multiple parts if databufsize > NPI_MAX_DATA
  8009.      */
  8010.  
  8011. #ifdef COMMENT
  8012. #ifdef DEBUG
  8013.     printf( "kermit: x25write(): writing data to x25 stream\n" );
  8014.     printf( "\tdata:\t" );
  8015.     x25dump_data(databuf, 0, databufsize);
  8016. #endif /* DEBUG */
  8017. #endif /* COMMENT */
  8018.     rc = x25putmsg(fd,
  8019.                    (N_npi_ctl_t*)data_req_ctl,
  8020.                    (N_npi_data_t*)databuf,
  8021.                    databufsize,
  8022.                    &write_flags
  8023.                    );
  8024.     if (data_req) { free(data_req_ctl);  data_req = NULL; }
  8025.  
  8026. #ifdef TRACE
  8027.     printf( "TRACE: leaving x25write\n" );
  8028. #endif /* TRACE */
  8029.  
  8030.     return(rc);
  8031. }
  8032.  
  8033. /*****************************************************************************
  8034.  * Function: x25local_nua
  8035.  *
  8036.  * Description:
  8037.  *      This routine is only interesting for IBM computers. In order
  8038.  *      to set up a connection (see x25bind()) you need to know the
  8039.  *      local NUA (x25 address). Unfortunately, you need all this code
  8040.  *      to find that out, I just hope this works for everyone else!
  8041.  *
  8042.  * Parameters:
  8043.  *      a pre-allocated character buffer, long enough to hold an X.25 address
  8044.  *      and the tailing null.
  8045.  *
  8046.  * Return Value:
  8047.  *      the length of the address string.
  8048.  *      0 = error
  8049.  */
  8050. int
  8051. x25local_nua(char *buf) {
  8052.     struct CuAt *response;      /* structure to fill with info from ODM */
  8053.     CLASS_SYMBOL retClass;      /* ODM class */
  8054.     char query[64];             /* odm database query */
  8055.     int rc = 0;                 /* return value (length of local NUA) */
  8056.     extern char x25name[];      /* x25 device name (sx25a0) */
  8057.  
  8058. #ifdef TRACE
  8059.     printf( "TRACE: entering x25local_nua\n" );
  8060. #endif /* TRACE */
  8061.  
  8062.     /* set up query string */
  8063.     if (x25name[0] == '\0') {
  8064. #ifdef DEBUG
  8065.         printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
  8066. #endif /* DEBUG */
  8067.         strcpy( x25name, "sx25a0" );
  8068.     }
  8069.     sprintf(query, "name like %s and attribute like local_nua", x25name);
  8070.  
  8071.     /* initialise ODM database */
  8072.     odmerrno = 0;
  8073.     if (odm_initialize() == -1) {
  8074.         printf( "x25local_nua(): can't initialize ODM database");
  8075.         switch (odmerrno) {
  8076.           case ODMI_INVALID_PATH:
  8077.             printf( "invalid path\n" );
  8078.             break;
  8079.           case ODMI_MALLOC_ERR:
  8080.             printf( "malloc failed\n" );
  8081.             break;
  8082.           default:
  8083.             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
  8084.         }
  8085.         return(rc);
  8086.     }
  8087.  
  8088.     /* open the CuAt class */
  8089.     retClass = odm_open_class(CuAt_CLASS);
  8090.     if (((int)retClass) == -1) {
  8091.         printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
  8092.         switch (odmerrno) {
  8093.           case ODMI_CLASS_DNE:
  8094.             printf( "CuAt class doesn't exist\n" );
  8095.             break;
  8096.           case ODMI_CLASS_PERMS:
  8097.             printf( "permission to CuAt class file denied\n" );
  8098.             break;
  8099.           case ODMI_MAGICNO_ERR:
  8100.             printf( "CuAt is an invalid ODM object class\n" );
  8101.             break;
  8102.           case ODMI_OPEN_ERR:
  8103.             printf( "cannot open CuAt class - and don't know why!\n" );
  8104.             break;
  8105.           case ODMI_INVALID_PATH:
  8106.             printf( "invalid path\n" );
  8107.             break;
  8108.           case ODMI_TOOMANYCLASSES:
  8109.             printf( "too many object classes have been opened\n" );
  8110.             break;
  8111.           default:
  8112.             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
  8113.         }
  8114.         return(rc);
  8115.     }
  8116.  
  8117. #ifdef DEBUG
  8118.     printf("retClass= %d\n", retClass);
  8119. #endif /* DEBUG */
  8120.  
  8121.     response = (struct CuAt *)odm_get_first( retClass, query, NULL );
  8122.     if (((int)response) == -1) {
  8123.         printf( "kermit: x25local_nua(): odm query failed " );
  8124.         switch (odmerrno) {
  8125.           case ODMI_BAD_CRIT:           /* Programming error */
  8126.             printf( "bad search criteria\n" );
  8127.             break;
  8128.           case ODMI_CLASS_DNE:
  8129.             printf( "CuAt class doesn't exist\n" );
  8130.             break;
  8131.           case ODMI_CLASS_PERMS:
  8132.             printf( "permission to CuAt class file denied\n" );
  8133.             break;
  8134.           case ODMI_INTERNAL_ERR:
  8135.             printf("odm internal error\nPlease contact your administrator\n" );
  8136.             break;
  8137.           case ODMI_INVALID_CLXN:
  8138.             printf("CuAt is invalid or inconsistent odm class collection\n");
  8139.             break;
  8140.           case ODMI_INVALID_PATH:
  8141.             printf( "invalid path\n" );
  8142.             break;
  8143.           case ODMI_MAGICNO_ERR:
  8144.             printf( "CuAt is an invalid ODM object class\n" );
  8145.             break;
  8146.           case ODMI_MALLOC_ERR:
  8147.             printf( "malloc failed\n" );
  8148.             break;
  8149.           case ODMI_OPEN_ERR:
  8150.             printf( "cannot open CuAt class - and don't know why!\n" );
  8151.             break;
  8152.           case ODMI_TOOMANYCLASSES:
  8153.             printf( "too many object classes have been opened\n" );
  8154.             break;
  8155.           default:
  8156.             printf( "unknown error %d\nPlease call IBM\n", odmerrno );
  8157.         }
  8158.         return(rc);
  8159.     }
  8160.  
  8161.     /* check for a meaningfull response */
  8162.     if (response != NULL) {
  8163.         if (response->value != NULL) {
  8164.             strcpy(buf, response->value);
  8165.             rc = strlen( buf );
  8166. #ifdef DEBUG
  8167. /*
  8168.             printf( "attribute name is: %s\n", (char *)response->attribute );
  8169.             printf( "I think my address is %s\n", (char*)response->value );
  8170. */
  8171. #endif /* DEBUG */
  8172.         } else {
  8173.             printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
  8174.         }
  8175.     } else {
  8176.         switch (odmerrno) {
  8177.           case ODMI_BAD_CRIT:
  8178.             printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
  8179.             break;
  8180.           case ODMI_CLASS_DNE:
  8181.             printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
  8182.             break;
  8183.           case ODMI_CLASS_PERMS:
  8184.             printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
  8185.             break;
  8186.           case ODMI_INTERNAL_ERR:
  8187.             printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
  8188.             break;
  8189.           case ODMI_INVALID_CLXN:
  8190.             printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
  8191.             break;
  8192.           case ODMI_INVALID_PATH:
  8193.             printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
  8194.             break;
  8195.           case ODMI_MAGICNO_ERR:
  8196.             printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
  8197.             break;
  8198.           case ODMI_MALLOC_ERR:
  8199.             printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
  8200.             break;
  8201.           case ODMI_OPEN_ERR:
  8202.             printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
  8203.             break;
  8204.           case ODMI_TOOMANYCLASSES:
  8205.             printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
  8206.             break;
  8207.           default:
  8208.             printf( "Unknown error!\n" );
  8209.         }
  8210.         return(rc);
  8211.     }
  8212.  
  8213.     /* close the database again */
  8214.     odm_close_class( retClass );
  8215.  
  8216.     /* forget about ODM all together */
  8217.     odm_terminate();
  8218.  
  8219. #ifdef TRACE
  8220.     printf( "TRACE: leaving x25local_nua\n" );
  8221. #endif /* TRACE */
  8222.  
  8223.     debug(F110, "x25local_nua local address is ", buf, 0);
  8224.     return(rc);
  8225. }
  8226.  
  8227. /*****************************************************************************
  8228.  * Function: x25facilities
  8229.  *
  8230.  * Description:
  8231.  *      build up the facilities data packet for a connection request
  8232.  *
  8233.  * Parameters:
  8234.  *      a pre-allocated char buffer, normally NPI_MAX_DATA big.
  8235.  *
  8236.  * Return Value:
  8237.  *      the number of characters inserted into the buffer
  8238.  */
  8239. int
  8240. x25facilities(buffer) char *buffer; {
  8241.     extern int revcall;
  8242.     extern int closgr;
  8243.     char *p;                            /* temp pointer */
  8244.     char *start;                        /* temp pointer */
  8245.  
  8246. #ifdef TRACE
  8247.     printf( "TRACE: entering x25facilities\n" );
  8248. #endif /* TRACE */
  8249.  
  8250.     p = buffer + 1;
  8251.     start = p;
  8252.  
  8253. #ifdef DEBUG
  8254.     printf( "kermit: x25facilities(): getting X25 facilities\n" );
  8255. #endif /* DEBUG */
  8256.  
  8257.     if (revcall != 0) {
  8258. #ifdef DEBUG
  8259.         printf("reverse charge: %d\n", revcall );
  8260. #endif /* DEBUG */
  8261.         *++p = 0x01;
  8262.         *++p = revcall;
  8263.     }
  8264.     if (closgr > 0) {
  8265. #ifdef DEBUG
  8266.         printf("closed user group: %d\n", closgr );
  8267. #endif /* DEBUG */
  8268.         *++p = 0x03;
  8269.         *++p = closgr;
  8270.     }
  8271.  
  8272. #ifdef DEBUG
  8273.     if (p == start) {
  8274.         printf( "no facilities\n" );
  8275.     }
  8276. #endif /* DEBUG */
  8277.  
  8278.     /* set the size of the facilities buffer */
  8279.     *buffer = (char)( p - start ) & 0xff;
  8280.  
  8281. #ifdef DEBUG
  8282.     printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer)  );
  8283. #endif /* DEBUG */
  8284.  
  8285. #ifdef TRACE
  8286.     printf( "TRACE: leaving x25facilities\n" );
  8287. #endif /* TRACE */
  8288.  
  8289.     /* return the size of the facilities with size byte */
  8290.     /* 1 == no facilities, 0 byte returned as facilities size */
  8291.     return( (int)(p - buffer) );
  8292. }
  8293.  
  8294. /*
  8295.  * reset the connection
  8296.  */
  8297. int
  8298. x25reset(cause, diagn) char cause; char diagn; {
  8299.     /* not implemented */
  8300.  
  8301. #ifdef TRACE
  8302.     printf( "TRACE: entering x25reset\n" );
  8303. #endif /* TRACE */
  8304.  
  8305. #ifdef TRACE
  8306.     printf( "TRACE: leaving x25reset\n" );
  8307. #endif /* TRACE */
  8308.  
  8309.     return(0);
  8310. }
  8311.  
  8312. /*
  8313.  * clear the x25 connection - ie: hang up
  8314.  */
  8315. int
  8316. x25clear() {
  8317.     int get_flags = 0;                  /* priority flag for getmsg */
  8318.     int put_flags = 0;                  /* send flags, always 0 */
  8319.     ulong type;                         /* primitive type */
  8320.     N_discon_req_t *discon_req;         /* pointer to N_DISCON_REQ */
  8321.     N_discon_ind_t *discon_ind;         /* pointer to N_DISCON_IND */
  8322.     N_npi_data_t *discon_data;          /* pointer to N_DISCON_IND data */
  8323.     int rc = 0;                         /* return code */
  8324.  
  8325. #ifdef TRACE
  8326.     printf( "TRACE: entering x25clear\n" );
  8327. #endif /* TRACE */
  8328.  
  8329. #ifdef DEBUG
  8330.     /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
  8331. #endif /* DEBUG */
  8332.  
  8333.     /*
  8334.     * The following checks are used to ensure that we don't disconnect
  8335.     * or unbind twice - this seems to throw the NPI interface right out of
  8336.     * kilter.
  8337.     */
  8338.     switch(x25lastmsg) {
  8339.       case N_BIND_ACK:
  8340.       case N_CONN_CON:
  8341.       case N_CONN_REQ:
  8342.       case N_DATA_REQ:
  8343.       case N_DATA_IND:
  8344.         {
  8345. #ifdef DEBUG
  8346.             /* printf("x25clear(): actively disconnecting\n"); */
  8347. #endif /* DEBUG */
  8348.  
  8349.                 discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
  8350.                 if (discon_req == NULL) {
  8351.                     perror("kermit x25clear(): discon_req malloc failed\n");
  8352.                     /* fallthrough, try to unbind the NPI anyway */
  8353.                 } else {
  8354.                     discon_req->PRIM_type = N_DISCON_REQ;
  8355.                     discon_req->DISCON_reason = 0;      /* not used by AIX */
  8356.                     discon_req->RES_length = 0;
  8357.                     discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
  8358.                     discon_req->SEQ_number = x25seqno;  /* global */
  8359.  
  8360.                     if (x25putmsg(ttyfd,
  8361.                                   (N_npi_ctl_t*)discon_req,
  8362.                                   (N_npi_data_t*)NULL,
  8363.                                   0,
  8364.                                   &put_flags
  8365.                                   ) < 0) {
  8366.                         perror("x25putmsg failed in x25clear()");
  8367.                     }
  8368.                     discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
  8369.                     discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
  8370.                     if((discon_ind == NULL) || (discon_data == NULL)) {
  8371.                         perror("x25clear(): discon_ind malloc failed\n");
  8372.                         /* fallthrough, try to unbind the NPI anyway */
  8373.                     } else {
  8374.                         if(x25getmsg(ttyfd,
  8375.                                      (N_npi_ctl_t*)discon_ind,
  8376.                                      NPI_MAX_CTL,
  8377.                                      (N_npi_data_t*)discon_data,
  8378.                                      NPI_MAX_DATA,
  8379.                                      &get_flags,
  8380.                                      N_OK_ACK
  8381.                                      ) < 0 ) {
  8382.                             perror("x25getmsg failed in x25clear()");
  8383.                             /* fallthrough, try to unbind the NPI anyway */
  8384.                         }
  8385.                     }
  8386.                 }
  8387.                 break;
  8388.             }
  8389.     }
  8390.  
  8391.     if (x25lastmsg != N_UNBIND_REQ) {
  8392.         rc = x25unbind(ttyfd);
  8393.     }
  8394.  
  8395. #ifdef TRACE
  8396.     printf( "TRACE: leaving x25clear\n" );
  8397. #endif /* TRACE */
  8398.  
  8399.     return(rc);
  8400. }
  8401.  
  8402. #ifdef DEBUG
  8403. /*
  8404.  * only for debugging
  8405.  *
  8406.  * turn the internal representation of a datablock into something
  8407.  * half-way readable. Because the length is known, we can print
  8408.  * the string including null's etc (important, because the first(!)
  8409.  * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
  8410.  */
  8411. x25dump_data(char *addr, ulong offset, ulong length) {
  8412.     char *ptr = addr + offset;
  8413.     ulong i = length;
  8414.     /* allocate enough memory for all unprintable chars */
  8415.     char *buf = (char *)malloc( length * 4 );
  8416.     char *bptr = buf;   /* pointer to current place in the print buffer */
  8417.  
  8418.     while (i > 0) {
  8419.         if (isprint(*ptr)) {
  8420.             *bptr++ = *ptr;
  8421.         } else {
  8422.             *bptr++ = '[';
  8423.             bptr += sprintf(bptr, "%2.2x", *ptr);
  8424.             *bptr++ = ']';
  8425.         }
  8426.         ptr++;
  8427.         i--;
  8428.     }
  8429.     if (length > 0) {
  8430.         *bptr = '\0';
  8431.         printf( "%s", buf );
  8432.     }
  8433.     printf( " (%d+%d)\n", offset, length );
  8434.  
  8435.     if (buf) { free(buf); buf = NULL; }
  8436.     return;
  8437. }
  8438.  
  8439. /*
  8440.  * only for debugging
  8441.  * print as much useful information about a packet as possible
  8442.  */
  8443. x25dump_prim(primitive)    N_npi_ctl_t *primitive; {
  8444.     printf("Primitive");
  8445.     switch (primitive->PRIM_type) {
  8446.       case N_BIND_ACK:
  8447.         printf( "\tN_BIND_ACK\n\taddress:\t" );
  8448.         x25dump_data( (char *)primitive,
  8449.                      primitive->bind_ack.ADDR_offset,
  8450.                      primitive->bind_ack.ADDR_length );
  8451.         printf( "\tproto id:\t" );
  8452.         x25dump_data( (char *)primitive,
  8453.                      primitive->bind_ack.PROTOID_offset,
  8454.                      primitive->bind_ack.PROTOID_length );
  8455.         printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
  8456.                primitive->bind_ack.CONIND_number,
  8457.                primitive->bind_ack.TOKEN_value );
  8458.         break;
  8459.  
  8460.       case N_BIND_REQ:
  8461.         printf( "\tN_BIND_REQ\n\taddress:\t" );
  8462.         x25dump_data( (char *)primitive,
  8463.                      primitive->bind_req.ADDR_offset,
  8464.                      primitive->bind_req.ADDR_length );
  8465.         printf( "\tproto id:\t" );
  8466.         x25dump_data( (char *)primitive,
  8467.                      primitive->bind_req.PROTOID_offset,
  8468.                      primitive->bind_req.PROTOID_length );
  8469.         printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
  8470.                primitive->bind_req.CONIND_number,
  8471.                primitive->bind_req.BIND_flags );
  8472.         break;
  8473.  
  8474.       case N_CONN_CON:
  8475.         printf( "\tN_CONN_CON\n" );
  8476.         printf( "\tRES\t\t" );
  8477.         x25dump_data( (char *)primitive,
  8478.                      primitive->conn_con.RES_offset,
  8479.                      primitive->conn_con.RES_length );
  8480.         printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
  8481.         break;
  8482.  
  8483.       case N_CONN_IND:
  8484.         printf( "\tN_CONN_IND\n" );
  8485.         printf( "\tsource:\t\t" );
  8486.         x25dump_data( (char *)primitive,
  8487.                      primitive->conn_ind.SRC_offset,
  8488.                      primitive->conn_ind.SRC_length );
  8489.         printf( "\tdestination:\t" );
  8490.         x25dump_data( (char *)primitive,
  8491.                      primitive->conn_ind.DEST_offset,
  8492.                      primitive->conn_ind.DEST_length );
  8493.         printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
  8494.         printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
  8495.         break;
  8496.  
  8497.       case N_CONN_REQ:
  8498.         printf( "\tN_CONN_REQ\n\tdestination:\t" );
  8499.         x25dump_data( (char *)primitive,
  8500.                      primitive->conn_req.DEST_offset,
  8501.                      primitive->conn_req.DEST_length );
  8502.         printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
  8503.         break;
  8504.  
  8505.       case N_CONN_RES:
  8506.         printf( "\tN_CONN_RES\n" );
  8507.         printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
  8508.         printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
  8509.         printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
  8510.         printf( "\tRES\t\t" );
  8511.         x25dump_data( (char *)primitive,
  8512.                      primitive->conn_res.RES_offset,
  8513.                      primitive->conn_res.RES_length );
  8514.         break;
  8515.  
  8516.       case N_DATACK_IND:
  8517.         printf( "\tN_DATACK_IND\n" );
  8518.         break;
  8519.  
  8520.       case N_DATACK_REQ:
  8521.         printf( "\tN_DATACK_REQ\n" );
  8522.         printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
  8523.         break;
  8524.  
  8525.       case N_DATA_IND:
  8526.         printf( "\tN_DATA_IND\n" );
  8527.         printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
  8528.         break;
  8529.  
  8530.       case N_DATA_REQ:
  8531.         printf( "\tN_DATA_REQ\n" );
  8532.         break;
  8533.  
  8534.       case N_DISCON_IND:
  8535.         printf( "\tN_DISCON_IND\n" );
  8536.         printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
  8537.         printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
  8538.         printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
  8539.         printf( "\tRES:\t" );
  8540.         x25dump_data( (char *)primitive,
  8541.                      primitive->discon_ind.RES_offset,
  8542.                      primitive->discon_ind.RES_length );
  8543.         break;
  8544.  
  8545.       case N_DISCON_REQ:
  8546.         printf( "\tN_DISCON_REQ\n" );
  8547.         printf( "\tDISCON_reason:\t%d\n",
  8548.                primitive->discon_req.DISCON_reason );
  8549.         printf( "\tRES:\t" );
  8550.         x25dump_data( (char *)primitive,
  8551.                      primitive->discon_req.RES_offset,
  8552.                      primitive->discon_req.RES_length );
  8553.         printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
  8554.         break;
  8555.  
  8556.       case N_ERROR_ACK:
  8557.         printf( "\tN_ERROR_ACK\n" );
  8558.         printf( "\tCaused by:\t%s\n",
  8559.                x25prim( primitive->error_ack.ERROR_prim ) );
  8560.         printf( "\tNPI error:\t%s\n",
  8561.                x25err( primitive->error_ack.NPI_error ));
  8562.         errno = primitive->error_ack.UNIX_error;
  8563.         perror( "\t" );
  8564.         break;
  8565.  
  8566.       case N_EXDATA_IND:
  8567.         printf( "\tN_EXDATA_ACK\n" );
  8568.         break;
  8569.  
  8570.       case N_EXDATA_REQ:
  8571.         printf( "\tN_EXDATA_REQ\n" );
  8572.         break;
  8573.  
  8574.       case N_INFO_ACK:
  8575.         printf( "\tN_INFO_ACK\n" );
  8576.         printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
  8577.         printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
  8578.         printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
  8579.         printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
  8580.         printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
  8581.         printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
  8582.         break;
  8583.  
  8584.       case N_INFO_REQ:
  8585.         printf( "\tN_INFO_REQ\n" );
  8586.         break;
  8587.  
  8588.       case N_OK_ACK:
  8589.         printf( "\tN_OK_ACK\n" );
  8590.         break;
  8591.  
  8592.       case N_OPTMGMT_REQ:
  8593.         printf( "\tN_OPTMGMT_REQ\n" );
  8594.         break;
  8595.  
  8596.       case N_RESET_CON:
  8597.         printf( "\tN_RESET_CON\n" );
  8598.         break;
  8599.  
  8600.       case N_RESET_IND:
  8601.         printf( "\tN_RESET_IND\n" );
  8602.         printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
  8603.         printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
  8604.         break;
  8605.  
  8606.       case N_RESET_REQ:
  8607.         printf( "\tN_RESET_REQ\n" );
  8608.         printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
  8609.         break;
  8610.  
  8611.       case N_RESET_RES:
  8612.         printf( "\tN_RESET_RES\n" );
  8613.         break;
  8614.  
  8615.       case N_UDERROR_IND:
  8616.         printf( "\tN_UDERROR_IND\n" );
  8617.         break;
  8618.  
  8619.       case N_UNBIND_REQ:
  8620.         printf( "\tN_UNBIND_REQ\n" );
  8621.         break;
  8622.  
  8623.       case N_UNITDATA_REQ:
  8624.         printf( "\tN_UNITDATA_REQ\n" );
  8625.         break;
  8626.  
  8627.       case N_UNITDATA_IND:
  8628.         printf( "\tN_UNITDATA_IND\n" );
  8629.         break;
  8630.  
  8631.       default:
  8632.         (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
  8633.         return 0;
  8634.     }
  8635. }
  8636. #endif /* DEBUG */
  8637.  
  8638. /* it looks like signal handling is not needed with streams! */
  8639. /* x25oobh()    - handle SIGURG signals - take from isode ? */
  8640.  
  8641. #endif /* IBMX25 */
  8642.  
  8643. #ifndef NOHTTP
  8644. #ifdef Plan9
  8645. #include <sys/time.h>
  8646. #else
  8647. #ifdef AIX41
  8648. #include <time.h>
  8649. #else
  8650. #ifdef SUNOS4
  8651. #include <sys/time.h>
  8652. #else
  8653. #ifdef SYSTIMEH
  8654. #include <sys/time.h>
  8655. #else
  8656. #ifdef OS2
  8657. #include <time.h>
  8658. #else
  8659. #include <time.h>
  8660. /* #include <utime.h> */
  8661. #endif /* OS2 */
  8662. #endif /* SYSTIMEH */
  8663. #endif /* SUNOS4 */
  8664. #endif /* AIX41 */
  8665. #endif /* Plan9 */
  8666.  
  8667. #ifdef OS2
  8668. #include <sys/utime.h>
  8669. #ifdef NT
  8670. #define utimbuf _utimbuf
  8671. #endif /* NT */
  8672. #define utime   _utime
  8673. #else
  8674. #ifdef SYSUTIMEH                        /* <sys/utime.h> if requested,  */
  8675. #include <sys/utime.h>                  /* for extra fields required by */
  8676. #else                                   /* 88Open spec. */
  8677. #ifdef UTIMEH                           /* or <utime.h> if requested */
  8678. #include <utime.h>                      /* (SVR4, POSIX) */
  8679. #define SYSUTIMEH                       /* Use this for both cases. */
  8680. #endif /* UTIMEH */
  8681. #endif /* SYSUTIMEH */
  8682. #endif /* OS2 */
  8683.  
  8684. #define HTTP_VERSION "HTTP/1.0"
  8685.  
  8686. #ifdef CMDATE2TM
  8687. time_t
  8688. #ifdef CK_ANSIC
  8689. http_date(char * date)
  8690. #else
  8691. http_date(date) char * date;
  8692. #endif /* CK_ANSIC */
  8693. /* http_date */ {
  8694.     /* HTTP dates are of the form:  "Sun, 12 Oct 1997 20:11:47 GMT" */
  8695.     extern char cmdatebuf[18];
  8696.     struct tm t_tm;
  8697.     time_t t;
  8698.     char ldate[32];
  8699.     int j;
  8700.  
  8701.     j = ckindex(",",date,0,0,0);
  8702.     ckstrncpy(ldate,&date[j+1],20);
  8703.  
  8704.     if (cmcvtdate(ldate,0) < 0)         /* Convert to normal form */
  8705.       return(0);
  8706.  
  8707.     t_tm = *cmdate2tm(cmdatebuf,1);
  8708.  
  8709.     t = mktime(&t_tm);                  /* PROBABLY NOT PORTABLE */
  8710. #ifdef XX_TIMEZONE
  8711.     t -= _timezone;                     /* NOT DECLARED */
  8712. #endif /* XX_TIMEZONE */
  8713.     return(t);
  8714. }
  8715. #endif /* CMDATE2TM */
  8716.  
  8717. char *
  8718. http_now() {
  8719.     static char nowstr[32];
  8720. #ifdef CMDATE2TM
  8721.     struct tm  *gmt;
  8722.     time_t ltime;                       /* NOT PORTABLE */
  8723.  
  8724.     time(<ime);
  8725.  
  8726.     gmt = gmtime(<ime);               /* PROBABLY NOT PORTABLE */
  8727.     strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
  8728.     /* not only is it not portable but it's locale-dependent */
  8729. #else
  8730. /*
  8731.   This is hopeless.  First of all, it seems that HTTP wants Day and Month
  8732.   NAMES?  In English?  Whose idea was that?  Even worse, the date/time must be
  8733.   expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
  8734.   nightmare.  Every platform does it differently, if at all -- even if we
  8735.   restrict ourselves to UNIX.  For example (quoting from recent C-Kermit edit
  8736.   history), "Fixed a longstanding bug in the BSDI version, in which incoming
  8737.   file dates were set in GMT rather than local time.  It seems in 4.4BSD,
  8738.   localtime() does not return the local time, but rather Zero Meridian (Zulu)
  8739.   time (GMT), and must be adjusted by the tm_gmtoff value."  Swell.  For
  8740.   greater appreciation of the scope of the problem, just take a look at the
  8741.   time-related #ifdefs in ckutio.c.  The only right way to do this is to add
  8742.   our own portable API for converting between local time and GMT/UTC/Zulu
  8743.   that shields us not only from UNIXisms like time_t and struct tm, but also
  8744.   the unbelievable amount of differences in time-related APIs -- e.g. is
  8745.   "timezone" an external variable or a function; which header file(s) do we
  8746.   include, etc etc etc.  It's a major project.
  8747. */
  8748.     int x;
  8749.     x = cmcvtdate("",1);
  8750.     if (x < 0)
  8751.       return("");
  8752. /*  yyyymmdd hh:mm:ss */
  8753. /*  01234567890123456 */
  8754.     nowstr[0]  = 'X';                   /* 1st letter of day */
  8755.     nowstr[1]  = 'x';                   /* 2nd letter of day */
  8756.     nowstr[2]  = 'x';                   /* 3rd letter of day */
  8757.     nowstr[3]  = ',';
  8758.     nowstr[4]  = ' ';
  8759.     nowstr[5]  = cmdate[6];
  8760.     nowstr[6]  = cmdate[7];
  8761.     nowstr[7]  = ' ';
  8762.     nowstr[8]  = ' ';                   /* first letter of month */
  8763.     nowstr[9]  = ' ';                   /* second letter of month */
  8764.     nowstr[10] = ' ';                   /* third letter of month */
  8765.     nowstr[11] = ' ';
  8766.     nowstr[12] = cmdate[0];
  8767.     nowstr[13] = cmdate[1];
  8768.     nowstr[14] = cmdate[2];
  8769.     nowstr[15] = cmdate[3];
  8770.     nowstr[16] = ' ';
  8771.     nowstr[17] = cmdate[9];
  8772.     nowstr[18] = cmdate[10];
  8773.     nowstr[19] = cmdate[11];
  8774.     nowstr[20] = cmdate[12];
  8775.     nowstr[21] = cmdate[13];
  8776.     nowstr[22] = cmdate[14];
  8777.     nowstr[23] = cmdate[15];
  8778.     nowstr[24] = cmdate[16];
  8779.     nowstr[25] = ' ';
  8780.     nowstr[26] = 'G';
  8781.     nowstr[27] = 'M';
  8782.     nowstr[28] = 'T';
  8783.     nowstr[29] = '\0';
  8784. #endif /* CMDATE2TM */
  8785.     return(nowstr);
  8786. }
  8787.  
  8788. #ifndef OS2
  8789. #ifndef CK_AUTHENTICATION
  8790. /* from ckuusr.h, which this module normally doesn't include */
  8791. _PROTOTYP( int dclarray, (char, int) );
  8792. #endif /* CK_AUTHENTICATION */
  8793. #endif /* OS2 */
  8794. /*
  8795.   Assign http response pairs to given array.
  8796.   For best results, response pairs should contain no spaces.
  8797.  
  8798.   Call with:
  8799.     resp  =  pointer to response list.
  8800.     n     =  size of response list.
  8801.     array =  array letter.
  8802.   Returns:
  8803.     0 on failure.
  8804.     >= 1, size of array, on success.
  8805. */
  8806. static int
  8807. #ifdef CK_ANSIC
  8808. http_mkarray(char ** resp, int n, char array)
  8809. #else
  8810. http_mkarray(resp, n, array) char ** resp; int n; char array;
  8811. #endif /* CK_ANSIC */
  8812. {
  8813. #ifndef NOSPL
  8814.     int i, x;
  8815.     char ** ap;
  8816.     extern char ** a_ptr[];
  8817.     extern int a_dim[];
  8818.  
  8819.     if (!array || n <= 0)
  8820.       return(0);
  8821.     if ((x = dclarray(array,n)) < 0) {
  8822.         printf("?Array declaration failure\n");
  8823.         return(-9);
  8824.     }
  8825.     ap = a_ptr[x];
  8826.     for (i = 1; i <=n; i++) {
  8827.         ap[i] = resp[i];                /* If resp elements were malloc'd */
  8828.         resp[i] = NULL;
  8829.     }
  8830.     a_dim[x] = n;
  8831.     return(n);
  8832. #else
  8833.     return(0);
  8834. #endif /* NOSPL */
  8835. }
  8836.  
  8837. #define HTTPBUFLEN  1024
  8838. #define HTTPHEADCNT 64
  8839.  
  8840. int
  8841. #ifdef CK_ANSIC
  8842. http_get(char * agent, char ** hdrlist, char * user,
  8843.          char * pwd, char array, char * local, char * remote)
  8844. #else
  8845. http_get(agent, hdrlist, user, pwd, array, local, remote)
  8846.     char * agent; char ** hdrlist; char * user;
  8847.     char * pwd; char array; char * local; char * remote;
  8848. #endif /* CK_ANSIC */
  8849. {
  8850.     char * request = NULL;
  8851.     int    i, j, len = 0, hdcnt = 0, rc = -1;
  8852.     int    ch;
  8853.     char   buf[HTTPBUFLEN], *p;
  8854.     int    nullline;
  8855. #ifdef OS2
  8856.     struct utimbuf u_t;
  8857. #else /* OS2 */
  8858. #ifdef SYSUTIMEH
  8859.     struct utimbuf u_t;
  8860. #else
  8861.     struct utimbuf {
  8862.         time_t atime;
  8863.         time_t mtime;
  8864.     } u_t;
  8865. #endif /* SYSUTIMH */
  8866. #endif /* OS2 */
  8867.     time_t mod_t = 0;
  8868.     time_t srv_t = 0;
  8869.     time_t local_t = 0;
  8870.     char passwd[64];
  8871.     char b64in[128];
  8872.     char b64out[256];
  8873.     char * headers[HTTPHEADCNT];
  8874.  
  8875.     if (ttyfd == -1)
  8876.       return(-1);
  8877.  
  8878.     if (array) {
  8879.         for (i = 0; i < HTTPHEADCNT; i++)
  8880.           headers[i] = NULL;
  8881.     }
  8882.     len = 8;                            /* GET */
  8883.     len += strlen(HTTP_VERSION);
  8884.     len += strlen(remote);
  8885.  
  8886.     for (i = 0; hdrlist[i]; i++)
  8887.       len += strlen(hdrlist[i]) + 2;
  8888.     if (agent)
  8889.       len += 13 + strlen(agent);
  8890.     if (user) {
  8891.         if (!pwd) {
  8892.             readpass("Password: ",passwd,64);
  8893.             pwd = passwd;
  8894.         }
  8895.         sprintf(b64in,"%s:%s",user,pwd);
  8896.         j = b8tob64(b64in,strlen(b64in),b64out,256);
  8897.         memset(pwd,0,strlen(pwd));      /* NOT PORTABLE */
  8898.         if (j < 0)
  8899.           return(-1);
  8900.         b64out[j] = '\0';
  8901.         len += j + 24;
  8902.     }
  8903.     len += 3;                           /* blank line + null */
  8904.  
  8905.     request = malloc(len);
  8906.     if (!request)
  8907.       return(-1);
  8908.  
  8909.     sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION);
  8910.     if (agent) {
  8911.         strcat(request,"User-Agent: ");
  8912.         strcat(request,agent);
  8913.         strcat(request,"\r\n");
  8914.     }
  8915.     if (user) {
  8916.         strcat(request,"Authorization: Basic ");
  8917.         strcat(request,b64out);
  8918.         strcat(request,"\r\n");
  8919.     }
  8920.     for (i = 0; hdrlist[i]; i++) {
  8921.         strcat(request,hdrlist[i]);
  8922.         strcat(request,"\r\n");
  8923.     }
  8924.     strcat(request,"\r\n");
  8925.     ttol((CHAR *)request,strlen(request));
  8926.  
  8927.     /* Process the headers */
  8928.     local_t = time(NULL);
  8929.     nullline = 0;
  8930.     i = 0;
  8931.     while (!nullline && (ch = ttinc(0)) >= 0 && i < HTTPBUFLEN) {
  8932.         buf[i] = ch;
  8933.         if ( buf[i] == 10 ) { /* found end of line */
  8934.             if (i <= 1)
  8935.               nullline = 1;
  8936.             i++;
  8937.             buf[i] = '\0';
  8938.             if (array && !nullline && hdcnt < HTTPHEADCNT)
  8939.               makestr(&headers[hdcnt++],buf);
  8940.             if (!strncmp(buf,"HTTP",4)) {
  8941.                 j = ckindex(" ",buf,0,0,0);
  8942.                 p = &buf[j];
  8943.                 if (strncmp(p,"200",3)) {
  8944.                     /* an error has occurred */
  8945.                     printf("Failure: Server reports %s",p);
  8946.                     rc = -1;
  8947.                     goto getexit;
  8948.                 }
  8949. #ifdef CMDATE2TM
  8950.             } else if (!strncmp(buf,"Last-Modified",13)) {
  8951.                 mod_t = http_date(&buf[15]);
  8952.             } else if (!strncmp(buf,"Date",4)) {
  8953.                 srv_t = http_date(&buf[4]);
  8954. #endif /* CMDATE2TM */
  8955.             }
  8956.             i = 0;
  8957.         } else {
  8958.             i++;
  8959.         }
  8960.     }
  8961.  
  8962.     /* Now we have the contents of the file */
  8963.     if ( local && local[0] ) {
  8964.         if (zopeno(ZOFILE,local,NULL,NULL)) {
  8965.             while ((ch = ttinc(0)) >= 0) {
  8966.                 zchout(ZOFILE,(CHAR)ch);
  8967.             }
  8968.             zclose(ZOFILE);
  8969. #ifdef CMDATE2TM
  8970. #ifdef OS2
  8971.             u_t.actime = srv_t ? srv_t : local_t;
  8972.             u_t.modtime = mod_t ? mod_t : local_t;
  8973. #else /* OS2 */
  8974. #ifdef SYSUTIMEH
  8975.             u_t.actime = srv_t ? srv_t : local_t;
  8976.             u_t.modtime = mod_t ? mod_t : local_t;
  8977. #else
  8978. #ifdef BSD44
  8979.             u_t[0].tv_sec = srv_t ? srv_t : local_t;
  8980.             u_t[1].tv_sec = mod_t ? mod_t : local_t;
  8981. #else
  8982.             u_t.mtime = srv_t ? srv_t : local_t;
  8983.             u_t.atime = mod_t ? mod_t : local_t;
  8984. #endif /* BSD44 */
  8985. #endif /* SYSUTIMEH */
  8986. #endif /* OS2 */
  8987.             utime(local,&u_t);
  8988. #endif /* CMDATE2TM */
  8989.             if (array)
  8990.                 http_mkarray(headers,hdcnt,array);
  8991.             rc = 0;
  8992.         } else {
  8993.             rc = -1;
  8994.         }
  8995.     } else {
  8996.         while ((ch = ttinc(0)) >= 0)
  8997.             conoc((CHAR)ch);
  8998.         if (array)
  8999.             http_mkarray(headers,hdcnt,array);
  9000.         rc = 0;
  9001.     }
  9002.  
  9003.   getexit:
  9004.     ttclos(0);
  9005.     free(request);
  9006.     for (i = 0; i < hdcnt; i++) {
  9007.         if (headers[i])
  9008.           free(headers[i]);
  9009.     }
  9010.     return(rc);
  9011. }
  9012.  
  9013. int
  9014. #ifdef CK_ANSIC
  9015. http_head(char * agent, char ** hdrlist, char * user,
  9016.           char * pwd, char array, char * local, char * remote)
  9017. #else
  9018. http_head(agent, hdrlist, user, pwd, array, local, remote)
  9019.     char * agent; char ** hdrlist; char * user;
  9020.     char * pwd; char array; char * local; char * remote;
  9021. #endif /* CK_ANSIC */
  9022. {
  9023.     char * request = NULL;
  9024.     int    i, j, len = 0, hdcnt = 0, rc = -1;
  9025.     int    ch;
  9026.     char   buf[HTTPBUFLEN], *p;
  9027.     int    nullline;
  9028.     time_t mod_t;
  9029.     time_t srv_t;
  9030.     time_t local_t;
  9031.     char passwd[64];
  9032.     char b64in[128];
  9033.     char b64out[256];
  9034.     char * headers[HTTPHEADCNT];
  9035.  
  9036.     if (ttyfd == -1)
  9037.       return(-1);
  9038.  
  9039.     if (array) {
  9040.         for (i = 0; i < HTTPHEADCNT; i++)
  9041.           headers[i] = NULL;
  9042.     }
  9043.     len = 9;                            /* HEAD */
  9044.     len += strlen(HTTP_VERSION);
  9045.     len += strlen(remote);
  9046.  
  9047.     for (i = 0; hdrlist[i]; i++)
  9048.       len += strlen(hdrlist[i]) + 2;
  9049.     if (agent)
  9050.       len += 13 + strlen(agent);
  9051.     if (user) {
  9052.         if (!pwd) {
  9053.             readpass("Password: ",passwd,64);
  9054.             pwd = passwd;
  9055.         }
  9056.         sprintf(b64in,"%s:%s",user,pwd);
  9057.         j = b8tob64(b64in,strlen(b64in),b64out,256);
  9058.         memset(pwd,0,strlen(pwd));      /* NOT PORTABLE */
  9059.         if (j < 0)
  9060.           return(-1);
  9061.         b64out[j] = '\0';
  9062.         len += j + 24;
  9063.     }
  9064.     len += 3;                           /* blank line + null */
  9065.  
  9066.     request = (char *)malloc(len);
  9067.     if (!request)
  9068.       return(-1);
  9069.  
  9070.     sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
  9071.     if (agent) {
  9072.         strcat(request,"User-Agent: ");
  9073.         strcat(request,agent);
  9074.         strcat(request,"\r\n");
  9075.     }
  9076.     if (user) {
  9077.         strcat(request,"Authorization: Basic ");
  9078.         strcat(request,b64out);
  9079.         strcat(request,"\r\n");
  9080.     }
  9081.     for (i = 0; hdrlist[i]; i++) {
  9082.         strcat(request,hdrlist[i]);
  9083.         strcat(request,"\r\n");
  9084.     }
  9085.     strcat(request,"\r\n");
  9086.  
  9087.     if (!zopeno(ZOFILE,local,NULL,NULL)) {
  9088.         free(request);
  9089.         return(-1);
  9090.     }
  9091.     ttol((CHAR *)request,strlen(request));
  9092.  
  9093.     /* Process the headers */
  9094.  
  9095.     local_t = time(NULL);
  9096.     nullline = 0;
  9097.     i = 0;
  9098.     while (!nullline && (ch = ttinc(0)) >= 0 && i < HTTPBUFLEN) {
  9099.         buf[i] = ch;
  9100.         if (buf[i] == 10) {             /* found end of line */
  9101.             if (i <= 1)
  9102.               nullline = 1;
  9103.             i++;
  9104.             buf[i] = '\0';
  9105.             if (array && !nullline && hdcnt < HTTPHEADCNT)
  9106.               makestr(&headers[hdcnt++],buf);
  9107.             if (!strncmp(buf,"HTTP",4)) {
  9108.                 j = ckindex(" ",buf,0,0,0);
  9109.                 p = &buf[j];
  9110.                 if (strncmp(p,"200",3)) {
  9111.                     /* an error has occurred */
  9112.                     printf("Failure: Server reports %s",p);
  9113.                     rc = -1;
  9114.                     goto headexit;
  9115.                 }
  9116.             } else {
  9117.                 zsout(ZOFILE,buf);
  9118.             }
  9119.             i = 0;
  9120.         } else {
  9121.             i++;
  9122.         }
  9123.     }
  9124.     if (array)
  9125.       http_mkarray(headers,hdcnt,array);
  9126.     rc = 0;
  9127.  
  9128.   headexit:
  9129.     zclose(ZOFILE);
  9130.     ttclos(0);
  9131.     free(request);
  9132.     for (i = 0; i < hdcnt; i++) {
  9133.         if (headers[i])
  9134.           free(headers[i]);
  9135.     }
  9136.     return(rc);
  9137. }
  9138.  
  9139. int
  9140. #ifdef CK_ANSIC
  9141. http_index(char * agent, char ** hdrlist, char * user, char * pwd,
  9142.              char array, char * local, char * remote)
  9143. #else
  9144. http_index(agent, hdrlist, user, pwd, array, local, remote)
  9145.     char * agent; char ** hdrlist; char * user; char * pwd;
  9146.     char array; char * local; char * remote;
  9147. #endif /* CK_ANSIC */
  9148. {
  9149.     char * request = NULL;
  9150.     int    i, j, len = 0, hdcnt = 0, rc = -1;
  9151.     int    ch;
  9152.     char   buf[HTTPBUFLEN], *p;
  9153.     int    nullline;
  9154.     time_t mod_t;
  9155.     time_t srv_t;
  9156.     time_t local_t;
  9157.     char passwd[64];
  9158.     char b64in[128];
  9159.     char b64out[256];
  9160.     char * headers[HTTPHEADCNT];
  9161.  
  9162.     if (ttyfd == -1)
  9163.       return(-1);
  9164.  
  9165.     if (array) {
  9166.         for (i = 0; i < HTTPHEADCNT; i++)
  9167.           headers[i] = NULL;
  9168.     }
  9169.     len = 10;                            /* INDEX */
  9170.     len += strlen(HTTP_VERSION);
  9171.     len += strlen(remote);
  9172.  
  9173.     for (i = 0; hdrlist[i]; i++)
  9174.       len += strlen(hdrlist[i]) + 2;
  9175.     if (agent)
  9176.         len += 13 + strlen(agent);
  9177.     if (user) {
  9178.         if (!pwd) {
  9179.             readpass("Password: ",passwd,64);
  9180.             pwd = passwd;
  9181.         }
  9182.         sprintf(b64in,"%s:%s",user,pwd);
  9183.         j = b8tob64(b64in,strlen(b64in),b64out,256);
  9184.         memset(pwd,0,strlen(pwd));
  9185.         if (j < 0)
  9186.           return(-1);
  9187.         b64out[j] = '\0';
  9188.         len += j + 24;
  9189.     }
  9190.     len += 3;                           /* blank line + null */
  9191.  
  9192.     request = malloc(len);
  9193.     if (!request)
  9194.       return(-1);
  9195.  
  9196.     sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
  9197.     if (agent) {
  9198.         strcat(request,"User-Agent: ");
  9199.         strcat(request,agent);
  9200.         strcat(request,"\r\n");
  9201.     }
  9202.     if (user) {
  9203.         strcat(request,"Authorization: Basic ");
  9204.         strcat(request,b64out);
  9205.         strcat(request,"\r\n");
  9206.     }
  9207.     for (i = 0; hdrlist[i]; i++) {
  9208.         strcat(request,hdrlist[i]);
  9209.         strcat(request,"\r\n");
  9210.     }
  9211.     strcat(request,"\r\n");
  9212.     ttol((CHAR *)request,strlen(request));
  9213.  
  9214.     /* Process the headers */
  9215.     local_t = time(NULL);
  9216.     nullline = 0;
  9217.     i = 0;
  9218.     while (!nullline && (ch = ttinc(0)) >= 0 && i < HTTPBUFLEN) {
  9219.         buf[i] = ch;
  9220.         if (buf[i] == 10) {             /* found end of line */
  9221.             if (i <= 1)
  9222.               nullline = 1;
  9223.             i++;
  9224.             buf[i] = '\0';
  9225.             if (array && !nullline && hdcnt < HTTPHEADCNT)
  9226.               makestr(&headers[hdcnt++],buf);
  9227.             if (!strncmp(buf,"HTTP",4)) {
  9228.                 j = ckindex(" ",buf,0,0,0);
  9229.                 p = &buf[j];
  9230.                 if (strncmp(p,"200",3)) {
  9231.                     /* an error has occurred */
  9232.                     printf("Failure: Server reports %s",p);
  9233.                     rc = -1;
  9234.                     goto indexexit;
  9235.                 }
  9236.             } else if ( !nullline ) {
  9237.                 printf("%s",buf);
  9238.             }
  9239.             i = 0;
  9240.         } else {
  9241.             i++;
  9242.         }
  9243.     }
  9244.  
  9245.     /* Now we have the contents of the file */
  9246.     if ( local && local[0] ) {
  9247.         if (zopeno(ZOFILE,local,NULL,NULL)) {
  9248.             while ( (ch = ttinc(0)) >= 0 ) {
  9249.                 zchout(ZOFILE,(CHAR)ch);
  9250.             }
  9251.             zclose(ZOFILE);
  9252.         }
  9253.     } else {
  9254.         while ((ch = ttinc(0)) >= 0)
  9255.             conoc((CHAR)ch);
  9256.     }
  9257.     if (array)
  9258.       http_mkarray(headers,hdcnt,array);
  9259.     rc = 0;
  9260.  
  9261.   indexexit:
  9262.     ttclos(0);
  9263.     free(request);
  9264.     for (i = 0; i < hdcnt; i++) {
  9265.         if (headers[i])
  9266.           free(headers[i]);
  9267.     }
  9268.     return(rc);
  9269. }
  9270.  
  9271. int
  9272. #ifdef CK_ANSIC
  9273. http_put(char * agent, char ** hdrlist, char * mime, char * user,
  9274.           char * pwd, char array, char * local, char * remote)
  9275. #else
  9276. http_put(agent, hdrlist, mime, user, pwd, array, local, remote)
  9277.     char * agent; char ** hdrlist; char * mime; char * user;
  9278.     char * pwd; char array; char * local; char * remote;
  9279. #endif /* CK_ANSIC */
  9280. {
  9281.     char * request=NULL;
  9282.     int    i, j, len = 0, hdcnt = 0, rc = -1;
  9283.     int    ch;
  9284.     char   buf[HTTPBUFLEN], *p;
  9285.     int    nullline;
  9286.     time_t mod_t;
  9287.     time_t srv_t;
  9288.     time_t local_t;
  9289.     char passwd[64];
  9290.     char b64in[128];
  9291.     char b64out[256];
  9292.     int  filelen;
  9293.     char * headers[HTTPHEADCNT];
  9294.  
  9295.     if (ttyfd == -1)
  9296.       return(-1);
  9297.  
  9298.     if (array) {
  9299.         for (i = 0; i < HTTPHEADCNT; i++)
  9300.           headers[i] = NULL;
  9301.     }
  9302.     filelen = zchki(local);
  9303.     if (filelen < 0)
  9304.       return(-1);
  9305.  
  9306.     /* Compute length of request header */
  9307.     len = 8;                            /* PUT */
  9308.     len += strlen(HTTP_VERSION);
  9309.     len += strlen(remote);
  9310.  
  9311.     for (i = 0; hdrlist[i]; i++)
  9312.       len += strlen(hdrlist[i]) + 2;
  9313.     if (agent)
  9314.       len += 13 + strlen(agent);
  9315.     if (user) {
  9316.         if (!pwd) {
  9317.             readpass("Password: ",passwd,64);
  9318.             pwd = passwd;
  9319.         }
  9320.         sprintf(b64in,"%s:%s",user,pwd);
  9321.         j = b8tob64(b64in,strlen(b64in),b64out,256);
  9322.         memset(pwd,0,strlen(pwd));
  9323.         if (j < 0)
  9324.           return(-1);
  9325.         b64out[j] = '\0';
  9326.         len += j + 24;
  9327.     }
  9328.     len += 16 + strlen(mime);           /* Content-type: */
  9329.     len += 32;                          /* Content-length: */
  9330.     len += 32;                          /* Date: */
  9331.     len += 3;                           /* blank line + null */
  9332.  
  9333.     request = malloc(len);
  9334.     if (!request)
  9335.       return(-1);
  9336.  
  9337.     sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
  9338.     strcat(request,"Date: ");
  9339. #ifdef CMDATE2TM
  9340.     strcat(request,http_now());
  9341. #else
  9342.     strcap(request,...);
  9343. #endif /* CMDATE2TM */
  9344.     strcat(request,"\r\n");
  9345.     if (agent) {
  9346.         strcat(request,"User-Agent: ");
  9347.         strcat(request,agent);
  9348.         strcat(request,"\r\n");
  9349.     }
  9350.     if (user) {
  9351.         strcat(request,"Authorization: Basic ");
  9352.         strcat(request,b64out);
  9353.         strcat(request,"\r\n");
  9354.     }
  9355.     for (i = 0; hdrlist[i]; i++) {
  9356.         strcat(request,hdrlist[i]);
  9357.         strcat(request,"\r\n");
  9358.     }
  9359.     strcat(request,"Content-type: ");
  9360.     strcat(request,mime);
  9361.     strcat(request,"\r\n");
  9362.     sprintf(buf,"Content-length: %d\r\n",filelen);
  9363.     strcat(request,buf);
  9364.     strcat(request,"\r\n");
  9365.  
  9366.     /* Now we have the contents of the file */
  9367.     if (zopeni(ZIFILE,local)) {
  9368.         if (ttol((CHAR *)request,strlen(request)) <= 0) { /* Send request */
  9369.             zclose(ZIFILE);
  9370.             goto putexit;
  9371.         }
  9372.         /* Request headers have been sent */
  9373.  
  9374.         i = 0;
  9375.         while (zchin(ZIFILE,&ch) == 0) {
  9376.             buf[i++] = ch;
  9377.             if (i == HTTPBUFLEN) {
  9378.                 ttol((CHAR *)buf,HTTPBUFLEN);
  9379.                 i = 0;
  9380.             }
  9381.         }
  9382.         if (i > 0)
  9383.           ttol((CHAR *)buf,i);
  9384.         zclose(ZIFILE);
  9385.  
  9386.         /* Process the response headers */
  9387.         local_t = time(NULL);
  9388.         nullline = 0;
  9389.         i = 0;
  9390.         while (!nullline && (ch = ttinc(0)) >= 0 && i < HTTPBUFLEN) {
  9391.             buf[i] = ch;
  9392.             if (buf[i] == 10) {         /* found end of line */
  9393.                 if (i <= 1)
  9394.                   nullline = 1;
  9395.                 i++;
  9396.                 buf[i] = '\0';
  9397.                 if (array && !nullline && hdcnt < HTTPHEADCNT)
  9398.                   makestr(&headers[hdcnt++],buf);
  9399.                 if (!strncmp(buf,"HTTP",4)) {
  9400.                     j = ckindex(" ",buf,0,0,0);
  9401.                     p = &buf[j];
  9402.                     if (strncmp(p,"200",3)) {
  9403.                         /* an error has occurred */
  9404.                         printf("Failure: Server reports %s",p);
  9405.                         rc = -1;
  9406.                         goto putexit;
  9407.                     }
  9408.                 } else {
  9409.                     printf("%s",buf);
  9410.                 }
  9411.                 i = 0;
  9412.             } else {
  9413.                 i++;
  9414.             }
  9415.         }
  9416.         if (array)
  9417.           http_mkarray(headers,hdcnt,array);
  9418.         rc = 0;
  9419.     }
  9420.  
  9421.   putexit:
  9422.     ttclos(0);
  9423.     free(request);
  9424.     for (i = 0; i < hdcnt; i++) {
  9425.         if (headers[i])
  9426.           free(headers[i]);
  9427.     }
  9428.     return(rc);
  9429. }
  9430.  
  9431. int
  9432. #ifdef CK_ANSIC
  9433. http_delete(char * agent, char ** hdrlist, char * user,
  9434.           char * pwd, char array, char * remote)
  9435. #else
  9436. http_delete(agent, hdrlist, user, pwd, array, remote)
  9437.     char * agent; char ** hdrlist; char * user;
  9438.     char * pwd; char array; char * remote;
  9439. #endif /* CK_ANSIC */
  9440. {
  9441.     char * request=NULL;
  9442.     int    i, j, len = 0, hdcnt = 0, rc = -1;
  9443.     int    ch;
  9444.     char   buf[HTTPBUFLEN], *p;
  9445.     int    nullline;
  9446.     time_t mod_t;
  9447.     time_t srv_t;
  9448.     time_t local_t;
  9449.     char passwd[64];
  9450.     char b64in[128];
  9451.     char b64out[256];
  9452.     char * headers[HTTPHEADCNT];
  9453.  
  9454.     if (ttyfd == -1)
  9455.       return(-1);
  9456.  
  9457.     if (array) {
  9458.         for (i = 0; i < HTTPHEADCNT; i++)
  9459.           headers[i] = NULL;
  9460.     }
  9461.  
  9462.     /* Compute length of request header */
  9463.     len = 11;                            /* DELETE */
  9464.     len += strlen(HTTP_VERSION);
  9465.     len += strlen(remote);
  9466.  
  9467.     for (i = 0; hdrlist[i]; i++)
  9468.       len += strlen(hdrlist[i]) + 2;
  9469.     if (agent)
  9470.       len += 13 + strlen(agent);
  9471.     if (user) {
  9472.         if (!pwd) {
  9473.             readpass("Password: ",passwd,64);
  9474.             pwd = passwd;
  9475.         }
  9476.         sprintf(b64in,"%s:%s",user,pwd);
  9477.         j = b8tob64(b64in,strlen(b64in),b64out,256);
  9478.         memset(pwd,0,strlen(pwd));
  9479.         if (j < 0)
  9480.           return(-1);
  9481.         b64out[j] = '\0';
  9482.         len += j + 24;
  9483.     }
  9484.     len += 32;                          /* Date: */
  9485.     len += 3;                           /* blank line + null */
  9486.  
  9487.     request = malloc(len);
  9488.     if (!request)
  9489.       return(-1);
  9490.  
  9491.     sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
  9492.     strcat(request,"Date: ");
  9493. #ifdef CMDATE2TM
  9494.     strcat(request,http_now());
  9495. #else
  9496.     strcap(request,...);
  9497. #endif /* CMDATE2TM */
  9498.     strcat(request,"\r\n");
  9499.     if (agent) {
  9500.         strcat(request,"User-Agent: ");
  9501.         strcat(request,agent);
  9502.         strcat(request,"\r\n");
  9503.     }
  9504.     if (user) {
  9505.         strcat(request,"Authorization: Basic ");
  9506.         strcat(request,b64out);
  9507.         strcat(request,"\r\n");
  9508.     }
  9509.     for (i = 0; hdrlist[i]; i++) {
  9510.         strcat(request,hdrlist[i]);
  9511.         strcat(request,"\r\n");
  9512.     }
  9513.     strcat(request,"\r\n");
  9514.  
  9515.     /* Process the response headers */
  9516.     local_t = time(NULL);
  9517.     nullline = 0;
  9518.     i = 0;
  9519.     while (!nullline && (ch = ttinc(0)) >= 0 && i < HTTPBUFLEN) {
  9520.         buf[i] = ch;
  9521.         if (buf[i] == 10) {         /* found end of line */
  9522.             if (i <= 1)
  9523.                 nullline = 1;
  9524.             i++;
  9525.             buf[i] = '\0';
  9526.             if (array && !nullline && hdcnt < HTTPHEADCNT)
  9527.                 makestr(&headers[hdcnt++],buf);
  9528.             if (!strncmp(buf,"HTTP",4)) {
  9529.                 j = ckindex(" ",buf,0,0,0);
  9530.                 p = &buf[j];
  9531.                 if (strncmp(p,"200",3)) {
  9532.                     /* an error has occurred */
  9533.                     printf("Failure: Server reports %s",p);
  9534.                     rc = -1;
  9535.                     goto putexit;
  9536.                 }
  9537.             } else {
  9538.                 printf("%s",buf);
  9539.             }
  9540.             i = 0;
  9541.         } else {
  9542.                 i++;
  9543.         }
  9544.     }
  9545.     if (array)
  9546.         http_mkarray(headers,hdcnt,array);
  9547.     rc = 0;
  9548.  
  9549.   putexit:
  9550.     ttclos(0);
  9551.     free(request);
  9552.     for (i = 0; i < hdcnt; i++) {
  9553.         if (headers[i])
  9554.           free(headers[i]);
  9555.     }
  9556.     return(rc);
  9557. }
  9558.  
  9559. int
  9560. #ifdef CK_ANSIC
  9561. http_post(char * agent, char ** hdrlist, char * mime, char * user,
  9562.           char * pwd, char array, char * local, char * remote)
  9563. #else
  9564. http_post(agent, hdrlist, mime, user, pwd, array, local, remote)
  9565.     char * agent; char ** hdrlist; char * mime; char * user;
  9566.     char * pwd; char array; char * local; char * remote;
  9567. #endif /* CK_ANSIC */
  9568. {
  9569.     char * request=NULL;
  9570.     int    i, j, len = 0, hdcnt = 0, rc = -1;
  9571.     int    ch;
  9572.     char   buf[HTTPBUFLEN], *p;
  9573.     int    nullline;
  9574.     time_t mod_t;
  9575.     time_t srv_t;
  9576.     time_t local_t;
  9577.     char passwd[64];
  9578.     char b64in[128];
  9579.     char b64out[256];
  9580.     int  filelen;
  9581.     char * headers[HTTPHEADCNT];
  9582.  
  9583.     if (ttyfd == -1)
  9584.       return(-1);
  9585.  
  9586.     if (array) {
  9587.         for (i = 0; i < HTTPHEADCNT; i++)
  9588.           headers[i] = NULL;
  9589.     }
  9590.     filelen = zchki(local);
  9591.     if (filelen < 0)
  9592.       return(-1);
  9593.  
  9594.     /* Compute length of request header */
  9595.     len = 9;                            /* POST */
  9596.     len += strlen(HTTP_VERSION);
  9597.     len += strlen(remote);
  9598.  
  9599.     for (i = 0; hdrlist[i]; i++)
  9600.       len += strlen(hdrlist[i]) + 2;
  9601.     if (agent)
  9602.       len += 13 + strlen(agent);
  9603.     if (user) {
  9604.         if (!pwd) {
  9605.             readpass("Password: ",passwd,64);
  9606.             pwd = passwd;
  9607.         }
  9608.         sprintf(b64in,"%s:%s",user,pwd);
  9609.         j = b8tob64(b64in,strlen(b64in),b64out,256);
  9610.         memset(pwd,0,strlen(pwd));
  9611.         if (j < 0)
  9612.           return(-1);
  9613.         b64out[j] = '\0';
  9614.         len += j + 24;
  9615.     }
  9616.     len += 16 + strlen(mime);           /* Content-type: */
  9617.     len += 32;                          /* Content-length: */
  9618.     len += 32;                          /* Date: */
  9619.     len += 3;                           /* blank line + null */
  9620.  
  9621.     request = malloc(len);
  9622.     if (!request)
  9623.       return(-1);
  9624.  
  9625.     sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
  9626.     strcat(request,"Date: ");
  9627.     strcat(request,http_now());
  9628.     strcat(request,"\r\n");
  9629.     if (agent) {
  9630.         strcat(request,"User-Agent: ");
  9631.         strcat(request,agent);
  9632.         strcat(request,"\r\n");
  9633.     }
  9634.     if (user) {
  9635.         strcat(request,"Authorization: Basic ");
  9636.         strcat(request,b64out);
  9637.         strcat(request,"\r\n");
  9638.     }
  9639.     for (i = 0; hdrlist[i]; i++) {
  9640.         strcat(request,hdrlist[i]);
  9641.         strcat(request,"\r\n");
  9642.     }
  9643.     strcat(request,"Content-type: ");
  9644.     strcat(request,mime);
  9645.     strcat(request,"\r\n");
  9646.     sprintf(buf,"Content-length: %d\r\n",filelen);
  9647.     strcat(request,buf);
  9648.     strcat(request,"\r\n");
  9649.     strcat(request,"\r\n");
  9650.  
  9651.     /* Now we have the contents of the file */
  9652.     if (zopeni(ZIFILE,local)) {
  9653.         ttol((CHAR *)request,strlen(request)); /* Send request */
  9654.  
  9655.         i = 0;
  9656.         while (zchin(ZIFILE,&ch) == 0) {
  9657.             buf[i++] = ch;
  9658.             if (i == HTTPBUFLEN) {
  9659.                 ttol((CHAR *)buf,HTTPBUFLEN);
  9660.                 i = 0;
  9661.             }
  9662.         }
  9663.         if (i > 0)
  9664.           ttol((CHAR *)buf,HTTPBUFLEN);
  9665.         zclose(ZIFILE);
  9666.  
  9667.         /* Process the response headers */
  9668.         local_t = time(NULL);
  9669.         nullline = 0;
  9670.         i = 0;
  9671.         while (!nullline && (ch = ttinc(0)) >= 0 && i < HTTPBUFLEN) {
  9672.             buf[i] = ch;
  9673.             if (buf[i] == 10) {         /* found end of line */
  9674.                 if (i <= 1)
  9675.                   nullline = 1;
  9676.                 i++;
  9677.                 buf[i] = '\0';
  9678.                 if (array && !nullline && hdcnt < HTTPHEADCNT)
  9679.                   makestr(&headers[hdcnt++],buf);
  9680.                 if (!strncmp(buf,"HTTP",4)) {
  9681.                     j = ckindex(" ",buf,0,0,0);
  9682.                     p = &buf[j];
  9683.                     if (strncmp(p,"200",3)) {
  9684.                         /* an error has occurred */
  9685.                         printf("Failure: Server reports %s",p);
  9686.                         rc = -1;
  9687.                         goto postexit;
  9688.                     }
  9689.                 } else {
  9690.                     printf("%s",buf);
  9691.                 }
  9692.                 i = 0;
  9693.             } else {
  9694.                 i++;
  9695.             }
  9696.         }
  9697.         if (array)
  9698.           http_mkarray(headers,hdcnt,array);
  9699.         rc = 0;
  9700.     }
  9701.  
  9702.   postexit:
  9703.     ttclos(0);
  9704.     free(request);
  9705.     for (i = 0; i < hdcnt; i++) {
  9706.         if (headers[i])
  9707.           free(headers[i]);
  9708.     }
  9709.     return(rc);
  9710. }
  9711. #endif /* NOHTTP */
  9712.  
  9713. #ifdef CK_DNS_SRV
  9714.  
  9715. #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
  9716. #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
  9717. #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
  9718.  
  9719. #ifndef CKQUERYTYPE
  9720. #ifdef UNIXWARE
  9721. #ifndef UW7
  9722. #define CKQUERYTYPE CHAR
  9723. #endif /* UW7 */
  9724. #endif /* UNIXWARE */
  9725. #endif /* CKQUERYTYPE */
  9726.  
  9727. #ifndef CKQUERYTYPE
  9728. #define CKQUERYTYPE char
  9729. #endif /* CKQUERYTYPE */
  9730.  
  9731. /* 1 is success, 0 is failure */
  9732. int
  9733. locate_srv_dns(host, service, protocol, addr_pp, naddrs)
  9734. #ifdef CK_ANSIC
  9735.     const char *host;                   /* "const" not portable... */
  9736.     const char *service;
  9737.     const char *protocol;
  9738. #else
  9739.     char *host;
  9740.     char *service;
  9741.     char *protocol;
  9742. #endif /* CK_ANSIC */
  9743.     struct sockaddr **addr_pp;
  9744.     int *naddrs;
  9745. {
  9746.     int code, nout, j, count;
  9747.     union {
  9748.         unsigned char bytes[2048];
  9749.         HEADER hdr;
  9750.     } answer;
  9751.     unsigned char *p=NULL;
  9752.     CKQUERYTYPE query[MAX_DNS_NAMELEN];
  9753.     struct sockaddr *addr = NULL;
  9754.     struct sockaddr_in *sin = NULL;
  9755.     struct hostent *hp = NULL;
  9756.     int type, class;
  9757.     int status, priority, weight, size, len, numanswers, numqueries, rdlen;
  9758.     unsigned short port;
  9759. #ifdef CK_ANSIC
  9760.     const
  9761. #endif /* CK_ANSIC */
  9762.       int hdrsize = sizeof(HEADER);
  9763.     struct srv_dns_entry {
  9764.         struct srv_dns_entry *next;
  9765.         int priority;
  9766.         int weight;
  9767.         unsigned short port;
  9768.         char *host;
  9769.     };
  9770.     struct srv_dns_entry *head = NULL;
  9771.     struct srv_dns_entry *srv = NULL, *entry = NULL;
  9772.     char * s = NULL;
  9773.  
  9774.     nout = 0;
  9775.     addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
  9776.     if (addr == NULL)
  9777.       return 0;
  9778.  
  9779.     count = 1;
  9780.  
  9781.     /*
  9782.      * First build a query of the form:
  9783.      *
  9784.      *   service.protocol.host
  9785.      *
  9786.      * which will most likely be something like:
  9787.      *
  9788.      *   _telnet._tcp.host
  9789.      *
  9790.      */
  9791.     if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
  9792.         > MAX_DNS_NAMELEN
  9793.         )
  9794.       goto dnsout;
  9795.     sprintf((char *)query, "_%s._%s.%s", service, protocol, host);
  9796.  
  9797.     size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
  9798.  
  9799.     if (size < hdrsize)
  9800.       goto dnsout;
  9801.  
  9802.     /* We got a reply - See how many answers it contains. */
  9803.  
  9804.     p = answer.bytes;
  9805.  
  9806.     numqueries = ntohs(answer.hdr.qdcount);
  9807.     numanswers = ntohs(answer.hdr.ancount);
  9808.  
  9809.     p += sizeof(HEADER);
  9810.  
  9811.     /*
  9812.      * We need to skip over all of the questions, so we have to iterate
  9813.      * over every query record.  dn_expand() is able to tell us the size
  9814.      * of compressed DNS names, so we use it.
  9815.      */
  9816.     while (numqueries--) {
  9817.         len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
  9818.         if (len < 0)
  9819.           goto dnsout;
  9820.         INCR_CHECK(p, len + 4);
  9821.     }
  9822.  
  9823.     /*
  9824.      * We're now pointing at the answer records.  Only process them if
  9825.      * they're actually T_SRV records (they might be CNAME records,
  9826.      * for instance).
  9827.      *
  9828.      * But in a DNS reply, if you get a CNAME you always get the associated
  9829.      * "real" RR for that CNAME.  RFC 1034, 3.6.2:
  9830.      *
  9831.      * CNAME RRs cause special action in DNS software.  When a name server
  9832.      * fails to find a desired RR in the resource set associated with the
  9833.      * domain name, it checks to see if the resource set consists of a CNAME
  9834.      * record with a matching class.  If so, the name server includes the CNAME
  9835.      * record in the response and restarts the query at the domain name
  9836.      * specified in the data field of the CNAME record.  The one exception to
  9837.      * this rule is that queries which match the CNAME type are not restarted.
  9838.      *
  9839.      * In other words, CNAMEs do not need to be expanded by the client.
  9840.      */
  9841.     while (numanswers--) {
  9842.  
  9843.         /* First is the name; use dn_expand() to get the compressed size. */
  9844.         len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
  9845.         if (len < 0)
  9846.           goto dnsout;
  9847.         INCR_CHECK(p, len);
  9848.  
  9849.         CHECK(p,2);                     /* Query type */
  9850.         type = NTOHSP(p,2);
  9851.  
  9852.         CHECK(p, 6);                    /* Query class */
  9853.         class = NTOHSP(p,6);            /* Also skip over 4-byte TTL */
  9854.  
  9855.         CHECK(p,2);                     /* Record data length */
  9856.         rdlen = NTOHSP(p,2);
  9857.         /*
  9858.          * If this is an SRV record, process it.  Record format is:
  9859.          *
  9860.          * Priority
  9861.          * Weight
  9862.          * Port
  9863.          * Server name
  9864.          */
  9865.         if (class == C_IN && type == T_SRV) {
  9866.             CHECK(p,2);
  9867.             priority = NTOHSP(p,2);
  9868.             CHECK(p, 2);
  9869.             weight = NTOHSP(p,2);
  9870.             CHECK(p, 2);
  9871.             port = NTOHSP(p,2);
  9872.             len = dn_expand(answer.
  9873.                             bytes,
  9874.                             answer.bytes + size,
  9875.                             p,
  9876.                             query,
  9877.                             sizeof(query)
  9878.                             );
  9879.             if (len < 0)
  9880.               goto dnsout;
  9881.             INCR_CHECK(p, len);
  9882.             /*
  9883.              * We got everything.  Insert it into our list, but make sure
  9884.              * it's in the right order.  Right now we don't do anything
  9885.              * with the weight field
  9886.              */
  9887.             srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
  9888.             if (srv == NULL)
  9889.               goto dnsout;
  9890.  
  9891.             srv->priority = priority;
  9892.             srv->weight = weight;
  9893.             srv->port = port;
  9894.             makestr(&s,(char *)query);  /* strdup() is not portable */
  9895.             srv->host = s;
  9896.  
  9897.             if (head == NULL || head->priority > srv->priority) {
  9898.                 srv->next = head;
  9899.                 head = srv;
  9900.             } else
  9901.                 /*
  9902.                  * Confusing.  Insert an entry into this spot only if:
  9903.                  *  . The next person has a higher priority (lower
  9904.                  *    priorities are preferred), or:
  9905.                  *  . There is no next entry (we're at the end)
  9906.                  */
  9907.               for (entry = head; entry != NULL; entry = entry->next)
  9908.                 if ((entry->next &&
  9909.                      entry->next->priority > srv->priority) ||
  9910.                     entry->next == NULL) {
  9911.                     srv->next = entry->next;
  9912.                     entry->next = srv;
  9913.                     break;
  9914.                 }
  9915.         } else
  9916.           INCR_CHECK(p, rdlen);
  9917.     }
  9918.  
  9919.     /*
  9920.      * Now we've got a linked list of entries sorted by priority.
  9921.      * Start looking up A records and returning addresses.
  9922.      */
  9923.     if (head == NULL)
  9924.       goto dnsout;
  9925.  
  9926.     for (entry = head; entry != NULL; entry = entry->next) {
  9927.         hp = gethostbyname(entry->host);
  9928.         if (hp != 0) {
  9929.  
  9930.             /* Watch out - memset() and memcpy() are not portable... */
  9931.  
  9932.             switch (hp->h_addrtype) {
  9933.               case AF_INET:
  9934.                 for (j = 0; hp->h_addr_list[j]; j++) {
  9935.                     sin = (struct sockaddr_in *) &addr[nout++];
  9936.                     memset ((char *) sin, 0, sizeof (struct sockaddr));
  9937.                     sin->sin_family = hp->h_addrtype;
  9938.                     sin->sin_port = htons(entry->port);
  9939.                     memcpy((char *) &sin->sin_addr,
  9940.                            (char *) hp->h_addr_list[j],
  9941.                            sizeof(struct in_addr));
  9942.                     if (nout + 1 >= count) {
  9943.                         count += 5;
  9944.                         addr = (struct sockaddr *)
  9945.                           realloc((char *) addr,
  9946.                                   sizeof(struct sockaddr) * count);
  9947.                         if (!addr)
  9948.                           goto dnsout;
  9949.                     }
  9950.                 }
  9951.                 break;
  9952.               default:
  9953.                 break;
  9954.             }
  9955.         }
  9956.     }
  9957.     for (entry = head; entry != NULL;) {
  9958.         free(entry->host);
  9959.         entry->host = NULL;
  9960.         srv = entry;
  9961.         entry = entry->next;
  9962.         free(srv);
  9963.         srv = NULL;
  9964.     }
  9965.  
  9966.   dnsout:
  9967.     if (srv)
  9968.       free(srv);
  9969.  
  9970.     if (nout == 0) {                    /* No good servers */
  9971.         if (addr)
  9972.           free(addr);
  9973.         return 0;
  9974.     }
  9975.     *addr_pp = addr;
  9976.     *naddrs = nout;
  9977.     return 1;
  9978. }
  9979. #endif /* CK_DNS_SRV */
  9980.  
  9981. #ifdef TNCODE
  9982. #ifdef CK_FORWARD_X
  9983. int
  9984. fwdx_create_listen_socket(screen) int screen; {
  9985. #ifdef NOPUTENV
  9986.     return(-1);
  9987. #else /* NOPUTENV */
  9988.     struct sockaddr_in saddr;
  9989.     int display, port, sock=-1, i;
  9990.     static char env[512];
  9991.  
  9992.     /*
  9993.      * X Windows Servers support multiple displays by listening on
  9994.      * one socket per display.  Display 0 is port 6000; Display 1 is
  9995.      * port 6001; etc.
  9996.      *
  9997.      * We start by trying to open port 6001 so that display 0 is
  9998.      * reserved for the local X Windows Server.
  9999.      */
  10000.  
  10001.     for ( display=1; display < 1000 ; display++  ) {
  10002.  
  10003.         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  10004.             debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
  10005.             return(-1);
  10006.         }
  10007.  
  10008.         port = 6000 + display;
  10009.         bzero((char *)&saddr, sizeof(saddr));
  10010.         saddr.sin_family = AF_INET;
  10011.         saddr.sin_addr.s_addr = inet_addr(myipaddr);
  10012.         saddr.sin_port = htons(port);
  10013.  
  10014.         if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
  10015.             i = errno;                  /* Save error code */
  10016. #ifdef TCPIPLIB
  10017.             socket_close(sock);
  10018. #else /* TCPIPLIB */
  10019.             close(sock);
  10020. #endif /* TCPIPLIB */
  10021.             sock = -1;
  10022.             debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
  10023.             continue;
  10024.         }
  10025.  
  10026.         debug(F100,"fdwx_create_listen_socket() bind OK","",0);
  10027.         break;
  10028.     }
  10029.  
  10030.     if ( display > 1000 ) {
  10031.         debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
  10032.         return(-1);
  10033.     }
  10034.  
  10035.     if (listen(sock, 5) < 0) {
  10036.         i = errno;                  /* Save error code */
  10037. #ifdef TCPIPLIB
  10038.         socket_close(sock);
  10039. #else /* TCPIPLIB */
  10040.         close(sock);
  10041. #endif /* TCPIPLIB */
  10042.         debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
  10043.         return(-1);
  10044.     }
  10045.     debug(F100,"fwdx_create_listen_socket() listen OK","",0);
  10046.  
  10047.     TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
  10048.     if (!myipaddr[0])
  10049.         getlocalipaddr();
  10050.     if ( myipaddr[0] )
  10051.         sprintf(env,"DISPLAY=%s:%d:%d",myipaddr,display,screen);
  10052.     else
  10053.         sprintf(env,"DISPLAY=%d:%d",display,screen);
  10054.     putenv(env);
  10055.     return(0);
  10056. #endif /* NOPUTENV */
  10057. }
  10058.  
  10059.  
  10060. int
  10061. fwdx_open_client_channel(channel) int channel; {
  10062.     char * env;
  10063.     struct sockaddr_in saddr;
  10064.     int colon, dot, display, port, sock, i;
  10065.     char buf[256];
  10066. #ifdef TCP_NODELAY
  10067.     int on=1;
  10068. #endif /* TCP_NODELAY */
  10069.  
  10070.     debug(F111,"fwdx_create_client_channel()","channel",channel);
  10071.  
  10072.     for ( i=0; i<MAXFWDX ; i++ ) {
  10073.         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
  10074.             /* Already open */
  10075.             debug(F110,"fwdx_create_client_channel()","already open",0);
  10076.             return(0);
  10077.         }
  10078.     }
  10079.  
  10080.     env = getenv("DISPLAY");
  10081.     if ( env )
  10082.         ckstrncpy(buf,env,256);
  10083.     else
  10084.         ckstrncpy(buf,"127.0.0.1:0.0",256);
  10085.  
  10086.     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  10087.         debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
  10088.         return(-1);
  10089.     }
  10090.  
  10091.     bzero((char *)&saddr,sizeof(saddr));
  10092.     saddr.sin_family = AF_INET;
  10093.  
  10094.     colon = ckindex(":",buf,0,0,1);
  10095.     dot   = ckindex(".",&buf[colon],0,0,1);
  10096.     if ( dot )
  10097.         buf[colon+dot-1] = '\0';
  10098.     display = atoi(&buf[colon+dot-1]);
  10099.  
  10100.     port = 6000 + display;
  10101.     saddr.sin_port = htons(port);
  10102.  
  10103.     if ( colon ) {
  10104.         buf[colon-1] = '\0';
  10105.         debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
  10106.         saddr.sin_addr.s_addr = inet_addr(buf);
  10107.     } else {
  10108.         debug(F110,"fwdx_create_client_channel() ip-address",myipaddr,0);
  10109.         saddr.sin_addr.s_addr = inet_addr(myipaddr);
  10110.     }
  10111.  
  10112.     if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
  10113.         debug(F110,"fwdx_create_client_channel()","connect() failed",0);
  10114. #ifdef TCPIPLIB
  10115.         socket_close(sock);
  10116. #else /* TCPIPLIB */
  10117.         close(sock);
  10118. #endif /* TCPIPLIB */
  10119.         return(-1);
  10120.     }
  10121.  
  10122. #ifdef TCP_NODELAY
  10123.     setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
  10124. #endif /* TCP_NODELAY */
  10125.  
  10126.     for ( i=0; i<MAXFWDX ; i++ ) {
  10127.         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
  10128.             TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
  10129.             TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
  10130.             debug(F111,"fwdx_create_client_channel()","socket",sock);
  10131.             return(0);
  10132.         }
  10133.     }
  10134.     return(-1);
  10135. }
  10136.  
  10137. int
  10138. fwdx_open_server_channel() {
  10139.     int sock, ready_to_accept, sock2,channel,i;
  10140. #ifdef TCP_NODELAY
  10141.     int on=1;
  10142. #endif /* TCP_NODELAY */
  10143. #ifdef UCX50
  10144.     static u_int saddrlen;
  10145. #else
  10146.     static SOCKOPT_T saddrlen;
  10147. #endif /* UCX50 */
  10148.     struct sockaddr_in saddr;
  10149.     char sb[8];
  10150.     extern char tn_msg[];
  10151. #ifdef BSDSELECT
  10152.     fd_set rfds;
  10153.     struct timeval tv;
  10154. #else
  10155. #ifdef BELLSELCT
  10156.     fd_set rfds;
  10157. #else
  10158.     fd_set rfds;
  10159.     struct timeval {
  10160.         long tv_sec;
  10161.         long tv_usec;
  10162.     } tv;
  10163. #endif /* BELLSELECT */
  10164. #endif /* BSDSELECT */
  10165.     unsigned short nchannel;
  10166.     unsigned char * p;
  10167.  
  10168.     sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
  10169.  
  10170.   try_again:
  10171.  
  10172. #ifdef BSDSELECT
  10173.     tv.tv_sec  = tv.tv_usec = 0L;
  10174.     tv.tv_usec = 50;
  10175.     FD_ZERO(&rfds);
  10176.     FD_SET(sock, &rfds);
  10177.     ready_to_accept =
  10178.         ((select(FD_SETSIZE,
  10179. #ifdef HPUX
  10180. #ifdef HPUX1010
  10181.                   (fd_set *)
  10182. #else
  10183.  
  10184.                   (int *)
  10185. #endif /* HPUX1010 */
  10186. #else
  10187. #ifdef __DECC
  10188.                   (fd_set *)
  10189. #endif /* __DECC */
  10190. #endif /* HPUX */
  10191.                   &rfds, NULL, NULL, &tv) > 0) &&
  10192.           FD_ISSET(sock, &rfds));
  10193. #else /* BSDSELECT */
  10194. #ifdef IBMSELECT
  10195.     ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
  10196. #else
  10197. #ifdef BELLSELECT
  10198.     FD_ZERO(rfds);
  10199.     FD_SET(sock, rfds);
  10200.     ready_to_accept =
  10201.         ((select(128, rfds, NULL, NULL, 50) > 0) &&
  10202.           FD_ISSET(sock, rfds));
  10203. #else
  10204. /* Try this - what's the worst that can happen... */
  10205.  
  10206.     tv.tv_sec  = tv.tv_usec = 0L;
  10207.     tv.tv_usec = 50;
  10208.     FD_ZERO(&rfds);
  10209.     FD_SET(sock, &rfds);
  10210.     ready_to_accept =
  10211.         ((select(FD_SETSIZE,
  10212.                   (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
  10213.           FD_ISSET(sock, &rfds));
  10214. #endif /* BELLSELECT */
  10215. #endif /* IBMSELECT */
  10216. #endif /* BSDSELECT */
  10217.  
  10218.     if ( !ready_to_accept )
  10219.         return(0);
  10220.  
  10221.     if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
  10222.         int i = errno;                  /* save error code */
  10223.         debug(F101,"tcpsrv_open accept errno","",i);
  10224.         return(-1);
  10225.     }
  10226.  
  10227.     /*
  10228.      * Now we have the open socket.  We must now find a channel to store
  10229.      * it in, and then notify the client.
  10230.      */
  10231.  
  10232.     for ( channel=0;channel<MAXFWDX;channel++ ) {
  10233.         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
  10234.             break;
  10235.     }
  10236.  
  10237.     if ( channel == MAXFWDX ) {
  10238. #ifdef TCPIPLIB
  10239.         socket_close(sock2);
  10240. #else /* TCPIPLIB */
  10241.         close(sock2);
  10242. #endif /* TCPIPLIB */
  10243.         return(-1);
  10244.     }
  10245.  
  10246.     if ( fwdx_send_open(channel) < 0 ) {
  10247. #ifdef TCPIPLIB
  10248.         socket_close(sock2);
  10249. #else /* TCPIPLIB */
  10250.         close(sock2);
  10251. #endif /* TCPIPLIB */
  10252.     }
  10253.  
  10254. #ifdef TCP_NODELAY
  10255.     setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
  10256. #endif /* TCP_NODELAY */
  10257.  
  10258.     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
  10259.     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
  10260.     goto try_again;
  10261.  
  10262.     return(0);  /* never reached */
  10263. }
  10264.  
  10265. int
  10266. fwdx_close_channel(channel) int channel; {
  10267.     int i;
  10268.  
  10269.     for ( i=0; i<MAXFWDX ; i++ ) {
  10270.         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
  10271.             break;
  10272.     }
  10273.     if ( i == MAXFWDX )
  10274.         return(-1);
  10275.  
  10276. #ifdef TCPIPLIB
  10277.     socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd);
  10278. #else /* TCPIPLIB */
  10279.     close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd);
  10280. #endif /* TCPIPLIB */
  10281.     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
  10282.     TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
  10283.     return(0);
  10284. }
  10285.  
  10286. int
  10287. fwdx_close_all() {
  10288.     int x;
  10289.  
  10290.     if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
  10291. #ifdef TCPIPLIB
  10292.         socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
  10293. #else /* TCPIPLIB */
  10294.         close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
  10295. #endif /* TCPIPLIB */
  10296.         TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
  10297.     }
  10298.  
  10299.     for ( x=0 ; x<MAXFWDX ; x++ ) {
  10300.         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1 ) {
  10301. #ifdef TCPIPLIB
  10302.             socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd);
  10303. #else /* TCPIPLIB */
  10304.             close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd);
  10305. #endif /* TCPIPLIB */
  10306.             TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
  10307.             TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
  10308.         }
  10309.     }
  10310.     return(0);
  10311. }
  10312.  
  10313. /* The following definitions are for Unix */
  10314. #ifndef socket_write
  10315. #define socket_write(f,s,n)    write(f,s,n)
  10316. #endif /* socket_write */
  10317. #ifndef socket_read
  10318. #define socket_read(f,s,n)     read(f,s,n)
  10319. #endif /* socket_read */
  10320.  
  10321. int
  10322. fwdx_write_data_to_channel(channel, data, len)
  10323.     int channel; char * data; int len;
  10324. {
  10325.     int sock, count, try=0, length = 0, i;
  10326.  
  10327.     for ( i=0; i<MAXFWDX ; i++ ) {
  10328.         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
  10329.             break;
  10330.     }
  10331.     if ( i == MAXFWDX ) {
  10332.         debug(F110,"fwdx_write_data_to_channel",
  10333.                "attempting to write to closed channel",0);
  10334.         return(-1);
  10335.     }
  10336.  
  10337.     sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
  10338.     debug(F111,"fwdx_write_data_to_channel","socket",sock);
  10339.     hexdump("fwdx_write_data_to_channel",data,len);
  10340.  
  10341.   fwdx_write_data_to_channel_retry:
  10342.  
  10343.     if ((count = socket_write(sock,data,len)) < 0) {
  10344.         int s_errno = socket_errno; /* maybe a function */
  10345.         debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
  10346. #ifdef OS2
  10347.         if (os2socketerror(s_errno) < 0)
  10348.             return(-2);
  10349. #endif /* OS2 */
  10350.         return(-1);                 /* Call it an i/o error */
  10351.     }
  10352.     if (count < len) {
  10353.         debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
  10354.         if (try > 25) {
  10355.             /* don't try more than 25 times */
  10356.             debug(F100,
  10357.           "fwdx_write_data_to_channel tried more than 25 times","",0);
  10358.             return(-1);
  10359.         }
  10360.         if (count > 0) {
  10361.             data += count;
  10362.             len -= count;
  10363.         }
  10364.         debug(F111,"fwdx_write_data_to_channel retry",data,len);
  10365.         if ( len > 0 )
  10366.             goto fwdx_write_data_to_channel_retry;
  10367.     }
  10368.  
  10369.     debug(F111,"fwdx_write_data_to_channel socket_write",data,length);
  10370.     return(length); /* success - return total length */
  10371. }
  10372.  
  10373. int
  10374. fwdx_send_data_from_channel(channel, data, len)
  10375.     int channel; char * data; int len;
  10376. {
  10377.     extern char tn_msg[];
  10378.     int nchannel;
  10379.     static CHAR sb[2048];
  10380.     CHAR * p;
  10381.     int i, j;
  10382.     unsigned int tmp;
  10383.  
  10384.     debug(F111,"fwdx_send_data_from_channel()","channel",channel);
  10385.  
  10386.     nchannel = htons(channel);
  10387.     p = (unsigned char *) &nchannel;
  10388.  
  10389.     sb[0] = (CHAR) IAC;                 /* I Am a Command */
  10390.     sb[1] = (CHAR) SB;                  /* Subnegotiation */
  10391.     sb[2] = TELOPT_FORWARD_X;           /* Forward X */
  10392.     sb[3] = FWDX_DATA;                  /* Data */
  10393.     sb[4] = p[0];
  10394.     sb[5] = p[1];
  10395.  
  10396.     for ( i=0, j=6 ; i<len ; i++ ) {
  10397.         tmp = (unsigned int)data[i];
  10398.         if ( tmp == IAC ) {
  10399.             sb[j++] = IAC;
  10400.             sb[j++] = IAC;
  10401.         } else {
  10402.             sb[j++] = tmp;
  10403.         }
  10404.         if ( j == 2046 && (i < len-1) ) {
  10405.             sb[j++] = (CHAR) IAC;                 /* End of Subnegotiation */
  10406.             sb[j++] = (CHAR) SE;                  /* marked by IAC SE */
  10407.             if ( ttol(sb,j) < 0 ) {
  10408.                 debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0);
  10409.                 return(-1);
  10410.             }
  10411. #ifdef DEBUG
  10412.             if (deblog || tn_deb || debses) {
  10413.                 sprintf(tn_msg,"TELNET SENT SB %s DATA %02x %02x ",
  10414.                          TELOPT(TELOPT_FORWARD_X),p[0],p[1]);
  10415. #ifdef HEXDISP
  10416.                 {
  10417.                     int was_hex = 1, k;
  10418.                     extern char hexbuf[];
  10419.                     for (k=6; k < j-2; k++) {
  10420.                         if (sb[k] < 32 || sb[k] >= 127) {
  10421.                             sprintf(hexbuf,"%s%02X ",was_hex?"":"\" ",sb[k]);
  10422.                             was_hex = 1;
  10423.                         } else {
  10424.                             sprintf(hexbuf,"%s%c",was_hex?"\"":"",sb[k]);
  10425.                             was_hex = 0;
  10426.                         }
  10427.                         strcat(tn_msg,hexbuf);
  10428.                     }
  10429.                     if (!was_hex)
  10430.                         strcat(tn_msg,"\" ");
  10431.                 }
  10432. #else /* HEXDISP */
  10433.                 memcpy(hexbuf,&sb[k],j-k);
  10434.                 hexbuf[j-k] = ' ';
  10435.                 hexbuf[j-k+1] = '\0';
  10436.                 strcat(tn_msg,hexbuf);
  10437. #endif /* HEXDISP */
  10438.                 strcat(tn_msg," IAC SE");
  10439.                 debug(F100,tn_msg,"",0);
  10440.                 if (tn_deb || debses) tn_debug(tn_msg);
  10441.             }
  10442. #endif /* DEBUG */
  10443.  
  10444.             sb[0] = (CHAR) IAC;                 /* I Am a Command */
  10445.             sb[1] = (CHAR) SB;                  /* Subnegotiation */
  10446.             sb[2] = TELOPT_FORWARD_X;           /* Forward X */
  10447.             sb[3] = FWDX_DATA;                  /* Data */
  10448.             sb[4] = p[0];
  10449.             sb[5] = p[1];
  10450.  
  10451.             j = 6;
  10452.         }
  10453.     }
  10454.  
  10455.     sb[j++] = (CHAR) IAC;                 /* End of Subnegotiation */
  10456.     sb[j++] = (CHAR) SE;                  /* marked by IAC SE */
  10457.     if ( ttol(sb,j) < 0 ) {
  10458.         debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0);
  10459.         return(-1);
  10460.     }
  10461.  
  10462. #ifdef DEBUG
  10463.     if (deblog || tn_deb || debses) {
  10464.         sprintf(tn_msg,"TELNET SENT SB %s DATA %02x %02x ",
  10465.                  TELOPT(TELOPT_FORWARD_X),p[0],p[1]);
  10466. #ifdef HEXDISP
  10467.         {
  10468.             int was_hex = 1, k;
  10469.             extern char hexbuf[];
  10470.             for (k=6; k < j-2; k++) {
  10471.                 if (sb[k] < 32 || sb[k] >= 127) {
  10472.                     sprintf(hexbuf,"%s%02X ",was_hex?"":"\" ",sb[k]);
  10473.                     was_hex = 1;
  10474.                 } else {
  10475.                     sprintf(hexbuf,"%s%c",was_hex?"\"":"",sb[k]);
  10476.                     was_hex = 0;
  10477.                 }
  10478.                 strcat(tn_msg,hexbuf);
  10479.             }
  10480.             if (!was_hex)
  10481.                 strcat(tn_msg,"\" ");
  10482.         }
  10483. #else /* HEXDISP */
  10484.         memcpy(hexbuf,&sb[k],j-k-2);
  10485.         hexbuf[j-k-2] = ' ';
  10486.         hexbuf[j-k-1] = '\0';
  10487.         strcat(tn_msg,hexbuf);
  10488. #endif /* HEXDISP */
  10489.         strcat(tn_msg," IAC SE");
  10490.         debug(F100,tn_msg,"",0);
  10491.         if (tn_deb || debses) tn_debug(tn_msg);
  10492.     }
  10493. #endif /* DEBUG */
  10494.  
  10495.     return(0);
  10496. }
  10497.  
  10498. VOID
  10499. fwdx_check_sockets(fd_set *ibits)
  10500. {
  10501.     int x, sock, channel;
  10502.     static char buffer[32000];
  10503.  
  10504.     debug(F100,"fwdx_check_sockets()","",0);
  10505.     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
  10506.          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
  10507.         debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
  10508.         return;
  10509.     }
  10510.  
  10511.     for (x = 0; x < MAXFWDX; x++) {
  10512.         if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 )
  10513.             continue;
  10514.  
  10515.         sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
  10516.         channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
  10517.         if (FD_ISSET(sock, ibits))
  10518.         {
  10519.             int bytes, nn = 1;
  10520.             fd_set fdset;
  10521.             struct timeval tv;
  10522.  
  10523.             debug(F111,"fwdx_check_sockets()","channel set",x);
  10524.  
  10525.             memset(&tv, 0, sizeof(tv));
  10526.             /* make sure we read _all_ available data */
  10527.             do {
  10528.  
  10529.                 bytes = socket_read(sock, buffer, sizeof(buffer));
  10530.                 if (bytes > 0)
  10531.                     fwdx_send_data_from_channel(channel, buffer, bytes);
  10532.                 else {
  10533.                     fwdx_close_channel(channel);
  10534.                     fwdx_send_close(channel);
  10535.                 }
  10536.                 FD_ZERO(&fdset);
  10537.                 FD_SET(sock, &fdset);
  10538.             } while (select(128, &fdset, NULL, NULL, &tv) > 0);
  10539.         }
  10540.     }
  10541. }
  10542.  
  10543. int
  10544. fwdx_init_fd_set(fd_set *ibits)
  10545. {
  10546.     int x,set=0;
  10547.     debug(F100,"fwdx_init_fd_set()","",0);
  10548.  
  10549.     if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
  10550.          !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
  10551.         debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
  10552.         return(0);
  10553.     }
  10554.  
  10555.     if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
  10556.         set++;
  10557.         FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
  10558.     }
  10559.     for (x = 0; x < MAXFWDX; x++) {
  10560.         if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
  10561.             set++;
  10562.             FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
  10563.         }
  10564.     }
  10565.     return(set);
  10566. }
  10567.  
  10568. #ifdef NT
  10569. VOID
  10570. fwdx_thread( VOID * dummy )
  10571. {
  10572.     fd_set ifds;
  10573.     struct timeval tv;
  10574.     extern int priority;
  10575.  
  10576.     setint();
  10577.     SetThreadPrty(priority,isWin95() ? 3 : 11);
  10578.  
  10579.     while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
  10580.             sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
  10581.     {
  10582.         FD_ZERO(&ifds);
  10583.         if (fwdx_init_fd_set(&ifds) > 0) {
  10584.             tv.tv_sec = 0;
  10585.             tv.tv_usec = 2500;
  10586.             if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
  10587.                 fwdx_check_sockets(&ifds);
  10588.  
  10589.         } else {
  10590.             TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
  10591.             ckThreadEnd(NULL);
  10592.         }
  10593.     }
  10594. }
  10595. #endif /* NT */
  10596. #endif /* CK_FORWARD_X */
  10597. #endif /* TNCODE */
  10598. #endif /* NETCONN */
  10599.