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

  1. char *cknetv = "Network support, 6.0.078, 6 Sep 1996";
  2.  
  3. /*  C K C N E T  --  Network support  */
  4.  
  5. /*
  6.   NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
  7.   C-Kermit source files, must be compatible with C preprocessors that support
  8.   only #ifdef, #else, #endif, #define, and #undef.  Please do not use #if,
  9.   logical operators, or other preprocessor features in any of the portable
  10.   C-Kermit modules.  You can, of course, use these constructions in
  11.   system-specific modules when you know they are supported.  Also, don't use
  12.   any ANSI C constructs except with #ifdef CK_ANSIC..#endif.
  13. */
  14.  
  15. /*
  16.   Authors:
  17.  
  18.   Frank da Cruz (fdc@columbia.edu),
  19.     Columbia University Academic Information Systems, New York City.
  20.   netopen() routine for TCP/IP originally by Ken Yap, Rochester University
  21.     (ken@cs.rochester.edu) (no longer at that address).
  22.   Jeffrey E Altman (jaltman@columbia.edu) -- OS/2 & Windows, etc.
  23.   Missing pieces for Excelan sockets library from William Bader.
  24.   TELNET protocol by Frank da Cruz and Jeffrey Altman.
  25.   TGV MultiNet code by Frank da Cruz.
  26.   MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
  27.   MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
  28.   TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
  29.   CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
  30.   X.25 support by Marcello Frutig, Catholic University,
  31.     Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from:
  32.     Stefaan Eeckels, Eurokom, Luxembourg;
  33.     David Lane, Status Computer.
  34.   Other contributions as indicated below.
  35.  
  36.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  37.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  38.   sold for profit as a software product itself, nor may it be included in or
  39.   distributed with commercial products or otherwise distributed by commercial
  40.   concerns to their clients or customers without written permission of the
  41.   Office of Kermit Development and Distribution, Columbia University.  This
  42.   copyright notice must not be removed, altered, or obscured.
  43. */
  44. #include "ckcsym.h"
  45. #include "ckcdeb.h"
  46. #include "ckcker.h"
  47. #ifdef I386IX                /* Has to come before ckcnet.h in */
  48. #include <errno.h>            /* this version, but after in others */
  49. #endif /* I386IX */
  50. #include "ckcnet.h"
  51.  
  52. #ifdef NETCONN
  53. /* Don't need these if there is no network support. */
  54.  
  55. #ifdef CK_SOCKS                /* SOCKS Internet relay package */
  56. #define accept  Raccept
  57. #define bind    Rbind
  58. #define connect Rconnect
  59. #define getsockname Rgetsockname
  60. #define listen Rlisten
  61. #endif /* CK_SOCKS */
  62.  
  63. #ifdef DEC_TCPIP
  64. #include <time.h>
  65. #include <inet.h>
  66. #endif /* DEC_TCPIP */
  67.  
  68. #ifdef CMU_TCPIP
  69. #include <time.h>
  70. #endif /* CMU_TCPIP */
  71.  
  72. #ifdef WINTCP
  73.  
  74. #include <setjmp.h>
  75. #include <signal.h>
  76. #include <sys/time.h>
  77. /*
  78.   The WIN/TCP code path is the same as that for MultiNet.
  79.   Only the routine names have changed ...
  80. */
  81. #define socket_read     netread
  82. #define socket_ioctl    ioctl
  83. #define socket_write     netwrite
  84. #define socket_close     netclose
  85.  
  86. #ifdef OLD_TWG                         /* some routines have evolved */
  87.     extern int vmserrno, uerrno;
  88. #define socket_errno    uerrno
  89. #define socket_perror   perror         /* which uses errno, not uerrno! */
  90. #else
  91. #define socket_errno    errno
  92. #define socket_perror   win$perror
  93. #endif /* OLD_TWG */
  94.  
  95. #else /* Not WINTCP */
  96.  
  97. #ifndef I386IX
  98. #include <errno.h>            /* Already included above */
  99. #endif /* I386IX */
  100.  
  101. #include <signal.h>            /* Everybody needs this */
  102.  
  103. #ifdef ZILOG                /* Zilog has different name for this */
  104. #include <setret.h>
  105. #else /* !ZILOG */
  106. #include <setjmp.h>
  107. #ifdef CK_POSIX_SIG            /* POSIX signal handling */
  108. #endif /* CK_POSIX_SIG */
  109. #endif /* ZILOG */
  110.  
  111. #endif /* WINTCP */
  112.  
  113. #ifdef datageneral            /* Data General AOS/VS */
  114. #include <:usr:include:vs_tcp_errno.h>
  115. #include <:usr:include:sys:vs_tcp_types.h>
  116. #ifdef SELECT
  117. /*
  118.   NOTE: This can be compiled and linked OK with SELECT defined
  119.   but it doesn't work at all.  Anybody who cares and knows how
  120.   to fix it, feel free.
  121. */
  122. #include <:usr:include:sys:vs_tcp_time.h>
  123. #endif /* SELECT */
  124. #include <:usr:include:sys:socket.h>
  125. #include <:usr:include:netinet:in.h>
  126. #include <:usr:include:netdb.h>
  127. #endif /* datageneral */
  128.  
  129. extern
  130. #ifdef OS2
  131. SIGTYP (* volatile saval)();        /* For saving alarm handler */
  132. #else /* OS2 */
  133. SIGTYP (*saval)();            /* For saving alarm handler */
  134. #endif /* OS2 */
  135.  
  136. _PROTOTYP( VOID bgchk, (void) );
  137. _PROTOTYP( static VOID tn_debug, (char *) );
  138.  
  139. #ifdef RLOGCODE
  140. #ifdef TCPIPLIB
  141. _PROTOTYP( static VOID rlog_oob, (CHAR *, int) );
  142. #else /* TCPIPLIB */
  143. _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
  144. #endif /* TCPIPLIB */
  145. _PROTOTYP( static int rlog_ini, (VOID) );
  146. int rlog_mode = RL_COOKED;
  147. int rlog_stopped = 0;
  148. #endif /* RLOGCODE */
  149.  
  150. /* NAWS state - used in both TELNET and RLOGIN */
  151. int nawsflg = 0;
  152.  
  153. extern int                /* External variables */
  154.   duplex, debses, seslog, sessft,
  155.   ttyfd, quiet, msgflg, what, nettype, ttmdm;
  156.  
  157. #ifdef DEBUG
  158. extern int deblog;
  159. #else
  160. #define deblog 0
  161. #endif /* DEBUG */
  162.  
  163. #ifdef OS2
  164. extern int tt_rows[], tt_cols[];
  165. extern int tt_status;
  166. #else /* OS2 */
  167. extern int tt_rows, tt_cols;        /* Everybody has this */
  168. #endif /* OS2 */
  169.  
  170.  
  171. #ifdef CK_TTGWSIZ
  172. _PROTOTYP( int ttgwsiz, (void) );
  173. #endif /* CK_TTGWSIZ */
  174. #ifdef CK_NAWS                /* Negotiate About Window Size */
  175. _PROTOTYP( int tn_snaws, (void) );
  176. #ifdef RLOGCODE
  177. #ifndef OS2
  178. _PROTOTYP(static int rlog_naws, (void) );
  179. #else
  180. _PROTOTYP( int rlog_naws, (void) );
  181. #endif /* OS2 */
  182. #endif /* RLOGCODE */
  183. #endif /* CK_NAWS */
  184.  
  185. #ifdef OS2                /* For terminal type name string */
  186. #include "ckuusr.h"
  187. #ifndef NT
  188. #include <os2.h>
  189. #endif /* NT */
  190. #include "ckocon.h"
  191. extern int tt_type, max_tt;
  192. extern struct tt_info_rec tt_info[];
  193. extern char ttname[];
  194. extern int  scrninitialized[];
  195. #endif /* OS2 */
  196.  
  197. #include "ckcsig.h"
  198.  
  199. #ifndef OS2                /* For timeout longjumps */
  200. static ckjmpbuf njbuf;
  201. #endif /* OS2 */
  202.  
  203. #define NAMECPYL 100            /* Local copy of hostname */
  204. #ifndef OS2                     
  205. static                    /* OS2 needs access in ckonet.c */
  206. #endif /* OS2 */
  207. char namecopy[NAMECPYL];        
  208.  
  209. char ipaddr[20] = { '\0' };        /* Global copy of IP address */
  210. char myipaddr[20] = { '\0' };        /* Global copy of my IP address */
  211.  
  212. #endif /* NETCONN */
  213.  
  214. int ttnet = NET_NONE;            /* Network type */
  215. int ttnproto = NP_NONE;            /* Network virtual terminal protocol */
  216. int tn_init = 0;            /* Telnet protocol initialized flag */
  217. int tn_exit = 0;            /* Exit on disconnect */
  218. int tn_duplex = 1;            /* Initial echo status */
  219. char *tn_term = NULL;            /* Terminal type override */
  220. int tn_nlm = TNL_CRLF;            /* Telnet CR -> CR LF mode */
  221. int tn_binary = TN_BM_AC;        /* Binary negotiation accepted */
  222. int tn_b_nlm = TNL_CR;            /* Telnet Binary CR RAW mode */
  223. int tn_b_meu = 0;            /* Telnet Binary ME means U too */
  224. int tn_b_ume = 0;            /* Telnet Binary U means ME too */
  225. #ifdef OS2
  226. int ttnum = -1;                /* Last Telnet Terminal Type sent */
  227. int ttnumend = 0;            /* Has end of list been found */
  228. #endif /* OS2 */
  229.  
  230. #ifdef TNCODE
  231. #ifdef CK_ENVIRONMENT
  232. static char tn_msg[1024];        /* For debugging */
  233. static char hexbuf[1024];
  234. #else /* CK_ENVIRONMENT */
  235. static char tn_msg[128];        /* For debugging */
  236. static char hexbuf[6];
  237. #endif /* CK_ENVIRONMENT */
  238. #endif /* TNCODE */
  239.  
  240. #ifdef NT
  241. extern int WSASafeToCancel;
  242. #endif /* NT */
  243.  
  244. #ifndef NOTCPOPTS
  245.  
  246. /* Skip all this if NOTCPOPTS specified. */
  247.  
  248. #ifdef SOL_SOCKET
  249. #ifdef TCP_NODELAY
  250. int tcp_nodelay = 0;            /* Nagle algorithm TCP_NODELAY */
  251. #endif /* TCP_NODELAY */
  252.  
  253. #ifdef SO_LINGER
  254. int tcp_linger  = 0;            /* SO_LINGER */
  255. int tcp_linger_tmo = 0;            /* SO_LINGER timeout */
  256. #endif /* SO_LINGER */
  257.  
  258. #ifdef HPUX                /* But the data structures */
  259. #ifndef HPUX8                /* needed for linger are not */
  260. #ifndef HPUX9                /* defined in HP-UX versions */
  261. #ifndef HPUX10                /* prior to 8.00. */
  262. #ifdef SO_LINGER
  263. #undef SO_LINGER
  264. #endif /* SO_LINGER */
  265. #endif /* HPUX10 */
  266. #endif /* HPUX9 */
  267. #endif /* HPUX8 */
  268. #endif /* HPUX */
  269.  
  270. #ifdef SO_SNDBUF 
  271. int tcp_sendbuf = -1;
  272. #endif /* SO_SNDBUF */
  273. #ifdef SO_RCVBUF
  274. int tcp_recvbuf = -1;
  275. #endif /* SO_RCVBUF */
  276. #ifdef SO_KEEPALIVE 
  277. int tcp_keepalive = 1;
  278. #endif /* SO_KEEPALIVE */
  279. #endif /* SOL_SOCKET */
  280.  
  281. #endif /* NOTCPOPTS */
  282.  
  283. #ifndef NETCONN
  284. /*
  285.   Network support not defined.
  286.   Dummy functions here in case #ifdef's forgotten elsewhere.
  287. */
  288. int                    /* Open network connection */
  289. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  290.     return(-1);
  291. }
  292. int                    /* Close network connection */
  293. netclos() {
  294.     return(-1);
  295. }
  296. int                    /* Check network input buffer */
  297. nettchk() {
  298.     return(-1);
  299. }
  300. int                    /* Flush network input buffer */
  301. netflui() {
  302.     return(-1);
  303. }
  304. int                    /* Send network BREAK */
  305. netbreak() {
  306.     return(-1);
  307. }
  308. int                    /* Input character from network */
  309. netinc(timo) int timo; {
  310.     return(-1);
  311. }
  312. int                    /* Output character to network */
  313. #ifdef CK_ANSIC
  314. nettoc(char c)
  315. #else
  316. nettoc(c) char c;
  317. #endif /* CK_ANSIC */
  318. /* nettoc */ {
  319.     return(-1);
  320. }
  321. int
  322. nettol(s,n) char *s; int n; {
  323.     return(-1);
  324. }
  325.  
  326. #else /* NETCONN is defined (rest of this module...) */
  327.  
  328. #ifdef VMS
  329. /*
  330.   In edit 190, we moved tn_ini() to be called from within netopen().
  331.   But tn_ini() calls ttol(), and ttol() checks to see if it's a net 
  332.   connection, but the flag for that isn't set until after netopen()
  333.   is finished.  Since, in this module, we are always doing network
  334.   output anyway, we just call nettol() directly, instead of going thru
  335.   ttol().  Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
  336.   net connections just like regular connections in ttol(), and OS/2
  337.   has a special routine for this.
  338. */
  339. #define ttol nettol
  340. #endif /* VMS */
  341.  
  342. extern int tn_binary;            /* Binary mode enabled */
  343. int me_binary = 0;            /* I'm not in TELNET binary mode */
  344. int u_binary = 0;            /* You're not in TELNET binary mode */
  345.  
  346. int tcpsrfd = -1;
  347.  
  348. #ifdef TCPSOCKET
  349. #ifndef OS2
  350. #ifndef NOLISTEN            /* For incoming connections */
  351.  
  352. #ifndef INADDR_ANY
  353. #define INADDR_ANY 0           
  354. #endif /* INADDR_ANY */
  355.  
  356. _PROTOTYP( int ttbufr, ( VOID ) );
  357. _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
  358.  
  359. static unsigned short tcpsrv_port = 0;
  360.  
  361. #endif /* NOLISTEN */
  362. #endif /* OS2 */
  363. #endif /* TCPSOCKET */
  364.  
  365. #ifndef NOSIGWINCH
  366. #ifdef CK_NAWS                /* Window size business */
  367. #ifdef SIGWINCH
  368. #ifdef UNIX
  369. static int sw_armed = 0;        /* SIGWINCH armed flag */
  370. SIGTYP
  371. winchh(foo) int foo; {
  372.     int x;
  373.     debug(F100,"SIGWINCH caught","",0);
  374.     signal(SIGWINCH,winchh);        /* Re-arm the signal */
  375.     if (ttyfd == -1)
  376.       return;
  377.     x = ttgwsiz();            /* Get new window size */
  378. /*
  379.   This should be OK.  It might seem that sending this from
  380.   interrupt level could interfere with another TELNET IAC string
  381.   that was in the process of being sent.  But we always send
  382.   TELNET strings with a single write(), which should prevent mixups.
  383. */
  384.     if (x > 0 && tt_rows > 0 && tt_cols > 0) {
  385.     tn_snaws();
  386. #ifdef RLOGCODE
  387.     rlog_naws();
  388. #endif /* RLOGCODE */
  389.     }
  390.     return;
  391. }
  392. #endif /* UNIX */
  393. #endif /* SIGWINCH */
  394. #endif /* CK_NAWS */
  395. #endif /* NOSIGWINCH */
  396.  
  397. /*
  398.   TCPIPLIB means use separate socket calls for i/o, while on UNIX the
  399.   normal file system calls are used for TCP/IP sockets too.
  400.   Means "DEC_TCPIP or MULTINET or WINTCP or OS2" (defined in ckcnet.h).
  401. */
  402.  
  403. #ifdef TCPIPLIB
  404.  
  405. /* For buffered network reads... */
  406. /*
  407.   If the buffering code is written right, it shouldn't matter
  408.   how long this buffer is.
  409. */
  410. #ifdef OS2
  411. #define TTIBUFL 32767
  412. #else /* OS2 */
  413. #define TTIBUFL 8191            /* Let's use 8K. */
  414. #endif /* OS2 */
  415.  
  416. CHAR ttibuf[TTIBUFL+1];
  417.  
  418. /*
  419.   select() is used in preference to alarm()/signal(), but different systems
  420.   use different forms of select()...
  421. */
  422. #ifndef NOSELECT         /* Option to override BSDSELECT */
  423. #ifdef BELLV10
  424. /*
  425.   Note: Although BELLV10 does have TCP/IP support, and does use the unique
  426.   form of select() that is evident in this module (and in ckutio.c), it does
  427.   not have a sockets library and so we can't build Kermit TCP/IP support for
  428.   it.  For this, somebody would have to write TCP/IP streams code.
  429. */
  430. #define BELLSELECT
  431. #ifndef FD_SETSIZE
  432. #define FD_SETSIZE 128
  433. #endif /* FD_SETSIZE */
  434. #else
  435. #ifdef WINTCP                /* VMS with Wollongong WIN/TCP */
  436. #ifndef OLD_TWG                /* TWG 3.2 has only select(read) */
  437. #define BSDSELECT
  438. #endif /* OLD_TWG */
  439. #else
  440. #ifdef CMU_TCPIP            /* LIBCMU can do select */
  441. #define BSDSELECT
  442. #else
  443. #ifdef DEC_TCPIP
  444. #define BSDSELECT
  445. #else
  446. #ifdef OS2                /* OS/2 with TCP/IP */
  447. #ifdef NT
  448. #define BSDSELECT
  449. #else /* NT */
  450. #define IBMSELECT
  451. #endif /* NT */
  452. #endif /* OS2 */
  453. #endif /* DEC_TCPIP */
  454. #endif /* CMU_TCPIP */
  455. #endif /* WINTCP */
  456. #endif /* BELLV10 */
  457. #endif /* NOSELECT */
  458. /*
  459.   Others (TGV, TCPware, ...) use alarm()/signal().  The BSDSELECT case does not
  460.   compile at all; the IBMSELECT case compiles and links but crashes at runtime.
  461.   NOTE: If any of these can be converted to select(), they should be for two
  462.   reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
  463.   their socket_read() calls to be interrupted; subsequent socket_read()'s tend
  464.   to fail with EBUSY.  This happened in the UCX case before it was converted
  465.   to use select().
  466. */
  467. #ifndef VMS
  468. static                    /* These are used in CKVTIO.C */
  469. #endif /* VMS */
  470. int
  471.   ttibp = 0,
  472.   ttibn = 0;
  473. /*
  474.   Read bytes from network into internal buffer ttibuf[].
  475.   To be called when input buffer is empty, i.e. when ttibn == 0.
  476.  
  477.   Other network reading routines, like ttinc, ttinl, ttxin, should check the
  478.   internal buffer first, and call this routine for a refill if necessary.
  479.  
  480.   Returns -1 on error, 0 if nothing happens.  When data is read successfully,
  481.   returns number of bytes read, and sets global ttibn to that number and
  482.   ttibp (the buffer pointer) to zero.
  483. */
  484. _PROTOTYP( int ttbufr, ( VOID ) );
  485. int
  486. ttbufr() {                /* TT Buffer Read */
  487.     int count;
  488.  
  489.     if (ttnet != NET_TCPB)        /* First make sure current net is */
  490.       return(-1);            /* TCP/IP; if not, do nothing. */
  491.  
  492.     if (ttibn > 0)            /* Our internal buffer is not empty, */
  493.       return(ttibn);            /* so keep using it. */
  494. #ifdef WINTCP
  495.     count = 512;            /* This works for WIN/TCP */
  496. #else
  497. #ifdef DEC_TCPIP
  498.     count = 512;            /* UCX */
  499. #else
  500. #ifdef OS2
  501.     count = TTIBUFL;
  502. #else                    /* Multinet, etc. */
  503.     count = ttchk();            /* Check network input buffer, */
  504.     if (ttibn > 0) return(ttibn);    /* which can put a char there! */
  505.     if (count < 0)            /* Read error - connection closed */
  506.       return(-2);
  507.     else if (count > TTIBUFL)        /* Too many to read */
  508.       count = TTIBUFL;
  509.     else if (count == 0)        /* None, so force blocking read */
  510.       count = 1;
  511. #endif /* OS2 */
  512. #endif /* DEC_TCPIP */
  513. #endif /* WINTCP */
  514.     debug(F101,"ttbufr count 1","",count);
  515.  
  516. #ifdef COMMENT
  517. /*
  518.  This is for nonblocking reads, which we don't do any more.  This code didn't
  519.  work anyway, in the sense that a broken connection was never sensed.
  520. */
  521.     if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
  522.     if (count == -1 && socket_errno == EWOULDBLOCK) {
  523.         debug(F100,"ttbufr finds nothing","",0);
  524.         return(0);
  525.     } else {
  526.         debug(F101,"ttbufr socket_read error","",socket_errno);
  527.         return(-1);
  528.     }
  529.  
  530.     } else if (count == 0) {
  531.     debug(F100,"ttbufr socket eof","",0);        
  532.     return(-1);
  533.     }
  534. #else /* COMMENT */
  535.  
  536. /* This is for blocking reads */
  537.  
  538. #ifndef VMS
  539. #ifdef SO_OOBINLINE
  540.     {
  541.     int outofband = 0;
  542. #ifdef BELLSELECT
  543.     if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
  544.       outofband = 1;
  545. #else
  546. #ifdef BSDSELECT
  547.     fd_set efds;
  548.     struct timeval tv;
  549.     FD_ZERO(&efds);
  550.     FD_SET(ttyfd, &efds);
  551.     tv.tv_sec  = tv.tv_usec = 0L;
  552.     debug(F100,"Out-of-Band BSDSELECT","",0);
  553. #ifdef NT
  554.     WSASafeToCancel = 1;
  555. #endif /* NT */
  556.     if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
  557.         FD_ISSET(ttyfd, &efds))
  558.       outofband = 1;
  559. #ifdef NT
  560.     WSASafeToCancel = 0;
  561. #endif /* NT */
  562. #else /* !BSDSELECT */
  563. #ifdef IBMSELECT
  564. /* Was used by OS/2, currently not used, but might come in handy some day... */
  565. /* ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set */
  566. /* and timeval stuff since this is the only place where it is used. */
  567.     int socket = ttyfd;
  568.     debug(F100,"Out-of-Band IBMSELECT","",0);
  569.     if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
  570.       outofband = 1;
  571. #else /* !IBMSELECT */
  572. /*
  573.   If we can't use select(), then we use the regular alarm()/signal()
  574.   timeout mechanism.
  575. */
  576.       debug(F101,"Out-of-Band data not supported","",0);
  577.       outofband = 0;
  578.  
  579. #endif /* IBMSELECT */
  580. #endif /* BSDSELECT */
  581. #endif /* BELLSELECT */
  582.       if (outofband) {
  583.          /* Get the Urgent Data */
  584.          /* if OOBINLINE is disabled this should be only a single byte      */
  585.          /* MS Winsock has a bug in Windows 95.  Extra bytes are delivered  */
  586.          /* That were never sent.                                           */
  587.       if ((count = socket_recv(ttyfd,ttibuf,count,MSG_OOB)) <= 0) {
  588.           int s_errno = socket_errno;
  589.           debug(F101, "ttbufr socket_recv MSG_OOB","",count);
  590.           debug(F101, "ttbufr socket_errno","",s_errno);
  591. #ifndef OS2
  592.           netclos();            /* *** *** */  
  593.           return(-2);
  594. #else /* OS2 */
  595.           if (count == 0) {
  596.           debug(F100,"ttbufr Closing Connection","",0);
  597.           ttclos(0);        /* if the connection was  */
  598.           if (ttname[0] == '*') { /* incoming, wait for another */
  599.               int local;
  600.               os2_netopen(ttname,&local,ttnet);
  601.               debug(F101,
  602.                 "ttbufr returns zero - try again immediately",
  603.                 "",
  604.                 0
  605.                 );
  606.               return 0;        /* try again immediately */
  607.           } else {
  608.               debug(F101, "ttbufr returns hard error","",-3);
  609.               return -3;    /* return a hard error    */
  610.           }
  611.           } else {
  612. #ifdef NT
  613.           if (s_errno == WSAETIMEDOUT)
  614.             debug(F100,"WSAETIMEDOUT","",0);
  615. #endif /* NT */ 
  616.           switch (s_errno) {
  617. #ifdef NT
  618.             case WSAETIMEDOUT:
  619. #else
  620.             case SOCETIMEDOUT:    
  621.             case SOCETIMEDOUT - SOCBASEERR:
  622. #endif /* NT */
  623.               debug(F100,"ttbufr ETIMEDOUT","",0);
  624.               return(-1);
  625. #ifdef NT
  626.             case WSAECONNRESET:
  627. #else /* NT */
  628.             case SOCECONNRESET:
  629.             case SOCECONNRESET - SOCBASEERR:
  630. #endif /* NT */
  631.               debug(F100,"ttbufr ECONRESET","",0);
  632.               netclos();    /* *** *** */
  633.               return(-2);    /* Connection is broken. */
  634. #ifdef NT
  635.             case WSAECONNABORTED:
  636. #else /* NT */
  637.             case SOCECONNABORTED:
  638.             case SOCECONNABORTED - SOCBASEERR:
  639. #endif /* NT */
  640.               debug(F100,"ttbufr ECONNABORTED","",0);
  641.               netclos();    /* *** *** */
  642.               return(-2);    /* Connection is broken. */
  643. #ifdef NT
  644.             case WSAENETRESET:  
  645. #else /* NT */
  646.             case SOCENETRESET:
  647.             case SOCENETRESET - SOCBASEERR:
  648. #endif /* NT */
  649.               debug(F100,"ttbufr ENETRESET","",0);
  650.               netclos();    /* *** *** */
  651.               return(-2);    /* Connection is broken. */
  652. #ifdef NT
  653.             case WSAENOTCONN:
  654. #else /* NT */
  655.             case SOCENOTCONN:
  656.             case SOCENOTCONN - SOCBASEERR:
  657. #endif /* NT */
  658.               debug(F100,"ttbufr ENOTCONN","",0);
  659.               netclos();    /* *** *** */
  660.               return(-2);    /* Connection is broken. */
  661. #ifdef NT
  662.             case WSAEWOULDBLOCK:
  663. #else
  664.             case SOCEWOULDBLOCK:
  665.             case SOCEWOULDBLOCK - SOCBASEERR:
  666. #endif /* NT */
  667.               debug(F100,"ttbufr EWOULDBLOCK","",0);
  668.               count = 1;
  669.               break;
  670. #ifdef NT
  671.             case WSAEINVAL:
  672. #else /* NT */
  673.             case SOCEINVAL:
  674.             case SOCEINVAL - SOCBASEERR:
  675. #endif /* NT */
  676.                       case 0:
  677.                       case 23: /* ??? */
  678.               /* These appear in OS/2 - don't know why   */
  679.               /* ignore it and read as normal data       */
  680.               /* and break, then we will attempt to read */
  681.               /* the port using normal read() techniques */
  682.               debug(F100,"ttbufr handing as in-band data","",0);
  683.               count = 1;
  684.               break;
  685.  
  686.             default:
  687.               debug(F101, "ttbufr Unknown Error ","",s_errno);
  688.               netclos();
  689.               return -2;    /* Return a hard error */
  690.           }
  691.           }   
  692. #endif /* OS2 */
  693.       } else {            /* we got out-of-band data */
  694.           debug(F111,"ttbufr out-of-band chars","",count);
  695. #ifdef RLOGCODE                /* blah */
  696.           if (ttnproto == NP_RLOGIN) {
  697.           /*
  698.             When urgent data is read with MSG_OOB and not OOBINLINE
  699.             then urgent data and normal data are not mixed.  So
  700.             treat the entire buffer as urgent data.
  701.           */
  702.           rlog_oob(ttibuf, count);
  703.           return ttbufr();
  704.           } else 
  705. #endif /* RLOGCODE */ /* blah */
  706. #ifdef COMMENT
  707.             /*
  708.            I haven't written this yet, nor do I know what it should do
  709.          */
  710.         if (ttnproto == NP_TELNET) {
  711.             tn_oob();
  712.             return 0;
  713.         } else 
  714. #endif /* COMMENT */
  715.           {
  716.            /* For any protocols we don't have a special out-of-band  */
  717.                    /* handler for, just put the bytes in the normal buffer   */
  718.                    /* and return                                             */
  719.  
  720.               ttibp = 0;    /* Reset buffer pointer. */
  721.               ttibn = count;
  722. #ifdef DEBUG
  723.               /* Got some bytes. */
  724.               debug(F101,"ttbufr count 2","",count);
  725.               if (count > 0) 
  726.             ttibuf[count] = '\0';
  727.               debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
  728. #endif /* DEBUG */
  729.               return(ttibn);    /* Return buffer count. */
  730.           }
  731.       }
  732.       }
  733.     }
  734. #endif /* SO_OOBINLINE */
  735. #endif /* VMS */
  736.  
  737.     if ((count = socket_read(ttyfd,ttibuf,count)) <= 0) {
  738.     int s_errno = socket_errno;
  739.     debug(F101,"ttbufr socket_read","",count);
  740.     debug(F101,"ttbufr socket_errno","",s_errno);
  741. #ifndef OS2
  742.     netclos();            /* *** *** */  
  743.     return(-2);
  744. #else /* OS2 */
  745.     if (count == 0) {
  746.         debug(F100,"ttbufr Closing Connection","",0);
  747.         ttclos(0);            /* if the connection was  */
  748.         if (ttname[0] == '*') {    /* incoming, wait for another */
  749.         int local;
  750.         os2_netopen(ttname,&local,ttnet);
  751.         debug(F101,
  752.               "ttbufr returns zero - try again immediately","",0);
  753.         return 0;        /* try again immediately */
  754.         } else {
  755.         debug(F101, "ttbufr returns hard error","",-3);
  756.         return -3;        /* return a hard error    */
  757.         }
  758.     } else {
  759. #ifdef NT
  760.         if (s_errno == WSAETIMEDOUT)
  761.           debug(F100, "WSAETIMEDOUT","",0);
  762. #endif /* NT */
  763.         switch (s_errno) {
  764. #ifdef NT
  765.           case WSAETIMEDOUT:
  766. #else
  767.           case SOCETIMEDOUT:
  768.           case SOCETIMEDOUT - SOCBASEERR:
  769. #endif /* NT */
  770.         debug(F100,"ttbufr ETIMEDOUT","",0);
  771.         return(-1);
  772. #ifdef NT
  773.           case WSAECONNRESET:
  774. #else /* NT */
  775.           case SOCECONNRESET:
  776.           case SOCECONNRESET - SOCBASEERR:
  777. #endif /* NT */
  778.         debug(F100,"ttbufr ECONRESET","",0);
  779.         netclos();            /* *** *** */
  780.         return(-2);            /* Connection is broken. */
  781. #ifdef NT
  782.           case WSAECONNABORTED:
  783. #else /* NT */
  784.           case SOCECONNABORTED:
  785.           case SOCECONNABORTED - SOCBASEERR:
  786. #endif /* NT */
  787.         debug(F100,"ttbufr ECONNABORTED","",0);
  788.         netclos();            /* *** *** */
  789.         return(-2);            /* Connection is broken. */
  790. #ifdef NT
  791.           case WSAENETRESET:  
  792. #else /* NT */
  793.           case SOCENETRESET:
  794.           case SOCENETRESET - SOCBASEERR:
  795. #endif /* NT */
  796.         debug(F100,"ttbufr ENETRESET","",0);
  797.         netclos();            /* *** *** */
  798.         return(-2);            /* Connection is broken. */
  799. #ifdef NT
  800.           case WSAENOTCONN:
  801. #else /* NT */
  802.           case SOCENOTCONN:
  803.           case SOCENOTCONN - SOCBASEERR:
  804. #endif /* NT */
  805.         debug(F100,"ttbufr ENOTCONN","",0);
  806.         netclos();            /* *** *** */
  807.         return(-2);            /* Connection is broken. */
  808. #ifdef NT
  809.           case WSAEWOULDBLOCK:
  810. #else
  811.           case SOCEWOULDBLOCK:
  812.           case SOCEWOULDBLOCK - SOCBASEERR:
  813. #endif /* NT */
  814.         debug(F100,"ttbufr EWOULDBLOCK","",0);
  815.         break;
  816.         }
  817.         debug(F101, "ttbufr returns timeout","",-1);
  818.         return -1;            /* Return a timeout */
  819.     }
  820. #endif /* OS2 */
  821.     }
  822. #endif /* COMMENT */
  823.     else {
  824.     ttibp = 0;            /* Reset buffer pointer. */
  825.     ttibn = count;
  826. #ifdef DEBUG
  827.     debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
  828.     if (count > 0) 
  829.           ttibuf[count] = '\0';
  830.     debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
  831. #endif /* DEBUG */
  832.     return(ttibn);            /* Return buffer count. */
  833.     }
  834. }
  835. #endif /* TCPIPLIB */
  836.  
  837. #ifndef IBMSELECT
  838. #ifndef BELLSELECT
  839. #ifndef BSDSELECT        /* Non-TCPIPLIB case */
  840. #ifdef SELECT
  841. #define BSDSELECT
  842. #endif /* SELECT */
  843. #endif /* BSDSELECT */
  844. #endif /* BELLSELECT */
  845. #endif /* IBMSELECT */
  846.  
  847. #define    TELNET_PORT 23         /* Should do lookup, but it won't change */
  848. #define RLOGIN_PORT 513
  849. #define KERMIT_PORT 1649
  850.  
  851. /* This symbol is not known to, e.g., Ultrix 2.0 */
  852. #ifndef TELOPT_TTYPE
  853. #define TELOPT_TTYPE 24
  854. #endif /* TELOPT_TTYPE */
  855.  
  856. /* This one seems to be not known to UCX */
  857. #ifndef TELOPT_BINARY
  858. #define TELOPT_BINARY 0
  859. #endif /* TELOPT_BINARY */
  860.  
  861. /* Type needed as 5th argument (length) to get/setsockopt() */
  862.  
  863. #ifndef SOCKOPT_T
  864. #define SOCKOPT_T int
  865. #ifdef UNIXWARE
  866. #undef SOCKOPT_T
  867. #define SOCKOPT_T size_t
  868. #else
  869. #ifdef VMS
  870. #ifdef DEC_TCPIP
  871. #ifdef __DECC_VER
  872. #undef SOCKOPT_T
  873. #define SOCKOPT_T size_t
  874. #endif /* __DECC_VER */
  875. #endif /* DEC_TCPIP */
  876. #endif /* VMS */
  877. #endif /* UNIXWARE */
  878. #endif /* SOCKOPT_T */
  879.  
  880. /*
  881.   C-Kermit network open/close functions for BSD-sockets.
  882.   Much of this code shared by SunLink X.25, which also uses the socket library.
  883. */
  884.  
  885. /*  N E T O P N  --  Open a network connection.  */
  886. /*
  887.   Call with:
  888.     name of host (or host:service),
  889.     lcl - local-mode flag to be set if this function succeeds,
  890.     network type - value defined in ckunet.h.
  891. */
  892. #ifdef TCPSOCKET
  893. #ifdef EXCELAN
  894. /*
  895.   Most other BSD sockets implementations define these in header files
  896.   and libraries.
  897. */
  898. struct servent {
  899.     unsigned short s_port;
  900. };
  901.  
  902. struct hostent {
  903.     short h_addrtype;
  904.     struct in_addr h_addr;
  905.     int h_length;
  906. };
  907.  
  908. struct servent *
  909. getservbyname(service, connection) char *service,*connection; {
  910.     static struct servent servrec;
  911.     int port;
  912.  
  913.     port = 0;
  914.     if (strcmp(service, "telnet") == 0) port = 23;
  915.     else if (strcmp(service, "smtp") == 0) port = 25;
  916.     else port = atoi(service);
  917.  
  918.     debug(F101,"getservbyname return port ","",port);
  919.  
  920.     if (port > 0) {
  921.         servrec.s_port = htons(port);
  922.         return(&servrec);
  923.     }
  924.     return((struct servent *) NULL);
  925. }
  926.  
  927. struct hostent *
  928. gethostbyname(hostname) char *hostname; {
  929.     return((struct hostent *) NULL);
  930. }
  931.  
  932. unsigned long
  933. inet_addr(name) char *name; {
  934.     unsigned long addr;
  935.  
  936.     addr = rhost(&name);
  937.     debug(F111,"inet_addr ",name,(int)addr);
  938.     return(addr);
  939. }
  940.  
  941. char *
  942. inet_ntoa(in) struct in_addr in; {
  943.     static char name[80];
  944.     sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
  945.     return(name);
  946. }
  947. #else
  948. #ifdef DEC_TCPIP            /* UCX */
  949. #ifndef __DECC                /* VAXC or GCC */
  950.  
  951. #define getservbyname my_getservbyname
  952.  
  953. #ifdef CK_ANSIC
  954. globalref int (*C$$GA_UCX_GETSERVBYNAME)();
  955. extern void C$$TRANSLATE();
  956. extern void C$$SOCK_TRANSLATE();
  957. #else
  958. globalref int (*C$$GA_UCX_GETSERVBYNAME)();
  959. extern VOID C$$TRANSLATE();
  960. extern VOID C$$SOCK_TRANSLATE();
  961. #endif /* CK_ANSIC */
  962.  
  963. struct servent *
  964. my_getservbyname (service, proto) char *service, *proto; {
  965.     static struct servent sent;
  966.     struct iosb {
  967.     union {
  968.         unsigned long status;
  969.         unsigned short st[2];
  970.     } sb;
  971.     unsigned long spare;
  972.     } s;
  973.     struct {
  974.     struct iosb *s;
  975.     char *serv;
  976.     char *prot;
  977.     } par;
  978.     unsigned long e;
  979.     char sbuf[30], pbuf[30];
  980.     char *p;
  981.  
  982.     debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
  983.  
  984.     p = sbuf;
  985.     strcpy(p, service);
  986.     while (*p = toupper(*p), *p++) {}
  987.     p = pbuf;
  988.     strcpy(p, proto);
  989.     while (*p = toupper(*p), *p++) {}
  990.  
  991.     par.s = &s;
  992.  
  993.     par.serv = "";
  994.     par.prot = "";
  995.     /* reset file pointer or something like that!?!? */
  996.     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
  997.     par.serv = sbuf;
  998.     par.prot = pbuf;        /* that is don't care */
  999.     e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
  1000.     if ((long)e == -1L)
  1001.       return NULL;
  1002.     if ((e & 1) == 0L) {
  1003.     C$$TRANSLATE(e);
  1004.     return NULL;
  1005.     }
  1006.     if ((s.sb.st[0] & 1) == 0) {
  1007.     C$$SOCK_TRANSLATE(&s.sb.st[0]);
  1008.     return NULL;
  1009.     }
  1010.     /* sent.s_port is returned by UCX in network byte order. */
  1011.     /* Calling htons here swaps the bytes, which ruins everything. */
  1012.  
  1013.     /* Oh yeah?  WHICH VERSION of UCX???  Let's try this... */
  1014.  
  1015. #ifndef __alpha /* Maybe it should be __DECC, or some version thereof... */
  1016. /*
  1017.   Hunter says: "In fact, the "#ifndef __alpha" isn't even needed, since
  1018.   my_getservbyname() isn't included if "__DECC" is defined, and that's
  1019.   always defined on Alpha."  But if it doesn't hurt either, better not risk
  1020.   taking it out.
  1021. */
  1022. #ifndef TCPWARE
  1023. #define DO_HTONS
  1024. #endif /* TCPWARE */
  1025. #endif /* __alpha */
  1026.  
  1027. #ifdef DO_HTONS
  1028.     sent.s_port = htons(sent.s_port);
  1029.     debug(F111,"UCX getservbyname","port",ntohs(sent.s_port));
  1030. #else
  1031.     debug(F111,"UCX getservbyname","port",sent.s_port);
  1032. #endif /* DO_HTONS */
  1033.     return &sent;
  1034. }
  1035. #endif /* __DECC */
  1036. #endif /* DEC_TCPIP */
  1037. #endif /* EXCELAN */
  1038. #endif /* TCPSOCKET */
  1039.  
  1040. #ifndef NOTCPOPTS
  1041. #ifndef datageneral
  1042. int
  1043. ck_linger(onoff, timo) int onoff; int timo; {
  1044. /*
  1045.   The following, from William Bader, turns off the socket linger parameter,
  1046.   which makes a close() block until all data is sent.  "I don't think that
  1047.   disabling linger can ever cause kermit to lose data, but you telnet to a
  1048.   flaky server (or to our modem server when the modem is in use), disabling
  1049.   linger prevents kermit from hanging on the close if you try to exit."
  1050.  
  1051.   Modified by Jeff Altman to be generally useful.
  1052. */
  1053. #ifdef SOL_SOCKET
  1054. #ifdef SO_LINGER
  1055.     struct linger linger_opt;
  1056.     SOCKOPT_T x;
  1057.  
  1058.     if (ttyfd == -1 ||
  1059.     nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1060.     tcp_linger = onoff;
  1061.     tcp_linger_tmo = timo;
  1062.     return(1);
  1063.     }
  1064.     x = sizeof(linger_opt);
  1065.     if (getsockopt(ttyfd, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, &x)) {
  1066.     perror("could not get SO_LINGER");    
  1067.     } else if (x != sizeof(linger_opt)) {
  1068.     debug(F101,"linger error: SO_LINGER len","",x);
  1069.     debug(F101,"linger SO_LINGER expected len","",sizeof(linger_opt));
  1070.     } else if (linger_opt.l_onoff != onoff || linger_opt.l_linger != timo) {
  1071.     linger_opt.l_onoff  = onoff;
  1072.     linger_opt.l_linger = timo;
  1073.     if (setsockopt(ttyfd,
  1074.                SOL_SOCKET,
  1075.                SO_LINGER,
  1076.                (char *)&linger_opt,
  1077.                sizeof(linger_opt))) {
  1078.             perror("error setting SO_LINGER");
  1079.          } else {
  1080.          debug(F101,"linger new SO_LINGER","",linger_opt.l_onoff);
  1081.          tcp_linger = onoff;
  1082.          tcp_linger_tmo = timo;
  1083.          return 1;
  1084.          }
  1085.     } else {
  1086.     debug(F101,"setlinger SO_LINGER unchanged","",linger_opt.l_onoff);
  1087.     tcp_linger = onoff;
  1088.     tcp_linger_tmo = timo;
  1089.     return 1;
  1090.     }
  1091. #else
  1092.     debug(F100,"SO_LINGER not defined","",0);
  1093. #endif /* SO_LINGER */
  1094. #else
  1095.     debug(F100,"SO_SOCKET not defined","",0);
  1096. #endif /* SOL_SOCKET */
  1097.     return(0);
  1098. }
  1099.  
  1100. int 
  1101. sendbuf(size) int size; {
  1102. /*
  1103.   The following, from William Bader, allows changing of socket buffer sizes,
  1104.   in case that might affect performance.
  1105.  
  1106.   Modified by Jeff Altman to be generally useful.
  1107. */
  1108. #ifdef SOL_SOCKET
  1109. #ifdef SO_SNDBUF
  1110.     int i, rc = 0;
  1111.     SOCKOPT_T x;
  1112.  
  1113.     if (ttyfd == -1 ||
  1114.     nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1115.     tcp_sendbuf = size;
  1116.     return 1;
  1117.     }
  1118.     x = sizeof(i);
  1119.     if (getsockopt(ttyfd, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
  1120.     perror("could not get SO_SNDBUF");
  1121.     } else if (x != sizeof(i)) {
  1122.     debug(F101,"setsockbuf error: SO_SNDBUF len","",x);
  1123.     debug(F101,"setsockbuf SO_SNDBUF expected len","",sizeof(i));
  1124.     } else if (size <= 0) {
  1125.     tcp_sendbuf = i;
  1126.     debug(F101,"setsockbuf SO_SNDBUF retrieved","",i);
  1127.     return 1;
  1128.     } else if (i != size) {
  1129.     x = size;
  1130.     if (setsockopt(ttyfd, SOL_SOCKET, SO_SNDBUF, (char *)&x, sizeof(x))) {
  1131.         perror("error setting SO_SNDBUF");
  1132.     } else {
  1133.         debug(F101,"setsockbuf old SO_SNDBUF","",i);
  1134.         debug(F101,"setsockbuf new SO_SNDBUF","",x);
  1135.         tcp_sendbuf = size;
  1136.         return 1;
  1137.     }
  1138.     } else {
  1139.     debug(F101,"setsockbuf SO_SNDBUF unchanged","",i);
  1140.     tcp_sendbuf = size;
  1141.     return 1;
  1142.     }
  1143. #else
  1144.     debug(F100,"SO_SNDBUF not defined","",0);
  1145. #endif /* SO_SNDBUF */
  1146. #else
  1147.     debug(F100,"SO_SOCKET not defined","",0);
  1148. #endif /* SOL_SOCKET */
  1149.     return(0);
  1150. }
  1151.  
  1152. int 
  1153. recvbuf(size) int size; {
  1154. /*
  1155.   The following, from William Bader, allows changing of socket buffer sizes,
  1156.   in case that might affect performance.
  1157.  
  1158.   Modified by Jeff Altman to be generally useful.
  1159. */
  1160. #ifdef SOL_SOCKET
  1161. #ifdef SO_RCVBUF
  1162.     int i, rc = 0;
  1163.     SOCKOPT_T x;
  1164.  
  1165.     if (ttyfd == -1 ||
  1166.     nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1167.     tcp_recvbuf = size;
  1168.     return(1);
  1169.     }
  1170.     x = sizeof(i);
  1171.     if (getsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
  1172.     perror("could not get SO_RCVBUF");
  1173.     } else if (x != sizeof(i)) {
  1174.     debug(F101,"setsockbuf error: SO_RCVBUF len","",x);
  1175.     debug(F101,"setsockbuf SO_RCVBUF expected len","",sizeof(i));
  1176.     } else if (size <= 0) {
  1177.     tcp_recvbuf = i;
  1178.     debug(F101,"setsockbuf SO_RCVBUF retrieved","",i);
  1179.     return 1;
  1180.     } else if (i != size) {
  1181.     x = size;
  1182.     if (setsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&x, sizeof(x))) {
  1183.         perror("error setting SO_RCVBUF");
  1184.     } else {
  1185.         debug(F101,"setsockbuf old SO_RCVBUF","",i);
  1186.         debug(F101,"setsockbuf new SO_RCVBUF","",x);
  1187.         tcp_recvbuf = size;
  1188.         return 1;
  1189.     }
  1190.     } else {
  1191.     debug(F101,"setsockbuf SO_RCVBUF unchanged","",i);
  1192.     tcp_recvbuf = size;
  1193.     return 1;
  1194.     }
  1195. #else
  1196.     debug(F100,"SO_RCVBUF not defined","",0);
  1197. #endif /* SO_RCVBUF */
  1198. #else
  1199.     debug(F100,"SO_SOCKET not defined","",0);
  1200. #endif /* SOL_SOCKET */
  1201.     return 0;
  1202. }
  1203.  
  1204. int
  1205. keepalive(onoff) int onoff; {
  1206. #ifdef SOL_SOCKET
  1207. #ifdef SO_KEEPALIVE
  1208.     int keepalive_opt;
  1209.     SOCKOPT_T x;
  1210.  
  1211.     if (ttyfd == -1 ||
  1212.     nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1213.     tcp_keepalive = onoff;
  1214.     return 1;
  1215.     }
  1216.     x = sizeof(keepalive_opt);
  1217.     if (getsockopt(ttyfd,
  1218.            SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive_opt, &x)) {
  1219.     perror("could not get SO_KEEPALIVE");
  1220.     } else if (x != sizeof(keepalive_opt)) {
  1221.     debug(F101,"setkeepalive error: SO_KEEPALIVE len","",x);
  1222.     debug(F101,"setkeepalive SO_KEEPALIVE expected len","",
  1223.           sizeof(keepalive_opt));
  1224.     } else if (keepalive_opt != onoff) {
  1225.     keepalive_opt = onoff;
  1226.     if (setsockopt(ttyfd,
  1227.                SOL_SOCKET,
  1228.                SO_KEEPALIVE,
  1229.                (char *)&keepalive_opt,
  1230.                sizeof(keepalive_opt))) {
  1231.         perror("error clearing SO_KEEPALIVE");
  1232.     } else {
  1233.         debug(F101,"setkeepalive new SO_KEEPALIVE","",keepalive_opt);
  1234.         tcp_keepalive = onoff;
  1235.         return 1;
  1236.     }
  1237.     } else {
  1238.     debug(F101,"setkeepalive SO_KEEPALIVE unchanged","",keepalive_opt);
  1239.     tcp_keepalive = onoff;
  1240.     return 1;
  1241.     }
  1242. #else
  1243.     debug(F100,"SO_KEEPALIVE not defined","",0);
  1244. #endif /* SO_KEEPALIVE */
  1245. #else
  1246.     debug(F100,"SO_SOCKET not defined","",0);
  1247. #endif /* SOL_SOCKET */
  1248.     return(0);
  1249. }
  1250.  
  1251. int
  1252. no_delay(onoff)  int onoff; {
  1253. #ifdef SOL_SOCKET
  1254. #ifdef TCP_NODELAY
  1255.     int nodelay_opt;
  1256.     SOCKOPT_T x;
  1257.  
  1258.     if (ttyfd == -1 ||
  1259.     nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
  1260.     tcp_nodelay = onoff;
  1261.     return(1);
  1262.     }
  1263.     x = sizeof(nodelay_opt);
  1264.     if (getsockopt(ttyfd, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay_opt, &x)) {
  1265.     perror("could not get TCP_NODELAY");
  1266.     } else if (x != sizeof(nodelay_opt)) {
  1267.     debug(F101,"setnodelay error: TCP_NODELAY len","",x);
  1268.     debug(F101,"setnodelay TCP_NODELAY expected len","",
  1269.           sizeof(nodelay_opt));
  1270.     } else if (nodelay_opt != onoff) {
  1271.     nodelay_opt = onoff;
  1272.     if (setsockopt(ttyfd,
  1273.                SOL_SOCKET,
  1274.                TCP_NODELAY,
  1275.                (char *)&nodelay_opt,
  1276.                sizeof(nodelay_opt))) {
  1277.         perror("error clearing TCP_NODELAY");
  1278.     } else {
  1279.         debug(F101,"setnodelay new TCP_NODELAY","",nodelay_opt);
  1280.         tcp_nodelay = onoff;
  1281.         return 1;
  1282.     }
  1283.     } else {
  1284.     debug(F101,"setnodelay TCP_NODELAY unchanged","",nodelay_opt);
  1285.     tcp_nodelay = onoff;
  1286.     return(1);
  1287.     }
  1288. #else
  1289.     debug(F100,"TCP_NODELAY not defined","",0);
  1290. #endif /* TCP_NODELAY */
  1291. #else
  1292.     debug(F100,"SO_SOCKET not defined","",0);
  1293. #endif /* SOL_SOCKET */
  1294.     return 0;
  1295. }
  1296. #endif /* datageneral */
  1297. #endif /* NOTCPOPTS */
  1298.  
  1299. #ifdef SUNX25
  1300. #ifndef X25_WR_FACILITY
  1301. /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
  1302. void
  1303. bzero(s,n) char *s; int n; {
  1304.     memset(s,0,n);
  1305. }
  1306. #endif /* X25_WR_FACILITY */
  1307. #endif /* SUNX25 */
  1308.  
  1309. #ifdef TCPSOCKET
  1310. #ifndef OS2
  1311. #ifndef NOLISTEN
  1312.  
  1313. #ifdef BSDSELECT
  1314. #ifndef VMS
  1315. #ifndef BELLV10
  1316. #ifndef datageneral
  1317. #ifdef hp9000s500            /* HP-9000/500 HP-U 5.21 */
  1318. #include <time.h>
  1319. #else
  1320. #include <sys/time.h>
  1321. #endif /* hp9000s500 */
  1322. #endif /* datageneral */
  1323. #endif /* BELLV10 */
  1324. #endif /* VMS */
  1325. #ifdef SELECT_H
  1326. #include <sys/select.h>
  1327. #endif /* SELECT_H */
  1328. #endif /* BSDSELECT */
  1329.  
  1330. #ifdef SELECT
  1331. #ifdef CK_SCOV5
  1332. #include <sys/select.h>
  1333. #endif /* CK_SCOV5 */
  1334. #endif /* SELECT */
  1335.  
  1336. #ifdef TCPSOCKET
  1337. #ifndef SO_OOBINLINE            /* Hopefully only HP-UX 7.0 */
  1338. #define SO_OOBINLINE 0x0100
  1339. #endif /* SO_OOBINLINE */
  1340. #endif /* TCPSOCKET */
  1341.  
  1342. #ifdef NOTUSED
  1343.  
  1344. /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
  1345.  
  1346. int
  1347. tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
  1348.     int on = 1;
  1349.     static struct servent *service, servrec;
  1350.     static struct hostent *host;
  1351.     static struct sockaddr_in saddr;
  1352.     static int saddrlen;
  1353. #ifdef BSDSELECT
  1354.     fd_set rfds;
  1355.     struct timeval tv;
  1356. #else
  1357. #ifdef BELLSELECT
  1358.     fd_set rfds;
  1359. #endif /* BELLSELECT */
  1360. #endif /* BSDSELECT */
  1361.  
  1362.     debug(F101,"tcpsocket_open nett","",nett);
  1363.     *ipaddr = '\0';
  1364.  
  1365.     if (nett != NET_TCPB)
  1366.       return(-1);            /* BSD socket support */
  1367.  
  1368.     netclos();                /* Close any previous connection. */
  1369.     strncpy(namecopy, name, NAMECPYL);    /* Copy the hostname. */
  1370.     ttnproto = NP_NONE;            /* No protocol selected yet. */
  1371.     debug(F110,"tcpsocket_open namecopy",namecopy,0);
  1372.  
  1373.     /* Assign the socket number to ttyfd and then fill in tcp structures */
  1374.     ttyfd = atoi(&name[1]);
  1375.     debug(F111,"tcpsocket_open","ttyfd",ttyfd);
  1376.  
  1377. #ifndef NOTCPOPTS
  1378. #ifdef SOL_SOCKET
  1379.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  1380.  
  1381. #ifndef datageneral
  1382. #ifdef TCP_NODELAY
  1383.     no_delay(tcp_nodelay);
  1384. #endif /* TCP_NODELAY */
  1385. #ifdef SO_KEEPALIVE
  1386.     keepalive(tcp_keepalive);
  1387. #endif /* SO_KEEPALIVE */
  1388. #ifdef SO_LINGER 
  1389.     ck_linger(tcp_linger, tcp_linger_tmo);
  1390. #endif /* SO_LINGER */
  1391. #ifdef SO_SNDBUF
  1392.     sendbuf(tcp_sendbuf);
  1393. #endif /* SO_SNDBUF */
  1394. #ifdef SO_RCVBUF
  1395.     recvbuf(tcp_recvbuf);
  1396. #endif /* SO_RCVBUF */
  1397. #endif /* datageneral */
  1398. #endif /* SOL_SOCKET */
  1399. #endif /* NOTCPOPTS */
  1400.  
  1401.     /* Get the name of the host we are connected to */
  1402.  
  1403.     saddrlen = sizeof(saddr);
  1404.     getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen); 
  1405.  
  1406.     if ((host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) != NULL) {
  1407.     debug(F100,"tcpsocket_open gethostbyname != NULL","",0);
  1408.     strncpy(name, host->h_name, 79);
  1409.     strncat(name, ":", 80 - strlen(name));
  1410. #ifdef COMMENT
  1411.     itoa(ntohs(saddr.sin_port), name + strlen(name), 10);
  1412. #else
  1413.     sprintf(name + strlen(name),"%d",ntohs(saddr.sin_port));
  1414. #endif /* COMMENT */
  1415.     sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
  1416.     printf("%s connected on port %d\n",host->h_name,ntohs(saddr.sin_port));
  1417.     }
  1418.     ttnet = nett;            /* TCP/IP (sockets) network */
  1419.  
  1420. #ifdef RLOGCODE
  1421.     if ( ntohs(saddr.sin_port) == 23 )
  1422.     ttnproto = NP_LOGIN ;
  1423.     else 
  1424. #endif /* RLOGCODE */
  1425.     /* Assume the service is TELNET. */
  1426.     {
  1427.     ttnproto = NP_TELNET;        /* Yes, set global flag. */
  1428.     tn_ini();            /* Start TELNET negotiations. */
  1429.     }
  1430.  
  1431.     if (*lcl < 0) *lcl = 1;        /* Local mode. */
  1432.  
  1433.     return(0);                /* Done. */
  1434. }
  1435. #endif /* NOTUSED */
  1436.  
  1437. /*  T C P S R V _ O P E N  --  Open a TCP/IP Server connection  */
  1438. /*
  1439.   Calling conventions same as ttopen(), except third argument is network
  1440.   type rather than modem type.
  1441. */
  1442. int
  1443. tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
  1444.     char *p;
  1445.     int i, x;
  1446.     SOCKOPT_T on = 1;
  1447.     int ready_to_accept = 0;
  1448.     static struct servent *service, servrec;
  1449.     static struct hostent *host;
  1450.     static struct sockaddr_in saddr;
  1451.     static SOCKOPT_T saddrlen;
  1452.  
  1453. #ifdef BSDSELECT
  1454.     fd_set rfds;
  1455.     struct timeval tv;
  1456. #else
  1457. #ifdef BELLSELCT
  1458.     fd_set rfds;
  1459. #endif /* BELLSELECT */
  1460. #endif /* BSDSELECT */
  1461.  
  1462.     debug(F101,"tcpsrv_open nett","",nett);
  1463.     *ipaddr = '\0';
  1464.  
  1465.     if (nett != NET_TCPB)
  1466.       return(-1);            /* BSD socket support */
  1467.  
  1468.     netclos();                /* Close any previous connection. */
  1469.     strncpy(namecopy, name, NAMECPYL);    /* Copy the hostname. */
  1470.     ttnproto = NP_NONE;            /* No protocol selected yet. */
  1471.     debug(F110,"tcpsrv_open namecopy",namecopy,0);
  1472.  
  1473. #ifdef COMMENT
  1474.     if (tcpsrfd != -1) {
  1475.     socket_close(tcpsrfd);
  1476.     tcpsrfd = -1;
  1477.     tcpsrv_port = 0;
  1478.     }
  1479. #endif /* COMMENT */
  1480.  
  1481.     p = namecopy;            /* Was a service requested? */
  1482.     while (*p != '\0' && *p != ':')
  1483.       p++; /* Look for colon */
  1484.     if (*p == ':') {            /* Have a colon */
  1485.     *p++ = '\0';            /* Get service name or number */
  1486.     } else {                /* Otherwise use kermit */
  1487.     p = "kermit";
  1488.     }
  1489.     debug(F110,"tcpsrv_open service requested",p,0);
  1490.     if (isdigit(*p)) {            /* Use socket number without lookup */
  1491.     service = &servrec;
  1492.     service->s_port = htons((unsigned short)atoi(p));
  1493.     } else {                /* Otherwise lookup the service name */
  1494.     service = getservbyname(p, "tcp");
  1495.     }
  1496.     if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
  1497.     service = &servrec;
  1498.     service->s_port = htons(1649);
  1499.     }
  1500. #ifdef RLOGCODE
  1501.     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
  1502.     fprintf(stderr,
  1503.         "  Warning: login service on port %d instead of port 513\n", 
  1504.          ntohs(service->s_port));
  1505.     fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
  1506.     debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
  1507.     }
  1508. #endif /* RLOGCODE */
  1509.     if (!service) {
  1510.     fprintf(stderr, "Cannot find port for service %s\n", p);
  1511.     debug(F101,"tcpsrv_open can't get service","",errno);
  1512.     errno = 0;            /* rather than mislead */
  1513.     return(-1);
  1514.     }
  1515.  
  1516.     /* If we currently have a listen active but port has changed then close */
  1517.  
  1518.     debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
  1519.     debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
  1520.     if (tcpsrfd != -1 &&
  1521.     tcpsrv_port != ntohs((unsigned short)service->s_port)) {
  1522.     debug(F100,"tcpsrv_open closing previous connection","",0);
  1523. #ifdef TCPIPLIB
  1524.     socket_close(tcpsrfd);
  1525. #else
  1526.     close(tcpsrfd);
  1527. #endif /* TCPIPLIB */
  1528.     tcpsrfd = -1;
  1529.     }
  1530.     debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
  1531.     if (tcpsrfd == -1) {
  1532.  
  1533.     /* Set up socket structure and get host address */
  1534.  
  1535.     bzero((char *)&saddr, sizeof(saddr));
  1536.     debug(F100,"tcpsrv_open bzero ok","",0);
  1537.     saddr.sin_family = AF_INET;
  1538.     saddr.sin_addr.s_addr = INADDR_ANY;
  1539.  
  1540.     /* Get a file descriptor for the connection. */
  1541.  
  1542.     saddr.sin_port = service->s_port;
  1543.     ipaddr[0] = '\0';
  1544.  
  1545.     debug(F100,"tcpsrv_open calling socket","",0);
  1546.     if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  1547.         perror("TCP socket error");
  1548.         debug(F101,"tcpsrv_open socket error","",errno);
  1549.         return (-1);
  1550.     }
  1551.     errno = 0;
  1552.  
  1553.     /* Specify the Port may be reused */
  1554.  
  1555.     debug(F100,"tcpsrv_open calling setsockopt","",0);
  1556.     x = setsockopt(tcpsrfd,
  1557.                SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
  1558.     debug(F101,"tcpsrv_open setsockopt","",x);
  1559.  
  1560. #ifndef NOTCPOPTS
  1561. #ifndef datageneral
  1562. #ifdef SOL_SOCKET
  1563. #ifdef TCP_NODELAY
  1564.     no_delay(tcp_nodelay);
  1565.     debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
  1566. #endif /* TCP_NODELAY */
  1567. #ifdef SO_KEEPALIVE
  1568.     keepalive(tcp_keepalive);
  1569.     debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
  1570. #endif /* SO_KEEPALIVE */
  1571. #ifdef SO_LINGER 
  1572.     ck_linger(tcp_linger, tcp_linger_tmo);
  1573.     debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
  1574. #endif /* SO_LINGER */
  1575. #ifdef SO_SNDBUF
  1576.     sendbuf(tcp_sendbuf);
  1577.     debug(F101,"tcpsrv_open sendbuf","",tcp_sendbuf);
  1578. #endif /* SO_SNDBUF */
  1579. #ifdef SO_RCVBUF
  1580.     recvbuf(tcp_recvbuf);
  1581.     debug(F101,"tcpsrv_open recvbuf","",tcp_recvbuf);
  1582. #endif /* SO_RCVBUF */
  1583. #endif /* SOL_SOCKET */
  1584. #endif /* datageneral */
  1585. #endif /* NOTCPOPTS */
  1586.  
  1587.        /* Now bind to the socket */
  1588.     printf("\nBinding socket to port %d ...\n",
  1589.            ntohs((unsigned short)service->s_port));
  1590.     if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
  1591.         i = errno;            /* Save error code */
  1592.         close(tcpsrfd);
  1593.         tcpsrfd = -1;
  1594.         tcpsrv_port = 0;
  1595.         ttyfd = -1;
  1596.         errno = i;            /* and report this error */
  1597.         debug(F101,"tcpsrv_open bind errno","",errno);
  1598.         return(-1);
  1599.     }
  1600.     debug(F100,"tcpsrv_open bind OK","",0);
  1601.     printf("Listening ...\n");
  1602.     if (listen(tcpsrfd, 15) < 0) {
  1603.         i = errno;            /* Save error code */
  1604.         close(tcpsrfd);
  1605.         tcpsrfd = -1;
  1606.         tcpsrv_port = 0;
  1607.         ttyfd = -1;
  1608.         errno = i;            /* And report this error */
  1609.         debug(F101,"tcpsrv_open listen errno","",errno);
  1610.         return(-1);
  1611.     }
  1612.     debug(F100,"tcpsrv_open listen OK","",0);
  1613.     tcpsrv_port = ntohs((unsigned short)service->s_port);
  1614.     }
  1615.     printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
  1616.            ntohs((unsigned short)service->s_port));
  1617.     saddrlen = sizeof(saddr);
  1618.  
  1619. #ifdef BSDSELECT
  1620.     tv.tv_sec  = tv.tv_usec = 0L;
  1621.     if (timo < 0)
  1622.       tv.tv_usec = (long) -timo * 10000L;
  1623.     else
  1624.       tv.tv_sec = timo;
  1625.     debug(F101,"tcpsrv_open BSDSELECT","",timo);
  1626. #else
  1627.     debug(F101,"tcpsrv_open not BSDSELECT","",timo);
  1628. #endif /* BSDSELECT */
  1629.  
  1630.     if (!timo) {
  1631.     while (!ready_to_accept) {
  1632. #ifdef BSDSELECT
  1633.         FD_ZERO(&rfds);
  1634.         FD_SET(tcpsrfd, &rfds);
  1635.         ready_to_accept =
  1636.           ((select(FD_SETSIZE, 
  1637. #ifdef HPUX
  1638. #ifdef HPUX1010
  1639.                (fd_set *)
  1640. #else
  1641.  
  1642.                (int *)
  1643. #endif /* HPUX1010 */
  1644. #else
  1645. #ifdef __DECC
  1646.                (fd_set *)
  1647. #endif /* __DECC */
  1648. #endif /* HPUX */
  1649.                &rfds, NULL, NULL, &tv) > 0) && 
  1650.            FD_ISSET(tcpsrfd, &rfds));
  1651. #else /* BSDSELECT */
  1652. #ifdef IBMSELECT
  1653. #define ck_sleepint 250
  1654.         ready_to_accept =
  1655.           (select(&tcpsrfd, 1, 0, 0,
  1656.               timo < 0 ? -timo :
  1657.               (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
  1658.            );
  1659. #else
  1660. #ifdef BELLSELECT
  1661.         FD_ZERO(rfds);
  1662.         FD_SET(tcpsrfd, rfds);
  1663.         ready_to_accept =
  1664.           ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
  1665.               (timo > 0 ? timo * 1000L)) > 0) && 
  1666.            FD_ISSET(tcpsrfd, rfds));
  1667. #else
  1668. SOME_FORM_OF_SELECT_IS_NEEDED_HERE
  1669. #endif /* BELLSELECT */
  1670. #endif /* IBMSELECT */
  1671. #endif /* BSDSELECT */
  1672.     }
  1673.     }
  1674.     if (ready_to_accept) {
  1675.     if ((ttyfd = accept(tcpsrfd,
  1676.                 (struct sockaddr *)&saddr,&saddrlen)) < 0) {
  1677.         i = errno;            /* save error code */
  1678.         close(tcpsrfd);
  1679.         ttyfd = -1;
  1680.         tcpsrfd = -1;
  1681.         tcpsrv_port = 0;
  1682.         errno = i;            /* and report this error */
  1683.         debug(F101,"tcpsrv_open accept errno","",errno);
  1684.         return(-1);
  1685.     }
  1686.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  1687.  
  1688.     ttnet = nett;            /* TCP/IP (sockets) network */
  1689.     /* See if the service is TELNET. */
  1690.     if ((x = ntohs((unsigned short)service->s_port)) ==
  1691.         getservbyname("telnet", "tcp")->s_port) {
  1692.         ttnproto = NP_TELNET;    /* Yes, set global flag. */
  1693.         tn_ini();            /* Start TELNET negotiations. */
  1694.     } else {
  1695.         tn_ini();            /* Initialize TELNET negotiations. */
  1696.     }
  1697.     debug(F101,"tcpsrv_open service","",x);
  1698.     if (*lcl < 0)            /* Set local mode. */
  1699.       *lcl = 1;
  1700.  
  1701. #ifdef COMMENT
  1702.     close(tcpsrfd);
  1703.     tcpsrfd = -1;
  1704.     tcpsrv_port = 0;
  1705. #endif /* COMMENT */
  1706.  
  1707.     if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
  1708.         debug(F100,"tcpsrv_open gethostbyname != NULL","",0);
  1709.         name[0] = '*';
  1710.         strncpy(&name[1],host->h_name,79);
  1711.         strncat(name,":",80-strlen(name));
  1712.         strncat(name,p,80-strlen(name));
  1713.         sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
  1714.         printf("%s connected on port %s\n",host->h_name,p);
  1715.     }
  1716.     return(0);            /* Done. */
  1717.     } else {
  1718.     i = errno;            /* save error code */
  1719.     close(tcpsrfd);
  1720.     ttyfd = -1;
  1721.     tcpsrfd = -1;
  1722.     tcpsrv_port = 0;
  1723.     errno = i;            /* and report this error */
  1724.     debug(F101,"tcpsrv_open accept errno","",errno);
  1725.     return(-1);
  1726.     }
  1727. }
  1728. #endif /* NOLISTEN */
  1729. #endif /* OS2 */
  1730. #endif /* TCPSOCKET */
  1731.  
  1732. /*  N E T O P E N  --  Open a network connection  */
  1733. /*
  1734.   Calling conventions same as ttopen(), except third argument is network
  1735.   type rather than modem type.  Designed to be called from within ttopen.
  1736. */
  1737. int
  1738. netopen(name, lcl, nett) char *name; int *lcl, nett; {
  1739.     char *p;
  1740.     int i, x;
  1741. #ifdef TCPSOCKET
  1742.     int isconnect = 0;
  1743. #ifdef SO_OOBINLINE
  1744.     int on = 1;
  1745. #endif /* SO_OOBINLINE */
  1746.     struct servent *service=NULL, servrec;
  1747.     struct hostent *host=NULL;
  1748.     struct sockaddr_in saddr;
  1749. #ifdef EXCELAN
  1750.     struct sockaddr_in send_socket;
  1751. #endif /* EXCELAN */
  1752. #endif /* TCPSOCKET */
  1753.  
  1754. #ifdef SUNX25                /* Code for SunLink X.25 support */
  1755. #define X29PID 1            /* X.29 Protocol ID */
  1756. _PROTOTYP(SIGTYP x25oobh, (int) );
  1757.     CONN_DB x25host;
  1758. #ifndef X25_WR_FACILITY
  1759.     FACILITY x25facil;
  1760. #else
  1761.     FACILITY_DB x25facil;
  1762. #endif /* X25_WR_FACILITY */
  1763.     static int needh = 1;
  1764.     PID_T pid;
  1765.     extern int linkid, lcn, x25ver;
  1766.     extern int revcall, closgr, cudata;
  1767.     extern char udata[];
  1768. #endif /* SUNX25 */
  1769.  
  1770.     debug(F101,"netopen nett","",nett);
  1771.     *ipaddr = '\0';            /* Initialize IP address string */
  1772.  
  1773. #ifdef SUNX25
  1774.     if (nett == NET_SX25) {        /* If network type is X.25 */
  1775.         netclos();            /* Close any previous net connection */
  1776.         ttnproto = NP_NONE;        /* No protocol selected yet */
  1777.  
  1778.         /* Set up host structure */
  1779.         bzero((char *)&x25host,sizeof(x25host));
  1780.         if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
  1781.             fprintf (stderr,"Invalid X.121 host address %s\n",name);
  1782.             errno = 0;
  1783.             return (-1);
  1784.         }
  1785.         x25host.datalen = X29PIDLEN;
  1786.         x25host.data[0] = X29PID;
  1787.  
  1788.     /* Set call user data if specified */
  1789.         if (cudata) {
  1790.             strncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
  1791.             x25host.datalen += (int)strlen(udata);
  1792.         }
  1793.  
  1794.         /* Open SunLink X.25 socket */
  1795.     if (!quiet && *name) printf(" Trying %s...\n", name);
  1796.         if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
  1797.         debug(F101,"netopen socket error","",errno);
  1798.             perror ("X.25 socket error");
  1799.             return (-1);
  1800.         }
  1801.  
  1802.         /* Setting X.25 out-of-band data handler */
  1803.         pid = getpid();
  1804.         if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
  1805.             perror("X.25 set process group id error");
  1806.             return(-1);
  1807.         }
  1808.         (VOID) signal(SIGURG,x25oobh);
  1809.  
  1810.         /* Set reverse charge call and closed user group if requested */
  1811.         bzero ((char *)&x25facil,sizeof(x25facil));
  1812.  
  1813. #ifndef X25_WR_FACILITY
  1814. /*  New SunLink (7.0 or 8.0, not sure which)... */
  1815.     x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
  1816.     x25facil.f_reverse_charge = revcall ? 1 : 0;
  1817.         if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
  1818.             perror ("Setting X.25 reverse charge");
  1819.             return (-1);
  1820.         }
  1821.     if (closgr > -1) {        /* Closed User Group (Outgoing) */
  1822.         bzero ((char *)&x25facil,sizeof(x25facil));
  1823.         x25facil.type = T_CUG;
  1824.         x25facil.f_cug_req = CUG_REQ_ACS;
  1825.         x25facil.f_cug_index = closgr;
  1826.         if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
  1827.         perror ("Setting X.25 closed user group");
  1828.         return (-1);
  1829.         }
  1830.     }
  1831. #else
  1832. /*  Old SunLink 6.0 (or 7.0?)... */
  1833.         if (revcall) x25facil.reverse_charge = revcall;
  1834.         if (closgr > -1) {
  1835.             x25facil.cug_req = 1;
  1836.             x25facil.cug_index = closgr;
  1837.         }
  1838.         if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
  1839.             perror ("Setting X.25 facilities");
  1840.             return (-1);
  1841.         }
  1842. #endif /* X25_WR_FACILITY */
  1843.  
  1844.         /*  Need X.25 header with bits Q and M */
  1845.         if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
  1846.             perror ("Setting X.25 header");
  1847.             return (-1);
  1848.         }
  1849.  
  1850.         /* Connects to remote host via SunLink X.25 */
  1851.         if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
  1852.         i = errno;
  1853.         debug(F101,"netopen connect errno","",i);
  1854.         if (i) {
  1855.         perror("netopen x25 connect");
  1856.         x25diag();
  1857.         }
  1858.         (VOID) netclos();
  1859.         ttyfd = -1;
  1860.         ttnproto = NP_NONE;
  1861.         errno = i;
  1862.         return (-1);
  1863.     }
  1864.  
  1865.         /* Get X.25 link identification used for the connection */
  1866.         if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
  1867.             perror ("Getting X.25 link id");
  1868.             return (-1);
  1869.         }
  1870.  
  1871.         /* Get X.25 logical channel number used for the connection */
  1872.         if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
  1873.             perror ("Getting X.25 lcn");
  1874.             return (-1);
  1875.         }
  1876.  
  1877.         /* Get SunLink X.25 version */
  1878.         if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
  1879.             perror ("Getting SunLink X.25 version");
  1880.             return (-1);
  1881.         }
  1882.         ttnet = nett;                   /* Sunlink X.25 network */
  1883.         ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
  1884.         if (*lcl < 0) *lcl = 1;         /* Local mode */
  1885.         return(0);
  1886.     } else /* Note that SUNX25 support can coexist with TCP/IP support. */
  1887. #endif /* SUNX25 */
  1888.  
  1889. /*   Add support for other networks here. */
  1890.  
  1891.       if (nett != NET_TCPB) return(-1);    /* BSD socket support */
  1892.  
  1893. #ifdef TCPSOCKET
  1894.     netclos();                /* Close any previous connection. */
  1895.     strncpy(namecopy, name, NAMECPYL);    /* Copy the hostname. */
  1896.     ttnproto = NP_NONE;            /* No protocol selected yet. */
  1897.     debug(F110,"netopen namecopy",namecopy,0);
  1898.  
  1899. #ifndef NOLISTEN
  1900.     if (name[0] == '*')
  1901.       return(tcpsrv_open(name, lcl, nett, 0));
  1902. #endif /* NOLISTEN */
  1903.  
  1904.     p = namecopy;            /* Was a service requested? */
  1905.     while (*p != '\0' && *p != ':') p++; /* Look for colon */
  1906.     if (*p == ':') {            /* Have a colon */
  1907.     *p++ = '\0';            /* Get service name or number */
  1908.     } else {                /* Otherwise use telnet */
  1909.     p = "telnet";
  1910.     }
  1911.     debug(F110,"netopen service requested",p,0);
  1912.     if (isdigit(*p)) {            /* Use socket number without lookup */
  1913.     service = &servrec;
  1914.     service->s_port = htons((unsigned short)atoi(p));
  1915.     } else {                /* Otherwise lookup the service name */
  1916.     service = getservbyname(p, "tcp");
  1917.     }
  1918.     if (!service) {
  1919.     fprintf(stderr, "Cannot find port for service %s\n", p);
  1920. #ifdef TGVORWIN
  1921.     debug(F101,"netopen can't get service","",socket_errno);
  1922. #else
  1923.     debug(F101,"netopen can't get service","",errno);
  1924. #endif /* TGVORWIN */
  1925.     errno = 0;            /* rather than mislead */
  1926.     return(-1);
  1927.     }
  1928.  
  1929. #ifdef RLOGCODE
  1930.     if (service && !strcmp("login",p) && service->s_port != htons(513)) {
  1931.     fprintf(stderr,
  1932.         "  Warning: login service on port %d instead of port 513\n", 
  1933.          ntohs(service->s_port));
  1934.     fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
  1935.     debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
  1936.     }
  1937. #endif /* RLOGCODE */
  1938.  
  1939.     /* Set up socket structure and get host address */
  1940.  
  1941.     bzero((char *)&saddr, sizeof(saddr));
  1942.     debug(F100,"netopen bzero ok","",0);
  1943.     if (
  1944. #ifdef NT
  1945.         /* we found that Win95 tries to call the DNS  */
  1946.         /* when a numeric IP Address is specified.    */
  1947.         /* and of course the lookup fails resulting   */
  1948.         /* in a long delay.  So we test for the IP    */
  1949.         /* numeric value before calling gethostbyname */
  1950.         /* but only in Win32 so as not to             */
  1951.         /* alter current code that works properly     */
  1952.         /* everywhere else.                           */
  1953.         inet_addr(namecopy) == INADDR_NONE &&
  1954. #endif /* NT */
  1955.         (host = gethostbyname(namecopy)) != NULL) {
  1956.     debug(F100,"netopen gethostbyname != NULL","",0);
  1957. #ifdef OS2
  1958.     strncpy(name,host->h_name,80);
  1959.     strncat(name,":",80-strlen(name));
  1960.     strncat(name,p,80-strlen(name));
  1961. #endif /* OS2 */
  1962.     saddr.sin_family = host->h_addrtype;
  1963. #ifdef HADDRLIST
  1964. #ifdef h_addr
  1965.     /* This is for trying multiple IP addresses - see <netdb.h> */
  1966.     if (!(host->h_addr_list))
  1967.       return(-1);
  1968.     bcopy(host->h_addr_list[0], (caddr_t)&saddr.sin_addr, host->h_length);
  1969. #else
  1970.     bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
  1971. #endif /* h_addr */
  1972. #else  /* HADDRLIST */
  1973.     bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
  1974. #endif /* HADDRLIST */
  1975. #ifndef EXCELAN
  1976.     debug(F111,"BCOPY","host->h_addr",host->h_addr);
  1977. #endif /* EXCELAN */
  1978.     debug(F111,"BCOPY"," (caddr_t)&saddr.sin_addr",
  1979.           (caddr_t)&saddr.sin_addr);
  1980.     debug(F111,"BCOPY","host->h_length",host->h_length);
  1981.     } else {
  1982. #ifdef INADDRX
  1983. /* inet_addr() is of type struct in_addr */
  1984.     struct in_addr ina;
  1985.     unsigned long uu;
  1986. #ifdef datageneral
  1987.     extern struct in_addr inet_addr();
  1988. #endif /* datageneral */
  1989.     debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
  1990.     ina = inet_addr(namecopy);
  1991.     uu = *(unsigned long *)&ina;
  1992. #else /* Not INADDRX */
  1993. /* inet_addr() is unsigned long */
  1994.     unsigned long uu;
  1995.     debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
  1996.     uu = inet_addr(namecopy);
  1997. #endif /* INADDRX */
  1998.     debug(F101,"netopen uu","",uu);
  1999.     if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
  2000.       saddr.sin_family = AF_INET;
  2001.     else {
  2002.         fprintf(stderr, "Can't get address for %s\n", namecopy);
  2003. #ifdef TGVORWIN
  2004.         debug(F101,"netopen can't get address","",socket_errno);
  2005. #else
  2006.         debug(F101,"netopen can't get address","",errno);
  2007. #endif /* TGVORWIN */
  2008.         errno = 0;        /* Rather than mislead */
  2009.         return(-1);
  2010.     }
  2011.     }
  2012.  
  2013.     /* Get a file descriptor for the connection. */
  2014.  
  2015.     saddr.sin_port = service->s_port;
  2016.     sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
  2017.     debug(F110,"netopen trying",ipaddr,0);
  2018.     if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
  2019.  
  2020.     /* Loop to try additional IP addresses, if any. */
  2021.  
  2022.     do {
  2023. #ifdef EXCELAN
  2024.     send_socket.sin_family = AF_INET;
  2025.     send_socket.sin_addr.s_addr = 0;
  2026.     send_socket.sin_port = 0;
  2027.     if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
  2028.                 &send_socket, SO_REUSEADDR)) < 0)
  2029. #else  /* EXCELAN */
  2030. #ifdef NT
  2031. #ifdef COMMENT
  2032.        /*
  2033.      Must make sure that all sockets are opened in
  2034.          Non-overlapped mode since we use the standard
  2035.          C RTL functions to read and write data.
  2036.          But it doesn't seem to work as planned.
  2037.        */
  2038.       {
  2039.           int optionValue = SO_SYNCHRONOUS_NONALERT;
  2040.           if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, 
  2041.                  (char *) &optionValue, sizeof(optionValue))
  2042.           != NO_ERROR)
  2043.         return(-1);
  2044.       }
  2045. #endif /* COMMENT */
  2046. #endif /* NT */
  2047.  
  2048.     if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  2049. #endif /* EXCELAN */
  2050.         {
  2051. #ifdef EXCELAN
  2052.         experror("TCP socket error");
  2053. #else
  2054. #ifdef TGVORWIN
  2055. #ifdef OLD_TWG
  2056.                 errno = socket_errno;
  2057. #endif /* OLD_TWG */
  2058.         socket_perror("TCP socket error");
  2059.         debug(F101,"netopen socket error","",socket_errno);
  2060. #else
  2061.         perror("TCP socket error");
  2062.         debug(F101,"netopen socket error","",errno);
  2063. #endif /* TGVORWIN */
  2064. #endif /* EXCELAN */
  2065.         return (-1);
  2066.         }
  2067.     errno = 0;
  2068.  
  2069. #ifdef RLOGCODE                                                    
  2070.        /* Not part of the RLOGIN RFC, but the BSD implementation     */
  2071.        /* requires that the client port be a priviliged port (<1024) */
  2072.        /* on a Unix system this would require SuperUser permissions  */
  2073.        /* thereby saying that the root of the Unix system has given  */
  2074.        /* permission for this connection to be created               */
  2075.        if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
  2076.        struct sockaddr_in sin;
  2077.        static unsigned short lport = 1024;    /* max reserved port */
  2078.        int s_errno;
  2079.  
  2080.        lport--;            /* Make sure we do not reuse a port */
  2081.        if (lport == 512)
  2082.              lport = 1023;
  2083.  
  2084.        sin.sin_family = AF_INET;
  2085.        sin.sin_addr.s_addr = INADDR_ANY;
  2086.        while (1) {
  2087.            sin.sin_port = htons(lport);
  2088.            if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  2089.          break;
  2090. #ifdef OS2
  2091.            s_errno = socket_errno;
  2092.            if (s_errno && /* OS2 bind fails with 0, if already in use */
  2093. #ifdef NT
  2094.            s_errno != WSAEADDRINUSE
  2095. #else
  2096.            s_errno != SOCEADDRINUSE &&
  2097.            s_errno != (SOCEADDRINUSE - SOCBASEERR)
  2098. #endif /* NT */
  2099.            )
  2100. #else /* OS2 */
  2101. #ifdef TGVORWIN
  2102.          if (socket_errno != EADDRINUSE)
  2103. #else
  2104.          if (errno != EADDRINUSE)
  2105. #endif /* TGVORWIN */
  2106. #endif /* OS2 */
  2107.            {
  2108.                printf("\nBind failed with errno %d  for port %d.\n",
  2109. #ifdef OS2
  2110.                   s_errno
  2111. #else
  2112. #ifdef TGVORWIN
  2113.                   socket_errno
  2114. #else
  2115.                   errno
  2116. #endif /* TGVORWIN */
  2117. #endif /* OS2 */
  2118.                   , lport
  2119.                   );
  2120. #ifdef OS2
  2121.                        debug(F101,"rlogin bind failed","",s_errno);
  2122. #else
  2123. #ifdef TGVORWIN
  2124.                        debug(F101,"rlogin bind failed","",socket_errno);
  2125. #ifdef OLD_TWG
  2126.                        errno = socket_errno;
  2127. #endif /* OLD_TWG */
  2128.                        socket_perror("rlogin bind");
  2129. #else
  2130.                        debug(F101,"rlogin bind failed","",errno);
  2131.                        perror("rlogin bind");
  2132. #endif /* TGVORWIN */
  2133. #endif /* OS2 */
  2134.                netclos();
  2135.                return -1;
  2136.            }
  2137.            lport--;
  2138.            if (lport == 512 /* lowest reserved port to use */ ) {
  2139.            printf("\nNo reserved ports available.\n");
  2140.            netclos();
  2141.            return -1;
  2142.            }
  2143.        }
  2144.        debug(F101,"rlogin lport","",lport);
  2145.        ttnproto = NP_RLOGIN;
  2146.        }
  2147. #endif /* RLOGCODE  */
  2148.  
  2149. /* Now connect to the socket on the other end. */
  2150.  
  2151. #ifdef EXCELAN
  2152.     if (connect(ttyfd, &saddr) < 0)
  2153. #else
  2154. #ifdef NT
  2155.       WSASafeToCancel = 1;
  2156. #endif /* NT */
  2157.     if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
  2158. #endif /* EXCELAN */
  2159.       {
  2160. #ifdef NT
  2161.           WSASafeToCancel = 0;
  2162. #endif /* NT */
  2163. #ifdef OS2
  2164.           i = socket_errno;
  2165. #else /* OS2 */
  2166. #ifdef TGVORWIN
  2167.               i = socket_errno;
  2168. #else
  2169.               i = errno;                /* Save error code */
  2170. #endif /* TGVORWIN */
  2171. #endif /* OS2 */
  2172. #ifdef RLOGCODE
  2173.           if (
  2174. #ifdef OS2
  2175.                  i && /* OS2 bind fails with 0, if already in use */
  2176. #ifdef NT
  2177.                  i == WSAEADDRINUSE
  2178. #else
  2179.          (i == SOCEADDRINUSE ||
  2180.          i == (SOCEADDRINUSE - SOCBASEERR))
  2181. #endif /* NT */
  2182. #else /* OS2 */
  2183. #ifdef TGVORWIN
  2184.                   socket_errno == EADDRINUSE
  2185. #else
  2186.                   errno == EADDRINUSE
  2187. #endif /* TGVORWIN */
  2188. #endif /* OS2 */
  2189.           && ttnproto == NP_RLOGIN) {
  2190. #ifdef TCPIPLIB
  2191.            socket_close(ttyfd); /* Close it. */
  2192. #else
  2193.            close(ttyfd);
  2194. #endif /* TCPIPLIB */
  2195.            continue;        /* Try a different lport */
  2196.            }
  2197. #endif /* RLOGCODE */
  2198. #ifdef HADDRLIST
  2199. #ifdef h_addr
  2200.           if (host && host->h_addr_list && host->h_addr_list[1]) {
  2201.           perror("");
  2202.           host->h_addr_list++;
  2203.           bcopy(host->h_addr_list[0],
  2204.             (caddr_t)&saddr.sin_addr,
  2205.             host->h_length);
  2206.  
  2207.           sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
  2208.           debug(F110,"netopen h_addr_list",ipaddr,0);
  2209.           if (!quiet && *ipaddr)
  2210.             printf(" Trying %s...\n", ipaddr);
  2211. #ifdef TCPIPLIB
  2212.           socket_close(ttyfd); /* Close it. */
  2213. #else
  2214.           close(ttyfd);
  2215. #endif /* TCPIPLIB */
  2216.           continue;
  2217.           }
  2218. #endif /* h_addr */
  2219. #endif  /* HADDRLIST */
  2220.           netclos();
  2221.           ttyfd = -1;
  2222.           ttnproto = NP_NONE;
  2223.           errno = i;        /* And report this error */
  2224. #ifdef EXCELAN
  2225.           if (errno) experror("netopen connect");
  2226. #else
  2227. #ifdef TGVORWIN
  2228.           debug(F101,"netopen connect error","",socket_errno);
  2229.           /* if (errno) socket_perror("netopen connect"); */
  2230. #ifdef OLD_TWG
  2231.               errno = socket_errno;
  2232. #endif /* OLD_TWG */
  2233.               socket_perror("netopen connect");
  2234. #else /* TGVORWIN */
  2235.           debug(F101,"netopen connect errno","",errno);
  2236. #ifdef DEC_TCPIP
  2237.           perror("netopen connect");
  2238. #endif /* DEC_TCPIP */
  2239. #ifdef CMU_TCPIP
  2240.           perror("netopen connect");
  2241. #endif /* CMU_TCPIP */
  2242. #endif /* TGVORWIN */
  2243. #endif /* EXCELAN */
  2244.           return(-1);
  2245.       }
  2246. #ifdef NT
  2247.     WSASafeToCancel = 0;
  2248. #endif /* NT */
  2249.     isconnect = 1;
  2250.     } while (!isconnect);
  2251.  
  2252. #ifdef SO_OOBINLINE
  2253. /*
  2254.   The symbol SO_OOBINLINE is not known to Ultrix 2.0.
  2255.   It means "leave out of band data inline".  The normal value is 0x0100,
  2256.   but don't try this on systems where the symbol is undefined.
  2257. */
  2258. /*
  2259.   Note from Jeff Altman: 12/13/95
  2260.   In implementing rlogin protocol I have come to the conclusion that it is 
  2261.   a really bad idea to read out-of-band data inline.  
  2262.   At least Windows and OS/2 does not handle this well.
  2263.   And if you need to know that data is out-of-band, then it becomes 
  2264.   absolutely pointless.
  2265.  
  2266.   Therefore, at least on OS2 and Windows (NT) I have changed the value of
  2267.   on to 0, so that out-of-band data stays out-of-band.
  2268.  
  2269.   12/18/95
  2270.   Actually, OOB data should be read inline when possible.  Especially with
  2271.   protocols that don't care about the Urgent flag.  This is true with Telnet.
  2272.   With Rlogin, you need to be able to catch OOB data.  However, the best 
  2273.   way to do this is to set a signal handler on SIGURG.  This isn't possible 
  2274.   on OS/2 and Windows.  But it is in UNIX.  We will also need OOB data for 
  2275.   FTP so better create a general mechanism.
  2276.  
  2277.   The reason for making OOB data be inline is that the standard ttinc/ttoc
  2278.   calls can be used for reading that data on UNIX systems.  If we didn't 
  2279.   have the OOBINLINE option set then we would have to use recv(,MSG_OOB) 
  2280.   to read it.
  2281.  
  2282. */
  2283. #ifdef RLOGCODE
  2284. #ifdef TCPIPLIB
  2285.     if (ttnproto == NP_RLOGIN || ttnproto == NP_FTP)
  2286.       on = 0;
  2287. #else /* TCPIPLIB */
  2288.     if (ttnproto == NP_RLOGIN) {
  2289.     debug(F100,"Installing rlogoobh on SIGURG","",0);
  2290.     signal(SIGURG, rlogoobh);
  2291.     } else 
  2292. #ifdef FTPCODE
  2293.       if (ttnproto == NP_FTP) {
  2294.       signal(SIGURG, ftpoobh);
  2295.       } else
  2296. #endif /* FTPCODE */
  2297.     {
  2298.         signal(SIGURG, SIG_DFL);
  2299.     }
  2300. #endif /* TCPIPLIB */
  2301. #endif /* RLOGCODE */
  2302.  
  2303. #ifdef datageneral
  2304.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2305. #else
  2306. #ifdef BSD43
  2307.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2308. #else
  2309. #ifdef OSF1
  2310.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2311. #else
  2312. #ifdef POSIX
  2313.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2314. #else
  2315. #ifdef MOTSV88R4 
  2316.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2317. #else
  2318. #ifdef SOLARIS
  2319. /*
  2320.   Maybe this applies to all SVR4 versions, but the other (else) way has been
  2321.   compiling and working fine on all the others, so best not to change it.
  2322. */
  2323.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2324. #else
  2325. #ifdef OSK
  2326.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2327. #else
  2328. #ifdef OS2
  2329.     {
  2330.     int rc;
  2331.     rc = setsockopt(ttyfd,
  2332.             SOL_SOCKET,
  2333.             SO_OOBINLINE,
  2334.             (char *) &on,
  2335.             sizeof on
  2336.             );
  2337.     debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
  2338.     }
  2339. #else
  2340. #ifdef VMS /* or, at least, VMS with gcc */
  2341.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  2342. #else
  2343.     setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
  2344. #endif /* VMS */
  2345. #endif /* OS2 */
  2346. #endif /* OSK */
  2347. #endif /* SOLARIS */
  2348. #endif /* MOTSV88R4 */
  2349. #endif /* POSIX */
  2350. #endif /* BSD43 */
  2351. #endif /* OSF1 */
  2352. #endif /* datageneral */
  2353. #endif /* SO_OOBINLINE */
  2354.  
  2355. #ifndef NOTCPOPTS
  2356. #ifndef datageneral
  2357. #ifdef SOL_SOCKET
  2358. #ifdef TCP_NODELAY
  2359.     no_delay(tcp_nodelay);
  2360. #endif /* TCP_NODELAY */
  2361. #ifdef SO_KEEPALIVE
  2362.     keepalive(tcp_keepalive);
  2363. #endif /* SO_KEEPALIVE */
  2364. #ifdef SO_LINGER 
  2365.     ck_linger(tcp_linger, tcp_linger_tmo);
  2366. #endif /* SO_LINGER */
  2367. #ifdef SO_SNDBUF
  2368.     sendbuf(tcp_sendbuf);
  2369. #endif /* SO_SNDBUF */
  2370. #ifdef SO_RCVBUF
  2371.     recvbuf(tcp_recvbuf);
  2372. #endif /* SO_RCVBUF */
  2373. #endif /* SOL_SOCKET */
  2374. #endif /* datageneral */
  2375. #endif /* NOTCPOPTS */
  2376.  
  2377.     ttnet = nett;            /* TCP/IP (sockets) network */
  2378.  
  2379.     x = ntohs((unsigned short)service->s_port);
  2380.     /* See if the service is TELNET. */
  2381.     if (x == TELNET_PORT) {
  2382.     ttnproto = NP_TELNET;        /* Yes, set global flag. */
  2383.     }
  2384. #ifdef RLOGCODE
  2385.     else if (x == RLOGIN_PORT) {
  2386.     ttnproto = NP_RLOGIN;
  2387.     if (rlog_ini() < 0) {
  2388.         debug(F100,"rlogin initialization failed","",0);
  2389.         netclos();
  2390.         return -1;
  2391.     }
  2392.     }
  2393. #endif /* RLOGCODE */
  2394. #ifdef COMMENT /* not yet */
  2395.     else if (x == KERMIT_PORT) {
  2396.     ttnproto = NP_KERMIT;
  2397.     }
  2398. #endif /* COMMENT */
  2399.  
  2400. #ifndef datageneral
  2401. /* Find out our own IP address */
  2402.     {
  2403.     struct sockaddr_in sa;
  2404.  
  2405. #ifndef GSOCKNAME_T
  2406. #define GSOCKNAME_T int
  2407. #ifdef UNIXWARE
  2408. #undef GSOCKNAME_T
  2409. #define GSOCKNAME_T size_t
  2410. #else
  2411. #ifdef VMS
  2412. #ifdef DEC_TCPIP
  2413. #ifdef __DECC_VER
  2414. #undef GSOCKNAME_T
  2415. #define GSOCKNAME_T size_t
  2416. #endif /* __DECC_VER */
  2417. #endif /* DEC_TCPIP */
  2418. #endif /* VMS */
  2419. #endif /* UNIXWARE */
  2420. #endif /* GSOCKNAME_T */
  2421.  
  2422.     GSOCKNAME_T slen;
  2423.  
  2424.     slen = sizeof(sa);
  2425. #ifdef COMMENT
  2426. /* memset is not portable */
  2427.     memset(&sa, 0, slen);
  2428. #else
  2429.     bzero((char *)&sa, slen);
  2430. #endif /* COMMENT */
  2431. #ifndef EXCELAN
  2432.     if (!getsockname(ttyfd, (struct sockaddr *)&sa, &slen) ) {
  2433.         sprintf(myipaddr,"%s", (char *)inet_ntoa(sa.sin_addr));
  2434.         debug(F110,"getsockname",myipaddr,0);
  2435.     }
  2436. #endif /* EXCELAN */
  2437.     }
  2438. #endif /* datageneral */
  2439.     tn_ini();
  2440.     debug(F101,"netopen service","",x);
  2441.     if (*lcl < 0) *lcl = 1;        /* Local mode. */
  2442. #endif /* TCPSOCKET */
  2443.     return(0);                /* Done. */
  2444. }
  2445.  
  2446. /*  N E T C L O S  --  Close current network connection.  */
  2447.  
  2448. int
  2449. netclos() {
  2450.     int x = 0;
  2451.     debug(F101,"netclos","",ttyfd);
  2452.     if (ttyfd == -1)            /* Was open? */
  2453.       return(0);            /* Wasn't. */
  2454.     if (ttyfd > -1) {            /* Was. */
  2455. #ifdef VMS    
  2456.     ck_cancio();            /* Cancel any outstanding reads. */
  2457. #endif /* VMS */
  2458. #ifdef TCPIPLIB
  2459.     x = socket_close(ttyfd);    /* Close it. */
  2460. #else
  2461. #ifndef OS2
  2462.     x = close(ttyfd);
  2463. #endif /* OS2 */
  2464. #endif /* TCPIPLIB */
  2465.     }
  2466.     ttyfd = -1;                /* Mark it as closed. */
  2467.     ttnproto = NP_NONE;            /* Reset the protocol type */
  2468.     debug(F100,"netclose setting tn_init = 0","",0);
  2469.     tn_init = 0;            /* Remember about telnet protocol... */
  2470.     *ipaddr = '\0';            /* Zero the IP address string */
  2471. #ifdef TCPIPLIB
  2472. /*
  2473.   Empty the internal buffers so they won't be used as invalid input on
  2474.   the next connect attempt (rlogin).
  2475. */
  2476.     ttibp = 0;
  2477.     ttibn = 0;
  2478. #endif /* TCPIPLIB */
  2479.     return(x);
  2480. }
  2481.  
  2482. /*  N E T T C H K  --  Check if network up, and how many bytes can be read */
  2483. /*
  2484.   Returns number of bytes waiting, or -1 if connection has been dropped.
  2485. */
  2486. int                    /* Check how many bytes are ready */
  2487. nettchk() {                /* for reading from network */
  2488. #ifdef TCPIPLIB
  2489.     long count = 0;
  2490.     int x = 0;
  2491.     long y;
  2492.     char c;
  2493.  
  2494.     debug(F101,"nettchk entry ttibn","",ttibn);
  2495.     debug(F101,"nettchk entry ttibp","",ttibp);
  2496. #ifndef OS2
  2497.     socket_errno = 0; /* This is a function call in NT */
  2498. #endif /* OS2 */
  2499.  
  2500.     if (ttyfd == -1) {
  2501.     debug(F100,"nettchk socket is closed","",0);
  2502.     return(-1);
  2503.     }
  2504. /*
  2505.   Note: this socket_ioctl() call does NOT return an error if the
  2506.   connection has been broken.  (At least not in MultiNet.)
  2507. */
  2508. #ifdef COMMENT
  2509. /*  Another trick that can be tried here is something like this: */
  2510.  
  2511.     if (ttnet == NET_TCPB) {
  2512.     char dummy;
  2513.     x = read(ttyfd,&dummy,0);    /* Try to read nothing */
  2514.     if (x < 0) {            /* "Connection reset by peer" */
  2515.         perror("TCP/IP");        /* or somesuch... */
  2516.         ttclos();            /* Close our end too. */
  2517.         return(-1);
  2518.     }
  2519.     }
  2520. #endif /* COMMENT */
  2521.  
  2522.     if (socket_ioctl(ttyfd,FIONREAD,
  2523. #ifdef COMMENT
  2524.     /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
  2525. #ifdef __DECC
  2526.     /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
  2527.              /* Cast needed for DECC 4.1 & later? */             
  2528.              /* Maybe, but __DECC_VER only exists in 5.0 and later */
  2529.              (char *)
  2530. #endif /* __DECC */
  2531. #endif /* COMMENT */
  2532.              &count
  2533.              ) < 0) {
  2534.     debug(F101,"nettchk socket_ioctl error","",socket_errno);
  2535.     if (ttibn < 1) {
  2536.         netclos();            /* *** *** */
  2537.         return(-1);
  2538.     } else return(ttibn);
  2539.     }
  2540.     debug(F101,"nettchk count","",count);
  2541. /*
  2542.   The following code works well in most settings, but messes things up in
  2543.   others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
  2544.   make it impossible to ever make a new connection to the same host again with
  2545.   CONNECT, once it has been logged out from the first time.  Not even if you
  2546.   HANGUP first, or SET HOST<CR>, or SET LINE<CR>.  Reportedly, however, it
  2547.   does work OK in later releases of UCX.  But there is no way we can
  2548.   accommodate both old and new -- we might have static linking or dynamic
  2549.   linking, etc etc.  If we have static, I only have access to 2.0, where this
  2550.   doesn't work, etc etc blah blah.
  2551.  
  2552.   In the following lines, we define a symbol NOCOUNT for builds where we want
  2553.   to omit this code.  By default, it is omitted for CMU/Tek.  You can force
  2554.   omission of it for other combinations by defining NOCOUNT in CFLAGS.  You
  2555.   can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
  2556.   in CFLAGS.
  2557. */
  2558. #ifdef NONOCOUNT
  2559. #ifdef NOCOUNT
  2560. #undef NOCOUNT
  2561. #endif /* NOCOUNT */
  2562. #else
  2563. #ifndef NOCOUNT
  2564. #ifdef CMU_TCPIP
  2565. #define NOCOUNT
  2566. #endif /* CMU_TCPIP */
  2567. #endif /* NOCOUNT */
  2568. #endif /* NONOCOUNT */
  2569.  
  2570.     if (count == 0) {
  2571. #ifndef NOCOUNT
  2572. /*
  2573.   Here we need to tell the difference between a 0 count on an active
  2574.   connection, and a 0 count because the remote end of the socket broke the
  2575.   connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
  2576.   the status of the connection, so we have to do a read.  -1 means there was
  2577.   no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
  2578.   down.  But if, by chance, we actually get a character, we have to put it
  2579.   where it won't be lost.
  2580. */
  2581.     y = 1;                /* Turn on nonblocking reads */
  2582.     x = socket_ioctl(ttyfd,FIONBIO,&y);
  2583.     debug(F101,"nettchk FIONBIO","",x);
  2584.     x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
  2585.     debug(F101,"nettchk socket_read","",x);
  2586.     if (x == -1) {
  2587.         int s_errno = socket_errno;    /* socket_errno may be a function */
  2588.         debug(F101,"nettchk socket_read errno","",s_errno);
  2589. #ifdef OS2
  2590.         switch (s_errno) {
  2591. #ifdef NT
  2592.           case WSAECONNRESET:
  2593. #else /* NT */
  2594.           case SOCECONNRESET:
  2595.           case SOCECONNRESET - SOCBASEERR:
  2596. #endif /* NT */
  2597.         debug(F100,"nettchk ECONRESET","",0);
  2598.         netclos();        /* *** *** */
  2599.         return(-1);        /* Connection is broken. */
  2600. #ifdef NT
  2601.           case WSAECONNABORTED:
  2602. #else /* NT */
  2603.           case SOCECONNABORTED:
  2604.           case SOCECONNABORTED - SOCBASEERR:
  2605. #endif /* NT */
  2606.         debug(F100,"nettchk ECONNABORTED","",0);
  2607.         netclos();        /* *** *** */
  2608.         return(-1);        /* Connection is broken. */
  2609. #ifdef NT
  2610.           case WSAENETRESET:  
  2611. #else /* NT */
  2612.           case SOCENETRESET:
  2613.           case SOCENETRESET - SOCBASEERR:
  2614. #endif /* NT */
  2615.         debug(F100,"nettchk ENETRESET","",0);
  2616.         netclos();        /* *** *** */
  2617.         return(-1);        /* Connection is broken. */
  2618. #ifdef NT
  2619.           case WSAENOTCONN:
  2620. #else /* NT */
  2621.           case SOCENOTCONN:
  2622.           case SOCENOTCONN - SOCBASEERR:
  2623. #endif /* NT */
  2624.         debug(F100,"nettchk ENOTCONN","",0);
  2625.         netclos();        /* *** *** */
  2626.         return(-1);        /* Connection is broken. */
  2627. #ifdef NT
  2628.           case WSAEWOULDBLOCK:
  2629. #else
  2630.           case SOCEWOULDBLOCK:
  2631.           case SOCEWOULDBLOCK - SOCBASEERR:
  2632. #endif /* NT */
  2633.         debug(F100,"nettchk EWOULDBLOCK","",0);
  2634.         break;
  2635.         }
  2636. #endif /* OS2 */
  2637.     }
  2638.     y = 0;                /* Turn them back off */
  2639.     socket_ioctl(ttyfd,FIONBIO,&y);
  2640.     if (x == 0) {
  2641.         debug(F100,"nettchk connection closed","",0);
  2642.         netclos();            /* *** *** */
  2643.         return(-1);            /* Connection is broken. */
  2644.     }
  2645.     if (x == 1) {            /* Oops, actually got a byte? */
  2646.         debug(F101,"nettchk socket_read char","",c);
  2647.         debug(F101,"nettchk ttibp","",ttibp);
  2648.         debug(F101,"nettchk ttibn","",ttibn);
  2649. /*
  2650.   So put the byte we got into the buffer at the current position.
  2651.   Increment the buffer count, but DON'T increment the buffer pointer.
  2652. */
  2653.         ttibuf[ttibp+ttibn] = c;
  2654.         ttibn++;
  2655. #ifdef DEBUG
  2656.         ttibuf[ttibp+ttibn] = '\0';
  2657.         debug(F111,"nettchk ttibn",ttibuf,ttibn);
  2658. #endif /* DEBUG */
  2659.     }
  2660. #else
  2661.     if (ttnet == NET_TCPB) {
  2662.         char dummy;
  2663.         x = read(ttyfd,&dummy,0);    /* Try to read nothing */
  2664.         if (x < 0) {        /* "Connection reset by peer" */
  2665.         perror("TCP/IP");    /* or somesuch... */
  2666.         ttclos();        /* Close our end too. */
  2667.         return(-1);
  2668.         }
  2669.     }
  2670. #endif /* NOCOUNT */
  2671.     }
  2672.     debug(F101,"nettchk returns","",count+ttibn);
  2673.     return(count + ttibn);
  2674.  
  2675. #else /* Not TCPIPLIB */
  2676. /*
  2677.   UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
  2678.   seem to work OK.
  2679. */
  2680.     return(0);
  2681. #endif /* TCPIPLIB */
  2682. /*
  2683.   But what about X.25?
  2684. */
  2685. }
  2686.  
  2687. #ifndef OS2
  2688. VOID
  2689. nettout(i) int i; {            /* Catch the alarm interrupts */
  2690.     debug(F100,"nettout caught timeout","",0);
  2691.     ttimoff();
  2692.     cklongjmp(njbuf, -1);
  2693. }
  2694. #endif /* !OS2 */
  2695.  
  2696. #ifdef TCPIPLIB
  2697.  
  2698. VOID
  2699. #ifdef CK_ANSIC
  2700. donetinc(void * threadinfo)
  2701. #else /* CK_ANSIC */
  2702. donetinc(threadinfo) VOID * threadinfo;
  2703. #endif /* CK_ANSIC */
  2704. /* donetinc */ {
  2705. #ifdef NTSIG
  2706.     extern int TlsIndex;
  2707.     if (threadinfo) {            /* Thread local storage... */
  2708.     TlsSetValue(TlsIndex,threadinfo);
  2709.     }
  2710. #endif /* NTSIG */
  2711.     while (1) {
  2712.     if (ttbufr() < 0)        /* Keep trying to refill it. */
  2713.       break;            /* Till we get an error. */
  2714.     if (ttibn > 0)            /* Or we get a character. */
  2715.       break;
  2716.     }
  2717. }
  2718. #endif /* TCPIPLIB */
  2719.  
  2720. VOID
  2721. #ifdef CK_ANSIC
  2722. failnetinc(void * threadinfo)
  2723. #else /* CK_ANSIC */
  2724. failnetinc(threadinfo) VOID * threadinfo;
  2725. #endif /* CK_ANSIC */
  2726. /* failnetinc */ {
  2727.     ; /* Nothing to do on an error */
  2728. }
  2729.  
  2730. /* N E T X I N -- Input block of characters from network */
  2731.  
  2732. int 
  2733. netxin(n,buf) int n; char * buf; {
  2734.     int len;
  2735.     int rc;
  2736.     int i, j;
  2737.     if (ttyfd == -1) {
  2738.     debug(F100,"netinc socket is closed","",0);
  2739.     return(-2);
  2740.     }
  2741. #ifdef TCPIPLIB
  2742.     if (!ttibn)
  2743.       if ((rc = ttbufr()) <= 0)
  2744.     return(rc);
  2745.  
  2746.     if (ttibn <= n) {
  2747.     len = ttibn;
  2748.     memcpy(buf,&ttibuf[ttibp],len);
  2749.     ttibp += len;
  2750.     ttibn = 0;
  2751.     } else {
  2752.     /* Watch out, memcpy not portable... */
  2753.     memcpy(buf,&ttibuf[ttibp],n);
  2754.     ttibp += n;
  2755.     ttibn -= n;
  2756.     len = n;
  2757.     }
  2758. #else /* TCPIPLIB */
  2759.     for (i = 0; i < n; i++) {
  2760.         if ((j = netinc(0)) < 0) {
  2761.         if (j < -1)
  2762.           return(j);
  2763.         else 
  2764.           break;
  2765.     }
  2766.         buf[i] = j;
  2767.     }
  2768.     len = i;
  2769. #endif /* TCPIPLIB */
  2770.     return(len);
  2771. }
  2772.  
  2773. /*  N E T I N C --  Input character from network */
  2774.  
  2775. int            
  2776. netinc(timo) int timo; {
  2777. #ifdef TCPIPLIB
  2778.     int x; unsigned char c;        /* The locals. */
  2779.  
  2780.     if (ttyfd == -1) {
  2781.     debug(F100,"netinc socket is closed","",0);
  2782.     return(-2);
  2783.     }
  2784.     if (ttibn > 0) {            /* Something in internal buffer? */
  2785. #ifdef COMMENT
  2786.     debug(F100,"netinc char in buf","",0); /* Yes. */
  2787. #endif /* COMMENT */
  2788.     x = 0;                /* Success. */
  2789.     } else {                /* Else must read from network. */
  2790.     x = -1;                /* Assume failure. */
  2791. #ifdef DEBUG
  2792.     debug(F101,"netinc goes to net, timo","",timo);
  2793.     ttibuf[ttibp+1] = '\0';
  2794.     debug(F111,"netinc ttibuf",ttibuf,ttibp);
  2795. #endif /* DEBUG */
  2796.     if (timo == 0) {        /* Untimed case. */
  2797.         while (1) {            /* Wait forever if necessary. */
  2798.         if (ttbufr() < 0)    /* Refill buffer. */
  2799.           break;        /* Error, fail. */
  2800.         if (ttibn > 0) {    /* Success. */
  2801.             x = 0;
  2802.             break;
  2803.         }
  2804.         }
  2805.     } else {            /* Timed case... */
  2806. #ifdef BSDSELECT
  2807.             fd_set rfds;
  2808.             struct timeval tv;
  2809.             FD_ZERO(&rfds);
  2810.             FD_SET(ttyfd, &rfds);
  2811.             tv.tv_sec  = tv.tv_usec = 0L;
  2812.             if (timo < 0)
  2813. #ifdef NT
  2814.               tv.tv_usec = (long) -timo * 1000L;
  2815. #else  /* NT */
  2816.               tv.tv_usec = (long) -timo * 10000L;
  2817. #endif /* NT */
  2818.             else
  2819.               tv.tv_sec = timo;
  2820.         debug(F101,"netinc BSDSELECT","",timo);
  2821. #ifdef NT
  2822.         WSASafeToCancel = 1;
  2823. #endif /* NT */
  2824.         if (select(FD_SETSIZE,
  2825. #ifdef __DECC
  2826.                (fd_set *)
  2827. #endif /* __DECC */
  2828.                &rfds,
  2829.                NULL, NULL, &tv) > 0 &&
  2830.         FD_ISSET(ttyfd, &rfds)) {
  2831. #ifdef NT
  2832.         WSASafeToCancel = 0;
  2833. #endif /* NT */
  2834.         while (1) {
  2835.             if (ttbufr() < 0)    /* Keep trying to refill it. */
  2836.               break;        /* Till we get an error. */
  2837.             if (ttibn > 0) {    /* Or we get a character. */
  2838.             x = 0;
  2839.             break;
  2840.             }
  2841.         }
  2842.         }    
  2843. #ifdef NT
  2844.         WSASafeToCancel = 0;
  2845. #endif /* NT */
  2846. #else /* !BSDSELECT */
  2847. #ifdef IBMSELECT
  2848. /*
  2849.   Was used by OS/2, currently not used, but might come in handy some day...
  2850.   ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
  2851.   and timeval stuff since this is the only place where it is used.
  2852. */
  2853.         int socket = ttyfd;
  2854.         debug(F101,"netinc IBMSELECT","",timo);
  2855.             if (select(&socket, 1, 0, 0,
  2856.                         timo < 0 ? -timo : timo * 1000L) == 1)
  2857.           while (1) {
  2858.           if (ttbufr() < 0)    /* Keep trying to refill it. */
  2859.             break;        /* Till we get an error. */
  2860.           if (ttibn > 0) {    /* Or we get a character. */
  2861.               x = 0;
  2862.               break;
  2863.           }
  2864.           }
  2865. #else /* !IBMSELECT */
  2866. #ifdef WINSOCK
  2867.        /* Actually, under WinSock we have a better mechanism than select() */
  2868.        /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
  2869.         SOCKET socket = ttyfd;
  2870.         debug(F101,"netinc NTSELECT","",timo);
  2871.         if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo, 
  2872.                 sizeof(timo))  == NO_ERROR)
  2873.           while (1) {
  2874.           if (ttbufr() < 0)    /* Keep trying to refill it. */
  2875.             break;        /* Till we get an error. */
  2876.           if (ttibn > 0) {    /* Or we get a character. */
  2877.               x = 0;
  2878.               break;
  2879.           }
  2880.           }
  2881. #else /* WINSOCK */
  2882. /*
  2883.   If we can't use select(), then we use the regular alarm()/signal()
  2884.   timeout mechanism.
  2885. */
  2886.         debug(F101,"netinc alarm","",timo);
  2887.         x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
  2888.         ttimoff();            /* Timer off. */
  2889. #endif /* WINSOCK */
  2890. #endif /* IBMSELECT */
  2891. #endif /* BSDSELECT */
  2892.     }
  2893.     }
  2894.     if (x < 0) {            /* Return -1 if we failed. */
  2895.     debug(F100,"netinc timed out","",0);
  2896.     return(-1);
  2897.     } else {                /* Otherwise */
  2898.     ttibn--;            /* Return what we got. */
  2899.     c = ttibuf[ttibp++];
  2900.     if (deblog) {
  2901. #ifdef COMMENT
  2902.         debug(F101,"netinc returning","",c);
  2903. #endif /* COMMENT */
  2904.         if (c == 0) {
  2905.         debug(F101,"netinc 0 ttibn","",ttibn);
  2906.         debug(F101,"netinc 0 ttibp","",ttibp);
  2907.         }
  2908.     }
  2909.     return((unsigned)(c & 0xff));
  2910.     }
  2911. #else /* Not using TCPIPLIB */
  2912.     return(-1);
  2913. #endif /* TCPIPLIB */
  2914. }
  2915.  
  2916. /*  N E T T O L  --  Output a string of bytes to the network  */
  2917. /*
  2918.   Call with s = pointer to string, n = length.
  2919.   Returns number of bytes actually written on success, or
  2920.   -1 on i/o error, -2 if called improperly.
  2921. */
  2922.  
  2923. nettol(s,n) char *s; int n; {
  2924. #ifdef TCPIPLIB
  2925.     int count;
  2926.     if (ttyfd == -1) {
  2927.     debug(F100,"nettol socket is closed","",0);
  2928.     return -1;
  2929.     }
  2930.     debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
  2931.     if (ttnet == NET_TCPB) {
  2932. #ifdef BSDSELECT
  2933.     fd_set wfds;
  2934.     struct timeval tv;
  2935.     FD_ZERO(&wfds);
  2936.     FD_SET(ttyfd, &wfds);
  2937.     tv.tv_sec  = tv.tv_usec = 0L;
  2938.     tv.tv_sec = 60;
  2939.     debug(F101,"nettol BSDSELECT","",0);
  2940. #ifdef NT
  2941.     WSASafeToCancel = 1;
  2942. #endif /* NT */
  2943.     if (!(select(FD_SETSIZE, NULL, &wfds, NULL, &tv) > 0 &&
  2944.            FD_ISSET(ttyfd, &wfds))) {
  2945. #ifdef NT
  2946.         WSASafeToCancel = 0;
  2947. #endif /* NT */
  2948.         debug(F101,"nettol select failed","",socket_errno);
  2949.         return(-1);
  2950.     }
  2951. #ifdef NT
  2952.     WSASafeToCancel = 0;
  2953. #endif /* NT */
  2954. #else /* BSDSELECT */
  2955. #ifdef IBMSELECT
  2956.         {
  2957.             int tries = 0;
  2958.             while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
  2959.                 if (tries++ >= 60) {
  2960.                     /* if after 60 seconds we can't get permission to write */
  2961.                     debug(F101,"nettol select failed","",socket_errno);
  2962.                     return(-1);
  2963.                 }
  2964. #ifdef OS2
  2965.                 {
  2966.                     char c;
  2967.                     socket_read(ttyfd,&c,0);
  2968.                 }
  2969. #endif /* OS2 */
  2970.             }
  2971.         }
  2972. #endif /* IBMSELECT */
  2973. #endif /* BSDSELECT */
  2974.  
  2975.     if ((count = socket_write(ttyfd,s,n)) < 1) {
  2976.         debug(F101,"nettol socket_write error","",socket_errno);
  2977.         return(-1);
  2978.     }
  2979.     debug(F111,"nettol socket_write",s,count);
  2980.     return(count);
  2981.     } else return(-2);
  2982. #else
  2983.     debug(F100,"nettol TCPIPLIB not defined","",0);
  2984.     return(-2);
  2985. #endif /* TCPIPLIB */
  2986. }
  2987.  
  2988. /*  N E T T O C  --   Output character to network */
  2989. /*
  2990.   Call with character to be transmitted.
  2991.   Returns 0 if transmission was successful, or
  2992.   -1 upon i/o error, or -2 if called improperly.
  2993. */
  2994. int            
  2995. #ifdef CK_ANSIC
  2996. nettoc(char c)
  2997. #else
  2998. nettoc(c) char c;
  2999. #endif /* CK_ANSIC */
  3000. /* nettoc */ {
  3001. #ifdef UNIX
  3002.     return(ttoc(c));
  3003. #else
  3004. #ifdef TCPIPLIB
  3005.     unsigned char cc;
  3006.     if (ttyfd == -1) {
  3007.     debug(F100,"nettoc socket is closed","",0);
  3008.     return -1;
  3009.     }
  3010.     cc = c;
  3011.     debug(F101,"nettoc cc","",cc);
  3012.     if (ttnet == NET_TCPB) {
  3013. #ifdef BSDSELECT
  3014.     fd_set wfds;
  3015.     struct timeval tv;
  3016.     FD_ZERO(&wfds);
  3017.     FD_SET(ttyfd, &wfds);
  3018.     tv.tv_sec  = tv.tv_usec = 0L;
  3019.     tv.tv_sec = 60;
  3020.     debug(F101,"nettoc BSDSELECT","",0);
  3021. #ifdef NT
  3022.     WSASafeToCancel = 1;
  3023. #endif /* NT */
  3024.     if (!(select(FD_SETSIZE, NULL, &wfds, NULL, &tv) > 0 &&
  3025.                FD_ISSET(ttyfd, &wfds))) {
  3026. #ifdef NT
  3027.         WSASafeToCancel = 0;
  3028. #endif /* NT */
  3029.         debug(F100,"nettoc select failed","",0);
  3030.         return(-1);
  3031.     }
  3032. #ifdef NT
  3033.     WSASafeToCancel = 0;
  3034. #endif /* NT */
  3035. #else /* BSDSELECT */
  3036. #ifdef IBMSELECT
  3037.     if (select(&ttyfd, 0, 1, 0, 60) != 1) {
  3038.         debug(F100,"nettoc select failed","",0);
  3039.         return(-1);
  3040.     }
  3041. #endif /* IBMSELECT */
  3042. #endif /* BSDSELECT */
  3043.     if (socket_write(ttyfd,&cc,1) < 1) {
  3044.         debug(F101,"nettoc socket_write error","",socket_errno);
  3045.         return(-1);
  3046.     }
  3047.     debug(F101,"nettoc socket_write","", cc);
  3048.     return(0);
  3049.     } else return(-2);
  3050. #else
  3051.     return(-2);
  3052. #endif /* TCPIPLIB */
  3053. #endif /* UNIX */
  3054. }
  3055.  
  3056. /*  N E T F L U I  --  Flush network input buffer  */
  3057.  
  3058. int
  3059. netflui() {
  3060.     int n;
  3061. #ifdef TCPIPLIB
  3062.     ttibuf[ttibp+1] = '\0';
  3063.     debug(F111,"netflui 1",ttibuf,ttibn);
  3064.     ttibn = ttibp = 0;            /* Flush internal buffer *FIRST* */
  3065.     if (ttyfd < 1)
  3066.       return(0);
  3067.     if ((n = nettchk()) > 0) {        /* Now see what's waiting on the net */
  3068.     if (n > TTIBUFL) n = TTIBUFL;    /* and sponge it up */
  3069.     debug(F101,"netflui 2","",n);    /* ... */
  3070.     n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
  3071.     if (n >= 0) ttibuf[n] = '\0';
  3072.     debug(F111,"netflui 3",ttibuf,n);
  3073.     ttibuf[0] = '\0';
  3074.     }
  3075. #else
  3076. /*
  3077.   It seems the UNIX ioctl()s don't do the trick, so we have to read the
  3078.   stuff ourselves.  This should be pretty much portable, if not elegant.
  3079. */
  3080.     if (ttyfd < 1)
  3081.       return(0);
  3082.     if ((n = ttchk()) > 0) {
  3083.     debug(F101,"netflui","",n);
  3084.     while ((n--) && ttinc(0) > -1); /* Don't worry, it's buffered. */
  3085.     }
  3086. #endif /* TCPIPLIB */
  3087.     return(0);
  3088. }
  3089.  
  3090. #ifdef RLOGCODE            /* TCP/IP RLOGIN protocol support code */
  3091. #ifndef OS2
  3092. static
  3093. #endif /* OS2 */
  3094. int
  3095. rlog_naws() {
  3096.     struct rlog_naws {
  3097.     char id[4];
  3098.     unsigned short rows, cols, ypix, xpix;
  3099.     } nawsbuf;
  3100.     
  3101.     if (ttnet != NET_TCPB)
  3102.       return 0;
  3103.     if (ttnproto != NP_RLOGIN)
  3104.       return 0;
  3105.     if (!nawsflg)
  3106.       return 0;
  3107.  
  3108.     nawsbuf.id[0] = nawsbuf.id[1] = 0xFF;
  3109.     nawsbuf.id[2] = nawsbuf.id[3] = 's';
  3110. #ifdef OS2
  3111.     nawsbuf.rows = htons((unsigned short) VscrnGetHeight(VTERM)
  3112.                           -(tt_status?1:0));
  3113.     nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
  3114. #else /* OS2 */
  3115.     nawsbuf.rows = htons((unsigned short) tt_rows);
  3116.     nawsbuf.cols = htons((unsigned short) tt_cols);
  3117. #endif /* OS2 */
  3118.     nawsbuf.ypix = htons(0);        /* y pixels */
  3119.     nawsbuf.xpix = htons(0);        /* x pixels */
  3120.     if (ttol((CHAR *) &nawsbuf, 12) < 0)
  3121.       return -1;
  3122.     return 0;
  3123. }
  3124.  
  3125. static int
  3126. rlog_ini() {
  3127.     int flag = 0;
  3128. #define TERMLEN 16
  3129.     extern char uidbuf[];
  3130.     char localuser[255];
  3131.     int userlen = 0;
  3132.     char terminal[TERMLEN+1];
  3133. #ifdef CONGSPD
  3134. #define CONSPDLEN 16
  3135.     char conspeed[CONSPDLEN+1];
  3136.     long conspd = -1L;
  3137. #endif /* CONGSPD */
  3138. #ifdef OS2
  3139.     extern int tt_type, max_tt;
  3140.     extern struct tt_info_rec tt_info[];
  3141. #endif /* OS2 */
  3142.     int i, n;
  3143.  
  3144.     int rc = 0;
  3145.     nawsflg = 0;            /* Assume no NAWS */
  3146. #ifdef CK_TTGWSIZ
  3147. /*
  3148.   But compute the values anyway before the first read since the out-
  3149.   of-band NAWS request would arrive before the first data byte (NULL).
  3150. */
  3151. #ifdef OS2
  3152.     /* Console terminal screen rows and columns */
  3153.     debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
  3154.            -(tt_status?1:0));
  3155.     debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
  3156.     /* Not known yet */
  3157.     if (VscrnGetWidth(VTERM) < 0 || 
  3158.     VscrnGetHeight(VTERM)-(tt_status?1:0) < 0) {
  3159.     ttgwsiz();            /* Try to get screen dimensions */
  3160.     }
  3161.     debug(F101,"rlog_ini tt_rows 2","",VscrnGetHeight(VTERM)-(tt_status?1:0));
  3162.     debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
  3163. #else /* OS2 */
  3164.     debug(F101,"rlog_ini tt_rows 1","",tt_rows);
  3165.     debug(F101,"rlog_ini tt_cols 1","",tt_cols);
  3166.     if (tt_rows < 0 || tt_cols < 0) {    /* Not known yet */
  3167.     ttgwsiz();            /* Try to find out */
  3168.     }
  3169.     debug(F101,"rlog_ini tt_rows 2","",tt_rows);
  3170.     debug(F101,"rlog_ini tt_cols 2","",tt_cols);
  3171. #endif /* OS2 */
  3172. #endif /* CK_TTGWSIZ */
  3173.  
  3174.     rlog_mode = RL_COOKED;
  3175.     ttoc(0);                /* Send an initial NUL as wake-up */
  3176.  
  3177.     /* Followed by client username ... */
  3178.  
  3179.     localuser[0] = '\0';
  3180. #ifdef NT
  3181.     {
  3182.     char localuid[64];
  3183.     unsigned long len = 64;
  3184.     localuid[0] = '\0';
  3185.     WNetGetUser(NULL, localuid, &len);
  3186.     ttol(localuid,strlen(localuid)+1);  /* strlen + 1 */
  3187.     }
  3188. #else /* NT */
  3189.     {
  3190.     char *s; char *p;
  3191.     char * user = getenv("USER");
  3192.     debug(F110,"rlogin local user",user,0);
  3193.     if (!user)
  3194.       user = "";
  3195.     userlen = strlen(user);
  3196.     s = user;
  3197.     p = (char *)localuser;
  3198. #ifdef VMS                /* Convert username to lowercase */
  3199.     for (s = user; *s; s++,p++)
  3200.       *p = isupper(*s) ? tolower(*s) : *s;
  3201.     *p = '\0';
  3202. #else
  3203.     while (*p++ = *s++) ;
  3204. #endif /* VMS */
  3205.     ttol((CHAR *)localuser,userlen+1); /* strlen + 1 */
  3206.     }
  3207. #endif /* NT */
  3208.  
  3209.     /* Then the server userid... */
  3210.  
  3211.     if (uidbuf[0])
  3212.       ttol((CHAR *) uidbuf,strlen(uidbuf)+1); /* strlen + 1 */
  3213.     else if (localuser[0])
  3214.       ttol((CHAR *) localuser,userlen+1);
  3215.     else
  3216.       ttoc(0);
  3217.  
  3218.     /* Finally the terminal type and speed */
  3219.  
  3220.     terminal[0] = '\0';
  3221.     if (tn_term) {            /* SET TELNET TERMINAL-TYPE value */
  3222.     if (*tn_term) {            /* (if any) takes precedence. */
  3223.         strncpy(terminal, tn_term, TERMLEN);
  3224.         flag = 1;
  3225.     }
  3226.     } else {                /* Otherwise the local terminal type */
  3227. #ifdef OS2
  3228.     /* In terminal-emulating versions, it's the SET TERM TYPE value */
  3229.     strncpy(terminal, (tt_type >= 0 && tt_type <= max_tt) ?
  3230.         tt_info[tt_type].x_name : "network", TERMLEN);
  3231. #else
  3232.     /* In the others, we just look at the TERM environment variable */
  3233.     {
  3234.         char *p = getenv("TERM");
  3235.         if (p)
  3236.           strncpy(terminal,p,TERMLEN);
  3237.         else
  3238.           terminal[0] = '\0';
  3239. #ifdef VMS
  3240.         for (p = (char *) terminal; *p; p++) {
  3241.         if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
  3242.           break;
  3243.         else if (isupper(*p))
  3244.           *p = tolower(*p);
  3245.         }
  3246.         *p = '\0';
  3247. #endif /* VMS */
  3248.     }
  3249. #endif /* OS2 */
  3250.     }
  3251.     n = strlen(terminal);
  3252.     if (n > 0) {            /* We have a terminal type */
  3253.     if (!flag) {            /* If not user-specified */
  3254.         for (i = 0; i < n; i++)    /* then lowercase it.    */
  3255.           if (isupper(terminal[i]))
  3256.         terminal[i] = tolower(terminal[i]);
  3257.     }
  3258.     ttol((CHAR *)terminal,n);
  3259. #ifdef CONGSPD
  3260.     /* conspd() is not yet defined in all ck*tio.c modules */
  3261.     conspd = congspd();
  3262.     if (conspd > 0L) {
  3263.         sprintf(conspeed,"/%ld",conspd);
  3264.         n = strlen(conspeed);
  3265.         ttol((CHAR *)conspeed,n+1);
  3266.     } else
  3267. #endif /* CONGSPD */
  3268.       ttol((CHAR *)"/19200",7);    /* strlen + 1 */
  3269.     } else {
  3270.     ttoc(0); 
  3271.     }
  3272.  
  3273.     /* Now we are supposed to get back a single zero byte as confirmation */
  3274.     errno = 0;
  3275.     rc = ttinc(60);
  3276.     debug(F101,"rlogin first ttinc","",rc);
  3277.     if (rc > 0) {
  3278.     debug(F101,"rlogin ttinc 1","",rc);
  3279.     printf("Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
  3280.     return(-1);
  3281.     } else if (rc < 0) {
  3282.     debug(F101,"rlogin ttinc errno","",errno);
  3283.     /* printf("Network error: %d\n", errno); */
  3284.     return(-1);
  3285.     }    
  3286.     return(0);
  3287. }
  3288.  
  3289. #ifdef TCPIPLIB
  3290. static VOID
  3291. rlog_oob(oobdata, count) CHAR * oobdata; int count; {
  3292.     int i;
  3293.  
  3294.     for (i = 0; i<count; i++)   {
  3295.     debug(F101,"rlogin out_of_band","",oobdata[i]);
  3296.     if (oobdata[i] == 0x02) { /* Flush Buffered Data not yet displayed */
  3297.         debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
  3298.         ttflui();
  3299.     }
  3300.     if (oobdata[i] & 0x10) {    /* Switch to RAW mode */
  3301.         debug(F101,"rlogin Raw Mode command","",oobdata[i]);
  3302.         rlog_mode = RL_RAW;
  3303.     }
  3304.  
  3305.     if (oobdata[i] & 0x20) {    /* Switch to COOKED mode */
  3306.         debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
  3307.         rlog_mode = RL_COOKED;
  3308.     }
  3309.     if (oobdata[i] & 0x80) {    /* Send Window Size Info */
  3310.         debug(F101,"rlogin Window Size command","",oobdata[i]);
  3311.         /* Remember to send WS Info when Window Size changes */
  3312.         nawsflg = 1;
  3313.         rlog_naws();
  3314.     }
  3315.     }
  3316. }
  3317. #else /* TCPIPLIB */
  3318. static SIGTYP
  3319. rlogoobh(sig) int sig; {
  3320. #ifdef SOLARIS
  3321.     char                /* Or should it be char for all? */
  3322. #else
  3323.     CHAR
  3324. #endif /* SOLARIS */
  3325.       oobdata;
  3326.  
  3327.     int  count = 0;
  3328.  
  3329.     while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) { 
  3330.       /* 
  3331.        * We need to do some special processing here.
  3332.        * Just in case the socket is blocked for input
  3333.        * 
  3334.        */
  3335.     switch (errno) {
  3336.       case EWOULDBLOCK:
  3337.         break;
  3338.       default:
  3339.         return;
  3340.     }
  3341.     }
  3342.     debug(F101,"rlogin out_of_band","",oobdata);
  3343.     if (oobdata == 0x02) {    /* Flush Buffered Data not yet displayed */
  3344.     debug(F101,"rlogin Flush Buffered Data command","",oobdata);
  3345.     netflui();
  3346.     }
  3347.     if (oobdata & 0x10) {        /* Switch to raw mode */
  3348.     debug(F101,"rlogin Raw Mode command","",oobdata);
  3349.     rlog_mode = RL_RAW;
  3350.     }
  3351.     if (oobdata & 0x20) {        /* Switch to cooked mode */
  3352.     debug(F101,"rlogin Cooked Mode command","",oobdata);
  3353.     rlog_mode = RL_COOKED;
  3354.     }
  3355.     if (oobdata & 0x80) {          /* Send Window Size Info */
  3356.     debug(F101,"rlogin Window Size command","",oobdata);
  3357.     nawsflg = 1; /* Remember to send WS Info when Window Size changes */
  3358.     rlog_naws();
  3359.     }
  3360. }
  3361. #endif /* TCPIPLIB */
  3362. #endif /* RLOGCODE */
  3363.  
  3364. #ifdef TNCODE                /* Compile in telnet support code */
  3365.  
  3366. /* TCP/IP TELNET protocol negotiation support code */
  3367.  
  3368. static int sgaflg = 0;            /* SUPRRESS GO-AHEAD state */
  3369. static int ttyflg = 0;            /* TERMINAL TYPE state */
  3370.  
  3371. static int wnawsflg = 0;        /* Initial WILL NAWS sent, no reply */
  3372. static int wmebinflg = 0,  /* initial WILL BINARY sent, no reply */
  3373.            dubinflg  = 0;  /* initial DO BINARY sent, no reply */
  3374.  
  3375. #ifndef TELCMDS
  3376. char *telcmds[] = {
  3377.     "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
  3378.     "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC"
  3379. };
  3380. int ntelcmds = sizeof(telcmds) / sizeof(char *);
  3381. #endif /* TELCMDS */
  3382.  
  3383. /*
  3384.    The following list is current as of October 1994 ASSIGNED NUMBERS
  3385.    RFC 1700.
  3386. */
  3387.  
  3388. char *tnopts[] = {
  3389.     "BINARY",                           /* RFC 856 */
  3390.     "ECHO",                             /* RFC 857 */
  3391.     "RECONNECTION",                     /* NIC 50005 */
  3392.     "SUPPRESS-GO-AHEAD",                /* RFC 858 */
  3393.     "APPROX-MESSAGE-SIZE",              /* ETHERNET */
  3394.     "STATUS",                           /* RFC 859 */
  3395.     "TIMING-MARK",                      /* RFC 860 */
  3396.     "REMOTE-CONTROL-TRANS-ECHO",        /* RFC 726 */
  3397.     "OPTION-LINE-WIDTH",                /* NIC 50005 */
  3398.     "OPTION-PAGE-SIZE",                 /* NIC 50005 */
  3399.     "OUTPUT-CR-DISPOSITION",            /* RFC 652 */
  3400.     "OUTPUT-HORIZ-TABSTOPS",            /* RFC 653 */
  3401.     "OUTPUT-HORIZ-TAB-DISPOSITION",     /* RFC 654 */
  3402.     "OUTPUT-FF-DISPOSITION",            /* RFC 655 */
  3403.     "OUTPUT-VERT-TABSTOPS",             /* RFC 666 */
  3404.     "OUTPUT-VERT-TAB-DISPOSITION",      /* RFC 667 */
  3405.     "OUTPUT-LF-DISPOSITION",            /* RFC 668 */
  3406.     "EXTENDED-ASCII",                   /* RFC 698 */
  3407.     "LOGOUT",                           /* RFC 727 */
  3408.     "BYTE-MACRO",                       /* RFC 735 */
  3409.     "DATA-ENTRY-TERMINAL",              /* RFC 1043, RFC 732 */
  3410.     "SUPDUP",                           /* RFC 736, RFC 734 */
  3411.     "SUPDUP-OUTPUT",                    /* RFC 749 */
  3412.     "SEND-LOCATION",                    /* RFC 779 */
  3413.     "TERMINAL-TYPE",                    /* RFC 1091 */
  3414.     "END-OF-RECORD",                    /* RFC 885 */
  3415.     "TACACS-UID",                       /* RFC 927 */
  3416.     "OUTPUT-MARKING",                   /* RFC 933 */
  3417.     "TERMINAL-LOCATION-NUMBER",         /* RFC 946 */
  3418.     "TELNET-3270-REGIME",               /* RFC 1041 */
  3419.     "X.3-PAD",                          /* RFC 1053 */
  3420.     "NEGOTIATE-ABOUT-WINDOW-SIZE",      /* RFC 1073 */
  3421.     "TERMINAL-SPEED",                   /* RFC 1079 */
  3422.     "REMOTE-FLOW-CONTROL",              /* RFC 1372 */
  3423.     "LINEMODE",                         /* RFC 1184 */
  3424.     "X-DISPLAY-LOCATION",               /* RFC 1096 */
  3425.     "ENVIRONMENT",                      /* RFC 1408 */
  3426.     "AUTHENTICATION",                   /* RFC 1409 */
  3427.     "ENCRYPTION",                       /* No Reference */
  3428.     "NEW-ENVIRONMENT",                  /* RFC 1572 */
  3429.     "TN3270E"                           /* RFC 1647 */
  3430. #ifdef COMMENT
  3431.     "UNKNOWN",
  3432.     "UNKNOWN",
  3433.     "UNKNOWN",
  3434.     "UNKNOWN",
  3435.     "UNKNOWN",
  3436.     "UNKNOWN",
  3437.     "UNKNOWN",
  3438.     "UNKNOWN",
  3439.     "UNKNOWN",
  3440.     "UNKNOWN",
  3441.     "UNKNOWN",
  3442.     "UNKNOWN",
  3443.     "UNKNOWN",
  3444.     "UNKNOWN",
  3445.     "UNKNOWN",
  3446.     "UNKNOWN",
  3447.     "UNKNOWN",
  3448.     "UNKNOWN",
  3449.     "UNKNOWN",
  3450.     "UNKNOWN",
  3451.     "UNKNOWN",
  3452.     "UNKNOWN",
  3453.     "UNKNOWN",
  3454.     "UNKNOWN",
  3455.     "UNKNOWN",
  3456.     "UNKNOWN",
  3457.     "UNKNOWN",
  3458.     "UNKNOWN",
  3459.     "UNKNOWN",
  3460.     "UNKNOWN",
  3461.     "UNKNOWN",
  3462.     "UNKNOWN",
  3463.     "UNKNOWN",
  3464.     "UNKNOWN",
  3465.     "UNKNOWN",
  3466.     "UNKNOWN",
  3467.     "UNKNOWN",
  3468.     "UNKNOWN",
  3469.     "UNKNOWN",
  3470.     "UNKNOWN",
  3471.     "UNKNOWN",
  3472.     "UNKNOWN",
  3473.     "UNKNOWN",
  3474.     "UNKNOWN",
  3475.     "UNKNOWN",
  3476.     "UNKNOWN",
  3477.     "UNKNOWN",
  3478.     "UNKNOWN",
  3479.     "UNKNOWN",
  3480.     "UNKNOWN",
  3481.     "UNKNOWN",
  3482.     "UNKNOWN",
  3483.     "UNKNOWN",
  3484.     "UNKNOWN",
  3485.     "UNKNOWN",
  3486.     "UNKNOWN",
  3487.     "UNKNOWN",
  3488.     "UNKNOWN",
  3489.     "UNKNOWN",
  3490.     "UNKNOWN",
  3491.     "UNKNOWN",
  3492.     "UNKNOWN",
  3493.     "UNKNOWN",
  3494.     "UNKNOWN",
  3495.     "UNKNOWN",
  3496.     "UNKNOWN",
  3497.     "UNKNOWN",
  3498.     "UNKNOWN",
  3499.     "UNKNOWN",
  3500.     "UNKNOWN",
  3501.     "UNKNOWN",
  3502.     "UNKNOWN",
  3503.     "UNKNOWN",
  3504.     "UNKNOWN",
  3505.     "UNKNOWN",
  3506.     "UNKNOWN",
  3507.     "UNKNOWN",
  3508.     "UNKNOWN",
  3509.     "UNKNOWN",
  3510.     "UNKNOWN",
  3511.     "UNKNOWN",
  3512.     "UNKNOWN",
  3513.     "UNKNOWN",
  3514.     "UNKNOWN",
  3515.     "UNKNOWN",
  3516.     "UNKNOWN",
  3517.     "UNKNOWN",
  3518.     "UNKNOWN",
  3519.     "UNKNOWN",
  3520.     "UNKNOWN",
  3521.     "UNKNOWN",
  3522.     "UNKNOWN",
  3523.     "UNKNOWN",
  3524.     "UNKNOWN",
  3525.     "UNKNOWN",
  3526.     "UNKNOWN",
  3527.     "UNKNOWN",
  3528.     "UNKNOWN",
  3529.     "UNKNOWN",
  3530.     "UNKNOWN",
  3531.     "UNKNOWN",
  3532.     "UNKNOWN",
  3533.     "UNKNOWN",
  3534.     "UNKNOWN",
  3535.     "UNKNOWN",
  3536.     "UNKNOWN",
  3537.     "UNKNOWN",
  3538.     "UNKNOWN",
  3539.     "UNKNOWN",
  3540.     "UNKNOWN",
  3541.     "UNKNOWN",
  3542.     "UNKNOWN",
  3543.     "UNKNOWN",
  3544.     "UNKNOWN",
  3545.     "UNKNOWN",
  3546.     "UNKNOWN",
  3547.     "UNKNOWN",
  3548.     "UNKNOWN",
  3549.     "UNKNOWN",
  3550.     "UNKNOWN",
  3551.     "UNKNOWN",
  3552.     "UNKNOWN",
  3553.     "UNKNOWN",
  3554.     "UNKNOWN",
  3555.     "UNKNOWN",
  3556.     "UNKNOWN",
  3557.     "UNKNOWN",
  3558.     "UNKNOWN",
  3559.     "UNKNOWN",
  3560.     "UNKNOWN",
  3561.     "UNKNOWN",
  3562.     "UNKNOWN",
  3563.     "UNKNOWN",
  3564.     "UNKNOWN",
  3565.     "UNKNOWN",
  3566.     "UNKNOWN",
  3567.     "UNKNOWN",
  3568.     "UNKNOWN",
  3569.     "UNKNOWN",
  3570.     "UNKNOWN",
  3571.     "UNKNOWN",
  3572.     "UNKNOWN",
  3573.     "UNKNOWN",
  3574.     "UNKNOWN",
  3575.     "UNKNOWN",
  3576.     "UNKNOWN",
  3577.     "UNKNOWN",
  3578.     "UNKNOWN",
  3579.     "UNKNOWN",
  3580.     "UNKNOWN",
  3581.     "UNKNOWN",
  3582.     "UNKNOWN",
  3583.     "UNKNOWN",
  3584.     "UNKNOWN",
  3585.     "UNKNOWN",
  3586.     "UNKNOWN",
  3587.     "UNKNOWN",
  3588.     "UNKNOWN",
  3589.     "UNKNOWN",
  3590.     "UNKNOWN",
  3591.     "UNKNOWN",
  3592.     "UNKNOWN",
  3593.     "UNKNOWN",
  3594.     "UNKNOWN",
  3595.     "UNKNOWN",
  3596.     "UNKNOWN",
  3597.     "UNKNOWN",
  3598.     "UNKNOWN",
  3599.     "UNKNOWN",
  3600.     "UNKNOWN",
  3601.     "UNKNOWN",
  3602.     "UNKNOWN",
  3603.     "UNKNOWN",
  3604.     "UNKNOWN",
  3605.     "UNKNOWN",
  3606.     "UNKNOWN",
  3607.     "UNKNOWN",
  3608.     "UNKNOWN",
  3609.     "UNKNOWN",
  3610.     "UNKNOWN",
  3611.     "UNKNOWN",
  3612.     "UNKNOWN",
  3613.     "UNKNOWN",
  3614.     "UNKNOWN",
  3615.     "UNKNOWN",
  3616.     "UNKNOWN",
  3617.     "UNKNOWN",
  3618.     "UNKNOWN",
  3619.     "UNKNOWN",
  3620.     "UNKNOWN",
  3621.     "UNKNOWN",
  3622.     "UNKNOWN",
  3623.     "UNKNOWN",
  3624.     "UNKNOWN",
  3625.     "UNKNOWN",
  3626.     "UNKNOWN",
  3627.     "UNKNOWN",
  3628.     "UNKNOWN",
  3629.     "UNKNOWN",
  3630.     "UNKNOWN",
  3631.     "UNKNOWN",
  3632.     "UNKNOWN",
  3633.     "UNKNOWN",
  3634.     "UNKNOWN",
  3635.     "UNKNOWN",
  3636.     "UNKNOWN",
  3637.     "UNKNOWN",
  3638.     "UNKNOWN",
  3639.     "UNKNOWN",
  3640.     "UNKNOWN",
  3641.     "UNKNOWN",
  3642.     "UNKNOWN",
  3643.     "UNKNOWN",
  3644.     "UNKNOWN",
  3645.     "EXTENDED-OPTIONS-LIST"        /* 255, RFC 861 */
  3646. #endif /* COMMENT */
  3647. };
  3648.  
  3649. /*
  3650.    Telnet Authentication Types
  3651.  
  3652.    In [RFC1409], a list of authentication types is introduced.  Additions
  3653.    to the list are registerd by the IANA and documented here.
  3654.  
  3655.    Type       Description                  Reference
  3656.      0        NULL                         [RFC1409]
  3657.      1        KERBEROS_V4                  [RFC1409]
  3658.      2        KERBEROS_V5                  [RFC1409]
  3659.      3        SPX                          [RFC1409]
  3660.      4-5      Unassigned
  3661.      6        RSA                          [RFC1409]
  3662.      7-9      Unassigned
  3663.     10        LOKI                         [RFC1409]
  3664.     11        SSA                          [Schoch]
  3665. */
  3666.  
  3667. /*
  3668.   In order to prevent an infinite telnet negotiation loop we maintain a
  3669.   count of the number of times the same telnet negotiation message is
  3670.   sent. When this count hits MAXTNCNT, we do not send any more of the
  3671.   message. The count is stored in the tncnts[][] array.
  3672.   
  3673.   The tncnts[][] array is indexed by negotiation option (SUPPRESS GO AHEAD,
  3674.   TERMINAL TYPE, NAWS, etc. - see the tnopts[] array) and the four
  3675.   negotiation message types (WILL, WONT, DO, DONT).  All telnet negotiations
  3676.   are kept track of in this way.
  3677.  
  3678.   The count for a message is zeroed when the "opposite" message is sent.
  3679.   WILL is the opposite of WONT, and DO is the opposite of DONT.
  3680.   For example sending "WILL SGA" increments tncnts[TELOPT_SGA][0]
  3681.   and zeroes tncnts[TELOPT_SGA][1].
  3682.  
  3683.   The code that does this is in tn_sopt().
  3684.  
  3685.   rogersh@fsj.co.jp, 18/3/1995
  3686. */
  3687.  
  3688. #define MAXTNCNT 4    /* Permits 4 intermediate telnet firewalls/gateways */
  3689.  
  3690. char tncnts[sizeof(tnopts) / sizeof(char *)][4];    /* counts */
  3691. char tnopps[4] = { 1,0,3,2 };                /* opposites */
  3692.  
  3693. int ntnopts = sizeof(tnopts) / sizeof(char *);
  3694. #endif /* TNCODE */
  3695.  
  3696. /* Send network BREAK */
  3697. /*
  3698.   Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
  3699. */
  3700. int
  3701. netbreak() {
  3702.     CHAR buf[3];
  3703.     if (ttnet == NET_TCPB) {
  3704.     if (ttnproto == NP_TELNET) {
  3705. #ifdef TNCODE
  3706.         buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
  3707.         if (
  3708. #ifdef OS2
  3709.         nettol((char *) buf, 2)
  3710. #else
  3711.         ttol(buf, 2)
  3712. #endif /* OS2 */
  3713.         < 2)
  3714.           return(-1);
  3715.         debug(F101,"telnet BREAK ok","",BREAK);
  3716.         return(1);
  3717. #else
  3718.         debug(F100,"netbreak no TNCODE","",0);
  3719.         return(0);
  3720. #endif /* TNCODE */
  3721.     }
  3722.     /* Insert other TCP/IP protocols here */
  3723.     }
  3724.     /* Insert other networks here */
  3725.     return(0);
  3726. }
  3727.  
  3728. /* Send a telnet option, avoid loops. */
  3729. /* Returns 1 if command was sent, 0 if not, -1 on error */
  3730.  
  3731. int
  3732. tn_sopt(cmd,opt) int cmd, opt; {    /* TELNET SEND OPTION */
  3733.     CHAR buf[5];
  3734.     int n,m;
  3735.  
  3736.     if (ttnet != NET_TCPB) return(0);    /* Must be TCP/IP */
  3737.     if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
  3738. #ifdef TNCODE
  3739.     n = cmd - SE;
  3740.     m = cmd - WILL;
  3741.     if (n < 0 || n > ntelcmds) return(0);
  3742.     if (m >= 0 && m < 4 && opt < ntnopts) {    /* See comment above about   */
  3743.     if (tncnts[opt][m] > MAXTNCNT) {    /* preventing infinite loops */
  3744.         if (debses || deblog) {
  3745.             sprintf(tn_msg,"TELNET negotiation loop %s %s",telcmds[n],
  3746.             tnopts[opt]);
  3747.         debug(F101,tn_msg,"",opt);
  3748.         if (debses) tn_debug(tn_msg);
  3749.         }
  3750.         return(0);
  3751.     }
  3752.     tncnts[opt][m]++;
  3753.     tncnts[opt][tnopps[m]] = 0;
  3754.     }
  3755.     buf[0] = (CHAR) IAC;
  3756.     buf[1] = (CHAR) (cmd & 0xff);
  3757.     buf[2] = (CHAR) (opt & 0xff);
  3758.     buf[3] = (CHAR) 0;
  3759.     if (ttol(buf,3) < 3)
  3760.       return(-1);
  3761.     if ((debses || deblog) && cmd != SB) {
  3762.     sprintf(tn_msg,"TELNET SENT %s %s",telcmds[n],
  3763.         (opt < ntnopts) ? tnopts[opt] : "UNKNOWN");
  3764.     debug(F101,tn_msg,"",opt);
  3765.     if (debses) tn_debug(tn_msg);
  3766.     }
  3767.     return(1);
  3768. #else
  3769.     debug(F100,"tn_sopt no TNCODE","",0);
  3770.     return(0);
  3771. #endif /* TNCODE */
  3772. }
  3773.  
  3774. /* Initialize a telnet connection. */
  3775. /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
  3776.  
  3777. int
  3778. tn_ini() {
  3779.     int x,i,j;
  3780. #ifndef TNCODE
  3781.     debug(F100,"tn_ini no TNCODE","",0);
  3782.     return(0);
  3783. #else /* TELNET protocol support */
  3784.     debug(F101,"tn_ini ttnproto","",ttnproto);
  3785.     debug(F101,"tn_ini tn_init","",tn_init);
  3786.  
  3787.     if (ttnet != NET_TCPB)        /* Make sure connection is TCP/IP */
  3788.       return(0);
  3789.     if (ttnproto == NP_RLOGIN)
  3790.       return(0);
  3791.     if (tn_init)            /* Have we done this already? */
  3792.       return(0);            /* Don't do it again. */
  3793.  
  3794.     /* Reset the TELNET OPTIONS counts */
  3795.     for (i = 0; i < sizeof(tnopts) / sizeof(char *); i++)
  3796.         for (j = 0; j < 4; j ++)
  3797.             tncnts[i][j] = 0;
  3798.  
  3799.     debug(F101,"tn_ini tn_duplex","",tn_duplex);
  3800.     duplex = tn_duplex;            /* Assume local echo. */
  3801.     sgaflg = 0;                /* Assume Go-Ahead suppressed. */
  3802.     nawsflg = 0;            /* Assume NAWS should not be sent. */
  3803.     if (ttnproto == NP_NONE) {        /* If not talking to a telnet port, */
  3804.     ttnproto = NP_TELNET;        /* pretend it's telnet anyway, */
  3805.     tn_init = 1;            /* but don't send initial options. */
  3806.     debug(F100,"tn_ini skipping telnet negotiations","",0);
  3807.     return(0);
  3808.     }
  3809.     debug(F100,"tn_ini about to send WILL TTYPE","",0);
  3810. /* 
  3811.   Talking to TELNET port, so send WILL TERMINAL TYPE and DO SGA.
  3812.   Also send WILL NAWS if we know our screen dimensions.
  3813. */
  3814.     if ((x = tn_sopt(WILL,TELOPT_TTYPE)) < 0) { /* Will send terminal type. */
  3815.     debug(F101,"tn_ini tn_sopt WILL TTYPE failed","",x);
  3816.     return(-1);
  3817.     }
  3818.     debug(F100,"tn_ini sent WILL TTYPE ok","",0);
  3819.     ttyflg = 1;                /* Remember I said I would. */
  3820. #ifdef OS2
  3821.     ttnum = -1;
  3822.     ttnumend = 0;
  3823. #endif /* OS2 */
  3824. #ifdef CK_NAWS
  3825.     /* Console terminal screen rows and columns */
  3826. #ifdef OS2
  3827.     debug(F101,"tn_ini tt_rows 1","",VscrnGetHeight(VTERM)-(tt_status?1:0));
  3828.     debug(F101,"tn_ini tt_cols 1","",VscrnGetWidth(VTERM));
  3829.     /* Not known yet */
  3830.     if (VscrnGetWidth(VTERM) < 0 ||
  3831.     VscrnGetHeight(VTERM)-(tt_status?1:0) < 0) {
  3832.     ttgwsiz();            /* Try to find out */
  3833.     }
  3834.     debug(F101,"tn_ini tt_rows 2","",VscrnGetHeight(VTERM)-(tt_status?1:0));
  3835.     debug(F101,"tn_ini tt_cols 2","",VscrnGetWidth(VTERM));
  3836.     /* Now do we know? */
  3837.     if (VscrnGetWidth(VTERM) > 0 &&
  3838.     VscrnGetHeight(VTERM)-(tt_status?1:0) > 0) {
  3839.     if (tn_sopt(WILL, TELOPT_NAWS) < 0)
  3840.       return(-1);
  3841.     wnawsflg = 1;            /* OK, we sent an initial WILL NAWS. */
  3842.     }
  3843. #else /* OS2 */
  3844.     debug(F101,"tn_ini tt_rows 1","",tt_rows);
  3845.     debug(F101,"tn_ini tt_cols 1","",tt_cols);
  3846.     if (tt_rows < 0 || tt_cols < 0) {    /* Not known yet */
  3847.     ttgwsiz();            /* Try to find out */
  3848.     }
  3849.     debug(F101,"tn_ini tt_rows 2","",tt_rows);
  3850.     debug(F101,"tn_ini tt_cols 2","",tt_cols);
  3851.     if (tt_rows > 0 && tt_cols > 0) {    /* Now do we know? */
  3852.     if (tn_sopt(WILL, TELOPT_NAWS) < 0)
  3853.       return(-1);
  3854.     wnawsflg = 1;            /* Ok, we sent an initial WILL NAWS. */
  3855.     }
  3856. #endif /* OS2 */
  3857. #endif /* CK_NAWS */
  3858.  
  3859.     if (tn_binary == TN_BM_RQ) {
  3860.         if (tn_sopt(WILL, TELOPT_BINARY) < 0)
  3861.       return(-1);
  3862.         wmebinflg = 1;            /* We sent an initial WILL BINARY. */
  3863.         if (tn_sopt(DO, TELOPT_BINARY) < 0)
  3864.       return(-1);
  3865.         dubinflg = 1;            /* We sent an initial DO BINARY. */
  3866.     }
  3867.     me_binary = 0;            /* We are not in binary mode */
  3868.     u_binary = 0;
  3869.  
  3870.  
  3871. #ifdef CK_ENVIRONMENT
  3872.     /* Will send terminal environment. */
  3873.     if ((x = tn_sopt(WILL,TELOPT_NEWENVIRON)) < 0) {
  3874.     debug(F101,"tn_ini tn_sopt WILL NEWENVIRON failed","",x);
  3875.     return(-1);
  3876.     }
  3877.     debug(F100,"tn_ini sent WILL NEWENVIRON ok","",0);
  3878. #endif /* CK_ENVIRONMENT */
  3879.  
  3880.     if (tn_sopt(DO,TELOPT_SGA) < 0)    /* Please suppress go-ahead. */
  3881.       return(-1);
  3882.  
  3883.     tn_init = 1;            /* Set telnet-initialized flag. */
  3884.  
  3885.     /* Don't send anthing else! */
  3886.  
  3887.     debug(F101,"tn_ini duplex","",duplex);
  3888.     debug(F101,"tn_ini done, tn_init","",tn_init);
  3889.     return(1);
  3890. #endif /* TNCODE */
  3891. }
  3892.  
  3893. static VOID
  3894. tn_debug(s) char *s; {
  3895. #ifdef OS2
  3896.     void cwrite(unsigned short);
  3897.     char *p = s;
  3898.     _PROTOTYP (void os2bold, (void));
  3899. #endif /* OS2 */
  3900.  
  3901. #ifdef OS2
  3902.     debug(F111,"tn_debug",s,0);
  3903.     if (debses == 0) /* Emulator is always active in OS/2 */
  3904.       return;
  3905.  
  3906.     if (!scrninitialized[VTERM]) {
  3907.     USHORT x,y;
  3908.     checkscreenmode();
  3909.     GetCurPos(&y, &x);
  3910.     SaveCmdMode(x+1,y+1);
  3911.     scrninit();
  3912.     RestoreCmdMode();
  3913.     }
  3914.     os2bold();                /* Toggle boldness */
  3915.     while (*p) 
  3916.       cwrite((CHAR) *p++);        /* Go boldly ... */
  3917.     os2bold();                /* Toggle boldness back */
  3918.     debses = 0;
  3919.     cwrite((CHAR) '\015');
  3920.     cwrite((CHAR) '\012');
  3921.     debses = 1;
  3922. #else
  3923.     debug(F111,"tn_debug",s,what);
  3924.     if (what != W_CONNECT || debses == 0) /* CONNECT command must be active */
  3925.       return;
  3926.     conoll(s);
  3927. #endif /* OS2 */
  3928. }
  3929.  
  3930. /*
  3931.   Process in-band Telnet negotiation characters from the remote host.
  3932.   Call with the telnet IAC character and the current duplex setting
  3933.   (0 = remote echo, 1 = local echo), and a pointer to a function to call
  3934.   to read more characters.  Returns:
  3935.     3 if server has sent us a quoted IAC
  3936.     2 if local echo must be changed to remote
  3937.     1 if remote echo must be changed to local
  3938.     0 if nothing happens or no action necessary
  3939.    -1 on failure (= internal or i/o error)
  3940. */
  3941.  
  3942. #ifdef CK_ENVIRONMENT
  3943. #define TSBUFSIZ 1024
  3944. char tn_env_acct[64];
  3945. char tn_env_disp[64];
  3946. char tn_env_job[64];
  3947. char tn_env_prnt[64];
  3948. char tn_env_sys[64];
  3949. extern char uidbuf[];
  3950. #else /* CK_ENVIRONMENT */
  3951. #define TSBUFSIZ 41
  3952. #endif /* CK_ENVIRONMENT */
  3953.  
  3954. unsigned char sb[TSBUFSIZ];        /* Buffer for subnegotiations */
  3955.  
  3956. int
  3957. #ifdef CK_ANSIC                /* TELNET DO OPTION */
  3958. tn_doop(CHAR z, int echo, int (*fn)(int))
  3959. #else
  3960. tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)();
  3961. #endif /* CK_ANSIC */
  3962. /* tn_doop */ {
  3963.     int c, x, y, n, m, flag;
  3964.  
  3965. #ifndef TNCODE
  3966.     debug(F100,"tn_doop no TNCODE","",0);
  3967.     return(0);
  3968. #else
  3969.     if (z != (CHAR) IAC) {
  3970.     debug(F101,"tn_doop bad call","",z);
  3971.     return(-1);
  3972.     }
  3973.     if (ttnet != NET_TCPB)        /* Check network type */
  3974.       return(0);
  3975.     if (ttnproto != NP_TELNET)        /* Check protocol */
  3976.       return(0);
  3977.  
  3978. /* Have IAC, read command character. */
  3979.  
  3980.     c = (*fn)(0) & 0xff;        /* Read command character */
  3981.     m = c - SE;                /* Check validity */
  3982.     if (m < 0 || m > ntelcmds) {
  3983.     debug(F101,"tn_doop bad cmd","",c);
  3984.     return(0);
  3985.     }
  3986.     if (seslog && sessft) {        /* Copy to session log, if any. */
  3987.     if (zchout(ZSFILE, (char) z) < 0) /* Log IAC. */
  3988.       seslog = 0;
  3989.     else if (zchout(ZSFILE, (char) c) < 0) /* Log command */
  3990.       seslog = 0;
  3991.     }
  3992.     if (c == (CHAR) IAC)        /* Quoted IAC */
  3993.       return(3);
  3994.     if (c < SB)                /* Other command with no arguments. */
  3995.       return(0);
  3996.  
  3997. /* SB, WILL, WONT, DO, or DONT need more bytes... */
  3998.  
  3999.     if ((x = (*fn)(0)) < 0)        /* Get the option. */
  4000.       return(-1);
  4001.     x &= 0xff;                /* Trim to 8 bits. */
  4002.  
  4003.     if (seslog && sessft)        /* Session log */
  4004.       if (zchout(ZSFILE, (char) x) < 0)
  4005.     seslog = 0;
  4006.  
  4007.     if ((deblog || debses) && c != SB) {
  4008.     sprintf(tn_msg,"TELNET RCVD %s %s",telcmds[m],
  4009.         (x < ntnopts) ? tnopts[x] : "UNKNOWN");
  4010.     debug(F101,tn_msg,"",x);
  4011.     if (debses) tn_debug(tn_msg);
  4012.     }
  4013.  
  4014.     /* Now handle the command */
  4015.  
  4016.     switch (x) {
  4017.       case TELOPT_BINARY:        /* TELNET BINARY mode. */
  4018.     switch (c) {            /* Command... */
  4019.       case WILL:
  4020.         if (tn_binary == TN_BM_RF) { /* If binary mode disabled */
  4021.         if (tn_sopt(DONT,x) < 0) 
  4022.           return(-1);
  4023.         else 
  4024.           return(0);
  4025.         } else if (!u_binary) {
  4026.         u_binary = 1;
  4027.         if (!dubinflg) {    /* Reply only if we did not initiate */
  4028.             if (tn_sopt(DO,x) < 0)   
  4029.               return -1;
  4030.         } else {
  4031.             dubinflg = 0;
  4032.         }
  4033.         u_binary = 1;
  4034.         }
  4035.         return(0);
  4036.       case WONT:
  4037.         if (u_binary) {
  4038.         u_binary = 0;
  4039.         if (tn_sopt(DONT,x) < 0) 
  4040.           return (-1);
  4041.         else
  4042.           return(0);
  4043.         } else return(0);
  4044.       case DO:
  4045.         if (tn_binary == TN_BM_RF) {
  4046.         if (tn_sopt(WONT,x) < 0) 
  4047.           return (-1);
  4048.         else
  4049.           return (0);
  4050.         } else if (!me_binary) {
  4051.         if (!wmebinflg) {    /* Reply only if we did not initiate */
  4052.             if (tn_sopt(WILL,x) < 0)   
  4053.               return -1;
  4054.         } else {
  4055.             wmebinflg = 0;
  4056.         }
  4057.         me_binary = 1;
  4058.         if (tn_binary == TN_BM_RQ && !u_binary) {
  4059.             if (!dubinflg) {
  4060.             if (tn_sopt(DO, TELOPT_BINARY) < 0)
  4061.               return(-1);
  4062.             dubinflg = 1;    /* We sent an initial DO BINARY. */
  4063.             }
  4064.         }
  4065.         }
  4066.         return(0);
  4067.       case DONT:
  4068.         if (me_binary) {
  4069.         me_binary = 0;
  4070.         if (tn_sopt(WONT,x) < 0) 
  4071.           return(-1);
  4072.         else
  4073.           return(0);
  4074.         } else
  4075.           return(0);
  4076.       default:
  4077.         return(0);
  4078.     }
  4079.  
  4080.       case TELOPT_ECHO:            /* ECHO mode. */
  4081.     switch (c) {            /* Command... */
  4082.       case WILL:            /* Host says it will echo.           */
  4083.         if (echo) {            /* We're locally echoing right now,  */
  4084.         if (tn_sopt(DO,x) < 0)    /* so switch to remote.  */
  4085.           return (-1); 
  4086.         else 
  4087.           return(2);
  4088.         } else
  4089.           return(0);        /* We're already remote echoing.     */
  4090.       case WONT:            /* Host says it won't echo.          */
  4091.         if (!echo) {        /* We're remote echoing right now,   */
  4092.         if (tn_sopt(DONT,x) < 0) /* so switch to local. */
  4093.           return (-1);
  4094.         else
  4095.           return (1);
  4096.         } else            /* We're already locally echoing.    */
  4097.           return(0);
  4098.       case DO:            /* Host wants me to echo.            */
  4099.       case DONT:            /* Host doesn't want me to echo.     */
  4100.                         /* ...But the client never echoes.   */
  4101.           if (tn_sopt(WONT,x) < 0)
  4102.         return (-1);
  4103.           else
  4104.         return (0);
  4105.  
  4106.       default:
  4107.         return(0);
  4108.     }
  4109.  
  4110.       case TELOPT_SGA:            /* Suppress Go-Ahead */
  4111.     switch (c) {            /* Command... */
  4112.       case WILL:            /* Server says it will SGA.          */
  4113. #ifdef COMMENT
  4114.         if (sgaflg) {        /* Remember new SGA state, but       */
  4115. #endif /* COMMENT */
  4116.           sgaflg = 0;        /* don't change echo state.          */
  4117.           if (tn_sopt(DO,x) < 0)
  4118.         return(-1);
  4119.           else
  4120.         return(0);
  4121. #ifdef COMMENT
  4122.         } else return(0);
  4123. #endif /* COMMENT */
  4124.       case WONT:            /* Server says it won't SGA.         */
  4125. #ifdef COMMENT
  4126.         if (!sgaflg) {        /* Remember new SGA state, and       */
  4127. #endif /* COMMENT */
  4128.           sgaflg = 1;        /* switch to local echo if needed.   */
  4129.           if (tn_sopt(DONT,x) < 0)
  4130.         return(-1);
  4131. #ifdef COMMENT
  4132.         }
  4133. #endif /* COMMENT */
  4134.         return(echo ? 0 : 1);
  4135. /*
  4136.   Note: The concerns expressed in the older comment below are now taken
  4137.   care of by the negotiation loop prevention code in tn_sopt() - see the
  4138.   comment about this near the definition of MAXTNCNT, above.
  4139. */
  4140. /*
  4141.   Note: The following is proper behavior, and required for talking to the
  4142.   Apertus interface to the NOTIS library system, e.g. at Iowa State U:
  4143.   scholar.iastate.edu.  Without this reply, the server hangs forever.  This
  4144.   code should not be loop-inducing, since C-Kermit never sends WILL SGA as
  4145.   an initial bid, so if DO SGA comes, it is never an ACK.
  4146. */
  4147.       case DO:            /* Server wants me to SGA,           */
  4148.                     /* so I will.                        */
  4149.       case DONT:            /* Server wants me not to SGA,       */
  4150.                     /* but I will anyway.                */
  4151.         if (tn_sopt(WILL,x) < 0) 
  4152.           return(-1);
  4153.         else 
  4154.           return (0);
  4155.  
  4156.       default:
  4157.         return(0);
  4158.     }
  4159.  
  4160. #ifdef TELOPT_TTYPE
  4161.       case TELOPT_TTYPE:        /* Terminal Type */
  4162.     switch (c) {
  4163.       case DONT:
  4164.         if (ttyflg) {
  4165.           ttyflg = 0;
  4166.           if (tn_sopt(WONT,x) < 0) 
  4167.         return (-1);
  4168.           else 
  4169.         return (0);
  4170.         } else return(0);
  4171.       case DO:
  4172.         if (!ttyflg) {
  4173.           ttyflg = 1;
  4174.           if (tn_sopt(WILL,x) < 0) 
  4175.         return(-1);
  4176.           else 
  4177.         return (0);
  4178.         } else
  4179.           return(0);
  4180.       case WILL:
  4181.       case WONT:
  4182.         if (!ttyflg) {
  4183.         ttyflg = 1;
  4184.         if (tn_sopt(DONT,x) < 0) 
  4185.           return(-1);
  4186.         else 
  4187.           return (0);
  4188.         } else
  4189.           return(0);
  4190.       case SB:
  4191.         n = flag = 0;        /* Flag for when done reading SB */
  4192.         while (n < TSBUFSIZ) {    /* Loop looking for IAC SE */
  4193.         if ((y = (*fn)(0)) < 0)    /* Read a byte */
  4194.           return(y);
  4195.         y &= 0xff;        /* Make sure it's just 8 bits. */
  4196.         sb[n++] = (char) y;    /* Deposit in buffer. */
  4197.         if (seslog && sessft)    /* Take care of session log */
  4198.           if (zchout(ZSFILE, (char) y) < 0)
  4199.             seslog = 0;
  4200.         if (y == IAC) {        /* If this is an IAC */
  4201.             if (flag) {        /* If previous char was IAC */
  4202.             n--;        /* it's quoted, keep one IAC */
  4203.             flag = 0;    /* and turn off the flag. */
  4204.             } else flag = 1;    /* Otherwise set the flag. */
  4205.         } else if (flag) {    /* Something else following IAC */
  4206.             if (y == SE)    /* If not SE, it's a protocol error */
  4207.               break;
  4208.             else if ( y == DONT ) { /* Used DONT instead of SE */
  4209.             debug(F100,
  4210. "TELNET Subnegotiation error - used DONT instead of SE!",
  4211.                   "",0);
  4212.             if (debses)
  4213.               tn_debug(
  4214. "TELNET Subnegotiation error - used DONT instead of SE!");
  4215.             flag = 3;
  4216.             break;
  4217.             } else {        /* Other protocol error */
  4218.             flag = 0;
  4219.             break;
  4220.             }
  4221.         } else if (!flag && y == SE) { /* Forgot the IAC ? */
  4222.             flag = 2;
  4223.             debug(F100,
  4224. "TELNET Subnegotiation error - forgot the IAC before SE!",
  4225.               "",0);
  4226.             if (debses)
  4227.               tn_debug(
  4228. "TELNET Subnegotiation error - forgot the IAC before SE!");
  4229.             break;
  4230.         }
  4231.         }
  4232.         if (!flag) {        /* Make sure we got a valid SB */
  4233.         debug(F100, "TELNET Subnegotiation prematurely broken", "",0);
  4234.         if (debses) 
  4235.           tn_debug("TELNET Subnegotiation prematurely broken");
  4236.         return(0);    /* Was -1 but that would be taken as */
  4237.                         /* an I/O error, so absorb it and go on. */
  4238.         }
  4239.         if (deblog || debses) {
  4240.         int i;
  4241.         sprintf(tn_msg,"TELNET RCVD SB %s %s ",tnopts[TELOPT_TTYPE],
  4242.             sb[0] ? "SEND" : "IS");
  4243.         for (i = 1; i < n-2; i++) {
  4244.             sprintf(hexbuf,"%c",sb[i]);
  4245.             strcat(tn_msg,hexbuf);
  4246.         }
  4247.         if (flag == 2)
  4248.           strcat(tn_msg," SE");
  4249.         else if (flag == 3)
  4250.           strcat(tn_msg," IAC DONT");
  4251.         else 
  4252.           strcat(tn_msg," IAC SE");
  4253.         debug(F100,tn_msg,"",0);
  4254.         if (debses) tn_debug(tn_msg);
  4255.         }
  4256.         if (sb[0] == 1) {        /* SEND terminal type? */
  4257.         if (tn_sttyp() < 0)    /* Yes, so send it. */
  4258.           return(-1);
  4259.         }
  4260. #ifdef OS2
  4261.         else {  /* IS terminal type -- host has chosen from the list */
  4262.         int i=0;
  4263.  
  4264.         /* isolate the specified terminal type string */
  4265.         while (sb[i++] != IAC) {
  4266.             if (i >= TSBUFSIZ)
  4267.               return (-1);
  4268.             if (sb[i] == IAC) {
  4269.             sb[i] = '\0';
  4270.             break;
  4271.                     }
  4272.                 }
  4273.         strupr(&(sb[1])); /* Upper case it */
  4274.         for (i=0;i<=max_tt;i++) {    /* find it in our list */
  4275.             if (!strcmp(&(sb[1]),tt_info[i].x_name)) {
  4276.             /* Set terminal type to the one chosen */
  4277.             settermtype(i,0);
  4278.             break;
  4279.             }
  4280.                 }
  4281.             }
  4282. #endif /* OS2 */
  4283.       default:            /* Others, ignore */
  4284.         return(0);
  4285.     }
  4286. #endif /* TELOPT_TTYPE */
  4287.  
  4288. #ifdef CK_NAWS
  4289.       case TELOPT_NAWS:            /* Terminal width and height */
  4290.     switch (c) {
  4291.       case DO:
  4292.         /* Get window size again in case it changed */
  4293.         if (ttgwsiz() > 0) {
  4294.         if (!wnawsflg) {    /* Reply WILL only if we */
  4295.             if (tn_sopt(WILL,x) < 0) /* didn't initiate this */
  4296.               return(-1);    /* negotiation with a WILL */
  4297.         } else
  4298.             wnawsflg = 0;
  4299.  
  4300.         nawsflg = 1;
  4301. #ifndef NOSIGWINCH
  4302. #ifdef SIGWINCH
  4303. #ifdef UNIX
  4304.         if (sw_armed++ < 1) {    /* Catch window-size changes. */ 
  4305.             debug(F100,"tn_doop arming SIGWINCH","",0);
  4306.             signal(SIGWINCH,winchh);
  4307.         }
  4308. #else
  4309.         debug(F100,"SIGWINCH defined but not used","",0);
  4310. #endif /* UNIX */    
  4311. #endif /* SIGWINCH */
  4312. #endif /* NOSIGWINCH */
  4313.         return((tn_snaws() < 0) 
  4314. #ifdef RLOGCODE
  4315.                || (rlog_naws() < 0)
  4316. #endif /* RLOGCODE */
  4317.                ? -1 : 0); /* And now do it. */
  4318.         } else {
  4319.         nawsflg = 0;
  4320.         wnawsflg = 0;
  4321.         return((tn_sopt(WONT,x) < 0) ? -1 : 0);
  4322.         }
  4323.       case DONT:
  4324.         nawsflg = 0;
  4325.         wnawsflg = 0;
  4326.         return ((tn_sopt(WONT,x) < 0) ? -1 : 0);
  4327.       case WILL:    /* For when we are a server */
  4328.       case WONT:
  4329.         return ((tn_sopt(DONT,x) < 0) ? -1 : 0);
  4330.       default:
  4331.         return(0);
  4332.     }
  4333. #endif /* CK_NAWS */
  4334.  
  4335. #ifdef CK_ENVIRONMENT
  4336.       case TELOPT_NEWENVIRON:         /* Telnet New-Environment */
  4337.     switch (c) {
  4338.       case DO:
  4339.         return ((tn_sopt(WILL,x) < 0) ? -1 : 0);
  4340.       case DONT:
  4341.         return ((tn_sopt(WONT,x) < 0) ? -1 : 0);
  4342.       case WILL: /* For when we are a server */
  4343.       case WONT:
  4344.         return ((tn_sopt(DONT,x) < 0) ? -1 : 0);
  4345.       case SB: {
  4346.           n = flag = 0;        /* Flag for when done reading SB */
  4347.           while (n < TSBUFSIZ) {    /* Loop looking for IAC SE */
  4348.           if ((y = (*fn)(0)) < 0) /* Read a byte */
  4349.             return(y);
  4350.           y &= 0xff;        /* Make sure it's just 8 bits. */
  4351.           sb[n++] = (char) y;    /* Deposit in buffer. */
  4352.           if (seslog && sessft)    /* Take care of session log */
  4353.             if (zchout(ZSFILE, (char) y) < 0)
  4354.               seslog = 0;
  4355.           if (y == IAC) {    /* If this is an IAC */
  4356.               if (flag) {    /* If previous char was IAC */
  4357.               n--;        /* it's quoted, keep one IAC */
  4358.               flag = 0;    /* and turn off the flag. */
  4359.               } else flag = 1;    /* Otherwise set the flag. */
  4360.           } else if (flag) {    /* Something else following IAC */
  4361.               if (y == SE)    /* If not SE, it's a protocol error */
  4362.             break;
  4363.               else if (y == DONT) { /* Used DONT instead of SE */
  4364.               debug(F100,
  4365.               "TELNET SB error - got DONT instead of SE!",
  4366.                  "",0);
  4367.               if (debses)
  4368.                 tn_debug(
  4369. "TELNET Subnegotiation error - got DONT instead of SE!");
  4370.               flag = 3;
  4371.               break;
  4372.               } else {        /* Other protocol error */
  4373.               flag = 0;
  4374.               break;
  4375.               }
  4376.           } else if (!flag && y == SE) { /* Forgot the IAC ? */
  4377.               flag = 2;
  4378.               debug(F100,
  4379. "TELNET Subnegotiation error - forgot the IAC before SE!",
  4380.                 "",0);
  4381.               if (debses)
  4382.             tn_debug(
  4383. "TELNET Subnegotiation error - forgot the IAC before SE!");
  4384.               break;
  4385.           }
  4386.           }
  4387.           if (!flag) {        /* Make sure we got a valid SB */
  4388.           debug(F100,"TELNET Subnegotiation prematurely broken","",0);
  4389.           if (debses) 
  4390.             tn_debug("TELNET Subnegotiation prematurely broken");
  4391.           return(0);        /* Was -1 but that would be taken as */
  4392.                     /* an I/O error, so absorb & go on. */
  4393.           }
  4394.           if (deblog || debses) {
  4395.           int i;
  4396.           sprintf(tn_msg,
  4397.               "TELNET RCVD SB %s %s ",
  4398.               tnopts[TELOPT_NEWENVIRON],
  4399.               sb[0] == 1 ? "SEND" : sb[0] == 0 ? "IS" : "INFO"
  4400.               );
  4401.           for (i = 1; i < n-2; i++) {
  4402.               sprintf(hexbuf,"%c",sb[i]);
  4403.               strcat(tn_msg,hexbuf);
  4404.           }
  4405.           if (flag == 2)
  4406.             strcat(tn_msg," SE");
  4407.           else if (flag == 3)
  4408.             strcat(tn_msg," IAC DONT");
  4409.           else 
  4410.             strcat(tn_msg," IAC SE");
  4411.           debug(F100,tn_msg,"",0);
  4412.           if (debses) tn_debug(tn_msg);
  4413.           }
  4414.           switch (sb[0]) {
  4415.         case 0:            /* IS */
  4416.           /* Ignore, we're not a server - yet */
  4417.           break;
  4418.         case 1:            /* SEND */
  4419.           /* We need to take the sb[] and build a structure */
  4420.           /* containing all of the variables and types that */
  4421.           /* we are supposed to keep track of and send to   */
  4422.           /* the host, then call tn_snenv().                */
  4423.           /* Or we can punt ...                             */
  4424.           if (tn_snenv(&sb[1],n-3) < 0)    /* Yes, so send it. */
  4425.             return(-1);
  4426.           break;
  4427.         case 2:            /* INFO */
  4428.           /* Ignore, we're not a server - yet */
  4429.           break;
  4430.           }
  4431.       }
  4432.       default:
  4433.         return(0);
  4434.     }
  4435. #endif /* CK_ENVIRONMENT */
  4436.  
  4437.       default:                /* All others: refuse */
  4438.     switch(c) {
  4439.       case WILL:            /* You will? */
  4440.         return((tn_sopt(DONT,x) < 0) ? -1 : 0); /* Please don't. */
  4441.       case WONT:            /* You won't? */
  4442.         return(0);            /* I didn't want you to. */
  4443.       case DO:            /* You want me to? */
  4444.       case DONT:            /* You don't want me to? */
  4445.         return((tn_sopt(WONT,x) < 0) ? -1 : 0); /* I won't */
  4446.       default:
  4447.         return(0);
  4448.     }
  4449.     }
  4450. #endif /* TNCODE */
  4451. }
  4452.  
  4453. #ifdef CK_ENVIRONMENT
  4454. /* Telnet send new environment */
  4455. /* Returns -1 on error, 0 if nothing happens, 1 on success */
  4456.  
  4457. int
  4458. #ifdef CK_ANSIC
  4459. tn_snenv(char * sb, int len) 
  4460. #else
  4461. tn_snenv() char * sb; int len;
  4462. #endif /* CK_ANSIC */
  4463. /* tn_snenv */ {             /* Send new environment */
  4464. #ifndef TNCODE
  4465.     debug(F100,"tn_snenv no TNCODE","",0);
  4466.     return(0);
  4467. #else
  4468.     char varname[16];
  4469.     char * reply = 0, * s = 0;
  4470.     int i,j,n;                /* Worker. */
  4471.     int type = 0;    /* 0 for NONE, 1 for VAR, 2 for USERVAR in progress */
  4472.  
  4473.     if (ttnet != NET_TCPB) return(0);
  4474.     if (ttnproto != NP_TELNET) return(0);
  4475.  
  4476.     /* First determine the size of the buffer we will need */
  4477.     for (i = 0, j = 0, n = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
  4478.     switch (sb[i]) {
  4479.       case 0:            /* VAR */
  4480.       case 3:            /* USERVAR */
  4481.       case IAC:            /* End of the list */
  4482.         switch (type) {
  4483.           case 0:            /* Nothing in progress */
  4484.         /* If we get IAC only, then that means send all */
  4485.         /* VAR and USERVAR.  But since we don't support */
  4486.         /* USERVAR yet, we can just pass through        */
  4487.         if (!(j == 0 && sb[i] == IAC))
  4488.           break;
  4489.           case 1:            /* VAR in progress */
  4490.         varname[j] = '\0' ;
  4491.         if (!varname[0]) {    /* Send All */
  4492.             if (uidbuf[0])
  4493.               n += strlen(uidbuf) + 4 + 2;
  4494.             if (tn_env_job[0])
  4495.               n += strlen(tn_env_job) + 3 + 2;
  4496.             if (tn_env_acct[0])
  4497.               n += strlen(tn_env_acct) + 4 + 2;    
  4498.             if (tn_env_prnt[0])
  4499.               n += strlen(tn_env_prnt) + 7 + 2;
  4500.             if (tn_env_sys[0])
  4501.               n += strlen(tn_env_sys) + 10 + 2;
  4502.             if (tn_env_disp[0])
  4503.               n += strlen(tn_env_disp) + 7 + 2;
  4504.         } else if (!strcmp(varname,"USER") && uidbuf[0])
  4505.           n += strlen(uidbuf) + 4 + 2;
  4506.         else if (!strcmp(varname,"JOB") && tn_env_job[0])
  4507.           n += strlen(tn_env_job) + 3 + 2;
  4508.         else if (!strcmp(varname,"ACCT") && tn_env_acct[0])
  4509.           n += strlen(tn_env_acct) + 4 + 2;
  4510.         else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0])
  4511.           n += strlen(tn_env_prnt) + 7 + 2;
  4512.         else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0])
  4513.           n += strlen(tn_env_sys) + 10 + 2;
  4514.         else if (!strcmp(varname,"DISPLAY") && tn_env_disp[0])
  4515.           n += strlen(tn_env_disp) + 7 + 2;
  4516.         break;
  4517.           case 2:            /* USERVAR in progress */
  4518.         break;            /* We don't support this yet */
  4519.         }
  4520.         varname[0] = '\0';
  4521.         j = 0;
  4522.         type = (sb[i] == 3 ? 2 :    /* USERVAR */
  4523.             sb[i] == 0 ? 1 :    /* VAR */
  4524.             0
  4525.            );
  4526.         break;
  4527.       case 1:            /* VALUE */
  4528.         /* Protocol Error */
  4529.         debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0);
  4530.         if (debses) 
  4531.           tn_debug("TELNET Subnegotiation error - VALUE in SEND");
  4532.         return(0);    /* Was -1 but that would be taken as */
  4533.                     /* an I/O error, so absorb it and go on. */
  4534.       case 2:    /* ESC */
  4535.         /* Not sure what this for.  Quote next character? */
  4536.         break;
  4537.       default:
  4538.         varname[j++] = sb[i];
  4539.     }
  4540.     }
  4541.     reply = (CHAR *) malloc(n + 7);    /* Leave room for IAC stuff */
  4542.     if (!reply) {
  4543.     debug(F100, "TELNET Subnegotiation error - malloc failed", "",0);
  4544.     if (debses) 
  4545.       tn_debug("TELNET Subnegotiation error - malloc failed");
  4546.  
  4547.     /* Send a return packet with no variables so that the host */
  4548.     /* may continue with additional negotiations               */
  4549.     sb[0] = (CHAR) IAC;        /* I Am a Command */
  4550.     sb[1] = (CHAR) SB;        /* Subnegotiation */
  4551.     sb[2] = TELOPT_NEWENVIRON;    /* New Environment */
  4552.     sb[3] = (CHAR) 0;        /* Is... */
  4553.     sb[4] = (CHAR) IAC;        /* End of Subnegotiation */
  4554.     sb[5] = (CHAR) SE;        /* marked by IAC SE */
  4555.     if (ttol((CHAR *)sb,6) < 0)    /* Send it. */
  4556.       return(-1);
  4557.     sb[4] = '\0';            /* For debugging */
  4558.     if (deblog || debses) {
  4559.         sprintf(tn_msg,"TELNET SENT SB %s IS  IAC SE",
  4560.              tnopts[TELOPT_NEWENVIRON]);
  4561.         debug(F100,tn_msg,"",0);
  4562.         if (debses) tn_debug(tn_msg);
  4563.     }
  4564.     return(0);     
  4565.     }
  4566.  
  4567.     /* Now construct the real reply */
  4568.     reply[0] = (CHAR) IAC;            /* I Am a Command */
  4569.     reply[1] = (CHAR) SB;            /* Subnegotiation */
  4570.     reply[2] = TELOPT_NEWENVIRON;        /* New Environment */
  4571.     reply[3] = (CHAR) 0;            /* Is... */
  4572.     n = 4; 
  4573. /* Pairs of <type> [VAR=0, VALUE=1, ESC=2, USERVAR=3] <value> "unterminated" */
  4574.     /* follow here until done */
  4575.     for (i = 0, j = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
  4576.     switch (sb[i]) {
  4577.       case 0:            /* VAR */
  4578.       case 3:            /* USERVAR */
  4579.       case IAC:            /* End of the list */
  4580.         switch (type) {
  4581.           case 0:            /* Nothing in progress */
  4582.         /* If we get IAC only, then that means send all */
  4583.         /* VAR and USERVAR.  But since we don't support */
  4584.         /* USERVAR yet, we can just pass through        */
  4585.         if (!(j == 0 && sb[i] == IAC))
  4586.           break;
  4587.           case 1:            /* VAR in progress */
  4588.         varname[j] = '\0';
  4589.         if (!varname[0]) {
  4590.             /* Send All */
  4591.             if ( uidbuf[0] ) {
  4592.             reply[n] = 0;    /* VAR */
  4593.             strcpy(&reply[n+1],"USER");
  4594.             reply[n+5] = 1;     /* VALUE */
  4595.             strcpy(&reply[n+6],uidbuf);
  4596.             n += strlen(uidbuf) + 4 + 2;
  4597.             }
  4598.             if (tn_env_job[0]) {
  4599.             reply[n] = 0;    /* VAR */
  4600.             strcpy(&reply[n+1],"JOB");
  4601.             reply[n+4] = 1;    /* VALUE */
  4602.             strcpy(&reply[n+5],tn_env_job);
  4603.             n += strlen(tn_env_job) + 3 + 2;
  4604.             }
  4605.             if (tn_env_acct[0]) {
  4606.             reply[n] = 0;    /* VAR */
  4607.             strcpy(&reply[n+1],"ACCT");
  4608.             reply[n+5] = 1;    /* VALUE */
  4609.             strcpy(&reply[n+6],tn_env_acct);
  4610.             n += strlen(tn_env_acct) + 4 + 2;
  4611.             }
  4612.             if (tn_env_prnt[0]) {
  4613.             reply[n] = 0;    /* VAR */
  4614.             strcpy(&reply[n+1],"PRINTER");
  4615.             reply[n+8] = 1;    /* VALUE */
  4616.             strcpy(&reply[n+9],tn_env_prnt);
  4617.             n += strlen(tn_env_prnt) + 7 + 2;
  4618.             }
  4619.             if (tn_env_sys[0]) {
  4620.             reply[n] = 0;    /* VAR */
  4621.             strcpy(&reply[n+1],"SYSTEMTYPE");
  4622.             reply[n+11] = 1; /* VALUE */
  4623.             strcpy(&reply[n+12],tn_env_sys);
  4624.             n += strlen(tn_env_sys) + 10 + 2;
  4625.             }
  4626.             if (tn_env_disp[0]) {
  4627.             reply[n] = 0;    /* VAR */
  4628.             strcpy(&reply[n+1],"DISPLAY");
  4629.             reply[n+8] = 1;    /* VALUE */
  4630.             strcpy(&reply[n+9],tn_env_disp);
  4631.             n += strlen(tn_env_disp) + 7 + 2;
  4632.             }
  4633.         } else if (!strcmp(varname,"USER") && uidbuf[0]) {
  4634.             reply[n] = 0;    /* VAR */
  4635.             strcpy(&reply[n+1],"USER");
  4636.             reply[n+5] = 1;     /* VALUE */
  4637.             strcpy(&reply[n+6],uidbuf);
  4638.                     n += strlen(uidbuf) + 4 + 2;
  4639.         } else if (!strcmp(varname,"JOB") && tn_env_job[0]) {
  4640.             reply[n] = 0;    /* VAR */
  4641.             strcpy(&reply[n+1],"JOB");
  4642.             reply[n+4] = 1;     /* VALUE */
  4643.             strcpy(&reply[n+5],tn_env_job);
  4644.             n += strlen(tn_env_job) + 3 + 2;
  4645.         } else if (!strcmp(varname,"ACCT") && tn_env_acct[0]) {
  4646.             reply[n] = 0;    /* VAR */
  4647.             strcpy(&reply[n+1],"ACCT");
  4648.             reply[n+5] = 1;     /* VALUE */
  4649.             strcpy(&reply[n+6],tn_env_acct);
  4650.             n += strlen(tn_env_acct) + 4 + 2;
  4651.         } else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0]) {
  4652.             reply[n] = 0;    /* VAR */
  4653.             strcpy(&reply[n+1],"PRINTER");
  4654.             reply[n+8] = 1;     /* VALUE */
  4655.             strcpy(&reply[n+9],tn_env_prnt);
  4656.             n += strlen(tn_env_prnt) + 7 + 2;
  4657.         } else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0]) {
  4658.             reply[n] = 0;    /* VAR */
  4659.             strcpy(&reply[n+1],"SYSTEMTYPE");
  4660.             reply[n+11] = 1;     /* VALUE */
  4661.             strcpy(&reply[n+12],tn_env_sys);
  4662.             n += strlen(tn_env_sys) + 10 + 2;
  4663.         } else if (!strcmp(varname,"DISPLAY") && tn_env_disp[0]) {
  4664.             reply[n] = 0;    /* VAR */
  4665.             strcpy(&reply[n+1],"DISPLAY");
  4666.             reply[n+8] = 1;     /* VALUE */
  4667.             strcpy(&reply[n+9],tn_env_disp);
  4668.             n += strlen(tn_env_disp) + 7 + 2;
  4669.         }
  4670.         break;
  4671.         case 2:    /* USERVAR in progress */
  4672.         /* we don't support this yet */
  4673.         break;
  4674.         }
  4675.         varname[0] = '\0';
  4676.         j = 0;
  4677.         type = (sb[i] == 3 ? 2 :    /* USERVAR */
  4678.             sb[i] == 0 ? 1 :    /* VAR */
  4679.             0
  4680.            );
  4681.         break;
  4682.       case 1: /* VALUE */
  4683.         /* Protocol Error */
  4684.         debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0);
  4685.         if (debses) 
  4686.           tn_debug("TELNET Subnegotiation error - VALUE in SEND");
  4687.         return(0);    /* Was -1 but that would be taken as */
  4688.                     /* an I/O error, so absorb it and go on. */
  4689.       case 2:    /* ESC */
  4690.         /* Not sure what this for.  Quote next character? */
  4691.         break;
  4692.       default:
  4693.         varname[j++] = sb[i];
  4694.     }
  4695.     }
  4696.     reply[n++] = (CHAR) IAC;        /* End of Subnegotiation */
  4697.     reply[n++] = (CHAR) SE;        /* marked by IAC SE */
  4698.     if (ttol((CHAR *)reply,n) < 0) {    /* Send it. */
  4699.          free(reply);
  4700.     return(-1);
  4701.     }
  4702.     reply[n-2] = '\0';            /* For debugging */
  4703.     if (deblog || debses) {
  4704.     int i;
  4705.     sprintf(tn_msg,"TELNET SENT SB %s %s ",
  4706.          tnopts[TELOPT_NEWENVIRON],
  4707.          reply[3] == 1 ? "SEND" : reply[3] == 0 ? "IS" : "INFO");
  4708.     for (i = 4; i < n-2; i++) {
  4709.         sprintf(hexbuf,"%c",reply[i]);
  4710.         strcat(tn_msg,hexbuf);
  4711.     }
  4712.     strcat(tn_msg," IAC SE");
  4713.     debug(F100,tn_msg,"",0);
  4714.     if (debses) tn_debug(tn_msg);
  4715.     }
  4716.     free(reply);
  4717.     return(1);
  4718. #endif /* TNCODE */
  4719. }
  4720. #endif /* CK_ENVIRONMENT */
  4721.  
  4722. /* Telnet send terminal type */
  4723. /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
  4724.  
  4725. int
  4726. tn_sttyp() {                /* Send telnet terminal type. */
  4727. #ifndef TNCODE
  4728.     debug(F100,"tn_sttyp no TNCODE","",0);
  4729.     return(0);
  4730. #else
  4731.     char *ttn;                /* Name of terminal type. */
  4732.     int i;                /* Worker. */
  4733.     int tntermflg = 0;
  4734.  
  4735.     if (ttnet != NET_TCPB) return(0);
  4736.     if (ttnproto != NP_TELNET) return(0);
  4737.  
  4738.     ttn = NULL;
  4739.  
  4740. #ifdef OS2
  4741.     if (ttnum == -1) {
  4742.         ttnum = tt_type;
  4743.     } else if (ttnumend) {
  4744.         ttnumend = 0;
  4745.     } else {
  4746.         if (--tt_type < 0)
  4747.       tt_type = max_tt;
  4748.         if (ttnum == tt_type)
  4749.       ttnumend = 1;
  4750.     }
  4751.     if (tt_type >= 0 && tt_type <= max_tt) {
  4752.     ttn = tt_info[tt_type].x_name;
  4753.     settermtype(tt_type,0);
  4754.     } else
  4755.       ttn = NULL;
  4756. #endif /* OS2 */
  4757.  
  4758.     if (tn_term) {            /* Terminal type override? */
  4759.     debug(F110,"tn_sttyp",tn_term,0);
  4760.     if (*tn_term) {
  4761.         ttn = tn_term;
  4762.         tntermflg = 1;
  4763.     }
  4764.     } else debug(F100,"tn_sttyp no term override","",0);
  4765.  
  4766. #ifndef datageneral
  4767.     if (!ttn) {                /* If no override, */
  4768.     ttn = getenv("TERM");        /* get it from the environment. */
  4769.     }
  4770. #endif /* datageneral */
  4771.     if ((ttn == ((char *)0)) || ((int)strlen(ttn) >= TSBUFSIZ))
  4772.       ttn = "UNKNOWN";
  4773.     sb[0] = (CHAR) IAC;            /* I Am a Command */
  4774.     sb[1] = (CHAR) SB;            /* Subnegotiation */
  4775.     sb[2] = TELOPT_TTYPE;        /* Terminal Type */
  4776.     sb[3] = (CHAR) 0;            /* Is... */
  4777.     for (i = 4; *ttn; ttn++,i++) {    /* Copy and uppercase it */
  4778. #ifdef VMS
  4779.     if (!tntermflg && *ttn == '-' &&
  4780.         (!strcmp(ttn,"-80") || !strcmp(ttn,"-132")))
  4781.       break;
  4782.     else
  4783. #endif /* VMS */
  4784.     sb[i] = (char) ((!tntermflg && islower(*ttn)) ? toupper(*ttn) : *ttn);
  4785.     }
  4786.     ttn = (char *)sb;            /* Point back to beginning */
  4787.     sb[i++] = (CHAR) IAC;        /* End of Subnegotiation */
  4788.     sb[i++] = (CHAR) SE;        /* marked by IAC SE */
  4789.     if (ttol((CHAR *)sb,i) < 0)        /* Send it. */
  4790.       return(-1);
  4791.     sb[i-2] = '\0';            /* For debugging */
  4792.     if (deblog || debses) {
  4793.     sprintf(tn_msg,"TELNET SENT SB %s IS %s IAC SE",
  4794.         tnopts[TELOPT_TTYPE],sb+4);
  4795.     debug(F100,tn_msg,"",0);
  4796.     if (debses) tn_debug(tn_msg);
  4797.     }
  4798.     return(1);
  4799. #endif /* TNCODE */
  4800. }
  4801.  
  4802. #ifdef CK_NAWS            /*  NAWS = Negotiate About Window Size  */
  4803. int
  4804. tn_snaws() {            /*  Send terminal width and height, RFC 1073 */
  4805. #ifndef TNCODE
  4806.     debug(F100,"tn_snaws no TNCODE","",0);
  4807. #else
  4808.     int i = 0;
  4809. #ifdef OS2 
  4810.     int x = VscrnGetWidth(VTERM), 
  4811.     y = VscrnGetHeight(VTERM) - (tt_status ? 1 : 0);
  4812. #else /* OS2 */
  4813.     int x = tt_cols, y = tt_rows;
  4814. #endif /* OS2 */
  4815.  
  4816.     if (ttnet != NET_TCPB) return(0);
  4817.     if (ttnproto != NP_TELNET) return(0);
  4818.     if (!nawsflg) return(0);
  4819.  
  4820.     if (x < 0) x = 0;
  4821.     if (y < 0) y = 0;
  4822.  
  4823.     sb[i++] = (CHAR) IAC;        /* Send a subnegotiation */
  4824.     sb[i++] = (CHAR) SB;
  4825.     sb[i++] = TELOPT_NAWS;
  4826.     sb[i++] = (CHAR) (x >> 8) & 0xff;
  4827.     /* IAC in data must be doubled */
  4828.     if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
  4829.     sb[i++] = (CHAR) (x & 0xff);
  4830.     if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
  4831.     sb[i++] = (CHAR) (y >> 8) & 0xff;
  4832.     if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
  4833.     sb[i++] = (CHAR) (y & 0xff);
  4834.     if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
  4835.     sb[i++] = (CHAR) IAC;
  4836.     sb[i++] = (CHAR) SE;
  4837.     if (ttol((CHAR *)sb,i) < 0)        /* Send it. */
  4838.       return(-1);
  4839.     if (deblog || debses) {
  4840.     sprintf(tn_msg,"TELNET SENT SB NAWS %d %d IAC SE",x,y);
  4841.     debug(F100,tn_msg,"",0);
  4842.     if (debses) tn_debug(tn_msg);
  4843.     }
  4844. #endif /* TNCODE */
  4845.     return (0);
  4846. }
  4847. #endif /* CK_NAWS */
  4848.  
  4849. #ifdef SUNX25
  4850. /*
  4851.   SunLink X.25 support by Marcello Frutig, Catholic University,
  4852.   Rio de Janeiro, Brazil, 1990.
  4853. */
  4854.  
  4855. /* PAD X.3, X.28 and X.29 support */
  4856.  
  4857. static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
  4858.  
  4859. /* Initialize PAD */
  4860.  
  4861. extern CHAR padparms[];
  4862.  
  4863. VOID
  4864. initpad() {
  4865.   padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
  4866.   padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
  4867.   padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
  4868.   padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
  4869.   padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
  4870.   padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
  4871.   padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
  4872.   padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
  4873.   padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
  4874.   padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
  4875.   padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
  4876.   padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
  4877.   padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
  4878.   padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
  4879.   padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
  4880.   padparms[PAD_EDITING]                = 1;  /* can edit */
  4881.   padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
  4882.   padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
  4883.   padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
  4884. }
  4885.  
  4886. /* Set PAD parameters */
  4887.  
  4888. VOID
  4889. setpad(s,n) CHAR *s; int n; {
  4890.     int i;
  4891.     CHAR *ps = s;
  4892.  
  4893.     if (n < 1) {
  4894.     initpad();
  4895.     } else {
  4896.     for (i = 0; i < n; i++) {
  4897.         if (*ps > MAXPADPARMS)
  4898.           x29err[i+2] = *ps;
  4899.         else
  4900.           padparms[*ps] = *(ps+1);
  4901.         ps += 2;
  4902.     }
  4903.     }
  4904. }
  4905.  
  4906. /* Read PAD parameters */
  4907.  
  4908. VOID
  4909. readpad(s,n,r) CHAR *s; int n; CHAR *r; {
  4910.     int i;
  4911.     CHAR *ps = s;
  4912.     CHAR *pr = r;
  4913.  
  4914.     *pr++ = X29_PARAMETER_INDICATION;
  4915.     if (n > 0) {
  4916.     for (i = 0; i < n; i++, ps++) {
  4917.         if (*ps > MAXPADPARMS) {
  4918.         x29err[i+2] = *ps++;
  4919.         } else {
  4920.         *pr++ = *ps;
  4921.         *pr++ = padparms[*ps++];
  4922.         }
  4923.     }
  4924.     } else {
  4925.     for (i = 1; i < MAXPADPARMS; i++) {
  4926.         *pr++ = i;
  4927.         *pr++ = padparms[i];
  4928.     }
  4929.     }
  4930. }
  4931.  
  4932. int
  4933. qbitpkt(s,n) CHAR *s; int n; {
  4934.     CHAR *ps = s;
  4935.     int x29cmd = *ps;
  4936.     CHAR *psa = s+1;
  4937.     CHAR x29resp[(MAXPADPARMS*2)+1];
  4938.  
  4939.     switch (x29cmd) {
  4940.  
  4941.         case X29_SET_PARMS:
  4942.             setpad (ps+1,n/2);
  4943.             if ((int)strlen((char *)x29err) > 2) {
  4944.                 ttol(x29err,(int)strlen((char *)x29err));
  4945.                 x29err[2] = '\0';
  4946.             }
  4947.             return (-2);
  4948.         case X29_READ_PARMS:
  4949.             readpad (ps+1,n/2,x29resp);
  4950.             setqbit ();
  4951.             ttol (x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
  4952.             if ((int)strlen((char *)x29err) > 2) {
  4953.                 ttol(x29err,(int)strlen((char *)x29err));
  4954.                 x29err[2] = '\0';
  4955.             }
  4956.             resetqbit();
  4957.             break;
  4958.         case X29_SET_AND_READ_PARMS:
  4959.             setpad (ps+1,n/2);
  4960.             readpad (ps+1,n/2,x29resp);
  4961.             setqbit();
  4962.             ttol (x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
  4963.             if ((int)strlen((char *)x29err) > 2) {
  4964.                 ttol (x29err,(int)strlen((char *)x29err));
  4965.                 x29err [2] = '\0';
  4966.             }
  4967.             resetqbit();
  4968.             return (-2);
  4969.         case X29_INVITATION_TO_CLEAR:
  4970.             (VOID) x25clear();
  4971.             return (-1);
  4972.         case X29_INDICATION_OF_BREAK:
  4973.         break;
  4974.     }
  4975.     return (0);
  4976. }
  4977.  
  4978. /* PAD break action processor */
  4979.  
  4980. VOID
  4981. breakact() {
  4982.     extern char x25obuf[MAXOX25];
  4983.     extern int obufl;
  4984.     extern int active;
  4985.     extern unsigned char tosend;
  4986.     static CHAR indbrk[3] = {
  4987.     X29_INDICATION_OF_BREAK,
  4988.     PAD_SUPPRESSION_OF_DATA,
  4989.     1
  4990.     };
  4991.     CHAR intudat, cause, diag;
  4992.  
  4993.     if (x25stat() < 0) return;    /* Ignore if no virtual call established */
  4994.  
  4995.     if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
  4996.         if (ttol((CHAR *)x25obuf,obufl) < 0) {
  4997.             perror ("\r\nCan't send characters");
  4998.             active = 0;
  4999.         } else {
  5000.             bzero (x25obuf,sizeof(x25obuf));
  5001.             obufl = 0;
  5002.             tosend = 0;
  5003.         };
  5004.  
  5005.     switch (padparms[PAD_BREAK_ACTION]) {
  5006.  
  5007.        case 0 : break;            /* do nothing */
  5008.        case 1 : /* send interrupt packet with interrupt user data field = 1 */
  5009.             intudat = 1;
  5010.                 x25intr (intudat);
  5011.                 break;
  5012.        case 2 : /* send reset packet with cause and diag = 0 */
  5013.         cause = diag = 0;
  5014.                 x25reset (cause,diag);
  5015.                 break;
  5016.        case 5 : /* send interrupt packet with interrupt user data field = 0 */
  5017.         intudat = 0;
  5018.                 x25intr (intudat);
  5019.                 setqbit ();
  5020.             /* send indication of break without a parameter field */
  5021.                 ttoc(X29_INDICATION_OF_BREAK);
  5022.                 resetqbit ();
  5023.                 break;
  5024.        case 8 : active = 0;        /* leave data transfer */
  5025.                 conol ("\r\n");
  5026.                 break;
  5027.        case 21: /* send interrupt packet with interrupt user data field = 0 */
  5028.         intudat = 0;
  5029.                 x25intr (intudat);
  5030.                 setpad (indbrk+1,2);    /* set pad to discard input */
  5031.                 setqbit ();
  5032.         /* send indication of break with parameter field */
  5033.                 ttol (indbrk,sizeof(indbrk));
  5034.                 resetqbit ();
  5035.                 break;
  5036.      }
  5037. }
  5038.  
  5039. /* X.25 support functions */
  5040.  
  5041. X25_CAUSE_DIAG diag;
  5042.  
  5043. /*
  5044.   Convert a null-terminated string representing an X.121 address
  5045.   to a packed BCD form.
  5046. */
  5047. int
  5048. pkx121(str,bcd) char *str; CHAR *bcd; {
  5049.     int i, j;
  5050.     u_char c;
  5051.  
  5052.     i = j = 0;
  5053.     while (str[i]) {
  5054.         if (i >= 15 || str [i] < '0' || str [i] > '9')
  5055.       return (-1);
  5056.         c = str [i] - '0';
  5057.         if (i & 1)
  5058.       bcd [j++] |= c;
  5059.         else
  5060.       bcd [j] = c << 4;
  5061.         i++;
  5062.     }
  5063.     return (i);
  5064. }
  5065.  
  5066. /* Reads and prints X.25 diagnostic */
  5067.  
  5068. int
  5069. x25diag () {
  5070.     int i;
  5071.  
  5072.     bzero ((char *)&diag,sizeof(diag));
  5073.     if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
  5074.         perror ("Reading X.25 diagnostic");
  5075.         return(-1);
  5076.     }
  5077.     if (diag.datalen > 0) {
  5078.         printf ("X.25 Diagnostic :");
  5079.         for (i = 0; i < (int)diag.datalen; i++)
  5080.       printf(" %02x",diag.data[i]);
  5081.         printf ("\r\n");
  5082.     }
  5083.     return(0);
  5084. }
  5085.  
  5086. /* X.25 Out-of-Band Signal Handler */
  5087.  
  5088. SIGTYP
  5089. x25oobh(foo) int foo; {
  5090.     int oobtype;
  5091.     u_char oobdata;
  5092.     int t;
  5093.  
  5094.     (VOID) signal(SIGURG,x25oobh);
  5095.     do {
  5096.         if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
  5097.             perror ("Getting signal type");
  5098.             return;
  5099.         }
  5100.         switch (oobtype) {
  5101.       case INT_DATA:
  5102.         if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
  5103.         perror ("Receiving X.25 interrupt data");
  5104.         return;
  5105.         }
  5106.         t = oobdata;
  5107.         printf ("\r\nInterrupt received, data = %d\r\n", t);
  5108.         break;
  5109.       case VC_RESET:
  5110.         printf ("\r\nVirtual circuit reset\r\n");
  5111.         x25diag ();
  5112.         break;
  5113.       case N_RESETS:
  5114.         printf ("\r\nReset timeout\r\n");
  5115.         break;
  5116.       case N_CLEARS:
  5117.         printf ("\r\nClear timeout\r\n");
  5118.         break;
  5119.       case MSG_TOO_LONG:
  5120.         printf ("\r\nMessage discarded, too long\r\n");
  5121.         break;
  5122.       default:
  5123.         if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
  5124.         break;
  5125.     }
  5126.     } while (oobtype);
  5127. }
  5128.  
  5129. /* Send a X.25 interrupt packet */
  5130.  
  5131. int
  5132. #ifdef CK_ANSIC
  5133. x25intr(char intr)
  5134. #else
  5135. x25intr(intr) char intr;
  5136. #endif /* CK_ANSIC */
  5137. /* x25intr */ {
  5138.     if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
  5139.     debug(F100,"X.25 intr","",0);
  5140.     return(0);
  5141. }
  5142.  
  5143. /* Reset X.25 virtual circuit */
  5144. int
  5145. #ifdef CK_ANSIC
  5146. x25reset(char cause, char diagn)
  5147. #else
  5148. x25reset(cause, diagn) char cause; char diagn;
  5149. #endif /* CK_ANSIC */
  5150. /* x25reset */ {
  5151.     bzero ((char *)&diag,sizeof(diag));
  5152.     diag.flags   = 0;
  5153.     diag.datalen = 2;
  5154.     diag.data[0] = cause;
  5155.     diag.data[1] = diagn;
  5156.     if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
  5157.       return(-1);
  5158.     debug(F100,"X.25 reset","",0);
  5159.     return(0);
  5160. }
  5161.  
  5162. /* Clear X.25 virtual circuit */
  5163. int
  5164. x25clear() {
  5165.     int i;
  5166.     debug(F100,"X.25 clear","",0);
  5167.     bzero ((char *)&diag,sizeof(diag));
  5168.     diag.flags = (1 << DIAG_TYPE);
  5169.     diag.datalen = 2;
  5170.     diag.data[0] = 0;
  5171.     diag.data[1] = 0;
  5172.     ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
  5173.     return(ttclos(0));            /* Close socket */
  5174. }
  5175.  
  5176. /* X.25 status */
  5177. int
  5178. x25stat() {
  5179.     if (ttyfd == -1) return (-1);
  5180.     return(0);
  5181. }
  5182.  
  5183. /* Set Q_BIT on */
  5184. VOID
  5185. setqbit() {
  5186.     static int qbiton = 1 << Q_BIT;
  5187.     ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
  5188. }
  5189.  
  5190. /* Set Q_BIT off */
  5191. VOID
  5192. resetqbit() {
  5193.     static int qbitoff = 0;
  5194.     ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
  5195. }
  5196.  
  5197. /* Read n characters from X.25 circuit into buf */
  5198.  
  5199. int
  5200. x25xin(n,buf) int n; CHAR *buf; {
  5201.     register int x, c;
  5202.     int qpkt;
  5203.  
  5204.     do {
  5205.     x = read(ttyfd,buf,n);
  5206.     if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
  5207.         /* If return -1 : invitation to clear; -2 : PAD changes */
  5208.         if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
  5209.         qpkt = 1;
  5210.     } else qpkt = 0;
  5211.     } while (qpkt);
  5212.     if (x > 0) buf[x] = '\0';
  5213.     if (x < 1) x = -1;
  5214.     debug(F101,"x25xin x","",x);
  5215.  
  5216.     return(x);
  5217. }
  5218.  
  5219. #ifdef COMMENT /* NO LONGER NEEDED! */
  5220. /* X.25 read a line */
  5221.  
  5222. int
  5223. #ifdef PARSENSE
  5224. #ifdef CK_ANSIC
  5225. x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
  5226. #else
  5227. x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
  5228. #endif /* CK_ANSIC */
  5229. #else /* not PARSENSE */
  5230. #ifdef CK_ANSIC
  5231. x25inl(CHAR *dest, int max,int timo, CHAR eol)
  5232. #else
  5233. x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
  5234. #endif /* __SDTC__ */
  5235. #endif /*PARSENSE */
  5236.  /* x25inl */ {
  5237.     CHAR *pdest;
  5238.     int pktype, goteol, rest, n;
  5239.     int i, flag = 0;
  5240.     extern int ttprty, ttpflg;
  5241.     int ttpmsk;
  5242.  
  5243.     ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
  5244.  
  5245.     debug(F101,"x25inl max","",max);
  5246.     debug(F101,"x25inl eol","",eol);
  5247.     pdest  = dest;
  5248.     rest   = max;
  5249.     goteol = 0;
  5250.     do {
  5251.     n = read(ttyfd,pdest,rest);
  5252.     n--;
  5253.     pktype = *pdest & 0x7f;
  5254.     switch (pktype) {
  5255.       case 1 << Q_BIT:
  5256.         if (qbitpkt(pdest+1,--n) < 0) return(-2);
  5257.         break;
  5258.       default:
  5259.         if (flag == 0) { /* if not in packet, search start */
  5260.         for (i = 1; (i < n) &&
  5261.              !(flag = ((dest[i] & 0x7f) == start));
  5262.              i++);
  5263.         if (flag == 0) { /* not found, discard junk */
  5264.             debug(F101,"x25inl skipping","",n);
  5265.             continue;
  5266.         } else {        /* found, discard junk before start */
  5267.             int k;
  5268.             n = n - i + 1;
  5269.             for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
  5270.         }
  5271.         }
  5272.         for (i = 0; (i < n) && /* search for eol */
  5273.          !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
  5274.          i++,pdest++);
  5275.         *pdest = '\0';
  5276.         rest -= n;
  5277.     }
  5278.     } while ((rest > 0) && (!goteol));
  5279.  
  5280.     if (goteol) {
  5281.     n = max - rest;
  5282.     debug (F111,"x25inl X.25 got",(char *) dest,n);
  5283.     if (timo) ttimoff();
  5284.     if (ttpflg++ == 0 && ttprty == 0) {
  5285.         if ((ttprty = parchk(dest,start,n)) > 0) {
  5286.         int j;
  5287.         debug(F101,"x25inl senses parity","",ttprty);
  5288.         debug(F110,"x25inl packet before",(char *)dest,0);
  5289.         ttpmsk = 0x7f;
  5290.         for (j = 0; j < n; j++)
  5291.           dest[j] &= 0x7f; /* Strip parity from packet */
  5292.         debug(F110,"x25inl packet after ",dest,0);
  5293.         } else {
  5294.         debug(F101,"parchk","",ttprty);
  5295.         if (ttprty < 0) { ttprty = 0; n = -1; }
  5296.         }
  5297.     }
  5298.     ttimoff();
  5299.     return(n);
  5300.     }
  5301.     ttimoff();
  5302.     return(-1);
  5303. }
  5304. #endif /* COMMENT */
  5305. #endif /* SUNX25 */
  5306.  
  5307. #endif /* NETCONN */
  5308.